実績の追加(1.7.10)

1.7.10の開発講座を修正中です。このページには誤りや古い情報が含まれる可能性があります。

実績を追加する方法。
※当チュートリアルでは、「イベントの実装」の内容を一部使用しております。
イベントの実装は現在チュートリアルにはありませんが、今後追加予定ですのでしばらくお待ち下さい。

ソースコード


package tutorial.aluminiummod;

import cpw.mods.fml.common.Mod; import cpw.mods.fml.common.event.FMLInitializationEvent; import cpw.mods.fml.common.event.FMLPreInitializationEvent; import cpw.mods.fml.common.registry.GameRegistry; import net.minecraft.block.Block; import net.minecraft.creativetab.CreativeTabs; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.init.Items; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraft.stats.Achievement; import net.minecraft.world.World; import net.minecraftforge.common.AchievementPage; import net.minecraftforge.common.MinecraftForge;

@Mod(modid = "AluminiumMod", name = "Aluminium Mod", version = "1.0.0") public class AluminiumMod {

//追加するアイテム・ブロックの宣言 public static Item aluminium; public static Block blockAluminiumOre; //追加する実績の宣言 public static Achievement getAluminium; public static Achievement slayCreeper;

@Mod.EventHandler public void preInit(FMLPreInitializationEvent event) { //アイテムの実装 aluminium = new Item() { //アイテムがクラフト・精錬されたときに呼ばれるメソッド。 public void onCreated(ItemStack stack, World world, EntityPlayer player) { //Player.triggerAchievement(Statbase) //Statbaseには実績のインスタンスを入れる。これにより、未解除の実績が解除される。 player.triggerAchievement(AluminiumMod.getAluminium); super.onCreated(stack, world, player); } } //以下はアイテム・ブロックの実装と同様。 .setCreativeTab(CreativeTabs.tabMaterials) .setUnlocalizedName("aluminium") .setTextureName("aluminiummod:aluminium"); GameRegistry.registerItem(aluminium, "aluminium");

blockAluminiumOre = new AluminiumOre() .setBlockName("blockAluminiumOre") .setBlockTextureName("aluminiummod:aluminium_ore"); GameRegistry.registerBlock(blockAluminiumOre, "blockAluminiumOre");

//実績の実装 //内部名称, 言語名称, 縦の位置, 横の位置, アイコンのアイテム, 親実績 //縦の位置はマイナスで上 横の位置はマイナスで左 //Achievement.setSpecial()で、エフェクトを付けられる。 this.getAluminium = new Achievement("getAluminium", "getAluminium", 0, 0, new ItemStack(this.aluminium, 0), null).registerStat(); this.slayCreeper = new Achievement("slayCreeper", "slayCreeper", 1, -1, new ItemStack(Items.skull, 0, 4), this.getAluminium).setSpecial().registerStat();

//実績ページの実装 //ページ名称, 実績の配列 AchievementPage.registerAchievementPage(new AchievementPage("AluminiumMod", new Achievement[]{this.getAluminium, this.slayCreeper}));

//イベントクラスの登録 MinecraftForge.EVENT_BUS.register(new AluminiumEvent()); }

@Mod.EventHandler public void init(FMLInitializationEvent event) { //クラフト・精錬レシピの追加 GameRegistry.addShapelessRecipe(new ItemStack(AluminiumMod.aluminium), AluminiumMod.blockAluminiumOre); GameRegistry.addSmelting(AluminiumMod.blockAluminiumOre, new ItemStack(AluminiumMod.aluminium), 0.8F); }

}

AluminiumOre.java

鉱石の追加 のものと同様。


package tutorial.aluminiummod;

import cpw.mods.fml.common.eventhandler.SubscribeEvent; import net.minecraft.entity.monster.EntityCreeper; import net.minecraft.entity.player.EntityPlayer; import net.minecraftforge.event.entity.living.LivingDeathEvent; import net.minecraftforge.event.entity.player.EntityItemPickupEvent;

//イベントクラス。詳細の解説は今後実装予定。 public class AluminiumEvent {

//アイテムを拾った時のイベント @SubscribeEvent public void EntityItemPickUpEvent(EntityItemPickupEvent e) { if (e.entityPlayer != null && e.item != null && e.item.getEntityItem() != null && e.item.getEntityItem().getItem() == AluminiumMod.aluminium) { e.entityPlayer.triggerAchievement(AluminiumMod.getAluminium); } }

//Entityが倒された時のイベント @SubscribeEvent public void LivingDeathEvent(LivingDeathEvent e) { if (e.entityLiving != null && e.entityLiving instanceof EntityCreeper && e.source.getEntity() != null && e.source.getEntity() instanceof EntityPlayer) { ((EntityPlayer) e.source.getEntity()).triggerAchievement(AluminiumMod.slayCreeper); } } }

なお、「バニラのアイテムがクラフトされたとき」などは以下のようなコードをAluminiumEventに追加すれば良い。
「アイテム"Skull"でメタデータ"4"に設定されたItemStackがプレイヤーのインベントリ内にあるかどうかチェックする」動作を実装したイベント。

//EntityLivingのアップデートごとに呼ばれるイベント。毎tick呼ばれるので非推奨。
    @SubscribeEvent
    public void LivingUpdateEvent(LivingEvent.LivingUpdateEvent e) {
        if (e.entityLiving instanceof EntityPlayer) {
            for (ItemStack itemStack : ((EntityPlayer) e.entityLiving).inventory.mainInventory) {
                if (itemStack != null && itemStack.getItem() == Items.skull && itemStack.getItemDamage() == 4){
                    ((EntityPlayer) e.entityLiving).triggerAchievement(AluminiumMod.slayCreeper);
                }
            }
        }
    }

解説

通常、MinecraftForgeのテスト環境ではユーザー名を毎回振り直すので実績は保存されない。
そのため、プログラム引数に"-username=[ユーザー名]"(例:-username=hogehoge)を渡すことでユーザー名を固定し、テスト環境でも実績を保存できる。
(なお、このような措置を取らなくても実際にMinecraftLauncherから起動した場合はユーザー名通りに実績が保存できる。)
これは、その他のスコアボード、マルチでのテスト等でも使えるテクニックである。

Item

void onCreated(ItemStack stack, World world, EntityPlayer player)

アイテムがクラフト・精錬されたときに呼ばれるメソッド。
作業台・かまどから取り出したときにこのメソッドが呼ばれる。

Achievement

コンストラクタ(String name, String localname, int Xpos, int Ypos, ItemStack stack, Achievement parent)
実績を定義する。コメントの通り引数を渡していく。

void setSpecial()

実績をレアとして設定する。

AchievementPage

コンストラクタ(String name, Achievement[] achievements)

実績ページを定義する。第一引数には名称(のunlocalizedname)、第二引数にはこのページに入れる実績を渡す。
static void registerAchievementPage(AchievementPage page)
実績ページを登録する。

EventBus

register(Object event)

引数にイベントを記述したクラスを渡す。

@SubscribeEvent

イベントを記述したメソッドに必ずつける。これの付いたメソッドには、引数としてフックしたいイベントを渡せるようにする。
詳しくは別ページで解説予定。

EntityPlayer

void triggerAchievement(StatBase stat)

引数に実績を渡すことで、その実績を解除できる。

2件のコメント

  1. 秋葉の大妖精

    プレイヤーのインベントリ内にあるかどうかチェックする動作を実装したイベントで、アイテムではなくブロックを指定したいのですが、「非互換オペランド型 Item と Block」と表示されてしまいできません。どうすればいいですか?

    • Tom Kate

      返信遅くなりまして申し訳ありません。

      基本的に、ItemとBlockは変換不可能(親クラスが異なる)ですので、ブロックの判定をしたい場合はItem.getItemFromBlock(Block block)を用いることになるかと思います。
      この関数を用いることで、ItemBlock (Itemクラスの子クラス)を取得できるので、アイテムとしてブロックの判定ができるかと思います。

コメントはこちらです。(スパム対策の為コメントは手動承認になっています。未承認のコメントは表示されないので連投はお控え下さい。)

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください