Il reste moins de 24h pour s'inscrire à la MFFJam !

Entité Agressive type Archer // Mauvaise précision du tir


  • Correcteurs

    Bonjour les gens,

    J'ai un petit mob munis d'un fusil qui est normalement capable de canarder les gens qui passent à portée.
    Il suit bien le joueur, il tire mais là je ne dirais pas qu'il tire bien…

    Il tire surtout un peu trop haut, alors je ne sais pas si c'est l'IA des archers qui voudrait qu'ils tirent plus haut pour compenser la gravité des flèches, mais les entités qui servent de balles n'y sont pas soumises.

    Du coup le mob ne tire "passablement" bien que si on s'approche de lui.
    Voici la classe du monstre:

    package fr.powergame.modpg2.common;
    
    import net.minecraft.entity.EntityLivingBase;
    import net.minecraft.entity.IRangedAttackMob;
    import net.minecraft.entity.SharedMonsterAttributes;
    import net.minecraft.entity.ai.EntityAIArrowAttack;
    import net.minecraft.entity.ai.EntityAIAttackOnCollide;
    import net.minecraft.entity.ai.EntityAIHurtByTarget;
    import net.minecraft.entity.ai.EntityAINearestAttackableTarget;
    import net.minecraft.entity.monster.EntityMob;
    import net.minecraft.entity.player.EntityPlayer;
    import net.minecraft.item.ItemStack;
    import net.minecraft.nbt.NBTTagCompound;
    import net.minecraft.world.World;
    
    public class EntityMobGangster3 extends EntityMob implements IRangedAttackMob
    {
         private EntityAIArrowAttack aiArrowAttack = new EntityAIArrowAttack(this, 1.0D, 20, 60, 15.0F);
         private EntityAIAttackOnCollide aiAttackOnCollide = new EntityAIAttackOnCollide(this, EntityPlayer.class, 1.2D, false);
         private static final ItemStack defaultHeldItem;
    
        public EntityMobGangster3(World world)
        {
            super(world);
            this.targetTasks.addTask(1, new EntityAIHurtByTarget(this, false));
            this.targetTasks.addTask(2, new EntityAINearestAttackableTarget(this, EntityPlayer.class, 0, true));
            if (world != null && !world.isRemote)
            {
                this.setCombatTask();
            }
        }
    
        protected int getExperiencePoints(EntityPlayer p_70693_1_)
        {
            return this.experienceValue = 0;
        }
    
        public void applyEntityAttributes()
        {
            super.applyEntityAttributes();
            this.getEntityAttribute(SharedMonsterAttributes.maxHealth).setBaseValue(60D);
            this.getEntityAttribute(SharedMonsterAttributes.attackDamage).setBaseValue(18D);
            this.getEntityAttribute(SharedMonsterAttributes.knockbackResistance).setBaseValue(0.5D);
            this.getEntityAttribute(SharedMonsterAttributes.movementSpeed).setBaseValue(0.3D);
        }
    
        protected void entityInit()
        {
            super.entityInit();
            this.dataWatcher.addObject(13, new Byte((byte)0));
        }
    
        public ItemStack getHeldItem()
        {
            return defaultHeldItem;
        }
    
        public boolean isAIEnabled()
        {
            return true;
        }
    
    //    protected String getHurtSound()
    //    {
    //        return "mob.skeleton.hurt";
    //    }
    //    
    //    protected String getDeathSound()
    //    {
    //        return "mob.skeleton.death";
    //    }
    
        public void setCombatTask()
        {
            this.tasks.removeTask(this.aiAttackOnCollide);
            this.tasks.removeTask(this.aiArrowAttack);
            ItemStack itemstack = this.getHeldItem();
    
            if (itemstack != null && itemstack.getItem() == ModPg2.itemSPR)
            {
                this.tasks.addTask(4, this.aiArrowAttack);
            }
            else
            {
                this.tasks.addTask(4, this.aiAttackOnCollide);
            }
        }
    
        @Override
        public void attackEntityWithRangedAttack(EntityLivingBase entity, float f)
        {
            EntityBulletSPR entityBulletSPR = new EntityBulletSPR(this.worldObj, this, entity, 2.0F, (float)(14 - this.worldObj.difficultySetting.getDifficultyId() * 4));
            this.worldObj.playSoundAtEntity(entity, "modPg2:thomson", 0.8F, 0.5F);
            this.worldObj.spawnEntityInWorld(entityBulletSPR);
            entityBulletSPR.setDamage((double)(f * 20.0F) + this.rand.nextGaussian() * 0.25D + (double)((float)this.worldObj.difficultySetting.getDifficultyId() * 0.11F));
        }
    
        static
        {
            defaultHeldItem = new ItemStack(ModPg2.itemSPR, 1);
        }
    
        public void readEntityFromNBT(NBTTagCompound nbt)
        {
            super.readEntityFromNBT(nbt);
            this.setCombatTask();
        }
    
        public void writeEntityToNBT(NBTTagCompound nbt)
        {
            super.writeEntityToNBT(nbt);
        }
    }
    


  • Il faut voir ça dans la classe de l'entité car ici tout ce que l'entité fait c'est tiré la flèche mais il n'y a aucun calcul de trajectoire.


  • Correcteurs

    Oh, je pensais que la trajectoire était avant tout fonction de l'action du mob.

    Voici la classe de l'entité, tirée avec l'arme en main du joueur, ça tire bien droit, là où on vise quoi.

    package fr.powergame.modpg2.common;
    
    import net.minecraft.entity.Entity;
    import net.minecraft.entity.EntityLivingBase;
    import net.minecraft.entity.projectile.EntityThrowable;
    import net.minecraft.util.DamageSource;
    import net.minecraft.util.EntityDamageSourceIndirect;
    import net.minecraft.util.MathHelper;
    import net.minecraft.util.MovingObjectPosition;
    import net.minecraft.world.World;
    
    public class EntityBulletSPR extends EntityThrowable
    {
        public float strength;
        public int ticksAlive;
        private EntityLivingBase thrower;
        public Entity shootingEntity;
        private double damage = 20.0D;
    
        public EntityBulletSPR(World worldIn)
        {
            super(worldIn);
            strength = 20F;
            this.setSize(0.3F, 0.3F);
            this.setThrowableHeading(this.motionX, this.motionY, this.motionZ, this.func_70182_d(), 1.0F);
        }
    
        public EntityBulletSPR(World worldIn, EntityLivingBase throwerIn)
        {
            super(worldIn, throwerIn);
            this.thrower = throwerIn;
            strength = 20F;
            this.setSize(0.3F, 0.3F);
            this.setThrowableHeading(this.motionX, this.motionY, this.motionZ, this.func_70182_d(), 1.0F);
        }
    
        public EntityBulletSPR(World worldIn, double x, double y, double p_i1778_6_)
        {
            super(worldIn, x, y, p_i1778_6_);
            strength = 20F;
            this.setSize(0.3F, 0.3F);
            this.setThrowableHeading(this.motionX, this.motionY, this.motionZ, this.func_70182_d(), 1.0F);
        }
    
        public EntityBulletSPR(World world, EntityLivingBase shooter, EntityLivingBase target, float f0, float f1)
        {
            super(world);
            this.renderDistanceWeight = 10.0D;
            this.shootingEntity = shooter;
    
            this.posY = shooter.posY + (double)shooter.getEyeHeight() - 0.25D;
            double d0 = target.posX - shooter.posX;
            double d1 = target.boundingBox.minY + (double)(target.height / 3.0F) - this.posY;
            double d2 = target.posZ - shooter.posZ;
            double d3 = (double)MathHelper.sqrt_double(d0 * d0 + d2 * d2);
    
            if (d3 >= 1.0E-7D)
            {
                float f2 = (float)(Math.atan2(d2, d0) * 180.0D / Math.PI) - 90.0F;
                float f3 = (float)(-(Math.atan2(d1, d3) * 180.0D / Math.PI));
                double d4 = d0 / d3;
                double d5 = d2 / d3;
                this.setLocationAndAngles(shooter.posX + d4, this.posY, shooter.posZ + d5, f2, f3);
                this.yOffset = 0.0F;
                float f4 = (float)d3 * 0.2F;
                this.setThrowableHeading(d0, d1 + (double)f4, d2, f0, f1);
            }
        }
    
        public void setArrowHeading(double d, double d1, double d2, float spread, float speed)
        {
            spread /= 2F;
            float f2 = MathHelper.sqrt_double(d * d + d1 * d1 + d2 * d2);
            d /= f2;
            d1 /= f2;
            d2 /= f2;
            d *= speed;
            d1 *= speed;
            d2 *= speed;
            d += rand.nextGaussian() * spread * speed * 0.005D ;
            d1 += rand.nextGaussian() * spread * speed * 0.005D ;
            d2 += rand.nextGaussian() * spread * speed * 0.005D ;
            this.motionX *= d;
            this.motionY *= d1;
            this.motionZ *= d2;
            float f3 = MathHelper.sqrt_double(d * d + d2 * d2);
            prevRotationYaw = rotationYaw = (float) ((Math.atan2(d, d2) * 180D) / 3.1415927410125732D);
            prevRotationPitch = rotationPitch = (float) ((Math.atan2(d1, f3) * 180D) / 3.1415927410125732D);    
        }
    
        public void setDamage(double p_70239_1_)
        {
            this.damage = p_70239_1_;
        }
    
        public double getDamage()
        {
            return this.damage;
        }
    
        @Override
        protected void onImpact(MovingObjectPosition mop)
        {
            DamageSource spr = new EntityDamageSourceIndirect("SPR", this, this.thrower).setProjectile();
            if(mop.entityHit != null)
            {
                mop.entityHit.attackEntityFrom(spr, (float) (mop.entityHit instanceof EntityLivingBase ? this.damage : this.damage));
                setDead();
            }
            else
            {
                setDead();
            }
        }
    
        public void onUpdate()
        {
            if(ticksAlive++>200)
            {
                setDead();
            }
            super.onUpdate();
        }
    
        protected float getGravityVelocity()
        {
            return 0.0F;
        }
    }
    


  • Normal car tu utilises surement un autre constructeur que celui de ton mob.

    Si ta balle n'est pas soumise à la gravité ce sera plus facile, dans le dernier constructeur il faudra modifier tout ce qui est trigonométrie et le refaire, je te conseille pour cela de bien identifier chaque variable pour ensuite retirer tout ce dont tu n'as pas besoin (petite aide : vu que tu n'as pas de gravité, les calculs sur l'axe Y seront allégés)



  • Il serait plus propre de tout refaire comme SCRAREX l'a dit. Mais si tu veux directement le truc en faute, c'est le 2.0F que tu mets quand tu appelles ton constructeur, argument f0 de celui ci et spread de setThrowableHeading, sachant que spread veut dire envergure selon Google traduction.

    Envoyé de mon RAINBOW LITE 4G en utilisant Tapatalk


  • Correcteurs

    Le 2.0F (dans la classe du mob) je l'ai fais varier, il gère la vitesse du projectile simplement



  • Ah OK autant pour moi, mais si tu montes la vitesse, il ira plus "droit" non ?

    Envoyé de mon RAINBOW LITE 4G en utilisant Tapatalk


  • Correcteurs

    C'est possible. Je sais déjà quel paramètre modifier dans la classe du projectile pour régler la précision.

    Mon problème est plus simple que ça je pense, c'est que mon entité vise trop haut.



  • public EntityBulletSPR(World world, EntityLivingBase shooter, EntityLivingBase target, float f0, float f1)
    {
    super(world);
    this.renderDistanceWeight = 10.0D;
    this.shootingEntity = shooter;
    
    this.posY = shooter.posY + (double)shooter.getEyeHeight() - 0.25D; // On positionne la flèche pour qu'elle parte de la tête du tireur
    double d0 = target.posX - shooter.posX; // Différence sur l'axe X
    double d1 = target.boundingBox.minY + (double)(target.height / 3.0F) - this.posY; // Différence sur l'axe Y (je suppose que le code supplémentaire permet de viser au 1/3 de la cible)
    double d2 = target.posZ - shooter.posZ; // Différence sur l'axe Z
    double d3 = (double)MathHelper.sqrt_double(d0 * d0 + d2 * d2); // Distance séparant les 2 entités sur l'axe X et Z (la hauteur n'est pas prise en compte)
    
    if (d3 >= 1.0E-7D) // Si la cible n'est pas collée au tireur
    {
    float f2 = (float)(Math.atan2(d2, d0) * 180.0D / Math.PI) - 90.0F; // Calcul de la direction sur le plan X,Z
    float f3 = (float)(-(Math.atan2(d1, d3) * 180.0D / Math.PI)); // Calcul de la direction sur le plan X,Y
    double d4 = d0 / d3; // distance sur l'axe X au lancement
    double d5 = d2 / d3; // distance sur l'axe Z au lancement
    this.setLocationAndAngles(shooter.posX + d4, this.posY, shooter.posZ + d5, f2, f3); // On place l'entité et on lui donne la direction
    this.yOffset = 0.0F;
    float f4 = (float)d3 * 0.2F; // Calcul de la hauteur (compensation de la gravité)
    this.setThrowableHeading(d0, d1 + (double)f4, d2, f0, f1); // On lui donne la direction
    }
    }
    

    J'ai commenté le code, je ne suis pas sûr que tout soit juste mais ça devrait t'aider


  • Correcteurs

    Parfait, un grand merci pour toutes ces annotations, cela m'a grandement aidé.

    J'ai réduis le coeff du f4 et j'ai indiqué un f1 de 0.5F (la précision jouait quand même au final)

    Du coup, ce mob est un redoutable sniper  maintenant 😃 Merci