[JAVA] Comment faire un MOD pour Slay the Spire

Je veux profiter de la création de MOD pour Slay the Spire

Reconnaître

C'est pourquoi il s'agit d'un cours sur la création d'un MOD pour Slay the Spire.

Wiki BaseMod dans Git https://github.com/daviscook477/BaseMod/wiki/Getting-Started-(For-Modders)

Liste des mods sur le wiki dans Mod The Spire's Git https://github.com/kiooeht/ModTheSpire/wiki/List-of-Known-Mods

Introduction au développement du mod Slay the Spire https://qiita.com/kojim/items/0c7164c78a5a909b4478 https://qiita.com/kojim/items/1a97f200fc8e545cee13 https://qiita.com/kojim/items/f61d9f3553e2d045aa2e

Vous pouvez le faire en regardant ce qui précède. Merci à mes ancêtres.

J'expliquerai "Premiers pas avec Modding Slay The Spire" sur le wiki BaseMod car cela n'augmentera pas le nombre de personnes qui le font. Le début est la construction de l'environnement de développement, mais si vous avez un environnement de développement Java, veuillez le lire en diagonale. En premier lieu, cet article est destiné aux super débutants.

Environnement de développement

Tout d'abord, il vous est demandé de créer un dossier. Vous pouvez aller n'importe où, mais veuillez créer un dossier. MOD Dans un dossier nommé "my_mods" que je vais faire beaucoup à partir de maintenant. Donc, il est dit que vous pouvez créer un dossier appelé "lib" dedans, alors créez-le. Mettez BaseMod.jar et ModTheSpire.jar là.

BaseMod.jar https://github.com/daviscook477/BaseMod/releases ModTheSpire.jar https://github.com/kiooeht/ModTheSpire/releases

BaseMod est l'API Mod, et Mod The Spire est nécessaire pour exécuter Slay the Spire avec MOD. Eh bien, les deux sont nécessaires. Oui. Oh, vous pouvez également entrer depuis Steam Workshop. Mettons-le dedans.

Ensuite, recherchez et placez desktop-1.0.jar dans le même dossier dans le dossier Slay the Spire.

Maintenant, en ce qui concerne l'élément "Configuration de l'environnement", puisqu'il s'agit d'un environnement de développement, veuillez choisir celui que vous aimez. Il était écrit que c'était facile, donc je l'ai fait avec Intel iJ, et je ne l'expliquerai qu'après cela. Installez d'abord Java SE Development Kit 8, puis Intel iJ.

Il dit que lorsque vous démarrez Intel iJ avec, veuillez créer un nouveau projet. Sélectionnez JDK1.8 et Maven Next, GroupID et ArtifactId doivent être le nom du mod que vous êtes sur le point de créer. L'exemple est ExampleMod. Enfin, terminez pour que le fichier projet soit créé dans le dossier créé précédemment.

Eh bien, tout à coup, il y a une chose importante écrite dedans, mais je pense que pom.xml est directement sous le dossier du projet, alors éditez-le.

Example Mod pom.xml https://gist.github.com/alexdriedger/fb74397086ee80073417f19d6305bb05

Ici, les emplacements des trois fichiers jar que vous placez dans le dossier lib et leurs versions sont spécifiés. Faites attention si la structure des répertoires est différente de l'exemple.

Je pense aussi qu'il était nécessaire d'éditer partiellement le paquet à partir de la 54e ligne ici. Veuillez l'écrire car c'est la destination de sortie après la construction.

Lorsque vous avez terminé de modifier le pom, vous verrez une fenêtre contextuelle indiquant «Les projets Maven doivent être importés», alors appuyez sur Importer les modifications pour le refléter. Appuyez ensuite sur Ctrl + Alt + Maj + S pour afficher l'écran Structure, sélectionnez Modules, et il y a 3 Mavens, alors vérifiez-le et appliquez.

Maintenant, pour le moment, double-cliquez sur «Cycle de vie> package» dans la fenêtre ouverte par «Affichage> Outils Windows> Projets Maven» pour construire et créer un fichier .jar dans le dossier cible.

Faisons de notre mieux jusqu'à ce que nous fassions un personnage approprié

Ajouter la couleur et la carte

La classe de personnage de Slay the Spire s'appelle COULEUR, Iron Clad est ROUGE, Silencieux est VERT et Défaut est BLEU. Si vous voulez créer un nouveau personnage, vous devez d'abord ajouter cette COULEUR (bien que ce serait plus facile si vous mettiez simplement une carte supplémentaire pour ces gars-là).

Custom Colors https://github.com/daviscook477/BaseMod/wiki/Custom-Colors

C'est difficile à lire et à comprendre, je vais donc l'expliquer moi-même à partir de maintenant. Allons-y un par un. Tout d'abord, ajoutez des couleurs et des cartes. Je ne sais pas s'il a été ajouté uniquement en couleur, je peux donc ajouter des cartes à la fois.

De plus, c'est ennuyeux à expliquer, donc si vous ne comprenez pas bien, veuillez consulter le référentiel suivant. Préparer une image est compliqué, alors commencez par ici. https://github.com/levelnineteen/stsmod

Au moment de la création du projet, je pense qu'il est structuré comme ça, mais la classe (partie programme) est placée sous java, et le texte et les images sont placés sous ressource.

examle_mod +.idea +src -+main --+java --+resource

Tout d'abord, créez un répertoire avec le nom du mod sous java, et un répertoire appelé patches en dessous, et créez les deux classes suivantes.

examle_mod +.idea +src -+main --+java ---+example_mod ----+patches --+resource

AbstractCardEnum.java


package example_mod.patches; //Je pense qu'il entrera ici automatiquement

import com.evacipated.cardcrawl.modthespire.lib.SpireEnum;
import com.megacrit.cardcrawl.cards.AbstractCard;

public class AbstractCardEnum {

    @SpireEnum
    public static AbstractCard.CardColor EXAMPLE_COLOR; //Nom de la variable préférée. Je vais l'utiliser pour toujours.

}

LibraryTypeEnum.java


package example_mod.patches; //Je pense qu'il entrera ici automatiquement

import com.evacipated.cardcrawl.modthespire.lib.SpireEnum;
import com.megacrit.cardcrawl.helpers.CardLibrary;

public class LibraryTypeEnum {

    @SpireEnum
    public static CardLibrary.LibraryType EXAMPLE_COLOR; //Comme ci-dessus. Je vais l'utiliser pour toujours.

}

Maintenant que nous avons préparé, créez la classe Main.java ou MOD name.java directement sous java / example_mod afin qu'elle soit facile à comprendre.

Main.java


import basemod.BaseMod;
import basemod.interfaces.*;
import com.evacipated.cardcrawl.modthespire.lib.SpireInitializer;
import com.megacrit.cardcrawl.core.Settings;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.Texture;
import com.megacrit.cardcrawl.helpers.CardHelper;
import com.megacrit.cardcrawl.localization.CardStrings;
import com.megacrit.cardcrawl.localization.CharacterStrings;

import example_mod.patches.*; //Je vais lire le patch que j'ai fait plus tôt

@SpireInitializer
public class Main implements
        EditCardsSubscriber,   //Implémenter lors de l'ajout d'une carte
        EditStringsSubscriber,  //Implémenter lors de la lecture d'un fichier de langue
{
    //Premièrement, il existe des variables pour les paramètres de couleur de base.
    private static final Color EXAMPLE_COLOR_BG = CardHelper.getColor(100.0f, 50.0f, 50.0f); //Il s'agit de la couleur d'arrière-plan de la barre lorsqu'elle apparaît dans la sélection de la liste de cartes.
    private static final String ATTACK_EXAMPLE         = "img/cards/bg_attack_512.png "; //Ce domaine sera expliqué plus tard
    private static final String SKILL_EXAMPLE          = "img/cards/bg_skill_512.png "; //Veuillez écrire le nom de la variable pour le moment
    private static final String POWER_EXAMPLE           = "img/cards/bg_power_512.png ";
    private static final String ENERGY_ORB_EXAMPLE         = "img/cards/orb_512.png ";
    private static final String ATTACK_PORT_EXAMPLE        = "img/cards/bg_attack_1024.png ";
    private static final String SKILL_PORT_EXAMPLE         = "img/cards/bg_skill_1024.png ";
    private static final String POWER_PORT_EXAMPLE         = "img/cards/bg_power_1024.png ";
    private static final String ENERGY_ORB_PORT_EXAMPLE = "img/cards/orb_1024.png ";
    private static final String ENERGY_ORB_CARD_EXAMPLE = "img/cards/orb_ui.png ";

    public Main(){
        BaseMod.subscribe(this);
        BaseMod.addColor(
                //C'est une partie d'ajout de couleur. Entrez simplement les variables définies ci-dessus.
                AbstractCardEnum.EXAMPLE_COLOR    //color
                , EXAMPLE_COLOR_BG //bgColor
                , EXAMPLE_COLOR_BG//backColor
                , EXAMPLE_COLOR_BG//frameColor
                , EXAMPLE_COLOR_BG//frameOutlineColor
                , EXAMPLE_COLOR_BG//descBoxColor
                , EXAMPLE_COLOR_BG //trailVfColor
                , EXAMPLE_COLOR_BG//glowColor
                , ATTACK_EXAMPLE//attackBg
                , SKILL_EXAMPLE//skillBg
                , POWER_EXAMPLE//powerBG
                , ENERGY_ORB_EXAMPLE//energyOrb
                , ATTACK_PORT_EXAMPLE//attackBgPortrait
                , SKILL_PORT_EXAMPLE//skillBgPortrait
                , POWER_PORT_EXAMPLE//powerBgPortrait
                , ENERGY_ORB_PORT_EXAMPLE//energyOrbPortrait
                , ENERGY_ORB_CARD_EXAMPLE//CardEnergyOrb
        );
    }

    public static void initialize() {
        Main main = new Main();
    }

    @Override
    public void receiveEditStrings() {
        //Les fichiers de langue seront expliqués plus tard.
        BaseMod.loadCustomStringsFile(CardStrings.class, "localization/cards-" + Settings.language + ".json");
    }

    @Override
    public void receiveEditCards() {
        //C'est la partie additionnelle de la carte. Cela sera également expliqué plus tard.
        BaseMod.addCard(new example_mod.cards.TestAttack());
    }
}

J'ai encore quelque chose à écrire. Parce que je dois écrire le contenu de la carte essentielle. Préparez un répertoire appelé cards directement sous java / example_mod et mettez les classes suivantes.

TestAttack.java


package example_mod.cards; //Eh bien ici devrait entrer automatiquement

import basemod.abstracts.CustomCard;
import com.megacrit.cardcrawl.actions.AbstractGameAction;
import com.megacrit.cardcrawl.cards.AbstractCard;
import com.megacrit.cardcrawl.cards.DamageInfo;
import com.megacrit.cardcrawl.characters.AbstractPlayer;
import com.megacrit.cardcrawl.core.CardCrawlGame;
import com.megacrit.cardcrawl.dungeons.AbstractDungeon;
import com.megacrit.cardcrawl.localization.CardStrings;
import com.megacrit.cardcrawl.monsters.AbstractMonster;
import example_mod.patches.AbstractCardEnum; //La couleur de la carte ne peut pas être gérée sauf si elle est importée

public class TestAttack extends CustomCard {
    public static final String ID = "examplemod:TestAttack"; //Ne vous trompez pas car c'est l'ID de référence du fichier de langue.
    private static CardStrings cardStrings = CardCrawlGame.languagePack.getCardStrings(ID);
    public static final String NAME = cardStrings.NAME;
    public static final String DESCRIPTION = cardStrings.DESCRIPTION;
    public static final String IMG_PATH = "img/cards/card.png "; //C'est une image de la carte. J'expliquerai plus tard.
    private static final int COST = 0; //Coût énergétique
    private static final int ATTACK_DMG = 4; //dommage
    private static final int UPGRADE_PLUS_DMG = 3; //Dommages lors de la mise à niveau

    public TestAttack() {
        super(ID, NAME, IMG_PATH, COST, DESCRIPTION,
                CardType.ATTACK, //Type de carte
                AbstractCardEnum.EXAMPLE_COLOR, //La variable de couleur de la carte que j'utilise depuis un certain temps. Ne fais pas d'erreur
                CardRarity.COMMON,   //Rareté de la carte
                CardTarget.ENEMY //Qui est la cible
        );
        this.damage=this.baseDamage = ATTACK_DMG;
    }

    @Override
    public void use(AbstractPlayer p, AbstractMonster m) {
        //A fait des dégats
        AbstractDungeon.actionManager.addToBottom(
                new com.megacrit.cardcrawl.actions.common.DamageAction(
                        m,
                        new DamageInfo(p, this.damage, this.damageTypeForTurn),
                        AbstractGameAction.AttackEffect.SLASH_DIAGONAL) //Effet d'écran
        );
    }

    @Override
    public AbstractCard makeCopy() {
        return new TestAttack();
    }

    //Traitement au moment de la mise à niveau de la carte
    @Override
    public void upgrade() {
        if (!this.upgraded) {
            upgradeName();
            upgradeDamage(UPGRADE_PLUS_DMG);
        }
    }
}

Oui, merci pour votre travail acharné. Il y a beaucoup de choses à faire simplement en ajoutant un nouveau type de carte. Il y a toujours.

examle_mod +.idea +src -+main --+java ---Main.java ---+example_mod ----+cards -----TestAttack.java ----+paches -----LibraryTypeEnum.java -----AbstractCardEnum.java --+resource

Nous devons maintenant ajouter les fichiers image et langue à la ressource. Créez un répertoire img / cards et un répertoire de localisation sous resource. Les fichiers suivants sont requis dans img / cards. Tous sont des fichiers png transparents.

bg_attack_512.png Contexte de la carte d'attaque. 512 x 512 bg_skill_512.png Contexte de la carte de compétence. 512 x 512 bg_power_512.png Arrière-plan de la carte d'alimentation. 512x512 Vous n'avez pas à préparer le groupe sous le nom de la carte. orb_512.png Orbe d'énergie. Puisqu'il peut être placé sur une carte 512x512, il doit être dessiné petit en haut à gauche. bg_attack_1024.png Cette zone doit être étendue de 512 à 1024x1024. bg_skill_1024.png bg_power_1024.png orb_1024.png Cependant, ce type ne doit pas agrandir 512 (le point central est différent). Eh bien, je pense qu'il vaut mieux réduire chacun de ces gros. orb_ui.png Affichage lorsqu'il est probablement utilisé dans les puces d'outils. 23 x 23 card.png Conception de cartes. À l'origine, il est facile de faire correspondre le nom de la carte (nom de la classe de la carte). Eh bien parce que c'est un test. 250 x 190 card_p.png Une grande version du design. Vous pouvez agrandir ce qui précède. 500x380. Puisqu'il est utilisé automatiquement, il n'est spécifié dans aucune classe.

Les fichiers json suivants sont requis pour la localisation.

cards-JPN.json


{
  "examplemod:TestAttack": { //Identifiant du mod:Écrivez avec le nom de la carte. Sinon, je le porterai.
  "NAME": "nom de la carte",
  "DESCRIPTION": "Une description de la carte.!d!Si vous écrivez, la valeur des dommages sortira, mais veuillez vérifier ici"
   }
}

Eh bien, il est fabriqué à l'étranger, alors veuillez créer cards-ENG.json et préparez-le en anglais.

Non, j'ai oublié, mais s'il n'y a pas de json ci-dessous directement sous les ressources, diverses choses seront dites lors de la sélection de Mod, alors veuillez le mettre.

ModTheSpire.json

{
  "modid": "examplemod",
  "name": "examplemod",
  "author_list": ["yourname"],
  "description": "",
  "version": "0.0.1",
  "sts_version": "01-01-2019",  //Quelle version de Slay the Spire devrait être supérieure?
  "mts_version": "3.6.0", //Je pense que c'est une histoire sur la version de Mod the Spire qui devrait être supérieure, donc c'est approprié
  "dependencies": ["basemod"],
  "update_json": ""
}

Vive le bon travail. Cela devrait maintenant fonctionner.

--+java ---Main.java ---+example_mod ----+cards -----TestAttack.java ----+paches -----LibraryTypeEnum.java -----AbstractCardEnum.java --+resource ---ModTheSpire.json ---+img ----+cards ----- Plein d'images pour les cartes ---+localization ----cards-JPN.json ----cards-ENG.json

Si vous double-cliquez sur "Cycle de vie> package" dans la fenêtre ouverte par "Afficher> Outils Windows> Projets Maven", vous pouvez le construire et vous aurez un fichier .jar dans le dossier cible. Veuillez traiter l'erreur.

Lancez le MOD

Créez un dossier appelé mods dans steamapps \ common \ SlayTheSpire dans la bibliothèque Steam. Mettez le example_mod.jar que vous avez créé précédemment et BaseMod.jar dans ce mods.

Directement sous steamapps \ common \ SlayTheSpire, mettez MTS.cmd qui était à l'intérieur lorsque ModTheSpire.zip a été décompressé. Les utilisateurs de Mac semblent préférer .sh.

Ainsi, lorsque j'exécute MTS.cmd,

image.png

Donc, vérifiez BaseMod et example_mod, puis vérifiez Debug et appuyez sur Play. D'une manière ou d'une autre, example_mod est gris et ne peut pas être sélectionné car la mts_version spécifiée dans ModTheSpire.json est incorrecte.

S'il démarre en toute sécurité, example_mod est ajouté à la bibliothèque de cartes et une carte sympa est ajoutée, il réussit jusqu'à présent. Je vous remercie pour votre travail acharné.

Ajouter un personnage ... Avant, relique ou pouvoir

Si vous souhaitez ajouter un personnage, vous avez besoin d'une relique de départ, et la carte a également besoin de puissance en plus des compétences. Alors allons-y tout à la fois. De l'ajout de reliques. Créez un répertoire de reliques sous java / example_mod et créez les classes suivantes.

TestRelic.java


package example_mod.relics;

import basemod.abstracts.CustomRelic;
import com.megacrit.cardcrawl.helpers.ImageMaster;
import com.megacrit.cardcrawl.relics.AbstractRelic;

//Entrez par capacité
import com.megacrit.cardcrawl.dungeons.AbstractDungeon;
import com.megacrit.cardcrawl.powers.RegenPower;
import com.megacrit.cardcrawl.actions.common.ApplyPowerAction;
import com.megacrit.cardcrawl.actions.common.RelicAboveCreatureAction;

public class TestRelic extends CustomRelic {

    public static final String ID = "examplemod:TestRelic";
    public static final String IMG = "img/relics/TestRelic.png ";
    public static final String OUTLINE_IMG = "img/relics/outline/TestRelic.png ";

    public TestRelic(){
        super(
                ID,
                ImageMaster.loadImage(IMG),
                ImageMaster.loadImage(OUTLINE_IMG),
                RelicTier.STARTER,  //Rareté. Voici la relique de départ
                LandingSound.FLAT
        );
    }

    public String getUpdatedDescription(){
        return DESCRIPTIONS[0];
    }

    @Override
    public AbstractRelic makeCopy(){
        return new TestRelic();
    }

    //Obtenez 5 pièces au début de la bataille
    @Override
    public void onEquip() {
        AbstractDungeon.rareRelicPool.remove("Dead Branch");
    }

    public void atBattleStart() {
        AbstractDungeon.actionManager.addToBottom(
                new RelicAboveCreatureAction(AbstractDungeon.player, this)
        );
        AbstractDungeon.actionManager.addToBottom(
                new ApplyPowerAction(
                        AbstractDungeon.player,
                        AbstractDungeon.player,
                        new RegenPower(AbstractDungeon.player, 5),
                        5
                )
        );
    }
}

Créez un répertoire de reliques sous resources / img et préparez les fichiers image suivants.

TestRelic.png 128x128 png transparent

De plus, créez un répertoire de contour sous le répertoire des reliques et préparez les fichiers image suivants.

TestRelic.png 128x128 png transparent. Celui avec l'image dans le répertoire ci-dessus peint en blanc.

Maintenant que vous avez également besoin d'un fichier texte, préparez les fichiers suivants dans resources / localisation.

relics-JPN.json


{
  "examplemod:TestRelic": {
    "NAME": "Nom de la relique",
    "FLAVOR": "Texte de la saveur",
    "DESCRIPTIONS": [
      "Texte explicatif. Notez qu'il est au pluriel avec S. Lorsque vous mettez une variable dans la description, décomposez-la et placez-la entre"
    ]
  }
}

Comme il est fabriqué à l'étranger, veuillez également créer relics-ENG.json et le préparer en anglais.

Ensuite, ajoutez de la puissance. La puissance elle-même est ajoutée et la carte qui gagne en puissance est ajoutée. Créez un répertoire powers sous example_mod et créez les classes suivantes.

TestPowerGold.java


package example_mod.powers;

import com.badlogic.gdx.graphics.Texture;
import com.megacrit.cardcrawl.core.AbstractCreature;
import com.megacrit.cardcrawl.core.CardCrawlGame;
import com.megacrit.cardcrawl.powers.AbstractPower;
import com.megacrit.cardcrawl.localization.PowerStrings;

public class TestPowerGold extends AbstractPower {
    public static final String POWER_ID = "examplemod:TestPowerGold";
    private static final PowerStrings powerStrings =
            CardCrawlGame.languagePack.getPowerStrings(POWER_ID);
    public static final String NAME = powerStrings.NAME;
    public static final String[] DESCRIPTIONS = powerStrings.DESCRIPTIONS;

    public TestPowerGold(AbstractCreature owner, int amount) {
        this.name = NAME;
        this.ID = POWER_ID;
        this.owner = owner;
        this.amount = amount;
        this.type = AbstractPower.PowerType.BUFF;
        updateDescription();
        this.img = new Texture("img/powers/TestPower.png ");
    }

    public void updateDescription() {
        this.description = (DESCRIPTIONS[0] + this.amount + DESCRIPTIONS[1]); //C'est ainsi que la description est divisée.
    }
}

Vous aurez également besoin d'un fichier texte, alors préparez les fichiers suivants dans resources / localisation.

powers-JPN.json


{
  "examplemod:TestPowerGold": {
    "NAME": "Nom de puissance",
    "DESCRIPTIONS": [
      "L'or à la fin de la bataille",
      "Avoir"
      ]
  }
}

Ce qui est préparé ici est un modèle de pouvoir. La puissance spécifique doit être inscrite sur la carte. Préparez les classes suivantes dans example_mod / cards.

TestPower.java


package example_mod.cards;

import basemod.abstracts.CustomCard;
import com.megacrit.cardcrawl.actions.common.ApplyPowerAction;
import com.megacrit.cardcrawl.cards.AbstractCard;
import com.megacrit.cardcrawl.characters.AbstractPlayer;
import com.megacrit.cardcrawl.core.CardCrawlGame;
import com.megacrit.cardcrawl.dungeons.AbstractDungeon;
import com.megacrit.cardcrawl.localization.CardStrings;
import com.megacrit.cardcrawl.monsters.AbstractMonster;

import example_mod.patches.AbstractCardEnum;
import example_mod.powers.*; //Celui avec le pouvoir que j'ai fait plus tôt. Parce que c'est ennuyeux*

import com.megacrit.cardcrawl.rooms.AbstractRoom.RoomPhase;


public class TestPower extends CustomCard {
    public static final String ID = "examplemod:TestPower";
    private static CardStrings cardStrings = CardCrawlGame.languagePack.getCardStrings(ID);
    public static final String NAME = cardStrings.NAME;
    public static final String DESCRIPTION = cardStrings.DESCRIPTION;
    public static final String IMG_PATH = "img/cards/card.png "; //Image de la carte. Je vais l'utiliser pour le moment
    private static final int COST = 0; //Coût énergétique
  //Variables spécifiques à la carte
    private static final int GETMONEY = 100;
    private static final int UPGRADE_GETMONEY = 10;

    public TestPower() {
        super(ID, NAME, IMG_PATH, COST, DESCRIPTION,
                CardType.POWER,
                AbstractCardEnum.EXAMPLE_COLOR, //Je le dis plusieurs fois, mais le nom de la couleur
                CardRarity.COMMON,   //Rareté
                CardTarget.SELF //La cible de la carte. Le pouvoir, c'est SELF
        );
        this.magicNumber = this.baseMagicNumber = GETMONEY;
    }

    @Override
    public void use(AbstractPlayer p, AbstractMonster m) {
        //La possibilité d'obtenir de l'argent à la fin de la bataille
        if (AbstractDungeon.getCurrRoom().phase == RoomPhase.COMBAT) {
            AbstractDungeon.getCurrRoom().addGoldToRewards(this.magicNumber);
            AbstractDungeon.actionManager.addToBottom(
                    new ApplyPowerAction(
                            p,
                            p,
                            new TestPowerGold(p, this.magicNumber), //Celui avec le pouvoir que je viens de créer
                            this.magicNumber
                    )
            );
        }
    }

    @Override
    public AbstractCard makeCopy() {
        return new TestPower();
    }

    //Traitement au moment de la mise à niveau de la carte
    @Override
    public void upgrade() {
        if (!this.upgraded) {
            this.upgradeName();
            this.upgradeDamage(UPGRADE_GETMONEY);
        }
    }
}

J'ai également besoin d'une image d'icône d'alimentation. Créez un répertoire powers sous resources / img et préparez les fichiers image suivants.

TestPower.png Fichier transparent 32x32. C'est le seul pouvoir.

--+java ---Main.java ---+example_mod ----+cards -----TestAttack.java -----TestPower.java ----+relics -----TestRelic.java ----+paches -----LibraryTypeEnum.java -----AbstractCardEnum.java ----+powers -----TestPowerGold.java --+resource ---ModTheSpire.json ---+img ----+cards ----- Plein d'images pour les cartes ----+relics -----TestRelic.png -----+outline ------TestRelic.png ----+powers -----TestPower.png ---+localization ----cards-JPN.json ----cards-ENG.json ----relics-JPN.json ----relics-ENG.json ----powers-JPN.json ----powers-ENG.json

Eh bien, cela seul ne fonctionnera pas. Il est nécessaire d'ajouter à example_mod / Main.java.

Modifier Main.java


//Les ajouts suivants sont requis pour l'importation.
import com.megacrit.cardcrawl.localization.RelicStrings;
import com.megacrit.cardcrawl.localization.PowerStrings;
import example_mod.relics.*;

//Plus d'endroits pour implémenter
public class Main implements
        PostInitializeSubscriber,   //Celui qui affiche un badge?
        EditCardsSubscriber,   //Implémenter lors de l'ajout d'une carte
        EditRelicsSubscriber,   //Implémentation lors de l'ajout d'une relique
        EditStringsSubscriber,  //Implémenter lors de la lecture d'un fichier de langue
{

//Augmenter les fichiers de langue
   @Override
    public void receiveEditStrings() {
        BaseMod.loadCustomStringsFile(CardStrings.class, "localization/cards-" + Settings.language + ".json");
        BaseMod.loadCustomStringsFile(RelicStrings.class, "localization/relics-" + Settings.language + ".json");
        BaseMod.loadCustomStringsFile(PowerStrings.class, "localization/powers-" + Settings.language + ".json");
    }

//Augmentez le nombre de cartes à ajouter
    @Override
    public void receiveEditCards() {
        BaseMod.addCard(new training_mod.cards.TestAttack());
        BaseMod.addCard(new training_mod.cards.TestPower());
    }

//Ajouter une relique
    public void receiveEditRelics() {
        //Ajouter une relique
        BaseMod.addRelicToCustomPool(
                new TestRelic(),
                AbstractCardEnum.EXAMPLE_COLOR //Ajoutez à la couleur. La relique commune devient une autre méthode
        );
    }

Si vous construisez et avez une carte pouvoir dans la liste des cartes et qu'elle apparaît dans la relique de départ dans la liste des reliques, vous réussissez. Il y a une création de carte de compétence bien que je ne l'ai pas expliqué, mais vous pouvez le faire pour le moment simplement en changeant le CardType de l'attaque en CardType.SKILL.

Enfin faire un personnage

Désolé de vous avoir fait attendre. Faisons un personnage. En pensant normalement, vous avez d'abord besoin d'une image de personnage, alors faisons-le. Dans l'explication de BaseMod, il est dit que vous pouvez utiliser Spriter. L'explication qui suit est le réglage par le jeu d'images réalisé avec Spine. …… Spine est un logiciel payant, alors allons-y avec Spriter.

Téléchargez ici. https://brashmonkey.com/download_spriter/

Après l'avoir installé, veuillez consulter le didacticiel suivant pour le moment. https://www.youtube.com/watch?v=aQy7eX_CWPM&list=PL8Vej0NhCcI5sxOT64-Z31LW59VUyAVfr&t=0s&index=2

C'est un logiciel amusant qui vous permet de créer un fichier png transparent pour chaque partie (bras, jambes, etc.), de le placer dans Spriter et de l'animer sur la timeline.

Je ne peux pas le faire parce que c'est trop amusant, alors créez d'abord un répertoire char / anim sous img, puis créez un projet Spriter en dessous. Eh bien, je pense que vous pouvez utiliser un nom de projet tel que exampleChar. Placez-y l'image du personnage.

--+java ---Main.java ---+example_mod ----+cards ----+relics ----+paches ----+powers --+resource ---+img ----+char -----+anim ------ CharacterImage.png Fichier PNG transparent 512x512

Ensuite CharacterImage.png sera visible sur le Splitter, donc si vous double-cliquez pour déterminer le point de référence, sélectionnez directement ci-dessous, jetez l'image et placez-la à x0, y0.

image.png

C'est bon, c'est approprié ... Je ne l'anime généralement pas, et vous ne l'avez pas vu, non? Caractère STS.

J'ai besoin de plus d'images que ça. Veuillez préparer ce qui suit.

--+java ---Main.java ---+example_mod ----+cards ----+relics ----+paches ----+powers --+resource ---+img ----+char ----- ExampleCorpse.png Fichier png transparent 512x512. C'est celui où il est mort. ----- ExampleShoulder.png 1920x1136 fichier png transparent. C'est une image de derrière qui est affichée dans un camp. -----+anim ------ CharacterImage.png Fichier png transparent 512x512. Il y a un instant ------ ExampleChar.scml Fichier enregistré par Spriter. Informations telles que le placement et l'animation. Je vais l'utiliser après cela. ----+charSelect ----- ExampleButton.png Fichier png transparent 200x200. Bouton à presser sur l'écran de sélection des personnages ----- ExamplePortrait.png 1920x1200 fichier png transparent. L'arrière-plan qui apparaît après avoir appuyé sur le bouton ci-dessus. Ravi de vous rencontrer.

Bon travail. Le matériel est maintenant terminé. Ajoutons des personnages. Tout d'abord, ajoutez la classe suivante à example_mod / paches.

ExampleClassEnum.java


package example_mod.patches;
import com.evacipated.cardcrawl.modthespire.lib.SpireEnum;
import com.megacrit.cardcrawl.characters.AbstractPlayer;

//L'exemple du nom de classe peut être le nom du MOD à créer.

public class ExampleClassEnum {
    @SpireEnum
    public static AbstractPlayer.PlayerClass ExampleClass;
}

Créez un répertoire example_mod / character et ajoutez-y les classes suivantes.

ExampleChar.java


package example_mod.character;

//Je l'ai importé même si je ne l'utilise pas, mais je pense qu'il viendra un moment où j'aurai besoin de quelque chose.
import java.util.ArrayList;
import java.util.List;

import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.BitmapFont;
import com.badlogic.gdx.graphics.g2d.TextureAtlas;
import basemod.abstracts.CustomPlayer;
import basemod.animations.SpriterAnimation;

import com.megacrit.cardcrawl.actions.AbstractGameAction;
import com.megacrit.cardcrawl.cards.AbstractCard;
import com.megacrit.cardcrawl.characters.AbstractPlayer;
import com.megacrit.cardcrawl.core.CardCrawlGame;
import com.megacrit.cardcrawl.core.EnergyManager;
import com.megacrit.cardcrawl.cutscenes.CutscenePanel;
import com.megacrit.cardcrawl.dungeons.AbstractDungeon;
import com.megacrit.cardcrawl.events.city.Vampires;
import com.megacrit.cardcrawl.helpers.*;
import com.megacrit.cardcrawl.localization.CardStrings;
import com.megacrit.cardcrawl.localization.CharacterStrings;
import com.megacrit.cardcrawl.screens.CharSelectInfo;
import com.megacrit.cardcrawl.screens.stats.CharStat;
import com.megacrit.cardcrawl.unlock.UnlockTracker;
import com.megacrit.cardcrawl.actions.AbstractGameAction.AttackEffect;

import example_mod.cards.*;
import example_mod.relics.*;
import example_mod.patches.*;

public class TrainingChar extends CustomPlayer {
    public static final CharacterStrings charStrings = CardCrawlGame.languagePack.getCharacterString("examplemod:ExampleChar");
    public static final int ENERGY_PER_TURN = 3; //Combien d'énergie pouvez-vous obtenir pour un tour
    public static final String EXAMPLECHAR_SHOULDER_2 = "img/char/ExampleShoulder.png "; //Dans les coulisses du camp
    public static final String EXAMPLECHAR_SHOULDER_1 = "img/char/ExampleShoulder.png "; //D'autres images derrière. Si vous voulez le diviser, faites-le.
    public static final String EXAMPLECHAR_CORPSE = "img/char/ExampleCorpse.png "; //Image de cadavre

    public ExampleChar(String name){
        super(name,
                ExampleClassEnum.ExampleClass,
                null,
                null,
                null,
                new SpriterAnimation("img/char/anim/ExampleChar.scml") //Fichiers créés avec Spriter
        );
        initializeClass(null,
                EXAMPLECHAR_SHOULDER_2,
                EXAMPLECHAR_SHOULDER_1,
                EXAMPLECHAR_CORPSE,
                getLoadout(),
                20.0F,
                -10.0F,
                220.0F,
                290.0F,
                new EnergyManager(ENERGY_PER_TURN)
        );

    }

    @Override
    public String getTitle(AbstractPlayer.PlayerClass playerClass){
        return charStrings.NAMES[0];
    }
    @Override
    public String getSpireHeartText(){
        return charStrings.TEXT[0];
    }
    @Override
    public String getLocalizedCharacterName() {
        return charStrings.NAMES[0]; //Je ne sais pas en quoi ce qui précède est différent. Est-ce normal d'être pareil?
    }
    @Override
    public String getVampireText() {
        //Événement vampire. Je pense que 0 est revêtu de fer et 1 est silencieux, mais je ne sais pas.
        return Vampires.DESCRIPTIONS[0];
    }
    public Color getCardRenderColor() {
        return CardHelper.getColor(100.0f, 50.0f, 50.0f);   //EXAMPLE_COLOR_Est-ce la même chose que BG?
    }
    public Color getCardTrailColor() {
        return CardHelper.getColor(100.0f, 50.0f, 50.0f);   //EXAMPLE_COLOR_Est-ce la même chose que BG?
    }
    public Color getSlashAttackColor() {
        return CardHelper.getColor(100.0f, 50.0f, 50.0f);   //EXAMPLE_COLOR_Est-ce la même chose que BG?
    }
    public AttackEffect[] getSpireHeartSlashEffect() {
        //Cela semble être un effet, mais je ne suis pas sûr de ce que c'est.
        return new AttackEffect[]{
                AttackEffect.SLASH_HEAVY,
                AttackEffect.FIRE,
                AttackEffect.SLASH_DIAGONAL,
                AttackEffect.SLASH_HEAVY,
                AttackEffect.FIRE,
                AttackEffect.SLASH_DIAGONAL
        };
    }
    public AbstractCard getStartCardForEvent() {
        return new TestPower() ;    //Je ne sais pas à quoi ça sert, mais pour le moment
    }
    public BitmapFont getEnergyNumFont() {
        return FontHelper.energyNumFontBlue;
    }
    public void doCharSelectScreenSelectEffect() {
        //Je pense que c'est le son et l'effet d'écran lorsque vous sélectionnez un personnage
        CardCrawlGame.sound.playV("AUTOMATON_ORB_SPAWN", 1.75f);
        CardCrawlGame.screenShake.shake(ScreenShake.ShakeIntensity.LOW, ScreenShake.ShakeDur.SHORT, true);
    }
    public String getCustomModeCharacterButtonSoundKey() {
        return "AUTOMATON_ORB_SPAWN";
    }

    public AbstractCard.CardColor getCardColor() {
        //La couleur de la carte utilisée pour ce personnage
        return AbstractCardEnum.EXAMPLE_COLOR; //Variable de couleur de carte. Ne fais pas d'erreur.
    }

    public AbstractPlayer newInstance() {
        return new ExampleChar(this.name);
    }


    public ArrayList<String> getStartingDeck() { //Le contenu du jeu initial. Insérez la rareté BASIQUE de base. comme vous voulez.
        ArrayList<String> retVal = new ArrayList<>();
        retVal.add(TestAttack.ID);
        retVal.add(TestAttack.ID);
        retVal.add(TestAttack.ID);
        retVal.add(TestAttack.ID);
        retVal.add(TestAttack.ID);
        retVal.add(TestAttack.ID);
        retVal.add(TestAttack.ID);
        retVal.add(TestAttack.ID);
        retVal.add(TestAttack.ID);
        return retVal;
    }

    public ArrayList<String> getStartingRelics() { //Désignation de la relique de départ.
        ArrayList<String> retVal = new ArrayList<>();
        retVal.add(TestRelic.ID);
        UnlockTracker.markRelicAsSeen(TestRelic.ID);
        return retVal;
    }

    //La partie qui détermine la capacité du personnage
    private static final int STARTING_HP = 75;
    private static final int MAX_HP = 75;
    private static final int STARTING_GOLD = 99;
    private static final int HAND_SIZE = 5;
    private static final int ORB_SLOTS = 0;
    private static final int ASCENSION_MAX_HP_LOSS = 5;

    public int getAscensionMaxHPLoss() {
        return ASCENSION_MAX_HP_LOSS;
    }

    public CharSelectInfo getLoadout() { //Je pense que ce sont les informations qui apparaissent sur l'écran de sélection des personnages
        return new CharSelectInfo(
                charStrings.NAMES[0],
                charStrings.TEXT[0],
                STARTING_HP,
                MAX_HP,
                ORB_SLOTS,
                STARTING_GOLD,
                HAND_SIZE,
                this,
                getStartingRelics(),
                getStartingDeck(),
                false);
    }
}

Ajoutez les fichiers suivants aux ressources / localisation.

char-JPN.json

{
  "examplemod:ExampleChar": {
    "NAMES": ["Le nom du personnage"],
    "TEXT": ["Texte explicatif. Si vous souhaitez le modifier en fonction de l'emplacement, divisez-le"]
  }
}

Puisqu'il s'agit d'un ry d'outre-mer, veuillez également préparer char-ENG.json.

Maintenant, la dernière modification de example_mod / Main.java.

Main.java

import basemod.BaseMod;
import basemod.interfaces.*;
import com.evacipated.cardcrawl.modthespire.lib.SpireInitializer;
import com.megacrit.cardcrawl.core.Settings;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.Texture;
import com.megacrit.cardcrawl.helpers.CardHelper;
import com.megacrit.cardcrawl.localization.CardStrings;
import com.megacrit.cardcrawl.localization.CharacterStrings;
import com.megacrit.cardcrawl.localization.RelicStrings;
import com.megacrit.cardcrawl.localization.PowerStrings;

//C'est à ce moment que vous souhaitez sortir le journal de débogage
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import example_mod.patches.*;
import example_mod.relics.*;

@SpireInitializer
public class Main implements
        EditCardsSubscriber,   //Implémenter lors de l'ajout d'une carte
        EditRelicsSubscriber,   //Implémentation lors de l'ajout d'une relique
        EditStringsSubscriber,  //Implémenter lors de la lecture d'un fichier de langue
        EditCharactersSubscriber //Implémenter lors de l'ajout d'un personnage
{
    private static final Color EXAMPLE_COLOR_BG = CardHelper.getColor(100.0f, 50.0f, 50.0f);
    private static final String ATTACK_EXAMPLE         = "img/cards/bg_attack_512.png ";
    private static final String SKILL_EXAMPLE          = "img/cards/bg_skill_512.png ";
    private static final String POWER_EXAMPLE           = "img/cards/bg_power_512.png ";
    private static final String ENERGY_ORB_EXAMPLE         = "img/cards/orb_512.png ";
    private static final String ATTACK_PORT_EXAMPLE        = "img/cards/bg_attack_1024.png ";
    private static final String SKILL_PORT_EXAMPLE         = "img/cards/bg_skill_1024.png ";
    private static final String POWER_PORT_EXAMPLE         = "img/cards/bg_power_1024.png ";
    private static final String ENERGY_ORB_PORT_EXAMPLE = "img/cards/orb_1024.png ";
    private static final String ENERGY_ORB_CARD_EXAMPLE = "img/cards/orb_ui.png ";

    //Lorsque vous souhaitez générer un journal de débogage.
    public static final Logger logger = LogManager.getLogger(Main.class.getName());


    public Main(){
        BaseMod.subscribe(this);
        BaseMod.addColor(
                AbstractCardEnum.EXAMPLE_COLOR    //Variables de couleur
                , EXAMPLE_COLOR_BG //bgColor
                , EXAMPLE_COLOR_BG//backColor
                , EXAMPLE_COLOR_BG//frameColor
                , EXAMPLE_COLOR_BG//frameOutlineColor
                , EXAMPLE_COLOR_BG//descBoxColor
                , EXAMPLE_COLOR_BG //trailVfColor
                , EXAMPLE_COLOR_BG//glowColor
                , ATTACK_EXAMPLE//attackBg
                , SKILL_EXAMPLE//skillBg
                , POWER_EXAMPLE//powerBG
                , ENERGY_ORB_EXAMPLE//energyOrb
                , ATTACK_PORT_EXAMPLE//attackBgPortrait
                , SKILL_PORT_EXAMPLE//skillBgPortrait
                , POWER_PORT_EXAMPLE//powerBgPortrait
                , ENERGY_ORB_PORT_EXAMPLE//energyOrbPortrait
                , ENERGY_ORB_CARD_EXAMPLE//CardEnergyOrb
        );
    }

    public static void initialize() {
        Main main = new Main();
    }

    @Override
    public void receiveEditStrings() {
        BaseMod.loadCustomStringsFile(CardStrings.class, "localization/cards-" + Settings.language + ".json");
        BaseMod.loadCustomStringsFile(RelicStrings.class, "localization/relics-" + Settings.language + ".json");
        BaseMod.loadCustomStringsFile(CharacterStrings.class, "localization/char-" + Settings.language + ".json");
        BaseMod.loadCustomStringsFile(PowerStrings.class, "localization/powers-" + Settings.language + ".json");
    }

    @Override
    public void receiveEditCards() {
        BaseMod.addCard(new example_mod.cards.TestAttack());
        BaseMod.addCard(new example_mod.cards.TestPower());
        //Je t'expliquerai plus tard
    }

    @Override
    public void receiveEditCharacters() {
        //Ajout de caractères définis de manière unique
        BaseMod.addCharacter(
                new example_mod.character.ExampleChar("ExampleCharacter"),
                "img/charSelect/ExampleButton.png ",
                "img/charSelect/ExamplePortrait.png ",
                ExampleClassEnum.ExampleClass
        );

    }

    public void receiveEditRelics() {
        //Ajouter une relique
        logger.info("begin editing relics"); //C'est ainsi que le journal de débogage est généré.
        BaseMod.addRelicToCustomPool(
                new TestRelic(),
                AbstractCardEnum.EXAMPLE_COLOR //Ajoutez à la couleur. La relique commune est une autre méthode
        );
        logger.info("done editing relics");
    }
}

Maintenant, construisez-le, sélectionnez le personnage et le jeu commence, et vous avez terminé! Je vous remercie pour votre travail acharné!

…… e? Va-t-il se solidifier une fois la bataille terminée?

Oh, c'est parce qu'il n'y a pas assez de cartes. Allez-vous afficher 3 cartes au hasard à la fin de la bataille? Si vous avez procédé comme ça maintenant, il n'y a que deux types, donc il plantera. Je pense que le journal de débogage est également arrêté à ce stade.

Ensuite, je ne sais pas combien de caractères sont nécessaires pour le personnage MOD (veuillez me le dire).

Je ne sais pas, mais la sélection de cartes est généralement de 3 cartes, elle peut être augmentée de +1 par relique, et lorsque le boss est vaincu, toutes sont rares, donc Eh bien, s'il y a 4 types de puissance d'attaque COMMUN, UNCOMMON et RARE, cela fonctionnera au moins. 3 catégories x 3 rares x 4 types, 36 feuilles? Si vous regardez les MOD des autres, il y en a environ 70 ...

Pour le moment, j'ai augmenté la production de cartes avec la même capacité dans mon référentiel pour que ça marche, donc je pense que c'est devenu un modèle.

C'était un peu embarrassant que le référentiel soit «formation» au lieu d '«exemple». Je me demande si l'exemple est le même que l'explication de BaseMod.

c'est tout.

Autres notes ・ Si vous piochez une carte qui n'est normalement pas disponible en raison de l'effet, préparez-lui une couleur de carte et rendez la rareté SPECIALE? -Préparer "UPGRADE_DESCRIPTION" lors de la modification de la description par mise à jour.

Recommended Posts

Comment faire un MOD pour Slay the Spire
Introduction au développement du mod Slay the Spire (1) Introduction
Introduction au développement de modules Slay the Spire (2) Construction de l'environnement de développement
Comment créer un conteneur Java
Comment signer Minecraft MOD
Comment créer un pilote JDBC
Comment créer un écran de démarrage
Comment créer un plug-in Jenkins
Comment faire un projet Maven
Comment créer un tableau Java
SDWebImage: Comment vider le cache pour une UIImageView particulière
Introduction au développement du mod Slay the Spire (3) Définition de la carte originale
Comment créer un résumé de calendrier Java
Comment créer un référentiel Maven pour 2020
Comment créer un robot Discord (Java)
Comment identifier le chemin sur lequel il est facile de se tromper
Comment vérifier le contenu de la chaîne de caractères java de longueur fixe
Comment faire un diamant révolutionnaire en utilisant Java pour déclaration wwww
Comment créer une base de données H2 n'importe où
Faire une marge à gauche du TextField
Comment créer des pages pour le tableau "kaminari"
[Java] (pour MacOS) Méthode de définition du chemin de classe
[Java] Comment rendre plusieurs boucles for uniques
Comment faire un pot ombré
Comment faire une méthode de jugement pour rechercher n'importe quel caractère dans le tableau
Comment créer une combinaison unique de données dans la table intermédiaire des rails
Comment exécuter l'application SpringBoot en tant que service
Comment utiliser un tableau pour la clé TreeMap
Comment écrire un test unitaire pour Spring Boot 2
[Spring Boot] Comment créer un projet (pour les débutants)
Comment écrire un mod de base dans Minecraft Forge 1.15.2
Comment étudier le kotlin pour la première fois ~ Partie 2 ~
Comment étudier le kotlin pour la première fois ~ Partie 1 ~
Java - Comment créer JTable
Comment laisser un commentaire
[Rails] Comment faire des graines
Comment insérer une vidéo
Comment créer une méthode
Comment créer une partie d'espace réservé à utiliser dans la clause IN
Apprendre Ruby avec AtCoder 13 Comment créer un tableau à deux dimensions
[Ruby] Comment récupérer le contenu du double hachage
Comment générer des valeurs de tableau sans utiliser d'instruction for
Comment ajouter les mêmes index dans un tableau imbriqué
Minecraft Modding [1.12] Comment attacher un rendu spécial pour Item
Un mémorandum pour atteindre le lieu qui démange pour Java Gold
[jsoup] Comment obtenir la totalité de la documentation
Comment créer et lancer un Dockerfile pour Payara Micro
Une petite histoire addictive après la mise à jour du pilote JDBC pour PostgreSQL
Comment créer un pilote JDBC
Comment obtenir le dernier ID de diffusion en direct pour une chaîne sans utiliser l'API de données YouTube
Mécanisme de conversion vers une langue que le navigateur peut reconnaître
Comment utiliser la méthode form_with
Essayez de faire un simple rappel
Comment spécifier la validation pour time_field
Comment installer JMeter pour Mac
Comment trouver l'angle moyen