[W.I.P] [Entitées] Diverses entitées !
-
Ce tutoriel est en chantier…
-J’m’appelle Teuse
-Et moi Sonneuse
-Bon ok…Il traîtera un grand nombre de personnalisation d’entitées ! (Grimpe aux murs, Rotation à la mort, Yeux brillants, Saut lors d’une attaque, téléportation…) Bref, y’en aura pour tout les goûts !
Il sera disponible dans un petit moment, mais vous pouvez voir son avancement ci-dessous !
Si le tutoriel est vraiment trop gros graphiquement il sera coupé en plusieurs petit tutoriels !
Sommaire
- Introduction
- Pré-requis
- Code
- Entité Simple Voir tutoriel “Créer un mob basique” de Robin
- Téléportation Comme L’enderman
- Escalade Comme l’araignée
- Nyctalopie Yeux qui brillent dans le noir
- Death Rotation Render de l’araignée
- Son(s) “Secret”
- Saut lors d’une attaque Comme l’araignée
- Drop(Simple/Avancé) Comme la sorcière
- Boule de feu Comme le Ghast
- Résultat
- Crédits
Introduction
Yellow tout le monde !
Préparez-vous pour un long tutoriel ! Sur différentes entitées, qui se retrouveront en UNE seul et même créature !
Tout ce que je vais faire ici vous pouvez vous même le faire c’est tout droit sortit des code de base de Minecraft ! Mais je vous mâche le travail !
Pré-requis
-Avoir une entitée simple, tutoriel disponible ICI
-Du temps, BEAUCOUP de temps !Code
Entité Simple
Je me répète mais allez voir ICI. Je me base entièrement de ce code ! (Rendu/Entité/Model)
Vous devriez avoir, donc, un mob agressif mais extrèmement stupide !
package fr.mff.zeamateis; import net.minecraft.entity.SharedMonsterAttributes; import net.minecraft.entity.monster.EntityMob; import net.minecraft.world.World; public class EntityTutoMFF extends EntityMob { public EntityTutoMFF(World world) { super(world); } public void applyEntityAttributes() { super.applyEntityAttributes(); this.getEntityAttribute(SharedMonsterAttributes.maxHealth).setAttribute(20D); this.getEntityAttribute(SharedMonsterAttributes.attackDamage).setAttribute(3D); this.getEntityAttribute(SharedMonsterAttributes.knockbackResistance).setAttribute(1D); this.getEntityAttribute(SharedMonsterAttributes.movementSpeed).setAttribute(0.8D); } }
Passons à la partie téléportation tout droit sortie du code de l’enderman !
Téléportation
Sans plus attendre allez voir le code de l’enderman !
Nous voyons déjà ça:
private int teleportDelay;
Le délais de téléportation, il nous sera utile !
Nous avons plus bas quelques code bien utile eux aussi pour la téléportation !
/** * Teleport the enderman to a random nearby position */ protected boolean teleportRandomly() { double d0 = this.posX + (this.rand.nextDouble() - 0.5D) * 64.0D; double d1 = this.posY + (double)(this.rand.nextInt(64) - 32); double d2 = this.posZ + (this.rand.nextDouble() - 0.5D) * 64.0D; return this.teleportTo(d0, d1, d2); } /** * Teleport the enderman to another entity */ protected boolean teleportToEntity(Entity par1Entity) { Vec3 vec3 = this.worldObj.getWorldVec3Pool().getVecFromPool(this.posX - par1Entity.posX, this.boundingBox.minY + (double)(this.height / 2.0F) - par1Entity.posY + (double)par1Entity.getEyeHeight(), this.posZ - par1Entity.posZ); vec3 = vec3.normalize(); double d0 = 16.0D; double d1 = this.posX + (this.rand.nextDouble() - 0.5D) * 8.0D - vec3.xCoord * d0; double d2 = this.posY + (double)(this.rand.nextInt(16) - 8) - vec3.yCoord * d0; double d3 = this.posZ + (this.rand.nextDouble() - 0.5D) * 8.0D - vec3.zCoord * d0; return this.teleportTo(d1, d2, d3); } /** * Teleport the enderman */ protected boolean teleportTo(double par1, double par3, double par5) { EnderTeleportEvent event = new EnderTeleportEvent(this, par1, par3, par5, 0); if (MinecraftForge.EVENT_BUS.post(event)){ return false; } double d3 = this.posX; double d4 = this.posY; double d5 = this.posZ; this.posX = event.targetX; this.posY = event.targetY; this.posZ = event.targetZ; boolean flag = false; int i = MathHelper.floor_double(this.posX); int j = MathHelper.floor_double(this.posY); int k = MathHelper.floor_double(this.posZ); int l; if (this.worldObj.blockExists(i, j, k)) { boolean flag1 = false; while (!flag1 && j > 0) { l = this.worldObj.getBlockId(i, j - 1, k); if (l != 0 && Block.blocksList[l].blockMaterial.blocksMovement()) { flag1 = true; } else { --this.posY; --j; } } if (flag1) { this.setPosition(this.posX, this.posY, this.posZ); if (this.worldObj.getCollidingBoundingBoxes(this, this.boundingBox).isEmpty() && !this.worldObj.isAnyLiquid(this.boundingBox)) { flag = true; } } } if (!flag) { this.setPosition(d3, d4, d5); return false; } else { short short1 = 128; for (l = 0; l < short1; ++l) { double d6 = (double)l / ((double)short1 - 1.0D); float f = (this.rand.nextFloat() - 0.5F) * 0.2F; float f1 = (this.rand.nextFloat() - 0.5F) * 0.2F; float f2 = (this.rand.nextFloat() - 0.5F) * 0.2F; double d7 = d3 + (this.posX - d3) * d6 + (this.rand.nextDouble() - 0.5D) * (double)this.width * 2.0D; double d8 = d4 + (this.posY - d4) * d6 + this.rand.nextDouble() * (double)this.height; double d9 = d5 + (this.posZ - d5) * d6 + (this.rand.nextDouble() - 0.5D) * (double)this.width * 2.0D; this.worldObj.spawnParticle("portal", d7, d8, d9, (double)f, (double)f1, (double)f2); } this.worldObj.playSoundEffect(d3, d4, d5, "mob.endermen.portal", 1.0F, 1.0F); this.playSound("mob.endermen.portal", 1.0F, 1.0F); return true; } }
Mixons tout ça pour le mettre dans la classe de notre entité !
Pour que nous ayons ceci:
package fr.mff.zeamateis; import net.minecraft.block.Block; import net.minecraft.entity.Entity; import net.minecraft.entity.SharedMonsterAttributes; import net.minecraft.entity.monster.EntityMob; import net.minecraft.util.MathHelper; import net.minecraft.util.Vec3; import net.minecraft.world.World; import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.event.entity.living.EnderTeleportEvent; public class EntityTutoMFF extends EntityMob { private int teleportDelay; public EntityTutoMFF(World world) { super(world); } public void applyEntityAttributes() { super.applyEntityAttributes(); this.getEntityAttribute(SharedMonsterAttributes.maxHealth).setAttribute(20D); this.getEntityAttribute(SharedMonsterAttributes.attackDamage).setAttribute(3D); this.getEntityAttribute(SharedMonsterAttributes.knockbackResistance).setAttribute(1D); this.getEntityAttribute(SharedMonsterAttributes.movementSpeed).setAttribute(0.8D); } /** * Teleport the ENTITYTUTO to a random nearby position */ protected boolean teleportRandomly() { double d0 = this.posX + (this.rand.nextDouble() - 0.5D) * 64.0D; double d1 = this.posY + (double)(this.rand.nextInt(64) - 32); double d2 = this.posZ + (this.rand.nextDouble() - 0.5D) * 64.0D; return this.teleportTo(d0, d1, d2); } /** * Teleport the ENTITYTUTO to another entity */ protected boolean teleportToEntity(Entity par1Entity) { Vec3 vec3 = this.worldObj.getWorldVec3Pool().getVecFromPool(this.posX - par1Entity.posX, this.boundingBox.minY + (double)(this.height / 2.0F) - par1Entity.posY + (double)par1Entity.getEyeHeight(), this.posZ - par1Entity.posZ); vec3 = vec3.normalize(); double d0 = 16.0D; double d1 = this.posX + (this.rand.nextDouble() - 0.5D) * 8.0D - vec3.xCoord * d0; double d2 = this.posY + (double)(this.rand.nextInt(16) - 8) - vec3.yCoord * d0; double d3 = this.posZ + (this.rand.nextDouble() - 0.5D) * 8.0D - vec3.zCoord * d0; return this.teleportTo(d1, d2, d3); } /** * Teleport the ENTITYTUTO */ protected boolean teleportTo(double par1, double par3, double par5) { EnderTeleportEvent event = new EnderTeleportEvent(this, par1, par3, par5, 0); if (MinecraftForge.EVENT_BUS.post(event)){ return false; } double d3 = this.posX; double d4 = this.posY; double d5 = this.posZ; this.posX = event.targetX; this.posY = event.targetY; this.posZ = event.targetZ; boolean flag = false; int i = MathHelper.floor_double(this.posX); int j = MathHelper.floor_double(this.posY); int k = MathHelper.floor_double(this.posZ); int l; if (this.worldObj.blockExists(i, j, k)) { boolean flag1 = false; while (!flag1 && j > 0) { l = this.worldObj.getBlockId(i, j - 1, k); if (l != 0 && Block.blocksList[l].blockMaterial.blocksMovement()) { flag1 = true; } else { --this.posY; --j; } } if (flag1) { this.setPosition(this.posX, this.posY, this.posZ); if (this.worldObj.getCollidingBoundingBoxes(this, this.boundingBox).isEmpty() && !this.worldObj.isAnyLiquid(this.boundingBox)) { flag = true; } } } if (!flag) { this.setPosition(d3, d4, d5); return false; } else { short short1 = 128; for (l = 0; l < short1; ++l) { double d6 = (double)l / ((double)short1 - 1.0D); float f = (this.rand.nextFloat() - 0.5F) * 0.2F; float f1 = (this.rand.nextFloat() - 0.5F) * 0.2F; float f2 = (this.rand.nextFloat() - 0.5F) * 0.2F; double d7 = d3 + (this.posX - d3) * d6 + (this.rand.nextDouble() - 0.5D) * (double)this.width * 2.0D; double d8 = d4 + (this.posY - d4) * d6 + this.rand.nextDouble() * (double)this.height; double d9 = d5 + (this.posZ - d5) * d6 + (this.rand.nextDouble() - 0.5D) * (double)this.width * 2.0D; this.worldObj.spawnParticle("portal", d7, d8, d9, (double)f, (double)f1, (double)f2); } this.worldObj.playSoundEffect(d3, d4, d5, "mob.endermen.portal", 1.0F, 1.0F); this.playSound("mob.endermen.portal", 1.0F, 1.0F); return true; } } }
Mais là notre mob ne ce téléporte pas donc modifions la fonction onLivingUpdate !
Pour qu’au final elle ressemble à ça:
/** * Called frequently so the entity can update its state every tick as required. For example, zombies and skeletons * use this to react to sunlight and start to burn. */ public void onLivingUpdate() { if (this.worldObj.isDaytime() && !this.worldObj.isRemote) { float f = this.getBrightness(1.0F); if (f > 0.5F && this.worldObj.canBlockSeeTheSky(MathHelper.floor_double(this.posX), MathHelper.floor_double(this.posY), MathHelper.floor_double(this.posZ)) && this.rand.nextFloat() * 30.0F < (f - 0.4F) * 2.0F) { this.entityToAttack = null; this.teleportRandomly(); } } this.isJumping = false; if (this.entityToAttack != null) { this.faceEntity(this.entityToAttack, 100.0F, 100.0F); } if (!this.worldObj.isRemote && this.isEntityAlive()) { if (this.entityToAttack != null) { if (this.entityToAttack instanceof EntityPlayer) { if (this.entityToAttack.getDistanceSqToEntity(this) < 16.0D) { this.teleportRandomly(); } this.teleportDelay = 0; } else if (this.entityToAttack.getDistanceSqToEntity(this) > 256.0D && this.teleportDelay++ >= 30 && this.teleportToEntity(this.entityToAttack)) { this.teleportDelay = 0; } } else { this.teleportDelay = 0; } } super.onLivingUpdate(); }
Mixons tout ces codes !
Pour que nous ayons comme entité:package fr.mff.zeamateis; import net.minecraft.block.Block; import net.minecraft.entity.Entity; import net.minecraft.entity.SharedMonsterAttributes; import net.minecraft.entity.monster.EntityMob; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.util.MathHelper; import net.minecraft.util.Vec3; import net.minecraft.world.World; import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.event.entity.living.EnderTeleportEvent; public class EntityTutoMFF extends EntityMob { private int teleportDelay; public EntityTutoMFF(World world) { super(world); } public void applyEntityAttributes() { super.applyEntityAttributes(); this.getEntityAttribute(SharedMonsterAttributes.maxHealth).setAttribute(20D); this.getEntityAttribute(SharedMonsterAttributes.attackDamage).setAttribute(3D); this.getEntityAttribute(SharedMonsterAttributes.knockbackResistance).setAttribute(1D); this.getEntityAttribute(SharedMonsterAttributes.movementSpeed).setAttribute(0.8D); } /** * Called frequently so the entity can update its state every tick as required. For example, zombies and skeletons * use this to react to sunlight and start to burn. */ public void onLivingUpdate() { if (this.worldObj.isDaytime() && !this.worldObj.isRemote) { float f = this.getBrightness(1.0F); if (f > 0.5F && this.worldObj.canBlockSeeTheSky(MathHelper.floor_double(this.posX), MathHelper.floor_double(this.posY), MathHelper.floor_double(this.posZ)) && this.rand.nextFloat() * 30.0F < (f - 0.4F) * 2.0F) { this.entityToAttack = null; this.teleportRandomly(); } } this.isJumping = false; if (this.entityToAttack != null) { this.faceEntity(this.entityToAttack, 100.0F, 100.0F); } if (!this.worldObj.isRemote && this.isEntityAlive()) { if (this.entityToAttack != null) { if (this.entityToAttack instanceof EntityPlayer) { if (this.entityToAttack.getDistanceSqToEntity(this) < 16.0D) { this.teleportRandomly(); } this.teleportDelay = 0; } else if (this.entityToAttack.getDistanceSqToEntity(this) > 256.0D && this.teleportDelay++ >= 30 && this.teleportToEntity(this.entityToAttack)) { this.teleportDelay = 0; } } else { this.teleportDelay = 0; } } super.onLivingUpdate(); } /** * Teleport the ENTITYTUTO to a random nearby position */ protected boolean teleportRandomly() { double d0 = this.posX + (this.rand.nextDouble() - 0.5D) * 64.0D; double d1 = this.posY + (double)(this.rand.nextInt(64) - 32); double d2 = this.posZ + (this.rand.nextDouble() - 0.5D) * 64.0D; return this.teleportTo(d0, d1, d2); } /** * Teleport the ENTITYTUTO to another entity */ protected boolean teleportToEntity(Entity par1Entity) { Vec3 vec3 = this.worldObj.getWorldVec3Pool().getVecFromPool(this.posX - par1Entity.posX, this.boundingBox.minY + (double)(this.height / 2.0F) - par1Entity.posY + (double)par1Entity.getEyeHeight(), this.posZ - par1Entity.posZ); vec3 = vec3.normalize(); double d0 = 16.0D; double d1 = this.posX + (this.rand.nextDouble() - 0.5D) * 8.0D - vec3.xCoord * d0; double d2 = this.posY + (double)(this.rand.nextInt(16) - 8) - vec3.yCoord * d0; double d3 = this.posZ + (this.rand.nextDouble() - 0.5D) * 8.0D - vec3.zCoord * d0; return this.teleportTo(d1, d2, d3); } /** * Teleport the ENTITYTUTO */ protected boolean teleportTo(double par1, double par3, double par5) { EnderTeleportEvent event = new EnderTeleportEvent(this, par1, par3, par5, 0); if (MinecraftForge.EVENT_BUS.post(event)){ return false; } double d3 = this.posX; double d4 = this.posY; double d5 = this.posZ; this.posX = event.targetX; this.posY = event.targetY; this.posZ = event.targetZ; boolean flag = false; int i = MathHelper.floor_double(this.posX); int j = MathHelper.floor_double(this.posY); int k = MathHelper.floor_double(this.posZ); int l; if (this.worldObj.blockExists(i, j, k)) { boolean flag1 = false; while (!flag1 && j > 0) { l = this.worldObj.getBlockId(i, j - 1, k); if (l != 0 && Block.blocksList[l].blockMaterial.blocksMovement()) { flag1 = true; } else { --this.posY; --j; } } if (flag1) { this.setPosition(this.posX, this.posY, this.posZ); if (this.worldObj.getCollidingBoundingBoxes(this, this.boundingBox).isEmpty() && !this.worldObj.isAnyLiquid(this.boundingBox)) { flag = true; } } } if (!flag) { this.setPosition(d3, d4, d5); return false; } else { short short1 = 128; for (l = 0; l < short1; ++l) { double d6 = (double)l / ((double)short1 - 1.0D); float f = (this.rand.nextFloat() - 0.5F) * 0.2F; float f1 = (this.rand.nextFloat() - 0.5F) * 0.2F; float f2 = (this.rand.nextFloat() - 0.5F) * 0.2F; double d7 = d3 + (this.posX - d3) * d6 + (this.rand.nextDouble() - 0.5D) * (double)this.width * 2.0D; double d8 = d4 + (this.posY - d4) * d6 + this.rand.nextDouble() * (double)this.height; double d9 = d5 + (this.posZ - d5) * d6 + (this.rand.nextDouble() - 0.5D) * (double)this.width * 2.0D; this.worldObj.spawnParticle("portal", d7, d8, d9, (double)f, (double)f1, (double)f2); } this.worldObj.playSoundEffect(d3, d4, d5, "mob.endermen.portal", 1.0F, 1.0F); this.playSound("mob.endermen.portal", 1.0F, 1.0F); return true; } } }
Voilà ! Lancez le jeu, faites spawn votre mob et TADA ! Il se téléporte aléatoirement !!!
Passons, si vous le voulez bien à la partie escalade ! Comme le font les araignées !
Escalade
Allons voir du côté de la classe de l’araignée…
Hummm… 90% des fonctions, si vous regardez bien, sont utiles pour l’escalade !
Prenons-les une à une !Quelque chose me dit que nous en aurons besoin !
protected void entityInit() { super.entityInit(); this.dataWatcher.addObject(16, new Byte((byte)0)); }
Ensuite…
Hummm… Bah suffit de lire le commentaire !/** * Called to update the entity's position/logic. */ public void onUpdate() { super.onUpdate(); if (!this.worldObj.isRemote) { this.setBesideClimbableBlock(this.isCollidedHorizontally); } }
Ah ! Le principe même de l’escalade dans Minecraft !
/** * returns true if this entity is by a ladder, false otherwise */ public boolean isOnLadder() { return this.isBesideClimbableBlock(); }
Ouais… Si nous ne mettons pas ça nous aurons des erreurs !
/** * Returns true if the WatchableObject (Byte) is 0x01 otherwise returns false. The WatchableObject is updated using * setBesideClimableBlock. */ public boolean isBesideClimbableBlock() { return (this.dataWatcher.getWatchableObjectByte(16) & 1) != 0; } /** * Updates the WatchableObject (Byte) created in entityInit(), setting it to 0x01 if par1 is true or 0x00 if it is * false. */ public void setBesideClimbableBlock(boolean par1) { byte b0 = this.dataWatcher.getWatchableObjectByte(16); if (par1) { b0 = (byte)(b0 | 1); } else { b0 &= -2; } this.dataWatcher.updateObject(16, Byte.valueOf(b0)); }
Je vous explique les codes tout de même !
• protected void entityInit():
Fait appel des des bytes lors de l’initialisation de l’entité, il y en a dans les autres code donc si nous n’avons pas cette fonction le jeu crash !• public void onUpdate():
“Called to update the entity’s position/logic.” Dois-je traduire ?• public boolean isOnLadder():
Comme si notre entité était sur une échelle, donc elle escalade !• public boolean isBesideClimbableBlock():
Fait justement appel à ces “Bytes”, sinon crash !• public void setBesideClimbableBlock(boolean par1):
Pareil, utilise des “Bytes” pour “SET” notre entité lors de l’escalade !Voilà pour les explications !
Mixons tout ce code avec la téléportation !Et vous devriez avoir ceci:
package fr.mff.zeamateis; import net.minecraft.block.Block; import net.minecraft.entity.Entity; import net.minecraft.entity.EnumCreatureAttribute; import net.minecraft.entity.SharedMonsterAttributes; import net.minecraft.entity.monster.EntityMob; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.util.MathHelper; import net.minecraft.util.Vec3; import net.minecraft.world.World; import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.event.entity.living.EnderTeleportEvent; public class EntityTutoMFF extends EntityMob { private int teleportDelay; public EntityTutoMFF(World world) { super(world); } protected void entityInit() { super.entityInit(); this.dataWatcher.addObject(16, new Byte((byte)0)); } public void applyEntityAttributes() { super.applyEntityAttributes(); this.getEntityAttribute(SharedMonsterAttributes.maxHealth).setAttribute(20D); this.getEntityAttribute(SharedMonsterAttributes.attackDamage).setAttribute(3D); this.getEntityAttribute(SharedMonsterAttributes.knockbackResistance).setAttribute(1D); this.getEntityAttribute(SharedMonsterAttributes.movementSpeed).setAttribute(0.8D); } /** * Called to update the entity's position/logic. */ public void onUpdate() { super.onUpdate(); if (!this.worldObj.isRemote) { this.setBesideClimbableBlock(this.isCollidedHorizontally); } } /** * Called frequently so the entity can update its state every tick as required. For example, zombies and skeletons * use this to react to sunlight and start to burn. */ /* public void onLivingUpdate() { if (this.worldObj.isDaytime() && !this.worldObj.isRemote) { float f = this.getBrightness(1.0F); if (f > 0.5F && this.worldObj.canBlockSeeTheSky(MathHelper.floor_double(this.posX), MathHelper.floor_double(this.posY), MathHelper.floor_double(this.posZ)) && this.rand.nextFloat() * 30.0F < (f - 0.4F) * 2.0F) { this.entityToAttack = null; this.teleportRandomly(); } } this.isJumping = false; if (this.entityToAttack != null) { this.faceEntity(this.entityToAttack, 100.0F, 100.0F); } if (!this.worldObj.isRemote && this.isEntityAlive()) { if (this.entityToAttack != null) { if (this.entityToAttack instanceof EntityPlayer) { if (this.entityToAttack.getDistanceSqToEntity(this) < 16.0D) { this.teleportRandomly(); } this.teleportDelay = 0; } else if (this.entityToAttack.getDistanceSqToEntity(this) > 256.0D && this.teleportDelay++ >= 30 && this.teleportToEntity(this.entityToAttack)) { this.teleportDelay = 0; } } else { this.teleportDelay = 0; } } super.onLivingUpdate(); }*/ /** * returns true if this entity is by a ladder, false otherwise */ public boolean isOnLadder() { return this.isBesideClimbableBlock(); } /** * Returns true if the WatchableObject (Byte) is 0x01 otherwise returns false. The WatchableObject is updated using * setBesideClimableBlock. */ public boolean isBesideClimbableBlock() { return (this.dataWatcher.getWatchableObjectByte(16) & 1) != 0; } /** * Updates the WatchableObject (Byte) created in entityInit(), setting it to 0x01 if par1 is true or 0x00 if it is * false. */ public void setBesideClimbableBlock(boolean par1) { byte b0 = this.dataWatcher.getWatchableObjectByte(16); if (par1) { b0 = (byte)(b0 | 1); } else { b0 &= -2; } this.dataWatcher.updateObject(16, Byte.valueOf(b0)); } /** * Teleport the ENTITYTUTO to a random nearby position */ protected boolean teleportRandomly() { double d0 = this.posX + (this.rand.nextDouble() - 0.5D) * 64.0D; double d1 = this.posY + (double)(this.rand.nextInt(64) - 32); double d2 = this.posZ + (this.rand.nextDouble() - 0.5D) * 64.0D; return this.teleportTo(d0, d1, d2); } /** * Teleport the ENTITYTUTO to another entity */ protected boolean teleportToEntity(Entity par1Entity) { Vec3 vec3 = this.worldObj.getWorldVec3Pool().getVecFromPool(this.posX - par1Entity.posX, this.boundingBox.minY + (double)(this.height / 2.0F) - par1Entity.posY + (double)par1Entity.getEyeHeight(), this.posZ - par1Entity.posZ); vec3 = vec3.normalize(); double d0 = 16.0D; double d1 = this.posX + (this.rand.nextDouble() - 0.5D) * 8.0D - vec3.xCoord * d0; double d2 = this.posY + (double)(this.rand.nextInt(16) - 8) - vec3.yCoord * d0; double d3 = this.posZ + (this.rand.nextDouble() - 0.5D) * 8.0D - vec3.zCoord * d0; return this.teleportTo(d1, d2, d3); } /** * Teleport the ENTITYTUTO */ protected boolean teleportTo(double par1, double par3, double par5) { EnderTeleportEvent event = new EnderTeleportEvent(this, par1, par3, par5, 0); if (MinecraftForge.EVENT_BUS.post(event)){ return false; } double d3 = this.posX; double d4 = this.posY; double d5 = this.posZ; this.posX = event.targetX; this.posY = event.targetY; this.posZ = event.targetZ; boolean flag = false; int i = MathHelper.floor_double(this.posX); int j = MathHelper.floor_double(this.posY); int k = MathHelper.floor_double(this.posZ); int l; if (this.worldObj.blockExists(i, j, k)) { boolean flag1 = false; while (!flag1 && j > 0) { l = this.worldObj.getBlockId(i, j - 1, k); if (l != 0 && Block.blocksList[l].blockMaterial.blocksMovement()) { flag1 = true; } else { --this.posY; --j; } } if (flag1) { this.setPosition(this.posX, this.posY, this.posZ); if (this.worldObj.getCollidingBoundingBoxes(this, this.boundingBox).isEmpty() && !this.worldObj.isAnyLiquid(this.boundingBox)) { flag = true; } } } if (!flag) { this.setPosition(d3, d4, d5); return false; } else { short short1 = 128; for (l = 0; l < short1; ++l) { double d6 = (double)l / ((double)short1 - 1.0D); float f = (this.rand.nextFloat() - 0.5F) * 0.2F; float f1 = (this.rand.nextFloat() - 0.5F) * 0.2F; float f2 = (this.rand.nextFloat() - 0.5F) * 0.2F; double d7 = d3 + (this.posX - d3) * d6 + (this.rand.nextDouble() - 0.5D) * (double)this.width * 2.0D; double d8 = d4 + (this.posY - d4) * d6 + this.rand.nextDouble() * (double)this.height; double d9 = d5 + (this.posZ - d5) * d6 + (this.rand.nextDouble() - 0.5D) * (double)this.width * 2.0D; this.worldObj.spawnParticle("portal", d7, d8, d9, (double)f, (double)f1, (double)f2); } this.worldObj.playSoundEffect(d3, d4, d5, "mob.endermen.portal", 1.0F, 1.0F); this.playSound("mob.endermen.portal", 1.0F, 1.0F); return true; } } }
-Pourquoi tu as commentez la fonction onLivingUpdate ?
C’est pour les tests, sinon mon entité ne fait que ce téléporter !
Décomentez-la fonction pour qu’elle puisse ce téléporter ! (Supprimez le /** et le */ en début et fin de fonction)Voilà voilà pour la partie Escalade en plus de la Téléportation !
Nyctalopie
Bien nous voilà pour la partie “Nyctalopie”,
Attention: J’enttends par la, non pas de voir aussi bien de jour comme de nuit, mais je veux plutôt vous monter comment faire briller les yeux de vos entités !
Pour ce faire nous passeront exclusivement dans la classe de Render !
-Hummm… Quel est le mob qui à les yeux qui brillent la nuit ?
-L’enderman et l’araignée !
-Eh ! Merci !
-De rien !Donc allons faire une tour du côté du render de l’araignée !
RenderSpider.java
spiderEyesTextures: Ah ! Un premier signe pour nous montrer que ses yeux brillent bel est bien !
protected int setSpiderEyeBrightness(EntitySpider par1EntitySpider, int par2, float par3)
Une fonction qui nous sera utile, UNE !
Ensuite…protected int shouldRenderPass(EntityLivingBase par1EntityLivingBase, int par2, float par3)
Obligatoire j’ai envie de dire ! Sinon les yeux ne brilleront pas !
Rendons-nous dans le render de notre mob !
package fr.mff.zeamateis; import net.minecraft.client.model.ModelBiped; import net.minecraft.client.renderer.entity.RenderLiving; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLiving; import net.minecraft.util.ResourceLocation; public class RenderTutoMFF extends RenderLiving { public final ResourceLocation texture = new ResourceLocation("viruz:mob/survivors/survivor0.png"); public RenderTutoMFF(ModelBiped model, float shadow) { super(model, shadow); } private ResourceLocation getMobTutorielTexture(EntityTutoMFF mobTutoriel) { return texture; } protected ResourceLocation getEntityTexture(Entity living) { return this.getMobTutorielTexture((EntityTutoMFF)living); } }
Et mettons, donc, les fonctions précédemment trouvés !
Pour nous donner ceci
package fr.mff.zeamateis; import net.minecraft.client.model.ModelBiped; import net.minecraft.client.model.ModelZombie; import net.minecraft.client.renderer.OpenGlHelper; import net.minecraft.client.renderer.entity.RenderLiving; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLivingBase; import net.minecraft.util.ResourceLocation; import org.lwjgl.opengl.GL11; public class RenderTutoMFF extends RenderLiving { public final ResourceLocation texture = new ResourceLocation("modid:chemin/vers/votre/entiteTuto.png"); private static final ResourceLocation tutoEyesTextures = new ResourceLocation("modid:chemin/vers/votre/textureyeuxtransparents.png");//La texture doit être transparente et si le skin du mob est en 64x64 la texture des yeux doit être aussi en 64x64 public RenderTutoMFF(ModelBiped model, float shadow) { super(model, shadow); } private ResourceLocation getMobTutorielTexture(EntityTutoMFF mobTutoriel) { return texture; } /** * Sets the tuto's glowing eyes */ protected int setTutoEyeBrightness(EntityTutoMFF par1EntityTutoMFF, int par2, float par3) { if (par2 != 0) { return -1; } else { this.bindTexture(tutoEyesTextures); float f1 = 1.0F; GL11.glEnable(GL11.GL_BLEND); GL11.glDisable(GL11.GL_ALPHA_TEST); GL11.glBlendFunc(GL11.GL_ONE, GL11.GL_ONE); if (par1EntityTutoMFF.isInvisible()) { GL11.glDepthMask(false); } else { GL11.glDepthMask(true); } char c0 = 61680; int j = c0 % 65536; int k = c0 / 65536; OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, (float)j / 1.0F, (float)k / 1.0F); GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F);//Ici, c'est le réglage pour l'intensité de la lumière ! Changez juste les floats GL11.glColor4f(1.0F, 1.0F, 1.0F, f1);//Ici aussi ! Changez juste les floats par le f1 return 1; } } protected ResourceLocation getEntityTexture(Entity living) { return this.getMobTutorielTexture((EntityTutoMFF)living); } protected int shouldRenderPass(EntityLivingBase par1EntityLivingBase, int par2, float par3) { return this.setTutoEyeBrightness((EntityTutoMFF)par1EntityLivingBase, par2, par3); } }
Lancez votre et jeu et TADA ! NullPointerExeption ! et Crash (Normalement)
-T’es nul en fait
-Je sais d’où viens l’erreur !Nous avons oublier quelque chose !
this.setRenderPassModel(new ModelBiped());
Il faut mettre ce bout de code dans le constructeur après:
super(model, shadow);
Ce qui nous donne ceci:
public RenderTutoMFF(ModelBiped model, float shadow) { super(model, shadow); this.setRenderPassModel(new ModelBiped()); }
Voilà voilà !
Lancez le jeu et TADA ! Notre mob à les yeux qui brillent !
Je vous ai laisser quelques explication dans le code !Vous voulez des yeux rouge en 64x32 ?
Tenez:
Passons à la Death Rotation
Death Rotation
Ce sera la partie la plus simple de ce tutoriel je pense !
Le code est tout droit sortit du render de l’araignée !
protected float setSpiderDeathMaxRotation(EntitySpider par1EntitySpider) { return 180.0F; }
Et
protected float getDeathMaxRotation(EntityLivingBase par1EntityLivingBase) { return this.setSpiderDeathMaxRotation((EntitySpider)par1EntityLivingBase); }
Il suffit tout simplement de changer l’angle (en float) et de faire en sorte que ce soit pour notre mob !
Donc,protected float setSpiderDeathMaxRotation(EntityTutoMFF par1EntityTutoMFF) { return 0.0F;//Là mon entité ne se tournera pas lors de sa mort ! }
Et, Suffi de le mettre tout en bas de la classe Render !
protected float getDeathMaxRotation(EntityLivingBase par1EntityLivingBase) { return this.setEntityTutoMFFDeathMaxRotation((EntityTutoMFF)par1EntityLivingBase); }
Voilà voilà c’est tout pour la rotation lors de la mort !
Son(s)
Pour la partie sons, qui est facultative, nous parlerons des sons lors d’une action spéciale !
Mais vu qu’il existe déjà un tutoriel là dessus et qu’il suffit de faire appel à des if() … Je ne vous en parlerais pas 107 ans !
Mais je vais vous donner une petite liste de boucles qui son utile(ou pas) lors d’événements spéciaux de notre mob !
//Si notre entité saute on joue un son de clic (Pour l'exemple) if(this.isJumping) { this.playSound("random.click", 1.0F, 1.0F); }
//Si notre entité escalade on joue un son de clic (Pour l'exemple) if(this.isOnLadder()) { this.playSound("random.click", 1.0F, 1.0F); }
//Si notre entité à la potion de poison d'active, elle joue le son de l'enderman qui prend un coup if(this.isPotionActive(Potion.poison)) { this.playSound("mob.endermen.hit", 1.0F, 1.0F); }
Biensûr ces codes là son bruts est non travaillés ! Je vous conseille, pour vous et vos oreilles, de faire appel à un random pour jouer les sons !
Saut lors d’une attaque
Pour le saut lors d’une attaque, rien-de-plus-simple !
Allons une fois de plus voir du côté de notre araignée !Je pari déjà que vous avez trouvé la fonction ! Hein ?
Regardez c’est celle là est en plus on a rien à faire un petit copier coller entre onUpdate() et onLivingUpdate()
/** * Basic mob attack. Default to touch of death in EntityCreature. Overridden by each mob to define their attack. */ protected void attackEntity(Entity par1Entity, float par2) { float f1 = this.getBrightness(1.0F); if (f1 > 0.5F && this.rand.nextInt(100) == 0) { this.entityToAttack = null; } else { if (par2 > 2.0F && par2 < 6.0F && this.rand.nextInt(10) == 0) { if (this.onGround) { double d0 = par1Entity.posX - this.posX; double d1 = par1Entity.posZ - this.posZ; float f2 = MathHelper.sqrt_double(d0 * d0 + d1 * d1); this.motionX = d0 / (double)f2 * 0.5D * 0.800000011920929D + this.motionX * 0.20000000298023224D; this.motionZ = d1 / (double)f2 * 0.5D * 0.800000011920929D + this.motionZ * 0.20000000298023224D; this.motionY = 0.4000000059604645D; } } else { super.attackEntity(par1Entity, par2); } } }
Et voilà si vous attaquez votre mob, Hop ! Il vous sautera dessus !
Si vous regardez bien il y a une fonction pour l’intensité lumineuse (jour/nuit), si vous n’en voulez pas, car elle sert à faire en sorte que notre mob n’attaque pas de jour !
Vous n’aurez qu’a gardez ceci:if (par2 > 2.0F && par2 < 6.0F && this.rand.nextInt(10) == 0) { if (this.onGround) { double d0 = par1Entity.posX - this.posX; double d1 = par1Entity.posZ - this.posZ; float f2 = MathHelper.sqrt_double(d0 * d0 + d1 * d1); this.motionX = d0 / (double)f2 * 0.5D * 0.800000011920929D + this.motionX * 0.20000000298023224D; this.motionZ = d1 / (double)f2 * 0.5D * 0.800000011920929D + this.motionZ * 0.20000000298023224D; this.motionY = 0.4000000059604645D; } } else { super.attackEntity(par1Entity, par2); }
Voilà voilà ! C’est tout pour l’événement de saut lors d’une attaque !
Drop(Simple/Avancé)
Pour la partie du drop simple et compliqué, je passerais directement au drops complexe qui est ma fois plus intéressante !
Pour ce faire j’ai jouer quelques minute à ce jeu que je possède depuis très très très longtemps pour me rappeler que la sorcière à des drops, pour le moins… divers…
Allons voir ça !
/** * Drop 0-2 items of this living's type. @param par1 - Whether this entity has recently been hit by a player. @param * par2 - Level of Looting used to kill this mob. */ protected void dropFewItems(boolean par1, int par2) { int j = this.rand.nextInt(3) + 1; for (int k = 0; k < j; ++k) { int l = this.rand.nextInt(3); int i1 = witchDrops[this.rand.nextInt(witchDrops.length)]; if (par2 > 0) { l += this.rand.nextInt(par2 + 1); } for (int j1 = 0; j1 < l; ++j1) { this.dropItem(i1, 1); } } }
Qu’est-ce que je disais ?!
Ce que nous allons modifer c’est ceci:
int i1 = witchDrops[this.rand.nextInt(witchDrops.length)];
Et si nous faisons un ctrl+clic gauche sur witchDrops on tombe sur ceci:
private static final int[] witchDrops = new int[] {Item.glowstone.itemID, Item.sugar.itemID, Item.redstone.itemID, Item.spiderEye.itemID, Item.glassBottle.itemID, Item.gunpowder.itemID, Item.stick.itemID, Item.stick.itemID};
C’est une sorte de tableau de “sélection” d’items qui tomberons aléatoirement lors de sa mort !
Appliquons tout ça à notre mob !
C’est simplement que nous allons ajouter:
private static final int[] tutoMFFDrops= new int[] {Item.glowstone.itemID, Item.sugar.itemID, Item.redstone.itemID, Item.spiderEye.itemID, Item.glassBottle.itemID, Item.gunpowder.itemID, Item.stick.itemID, Item.stick.itemID};
Avant le constructeur
Et
/** * Drop 0-2 items of this living's type. @param par1 - Whether this entity has recently been hit by a player. @param * par2 - Level of Looting used to kill this mob. */ protected void dropFewItems(boolean par1, int par2) { int j = this.rand.nextInt(3) + 1; for (int k = 0; k < j; ++k) { int l = this.rand.nextInt(3); int i1 = tutoMFFDrops[this.rand.nextInt(tutoMFFDrops.length)]; if (par2 > 0) { l += this.rand.nextInt(par2 + 1); } for (int j1 = 0; j1 < l; ++j1) { this.dropItem(i1, 1); } } }
A la fin de notre classe EntityTutoMFF !
NB: Vous pouvez aussi modifier les int des “rand” pour faire en sorte de faire des drops rare ou non !
Ex: int j = this.rand.nextInt(3) + 1; -> int j = this.rand.nextInt(100) + 50;Faisons les tests…
Et TADA !!!Notre mob drop aléatoirement les items (que je n’ai pas changé, mais ça peut aussi être des blocs !) défini dans ce “tableau de sélection” !
Voilà pour cette partie sympatrique !
Boule de feu
Résultat
Crédits
Robin, pour son mob basique !
-
Pour le fly, s’inspirer du système du ghast est une très mauvaise idée car le ghast a été codé de sorte à ce qu’il motionY en permanence ^^
-
Oui mais je l’améliorerais !
-
EDIT: 15/03/2014 15h36
- La téléportation
- L’escalade
-
Bravo c’est très complet
-
Merci, même si c’est loin d’être fini, mais Merci !
Demain je ferais la partie Nyctalopie, Death Rotation, et Son(s) !
-
l’idée est plaisante, les fonctions présentés sont utiles bien que facilement retrouvable si on cherche, enfin cela peut aider quand même les débutants
Juste, la nyctalopie c’est le fait de voir dans le noir, pas les yeux qui brillent me semble ^^ -
Oui je sais, mais si on pointe une lumière dans les yeux des animaux ils brillent (I.R.L) Mais là en jeu on fera des yeux qui brillent !
-
Si tu as besoin de mon aide pour certaines parties du tuto je suis là.
-
Ok ! Y’a pas de souci !
-
Tu devrais cibler tes tutoriels quitte a en faire plusieurs. Un tuto aussi long, c’est indigeste. Et les gens qui vont chercher comment jouer du sons ne ont pas cliquer sur un article qui a pour titre ‘[Entitées] Diverses entitées !’ par exemple je pense.
-
EDIT: 16/03/2014 15:47
- Nyctalopie
- Death Rotation
+Son(s)
-
de mieux en mieux, quand tu sera arrivé a la boule de feu, va tu faire de nouveau truc pour les entité ou non?
-
Je verrais oui
-
EDIT: 16/03/2014 18h42
+Saut lors d’une attaque
-
La semaine je ne suis pas là donc je terminerai le tutoriel week-end prochain ! 29/30 mars
-
Je ne finirais pas de le tutoriel avant un petit moment 2/3 semaines je sais pas encore ! Si vous voyez que ça traîne trop mettez moi ça aux ordures ! Merci de votre compréhension !
-
Partie sur les drops faite !
-
Je ne continuerais pas ce tutoriel ! Je préfère me cibler sur UN tutoriel, pour vraiment bien le traivailler que sur plusieurs tutoriel en un et pas forcément tous “utile” !
Donc, à mettre dans la section non validés pour que les gens qui passe par là aient déjà un aperçu de ce que l’on peut faire !
Merci !