20 juin 2013, 21:00

Créer un mob basique :

Dans ce tutoriel, je vais vous apprendre à faire un mob BASIQUE (je précise :D) !

Un mob basique ? C’est à dire ?
-Un mob qui ne fait rien, qui se balade, juste.

Aaaaaah, ok ! Mais… pourquoi un mob basique et pas avancé ?
-Il est important de savoir la base d’un mob avant d’enchaîner sur ce qui est “avancé”. 😉 Croyez moi, cela en vaut la peine.

Pour commencez, vous devez :
-Créer la classe du mob.
-Ajouter les lignes d’enregistrement de l’entité dans votre classe principale.

Et c’est tout. ^^ Le mob sera vraiment simple, vous verrez.

Nous allons donc créer une class qui va s’appeler “EntityAniZob” et nous allons définir sa class parente qui va s’appeler EntityCreature.
N’OUBLIEZ PAS D’AJOUTER LES DÉCLARATIONS DE PACKAGES ! package net.minecraft.src; par exemple !
Exemple de ce que je viens d’expliquer en code :

public class EntityAniZob extends EntityCreature

Inutile d’expliquer le code que je viens de citer, il est déjà expliqué. x)

Je ne vais pas vous apprendre à mettre des accolades où il faut, vous devez avoir un minimum de connaissances en Java.

Une fois notre belle classe créer, elle doit avoir cette tronche là :

package votre.package;
public class EntityAniZob extends EntityCreature
{

}

Vous allez me dire :

Pourquoi est-ce que EntityAniZob est souligné en rouge ?
-Tout simplement qu’il faut ajouter le constructeur de la super class (de la classe parente de EntityAniZob, donc EntityCreature)

Passez donc le curseur là où c’est souligné. Il vous proposera donc d’ajouter le constructeur.

Oui mais… j’ai beau ajouter le constructeur, c’est encore souligné… Pourquoi ?
-Et bien cela signifie que la class parente (donc EntityCreature) contient une fonction Abstract qui est OBLIGATOIRE pour les classes héritant de EntityCreature.

Il faut donc repasser de nouveau le curseur sur ce qui est souligné, pour ensuite cliquer sur “Add unimplemented methods”. Une fois fait, vous allez voir apparaître ce que la classe nécessite pour être reconnu (avec le constructeur). Pour les mobs, c’est getMaxHealth() donc une fonction de type int qui retourne le nombre de DEMI-CŒURS que le mob contient. Si vous mettez 20, le mob aura donc 10 cœurs, comme le joueur.

Normalement, vous n’êtes plus censé avoir d’erreurs + getMaxHealth() n’existe plus !!! Nous allons voir plus bas comment configurer tout cela !

Donc maintenant, notre class doit ressembler à ça :

package votre.package;
public class EntityAniZob extends EntityCreature
{
    public EntityAniZob(World world)
    {
        super(world);
    }
}

Lexique :

super(world); -> Une ligne obligatoire dans un constructeur héritant d’une class.

Le système de point de vies en 1.6 :

Comme vous auriez pu le constater, en 1.6, le système de point de vies a complètement été refait ! Il ne s’agit plus d’un simple field “health” ou d’une fonction getMaxHealth()… De même pour la vitesse du mob !

Mais comment utiliser ce nouveau système ?
-C’est simple !

Créez une nouvelle méthode en dessous du constructeur :

@Override
protected void func_110147_ax()
{
    super.func_110147_ax();
}

SI VOUS UTILISEZ UNE BUILD DE FORGE À PARTIR DE 849, LA MÉTHODE A CHANGÉ (de nom) ! VOICI LA NOUVELLE :

protected void applyEntityAttributes()
{
    super.applyEntityAttributes();
}

Alors ne me demandez pas pourquoi c’est sous forme de “func_ blablabla” c’est (apparement) un problème de mappings ! (Réglé à partir de la build 849 !!!)

On n’oublie pas le super et le @Override pour que la méthode soit reconnue !

Et en dessous du super.func_110147_ax(); ou super.applyEntityAttributes(); ajoutez ces lignes :

[POUR LES BUILDS EN DESSOUS DE 849] :

this.func_110148_a(SharedMonsterAttributes.field_111267_a).func_111128_a(40D);
this.func_110148_a(SharedMonsterAttributes.field_111265_b).func_111128_a(40.0D);
this.func_110148_a(SharedMonsterAttributes.field_111263_d).func_111128_a(0.699999988079071D);
this.func_110148_a(SharedMonsterAttributes.field_111264_e).func_111128_a(8.0D);

[POUR LES BUILDS À PARTIR DE 849] :

this.getEntityAttribute(SharedMonsterAttributes.maxHealth).setAttribute(40D);
this.getEntityAttribute(SharedMonsterAttributes.followRange).setAttribute(40.0D);
this.getEntityAttribute(SharedMonsterAttributes.movementSpeed).setAttribute(0.699999988079071D);
this.getEntityAttribute(SharedMonsterAttributes.attackDamage).setAttribute(8.0D);

Vous voyez le gros changement ? xDD

Pas de panique ! Je vais vous expliquer en détail ce qu’elles veulent dire !

La première ligne va servir à attribuer la vie au mob ! (donc remplace le getMaxHealth())

La deuxième signifie la portée de détection d’entités ! (??)

La troisième ligne permet d’attribuer la vitesse du mob ! (donc remplace le float “moveSpeed”, là il est reglé à la vitesse par défaut)

Et enfin la dernière ligne permet d’attribuer la force d’attaque du mob !(donc remplace le INT getAttackStrength(), qui était anciennement : attackStrength)*

Comme vous l’auriez remarqué, les lignes ont le même début et fin, juste les fields au milieu qui changent, donc voici une lexique de TOUS les fields de la classe SharedMonsterAttributes :

  • field_111267_a = pour la vie du mob
  • field_111265_b = follow range ou portée de détection si vous préferez !
  • field_111266_c = knockback resistance ! (utile pour un mob custom)
  • field_111263_d = vitesse du mob !
  • field_111264_e = field qui remplace **getAttackStrength() **(anciennement “attackStrngth”) NE L’UTILISEZ PAS POUR L’INSTANT, CE FIELD SEMBLE BUGGÉ !!

Voilà pour ce qui est du changement 1.6aire !(UnPointSixaire, c’est très français ! xD)

Notre mob est enfin prêt… OU PAS ! Il reste encore à l’enregistrer dans votre class principale !

Dans la fonction d’INITIALISATION (donc pas dans la pré init, ni dans la post init), vous allez insérer ces 4 lignes :

EntityRegistry.registerGlobalEntityID(EntityAniZob.class, “AniZob”, EntityRegistry.findGlobalUniqueEntityId(), 24, 30);
EntityRegistry.registerModEntity(EntityAniZob.class, “AniZob”, 250, this, 40, 1, true);
EntityRegistry.addSpawn(EntityAniZob.class, 1, 4, 4, EnumCreatureType.creature);
LanguageRegistry.instance().addStringLocalization(“entity.AniZob.name”, “AniZob”);

Explications (dans l’ordre) de ces 4 lignes :

La première ligne permet d’enreigstrer l’oeuf et l’entité associé, le nom, l’ID de l’oeuf (je vous conseil de mettre comme j’ai mis, donc EntityRegistry.findGlobalUniqueEntityId() UNIQUEMENT POUR L’OEUF)
et enfin les deux autres nombres sont la couleurs de fond et celle des taches de l’oeuf. (background color, foreground color)

La deuxième ligne permet d’enregistrer l’entité du mod. Dans l’ordre croissant : La class de l’entité, le nom, l’id, l’instance du mod (mettez this), la valeur “trackingRange” mettez un nombre élevé comme moi j’ai mis, le nombre d’update par tick (20 ticks = 1 seconde) et enfin, un boolean qui nous demande d’envoyer les updates de velocités ou pas, je vous conseil de mettre “true”

La troisième ligne va vous permettre d’enregistrer les paramètre de spawn du mob, donc par ordre croissant : La class de l’entité, la chance d’apparition, le nombre mini par groupe, le nombre maxi par groupe et enfin on finit par ce fameux EnumCreatureType… Pour ce tuto, nous allons utiliser EnumCreatureType.creature (cela permet de définir quel type de mob il s’agit).

Et pour finir donc, la dernière ligne permet d’attribuer un nom à l’entité. Je vous la recommande fortement cette ligne ! Si vous ne la mettez pas, si vous vous faites tuer par l’entité, le message dans le tchat affichera :
“…was slain by entity.AniZob.name” et ce entity.AniZob.name sera affiché sur le nom de l’oeuf aussi, donc je vous conseil d’utiliser la ligne que je vous mets à disposition pour ne pas avoir ce bug chiant. ^^

Parmi ces lignes, dans la première, vous retrouverez au bout de celle ci : 24, 30
Détails :
-24 : couleur du BACKGROUND de l’oeuf
-30 : couleur du FOREGROUND de l’œuf (des taches de l’œuf)
Pour des couleurs personnalisé de l’œuf, je vous invite à aller sur ce site : http://code-couleur.com
si vous avez trouvé votre couleur, ne prenez pas le #, mais ce qu’il y a après !!! Et dans le code, ajoutez un 0x avant d’ajouter le code couleur. 🙂 par exemple pour le blanc 0xFFFFF :

EntityRegistry.registerGlobalEntityID(EntityAniZob.class, “AniZob”, EntityRegistry.findGlobalUniqueEntityId(), 0xFFFFF, 0xFFFFF);

Là, l’oeuf sera entièrement BLANC ! 😄

Voilà, notre mob est fin prêt à être testé… MAIS ! Il reste une chose !

Encore ?!..
-Ne vous en faites pas, ce n’est pas long ! Juste une ligne à rajouter dans le ClientProxy !

Donc, dans votre client proxy, vous devez avoir votre méthode qui permet d’initialiser vos render non ? Et bien nous allons en profiter pour y ajouter cette ligne :

RenderingRegistry.registerEntityRenderingHandler(EntityAniZob.class, new RenderAnizob(new ModelBiped(), 0.5f));

Cette ligne est OBLIGATOIRE si vous ne voulez pas que votre mob soit buggé ! Cela permet de faire le rendu de votre mob !

Explications de la ligne :

Premièrement, nous avons la classe de l’entity, ensuite nous avons “new RenderBiped(new ModelBiped(), 0.5f)”

Mais… à quoi sert ce passage ?
-A définir quel model et render que l’entity va utiliser, là, c’est : RenderBiped et ModelBiped.

Hum, je comprend mieux maintenant… Mais il reste ce 0.5f là… à quoi sert-il ?
-Roooh c’est facile ! 😄 Il s’agit de la taille de l’ombre du mob ! 🙂

PS : Pour ajouter une texture à votre mob, ajoutez ceci dans votre constructeur :

texture = "/le/chemin/de/votre/texture.png";

Depuis la 1.6, pour ajouter la texture, cela se passe dans le RENDER !!!

Donc dans votre render, ajoutez cette ligne avant le constructeur :

protected static final ResourceLocation texture = new ResourceLocation("ModID:texture.png");

Alors pareil pour les mobs, le système de détection de texture est devenu comme les blocks/items !! MAIS, vous devez ajouter le .png à la fin ! ^^
Là par exemple, j’ai mis “ModID:texture.png”

Mais où est-ce que je vais placer ma texture ?
Dans asset(anciennement nommé “mods”) : /assets/modid/texture.png

le dossier modid DOIT ÊTRE EN MINUSCULE !

Ensuite, ajoutez ces deux fonctions :

protected ResourceLocation func_110870_a(EntityAniZob entity)
{
    return texture;
}

@Override
protected ResourceLocation func_110775_a(Entity par1Entity)
{
    return this.func_110870_a((EntityAniZob)par1Entity);
}

(Build 849 et + de forge uniquement)

protected ResourceLocation getAniZobTextures(EntityAnizob anizob)
{
    return texture;
}

protected ResourceLocation getEntityTexture(Entity par1Entity)
{
    return this.getAniZobTextures((EntityAnizob)par1Entity);
}

Elles permettent l’enregistrement de la ligne que nous avons ajouté au dessus du constructeur !

Voici la class render en intégralité :

Build en dessous de 849 :

package votre.package.client;

public class RenderAnizob extends RenderBiped {

    protected static final ResourceLocation texture = new ResourceLocation("ModID:texture.png");

    public RenderAnizob(ModelBiped biped, float tailleOmbre)
    {
        super(biped, tailleOmbre);
    }

    protected ResourceLocation func_110870_a(EntityAniZob entity)
    {
        return texture;
    }

    @Override
    protected ResourceLocation func_110775_a(Entity par1Entity)
    {
        return this.func_110870_a((EntityAniZob)par1Entity);
    }
}

Maintenant, rendez-vous dans votre ClientProxy, et mettez cette ligne dans une de vos méthodes :

RenderingRegistry.registerEntityRenderingHandler(EntityAnizob.class, new RenderAnizob(new ModelBiped(), 0.5F);

–----------------
Voilà voilà, j’espère que ce tutoriel vous a plu, n’hésitez pas à me dire ce que vous en pensez; si j’ai oublié un truc, etc… 🙂

Plus tard nous verrons les différents mobs avancés !
Je ne peux malheureusement pas vous donner le code source java du tuto, je l’ai fait à la main xD…

Sur ce, good luck !