# tAPI[Tutorial] Summoner Weapon (Programming knowledge required)

Hola, I'm trying to make a Sniper Summon who has Frost Hydra AI, but shoots a certain bullet.

float moveToX = projectile.position.X;
float moveToY = projectile.position.Y;
float moveDist = 100000f; //This is basically the view range of your minion; you might want to make it slightly larger than this.
int attacking = -1;
for(int k = 0; k < 200; k++)
{
if(Main.npc[k].active && !Main.npc[k].dontTakeDamage && !Main.npc[k].friendly && Main.npc[k].lifeMax > 5)
{
float monsterX = Main.npc[k].position.X + (float)(Main.npc[k].width / 2);
float monsterY = Main.npc[k].position.Y + (float)(Main.npc[k].height / 2);
float monsterDist = System.Math.Abs(projectile.position.X + (float)(projectile.width / 2) - monsterX) + System.Math.Abs(projectile.position.Y + (float)(projectile.height / 2) - monsterY);
if(monsterDist < moveDist)
{
if(monsterDist < moveDist && Collision.CanHit(projectile.position, projectile.width, projectile.height, Main.npc[k].position, Main.npc[k].width, Main.npc[k].height))
{
moveDist = monsterDist;
moveToX = monsterX;
moveToY = monsterY;
attacking = k;
}
}
}
}
moveDist is the distance from the distance from the nearest monster your projectile can see; moveToX and moveToY specify the location of this monster; and attacking is the index location of the monster in Main.npc.
Where do i put this piece of code?
also, you haven't really said where any of these should be so it's kind of hard to figure out

Where do i put this piece of code?
also, you haven't really said where any of these should be so it's kind of hard to figure out
You'd put that in the AI method, where the comment says to do what the minion what normally do (attacking enemies or following the player).

Does anyone know how to give a buff to the player when they have a helmet equipped and also (at a different time) have a full armor set on?

Now that r15 for tAPI has finally been released, I've updated my tutorial. Basically, a bug was fixed so that we don't need to manually despawn minions anymore. This means that we don't need a ModItem class anymore, so that's less source code we need to copy!
Now to wait for the same bug to be fixed with Damage...
Also, I recognized that the AI part (ModProjectile) of the tutorial was a bit lacking, so I included a link to my NPC AI tutorial, since NPCs and projectiles are very similar.

Also I finally get to use the thread changelog I had at the end of the post, lol

Now that r15 for tAPI has finally been released, I've updated my tutorial. Basically, a bug was fixed so that we don't need to manually despawn minions anymore. This means that we don't need a ModItem class anymore, so that's less source code we need to copy!
Now to wait for the same bug to be fixed with Damage...
Also, I recognized that the AI part (ModProjectile) of the tutorial was a bit lacking, so I included a link to my NPC AI tutorial, since NPCs and projectiles are very similar.

Also I finally get to use the thread changelog I had at the end of the post, lol

Less hard code?

Less hard code?
To be honest, the code doesn't really become any easier; we just don't need to copy over a bunch of source code anymore to free minion slots.

To be honest, the code doesn't really become any easier; we just don't need to copy over a bunch of source code anymore to free minion slots.

Question: If I want it to be that when you crit, you get 1 of 5 buffs, will this code work?
Code:
``````using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

using TAPI;
using Terraria;

namespace Terra.Items
{
{
public override void DamageNPC(Player p, NPC n, int hitDir, ref int damage, ref float knockback, ref bool crit, ref float critMult)
{
if (crit)
{
if (Main.rand.Next(5) == 0)
{
}

else
{
}

else
{
}

else
{
}

else
{
}
}
}
}
}``````

Question: If I want it to be that when you crit, you get 1 of 5 buffs, will this code work?
Code:
``````using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

using TAPI;
using Terraria;

namespace Terra.Items
{
{
public override void DamageNPC(Player p, NPC n, int hitDir, ref int damage, ref float knockback, ref bool crit, ref float critMult)
{
if (crit)
{
if (Main.rand.Next(5) == 0)
{
}

else
{
}

else
{
}

else
{
}

else
{
}
}
}
}
}``````
It looks like you have the right idea; it's just the syntax that's incorrect. Specifically, this part of the code:
Code:
``````if (Main.rand.Next(5) == 0)
{
}

else
{
}

else
{
}

else
{
}

else
{
}``````
What you want to do is assign the random number to a variable, then use that variable either in an if/else chain or a switch statement, like this:
Code:
``````int choice = Main.rand.Next(5);
if(choice == 0)
{
}
else if(choice == 1)
{
}
else if(choice == 2)
{
//etc.
}``````
All the way to if(choice == 4). If you want to use a switch statement instead, then it would work something like this:
Code:
``````int choice = Main.rand.Next(5);
switch(choice)
{
case 0:
break;
case 1:
break;
case 2:
//etc.
break;
case 3:
//etc.
break;
default:
//this is the last choice
break;
}``````

It looks like you have the right idea; it's just the syntax that's incorrect. Specifically, this part of the code:
Code:
``````if (Main.rand.Next(5) == 0)
{
}

else
{
}

else
{
}

else
{
}

else
{
}``````
What you want to do is assign the random number to a variable, then use that variable either in an if/else chain or a switch statement, like this:
Code:
``````int choice = Main.rand.Next(5);
if(choice == 0)
{
}
else if(choice == 1)
{
}
else if(choice == 2)
{
//etc.
}``````
All the way to if(choice == 4). If you want to use a switch statement instead, then it would work something like this:
Code:
``````int choice = Main.rand.Next(5);
switch(choice)
{
case 0:
break;
case 1:
break;
case 2:
//etc.
break;
case 3:
//etc.
break;
default:
//this is the last choice
break;
}``````

Testing it right now. Hope it works!

Sweet Ill definitly use this in my new mod, been wanting a summoner weapon for awhile and this is very helpful.

FOR THE LIFE OF ME, WHY ISN'T MY PROJECTILE DOING DAMAGE (MINION)?

Code:
``````{
"displayName": "Piranha Minion",
"tip": "This is a Piranha Minion. Yay, a Summoner Weapon.",
"noTimer": true
}``````
Code:
``````using System;
using Terraria;
using TAPI;

namespace Terra.Buffs {
public class Piranhaminion : ModBuff
{
public override void Start(Player player, int index)
{
player.buffTime[index] = 3600;
}

public override void MidUpdate(Player player)
{
bool flag = false;
for(int k = 0; k < 1000; k++)
{
if(Main.projectile[k].active && Main.projectile[k].owner == player.whoAmI && Main.projectile[k].type == ProjDef.byName["Terra:Piranhasummon"].type)
{
flag = true;
break;
}
}
MPlayer modPlayer = player.GetSubClass<MPlayer>();
if(flag)
{
modPlayer.ModMinion = true;
}
int type = BuffDef.byName["Terra:Piranhaminion"];
int index = -1;
for(int k = 0; k < player.maxBuffs; k++)
{
if(player.buffType[k] == type)
{
index = k;
break;
}
}
if(index < 0)
{
return;
}
if(!modPlayer.ModMinion)
{
player.DelBuff(index);
}
else
{
player.buffTime[index] = 18000;
}
}
}}``````
Code:
``````{
"displayName": "Piranha Summon",
"size": [28, 22],
"aiStyle": 54, //This is the Raven AI. List of different summon AIs below.
"timeLeft": 99999999999999999999999999, //Just to make sure the projectile doesn't despawn.
"friendly": true,
"hostile": false,
"damage": 13,//Damage projectiles from this summon do.
"minionSlots": 1, //Takes up 1 minion slot
"penetrate": -1 //Lasts forever
}``````
Code:
``````using System;
using Microsoft.Xna.Framework;
using Terraria;
using TAPI;

namespace Terra.Projectiles {

public class Piranhasummon : ModProjectile
{
//If you want to store information, place fields here.

public override void AI()
{
Player owner = Main.player[projectile.owner];
if (owner == null || !owner.active || owner.dead)
{
projectile.Kill();
return;
}
if (Main.myPlayer == owner.whoAmI)
{
int id = owner.HasBuff("Terra:Piranhaminion");
if(id == -1)
{
projectile.Kill();
return;
}
}
}

private void UpdateFrame()
{
//Set projectile.frame here based on your projectile's state. I'll explain what this is later. To keep track of animation time, you can use projectile.frameCounter.
//projectile.frameCounter++; //Only if you are using projectile.frameCounter.
//projectile.frameCounter %= 10; //Or however long you want one cycle of animation to last.
}
}}``````
Code:
``````{
"displayName": "Piranha Staff",
"size": [84, 84],
"maxStack": 1,
"value": [0, 3, 0, 0],
"rare": 2,
"useStyle": 1,
"useAnimation": 18,
"tooltip": "Spawns a Piranha that hopefully isn't buggy",
"useTime": 18,
"useSound": 44,
"damage": 8,
"knockback": 6,
"autoReuse": false,
"noMelee": true,
"buff": "Terra:Piranhaminion",
"buffTime": 99999999999999999999999,
"shoot": "Terra:Piranhasummon",
"shootSpeed": 3,
"summon": true,
"mana": 10
}``````
It builds fine, but it won't do any damage.

FOR THE LIFE OF ME, WHY ISN'T MY PROJECTILE DOING DAMAGE (MINION)?

Code:
``````{
"displayName": "Piranha Minion",
"tip": "This is a Piranha Minion. Yay, a Summoner Weapon.",
"noTimer": true
}``````
Code:
``````using System;
using Terraria;
using TAPI;

namespace Terra.Buffs {
public class Piranhaminion : ModBuff
{
public override void Start(Player player, int index)
{
player.buffTime[index] = 3600;
}

public override void MidUpdate(Player player)
{
bool flag = false;
for(int k = 0; k < 1000; k++)
{
if(Main.projectile[k].active && Main.projectile[k].owner == player.whoAmI && Main.projectile[k].type == ProjDef.byName["Terra:Piranhasummon"].type)
{
flag = true;
break;
}
}
MPlayer modPlayer = player.GetSubClass<MPlayer>();
if(flag)
{
modPlayer.ModMinion = true;
}
int type = BuffDef.byName["Terra:Piranhaminion"];
int index = -1;
for(int k = 0; k < player.maxBuffs; k++)
{
if(player.buffType[k] == type)
{
index = k;
break;
}
}
if(index < 0)
{
return;
}
if(!modPlayer.ModMinion)
{
player.DelBuff(index);
}
else
{
player.buffTime[index] = 18000;
}
}
}}``````
Code:
``````{
"displayName": "Piranha Summon",
"size": [28, 22],
"aiStyle": 54, //This is the Raven AI. List of different summon AIs below.
"timeLeft": 99999999999999999999999999, //Just to make sure the projectile doesn't despawn.
"friendly": true,
"hostile": false,
"damage": 13,//Damage projectiles from this summon do.
"minionSlots": 1, //Takes up 1 minion slot
"penetrate": -1 //Lasts forever
}``````
Code:
``````using System;
using Microsoft.Xna.Framework;
using Terraria;
using TAPI;

namespace Terra.Projectiles {

public class Piranhasummon : ModProjectile
{
//If you want to store information, place fields here.

public override void AI()
{
Player owner = Main.player[projectile.owner];
if (owner == null || !owner.active || owner.dead)
{
projectile.Kill();
return;
}
if (Main.myPlayer == owner.whoAmI)
{
int id = owner.HasBuff("Terra:Piranhaminion");
if(id == -1)
{
projectile.Kill();
return;
}
}
}

private void UpdateFrame()
{
//Set projectile.frame here based on your projectile's state. I'll explain what this is later. To keep track of animation time, you can use projectile.frameCounter.
//projectile.frameCounter++; //Only if you are using projectile.frameCounter.
//projectile.frameCounter %= 10; //Or however long you want one cycle of animation to last.
}
}}``````
Code:
``````{
"displayName": "Piranha Staff",
"size": [84, 84],
"maxStack": 1,
"value": [0, 3, 0, 0],
"rare": 2,
"useStyle": 1,
"useAnimation": 18,
"tooltip": "Spawns a Piranha that hopefully isn't buggy",
"useTime": 18,
"useSound": 44,
"damage": 8,
"knockback": 6,
"autoReuse": false,
"noMelee": true,
"buff": "Terra:Piranhaminion",
"buffTime": 99999999999999999999999,
"shoot": "Terra:Piranhasummon",
"shootSpeed": 3,
"summon": true,
"mana": 10
}``````
It builds fine, but it won't do any damage.
Hm, it's hard to tell. Did you try copying over the Damage() source code and removing the first two if statements? Also, did you try making sure projectile.friendly is true when it is attacking?

Hm, it's hard to tell. Did you try copying over the Damage() source code and removing the first two if statements? Also, did you try making sure projectile.friendly is true when it is attacking?

Friendly is set to true.

Friendly is set to true.
Have you tried setting the projectile's damage directly in the AI? For example...

Code:
``````public override void AI()
{
projectile.damage = 10;
}``````

I have a question. When you write "ExamplePlayer", what should we replace that with?
Just whatever name you want. For example, I use BluemagicPlayer since it's easy for me to remember.

or a toturial to learn c# pleaseeeeee... i really want to do it :'(

using System;
using Microsoft.Xna.Framework;
using Terraria;

namespace Hypaxi.Projectiles.Minions
{
public abstract class Mancer : Minion
{
protected float idleAccel = 0.05f;
protected float spacingMult = 1f;
protected float viewDist = 400f;
protected float chaseDist = 200f;
protected float chaseAccel = 6f;
protected float inertia = 40f;
protected float shootCool = 90f;
protected float shootSpeed;
protected int shoot;

public virtual void CreateDust()
{
}

public virtual void SelectFrame()
{
}

public override void Behavior()
{
Player player = Main.player[projectile.owner];
float spacing = (float)projectile.width * spacingMult;
for (int k = 0; k < 1000; k++)
{
Projectile otherProj = Main.projectile[k];
if (k != projectile.whoAmI && otherProj.active && otherProj.owner == projectile.owner && otherProj.type == projectile.type && System.Math.Abs(projectile.position.X - otherProj.position.X) + System.Math.Abs(projectile.position.Y - otherProj.position.Y) < spacing)
{
if (projectile.position.X < Main.projectile[k].position.X)
{
projectile.velocity.X -= idleAccel;
}
else
{
projectile.velocity.X += idleAccel;
}
if (projectile.position.Y < Main.projectile[k].position.Y)
{
projectile.velocity.Y -= idleAccel;
}
else
{
projectile.velocity.Y += idleAccel;
}
}
}
Vector2 targetPos = projectile.position;
float targetDist = viewDist;
bool target = false;
projectile.tileCollide = true;
for (int k = 0; k < 200; k++)
{
NPC npc = Main.npc[k];
if (npc.CanBeChasedBy(this, false))
{
float distance = Vector2.Distance(npc.Center, projectile.Center);
if ((distance < targetDist || !target) && Collision.CanHitLine(projectile.position, projectile.width, projectile.height, npc.position, npc.width, npc.height))
{
targetDist = distance;
targetPos = npc.Center;
target = true;
}
}
}
if (Vector2.Distance(player.Center, projectile.Center) > (target ? 1000f : 500f))
{
projectile.ai[0] = 1f;
projectile.netUpdate = true;
}
if (projectile.ai[0] == 1f)
{
projectile.tileCollide = false;
}
if (target && projectile.ai[0] == 0f)
{
Vector2 direction = targetPos - projectile.Center;
if (direction.Length() > chaseDist)
{
direction.Normalize();
projectile.velocity = (projectile.velocity * inertia + direction * chaseAccel) / (inertia + 1);
}
else
{
projectile.velocity *= (float)Math.Pow(0.97, 40.0 / inertia);
}
}
else
{
if (!Collision.CanHitLine(projectile.Center, 1, 1, player.Center, 1, 1))
{
projectile.ai[0] = 1f;
}
float speed = 6f;
if (projectile.ai[0] == 1f)
{
speed = 15f;
}
Vector2 center = projectile.Center;
Vector2 direction = player.Center - center;
projectile.ai[1] = 3600f;
projectile.netUpdate = true;
int num = 1;
for (int k = 0; k < projectile.whoAmI; k++)
{
if (Main.projectile[k].active && Main.projectile[k].owner == projectile.owner && Main.projectile[k].type == projectile.type)
{
num++;
}
}
direction.X -= (float)((10 + num * 40) * player.direction);
direction.Y -= 70f;
float distanceTo = direction.Length();
if (distanceTo > 200f && speed < 9f)
{
speed = 9f;
}
if (distanceTo < 100f && projectile.ai[0] == 1f && !Collision.SolidCollision(projectile.position, projectile.width, projectile.height))
{
projectile.ai[0] = 0f;
projectile.netUpdate = true;
}
if (distanceTo > 2000f)
{
projectile.Center = player.Center;
}
if (distanceTo > 48f)
{
direction.Normalize();
direction *= speed;
float temp = inertia / 2f;
projectile.velocity = (projectile.velocity * temp + direction) / (temp + 1);
}
else
{
projectile.direction = Main.player[projectile.owner].direction;
projectile.velocity *= (float)Math.Pow(0.9, 40.0 / inertia);
}
}
projectile.rotation = projectile.velocity.X * 0.05f;
SelectFrame();
CreateDust();
if (projectile.velocity.X > 0f)
{
projectile.spriteDirection = (projectile.direction = -1);
}
else if (projectile.velocity.X < 0f)
{
projectile.spriteDirection = (projectile.direction = 1);
}
if (projectile.ai[1] > 0f)
{
projectile.ai[1] += 1f;
if (Main.rand.Next(3) == 0)
{
projectile.ai[1] += 1f;
}
}
if (projectile.ai[1] > shootCool)
{
projectile.ai[1] = 0f;
projectile.netUpdate = true;
}
if (projectile.ai[0] == 0f)
{
if (target)
{
if ((targetPos - projectile.Center).X > 0f)
{
projectile.spriteDirection = (projectile.direction = -1);
}
else if ((targetPos - projectile.Center).X < 0f)
{
projectile.spriteDirection = (projectile.direction = 1);
}
if (projectile.ai[1] == 0f)
{
projectile.ai[1] = 1f;
if (Main.myPlayer == projectile.owner)
{
Vector2 shootVel = targetPos - projectile.Center;
if (shootVel == Vector2.Zero)
{
shootVel = new Vector2(0f, 1f);
}
shootVel.Normalize();
shootVel *= shootSpeed;
int proj = Projectile.NewProjectile(projectile.Center.X, projectile.Center.Y, shootVel.X, shootVel.Y, shoot, projectile.damage, projectile.knockBack, Main.myPlayer, 0f, 0f);
Main.projectile[proj].timeLeft = 300;
Main.projectile[proj].netUpdate = true;
projectile.netUpdate = true;
}
}
}
}
}

public override void TileCollideStyle(ref int width, ref int height, ref bool fallThrough)
{
fallThrough = true;
}
}
}

I had someone help me out with this and I'm a little bad at C so can someone explain to me why my minions sprite is flapping like a bird.

using System;
using Microsoft.Xna.Framework;
using Terraria;

namespace Hypaxi.Projectiles.Minions
{
public abstract class Mancer : Minion
{
protected float idleAccel = 0.05f;
protected float spacingMult = 1f;
protected float viewDist = 400f;
protected float chaseDist = 200f;
protected float chaseAccel = 6f;
protected float inertia = 40f;
protected float shootCool = 90f;
protected float shootSpeed;
protected int shoot;

public virtual void CreateDust()
{
}

public virtual void SelectFrame()
{
}

public override void Behavior()
{
Player player = Main.player[projectile.owner];
float spacing = (float)projectile.width * spacingMult;
for (int k = 0; k < 1000; k++)
{
Projectile otherProj = Main.projectile[k];
if (k != projectile.whoAmI && otherProj.active && otherProj.owner == projectile.owner && otherProj.type == projectile.type && System.Math.Abs(projectile.position.X - otherProj.position.X) + System.Math.Abs(projectile.position.Y - otherProj.position.Y) < spacing)
{
if (projectile.position.X < Main.projectile[k].position.X)
{
projectile.velocity.X -= idleAccel;
}
else
{
projectile.velocity.X += idleAccel;
}
if (projectile.position.Y < Main.projectile[k].position.Y)
{
projectile.velocity.Y -= idleAccel;
}
else
{
projectile.velocity.Y += idleAccel;
}
}
}
Vector2 targetPos = projectile.position;
float targetDist = viewDist;
bool target = false;
projectile.tileCollide = true;
for (int k = 0; k < 200; k++)
{
NPC npc = Main.npc[k];
if (npc.CanBeChasedBy(this, false))
{
float distance = Vector2.Distance(npc.Center, projectile.Center);
if ((distance < targetDist || !target) && Collision.CanHitLine(projectile.position, projectile.width, projectile.height, npc.position, npc.width, npc.height))
{
targetDist = distance;
targetPos = npc.Center;
target = true;
}
}
}
if (Vector2.Distance(player.Center, projectile.Center) > (target ? 1000f : 500f))
{
projectile.ai[0] = 1f;
projectile.netUpdate = true;
}
if (projectile.ai[0] == 1f)
{
projectile.tileCollide = false;
}
if (target && projectile.ai[0] == 0f)
{
Vector2 direction = targetPos - projectile.Center;
if (direction.Length() > chaseDist)
{
direction.Normalize();
projectile.velocity = (projectile.velocity * inertia + direction * chaseAccel) / (inertia + 1);
}
else
{
projectile.velocity *= (float)Math.Pow(0.97, 40.0 / inertia);
}
}
else
{
if (!Collision.CanHitLine(projectile.Center, 1, 1, player.Center, 1, 1))
{
projectile.ai[0] = 1f;
}
float speed = 6f;
if (projectile.ai[0] == 1f)
{
speed = 15f;
}
Vector2 center = projectile.Center;
Vector2 direction = player.Center - center;
projectile.ai[1] = 3600f;
projectile.netUpdate = true;
int num = 1;
for (int k = 0; k < projectile.whoAmI; k++)
{
if (Main.projectile[k].active && Main.projectile[k].owner == projectile.owner && Main.projectile[k].type == projectile.type)
{
num++;
}
}
direction.X -= (float)((10 + num * 40) * player.direction);
direction.Y -= 70f;
float distanceTo = direction.Length();
if (distanceTo > 200f && speed < 9f)
{
speed = 9f;
}
if (distanceTo < 100f && projectile.ai[0] == 1f && !Collision.SolidCollision(projectile.position, projectile.width, projectile.height))
{
projectile.ai[0] = 0f;
projectile.netUpdate = true;
}
if (distanceTo > 2000f)
{
projectile.Center = player.Center;
}
if (distanceTo > 48f)
{
direction.Normalize();
direction *= speed;
float temp = inertia / 2f;
projectile.velocity = (projectile.velocity * temp + direction) / (temp + 1);
}
else
{
projectile.direction = Main.player[projectile.owner].direction;
projectile.velocity *= (float)Math.Pow(0.9, 40.0 / inertia);
}
}
projectile.rotation = projectile.velocity.X * 0.05f;
SelectFrame();
CreateDust();
if (projectile.velocity.X > 0f)
{
projectile.spriteDirection = (projectile.direction = -1);
}
else if (projectile.velocity.X < 0f)
{
projectile.spriteDirection = (projectile.direction = 1);
}
if (projectile.ai[1] > 0f)
{
projectile.ai[1] += 1f;
if (Main.rand.Next(3) == 0)
{
projectile.ai[1] += 1f;
}
}
if (projectile.ai[1] > shootCool)
{
projectile.ai[1] = 0f;
projectile.netUpdate = true;
}
if (projectile.ai[0] == 0f)
{
if (target)
{
if ((targetPos - projectile.Center).X > 0f)
{
projectile.spriteDirection = (projectile.direction = -1);
}
else if ((targetPos - projectile.Center).X < 0f)
{
projectile.spriteDirection = (projectile.direction = 1);
}
if (projectile.ai[1] == 0f)
{
projectile.ai[1] = 1f;
if (Main.myPlayer == projectile.owner)
{
Vector2 shootVel = targetPos - projectile.Center;
if (shootVel == Vector2.Zero)
{
shootVel = new Vector2(0f, 1f);
}
shootVel.Normalize();
shootVel *= shootSpeed;
int proj = Projectile.NewProjectile(projectile.Center.X, projectile.Center.Y, shootVel.X, shootVel.Y, shoot, projectile.damage, projectile.knockBack, Main.myPlayer, 0f, 0f);
Main.projectile[proj].timeLeft = 300;
Main.projectile[proj].netUpdate = true;
projectile.netUpdate = true;
}
}
}
}
}

public override void TileCollideStyle(ref int width, ref int height, ref bool fallThrough)
{
fallThrough = true;
}
}
}

I had someone help me out with this and I'm a little bad at C so can someone explain to me why my minions sprite is flapping like a bird.

I forgot to make multiple sprite parts for it oops.

what do you with the enemy detection.