zkm00323
加特效,加特技Duang!Duang!Duang!
记得原版了有2个物品的贴图会不断改变
钟和指南针,今天就是参考这两个物品的代码写的

1.给proxy新的功能
我们先来了解一下有哪些方法可以只让单边读取


点击图片查看原网址

但如果有要写在物品的构造函数里的单边函数,以上的方法都行不通
所以我们要自己创造一个方法
在CommonProxy里新建一个方法
public interface CommonProxy {
        public void init();
        
        abstract public boolean isServerSider();
}


abstract表示必须要重写这个方法

之后再ClientProxy里添加这个方法
        @Override
        public boolean isServerSider() {
                return false;
        }


ServerProxy里也要
        @Override
        public boolean isServerSider() {
                return true;
        }






2.研究动态贴图
好接下来我们看一下ItemClock和ItemCompass
有什么共同的东西



他们都有this.addPropertyOverride(new ResourceLocation("xxxx"), new IItemPropertyGetter(){
         ...
         public float apply(ItemStack stack, @Nullable World worldIn, @Nullable EntityLivingBase entityIn){
                  ...
         }
}

注意new ResourceLocation("angle")里面的参数名
呢我们看一下 IItemPropertyGetter()里是什么


所以 IItemPropertyGetter(){后面的 public float apply()应该就是直接实现了这个方法,注意到这个方法的回传是一个float

然后我们去看看ItemCompass的json文件


我们打开 compass.json
{
    "parent": "item/generated",
    "textures": {
        "layer0": "items/compass_16"
    },
    "overrides": [
        { "predicate": { "angle": 0.000000 }, "model": "item/compass" },
        { "predicate": { "angle": 0.015625 }, "model": "item/compass_17" },
        { "predicate": { "angle": 0.046875 }, "model": "item/compass_18" },
        { "predicate": { "angle": 0.078125 }, "model": "item/compass_19" },
        { "predicate": { "angle": 0.109375 }, "model": "item/compass_20" },
        { "predicate": { "angle": 0.140625 }, "model": "item/compass_21" },
        { "predicate": { "angle": 0.171875 }, "model": "item/compass_22" },
        { "predicate": { "angle": 0.203125 }, "model": "item/compass_23" },
        { "predicate": { "angle": 0.234375 }, "model": "item/compass_24" },
        { "predicate": { "angle": 0.265625 }, "model": "item/compass_25" },
        { "predicate": { "angle": 0.296875 }, "model": "item/compass_26" },
        { "predicate": { "angle": 0.328125 }, "model": "item/compass_27" },
        { "predicate": { "angle": 0.359375 }, "model": "item/compass_28" },
        { "predicate": { "angle": 0.390625 }, "model": "item/compass_29" },
        { "predicate": { "angle": 0.421875 }, "model": "item/compass_30" },
        { "predicate": { "angle": 0.453125 }, "model": "item/compass_31" },
        { "predicate": { "angle": 0.484375 }, "model": "item/compass_00" },
        { "predicate": { "angle": 0.515625 }, "model": "item/compass_01" },
        { "predicate": { "angle": 0.546875 }, "model": "item/compass_02" },
        { "predicate": { "angle": 0.578125 }, "model": "item/compass_03" },
        { "predicate": { "angle": 0.609375 }, "model": "item/compass_04" },
        { "predicate": { "angle": 0.640625 }, "model": "item/compass_05" },
        { "predicate": { "angle": 0.671875 }, "model": "item/compass_06" },
        { "predicate": { "angle": 0.703125 }, "model": "item/compass_07" },
        { "predicate": { "angle": 0.734375 }, "model": "item/compass_08" },
        { "predicate": { "angle": 0.765625 }, "model": "item/compass_09" },
        { "predicate": { "angle": 0.796875 }, "model": "item/compass_10" },
        { "predicate": { "angle": 0.828125 }, "model": "item/compass_11" },
        { "predicate": { "angle": 0.859375 }, "model": "item/compass_12" },
        { "predicate": { "angle": 0.890625 }, "model": "item/compass_13" },
        { "predicate": { "angle": 0.921875 }, "model": "item/compass_14" },
        { "predicate": { "angle": 0.953125 }, "model": "item/compass_15" },
        { "predicate": { "angle": 0.984375 }, "model": "item/compass" }
    ]
}



不难发现"angle"就是上面打在this.addPropertyOverride()里面的参数
而这些0.625526的数字就是apply的回传值,用此值判断所在区间
0.000000~0.015624就跑去读取 "model": "item/compass"
0.015625~0.046874就派去读取 "model": "item/compass_17"
...





3.自制动态贴图
好既然我们已经知道动态贴图的秘密了我们就自己做一个吧
在compass里的apply方法,官方在每一个变数和和方法上面加上
@SideOnly(Side.CLIENT)注解来实现单边读取,而我们可以用之前做的proxy判断法来实现

现在我们回到ItemBloodsave的构造函数里添加一句
        public ItemBloodsave(){
                setUnlocalizedName("itembloodsave");
                setRegistryName("itembloodsave");
                setCreativeTab(CreativeTabs.MATERIALS);
                setMaxStackSize(1);
               
                if(!Main.proxy.isServerSider())this.addPropertyOverride(new ResourceLocation("bloodsave"), new ItemBloodsaveTextures());
        }


这样只有客户端会执行此句话
我们设定参数名为"bloodsave"
new 一个 ItemBloodsaveTextures()这里我们还没创建会报错

我们现在来创建ItemBloodsaveTextures()



ItemBloodsaveTextures里输入
public class ItemBloodsaveTextures implements IItemPropertyGetter{
        @Override
        public float apply(ItemStack stack, World worldIn, EntityLivingBase entityIn) {
                if(worldIn == null && entityIn != null)
                        worldIn = entityIn.getEntityWorld();//玩家背包內的物品沒有世界
            if (worldIn != null && stack.getTagCompound() != null && stack.getTagCompound().hasKey("blood")){//阻擋創造模式物品欄
                       return stack.getTagCompound().getInteger("bloodsave");
        }
                return 0;
        }
}



这里我来解释一下,apply是每一个ItemBloodsave,不管在地上,手里,箱子里,玩家物品栏里,创造模式物品栏里,
每一tick都会执行一次(20tick=1sec)
经过我的测试,在不同地方的物品的输入值也不一样
玩家物品栏 worldIn == null,entityIn != null
地上 worldIn != null,entityIn == null
手里 worldIn != null,entityIn != null
创造模式物品栏 worldIn == null,entityIn == null

我们的物品必须被玩家右击以后才有nbt资料
而创造模式物品栏里的item是不可能有nbt资料的,如果硬要去读取则会崩溃
所以以上代码让还没有nbt的血瓶以及创造模式物品栏内的血瓶回传值为0
其他则读取nbt资料来回传1~20

接下来就剩下json文件和把贴图放进去了
我们回到models.item.itembloodsave.json里改写
{
    "parent": "item/generated",
    "textures": {
        "layer0": "soa:items/itembloodsave"
    },
  "overrides": [
    { "predicate": { "bloodsave": 0 },  "model": "soa:item/itembloodsave"    },
    { "predicate": { "bloodsave": 1 },  "model": "soa:item/itembloodsave_1"  },
    { "predicate": { "bloodsave": 8 }, "model": "soa:item/itembloodsave_2" },
    { "predicate": { "bloodsave": 13 }, "model": "soa:item/itembloodsave_3" },
    { "predicate": { "bloodsave": 20 }, "model": "soa:item/itembloodsave_4" }
  ]

}


apply回传值↓
0→"model": "soa:item/itembloodsave"
1~7→"model": "soa:item/itembloodsave_1"
8~12→"model": "soa:item/itembloodsave_2"
13~19→ "model": "soa:item/itembloodsave_3"
20→"model": "soa:item/itembloodsave_4"

再来把1,2,3,4models补上



我就写itembloodsave_1.json的内容吧
{
    "parent": "item/generated",
    "textures": {
        "layer0": "soa:items/itembloodsave_1"
    }
}



"layer0": "soa:items/itembloodsave_1"就是导向的贴图文件路径我之前也说过了
其他的json只是导向不同的贴图文件路径而已我就不写出来了

附上贴图文件,应该知道要丢哪里了吧(textures.items里)
itembloodsave_1
itembloodsave_2
itembloodsave_3
itembloodsave_4






好我们进游戏看看







好,物品的高级玩法似乎就剩多态没讲了我
也是尽量希望做一个实用,并且可以把教程融合在一起的物品
不知道这个血瓶你喜不喜欢呢~

源代码
src_教程6.rar (10.5 KB, 下载次数: 29)



2021.12 数据,可能有更多内容加特效,加特技Duang!Duang!Duang!
记得原版了有2个物品的贴图会不断改变
钟和指南针,今天就是参考这两个物品的代码写的


1.给proxy新的功能
我们先来了解一下有哪些方法可以只让单边读取



点击图片查看原网址


但如果有要写在物品的构造函数里的单边函数,以上的方法都行不通
所以我们要自己创造一个方法
在CommonProxy里新建一个方法
public interface CommonProxy {
  public void init();
 
  abstract public boolean isServerSider();
}



abstract表示必须要重写这个方法


之后再ClientProxy里添加这个方法
  @Override
  public boolean isServerSider() {
    return false;
  }



ServerProxy里也要
  @Override
  public boolean isServerSider() {
    return true;
  }



2.研究动态贴图
好接下来我们看一下ItemClock和ItemCompass
有什么共同的东西




他们都有this.addPropertyOverride(new ResourceLocation("xxxx"), new IItemPropertyGetter(){
   ...
   public float apply(ItemStack stack, @Nullable World worldIn, @Nullable EntityLivingBase entityIn){
   ...
   }
}

注意new ResourceLocation("angle")里面的参数名
呢我们看一下 IItemPropertyGetter()里是什么



所以 IItemPropertyGetter(){后面的 public float apply()应该就是直接实现了这个方法,注意到这个方法的回传是一个float


然后我们去看看ItemCompass的json文件


我们打开 compass.json
{
    "parent": "item/generated",
    "textures": {
  "layer0": "items/compass_16"
    },
    "overrides": [
  { "predicate": { "angle": 0.000000 }, "model": "item/compass" },
  { "predicate": { "angle": 0.015625 }, "model": "item/compass_17" },
  { "predicate": { "angle": 0.046875 }, "model": "item/compass_18" },
  { "predicate": { "angle": 0.078125 }, "model": "item/compass_19" },
  { "predicate": { "angle": 0.109375 }, "model": "item/compass_20" },
  { "predicate": { "angle": 0.140625 }, "model": "item/compass_21" },
  { "predicate": { "angle": 0.171875 }, "model": "item/compass_22" },
  { "predicate": { "angle": 0.203125 }, "model": "item/compass_23" },
  { "predicate": { "angle": 0.234375 }, "model": "item/compass_24" },
  { "predicate": { "angle": 0.265625 }, "model": "item/compass_25" },
  { "predicate": { "angle": 0.296875 }, "model": "item/compass_26" },
  { "predicate": { "angle": 0.328125 }, "model": "item/compass_27" },
  { "predicate": { "angle": 0.359375 }, "model": "item/compass_28" },
  { "predicate": { "angle": 0.390625 }, "model": "item/compass_29" },
  { "predicate": { "angle": 0.421875 }, "model": "item/compass_30" },
  { "predicate": { "angle": 0.453125 }, "model": "item/compass_31" },
  { "predicate": { "angle": 0.484375 }, "model": "item/compass_00" },
  { "predicate": { "angle": 0.515625 }, "model": "item/compass_01" },
  { "predicate": { "angle": 0.546875 }, "model": "item/compass_02" },
  { "predicate": { "angle": 0.578125 }, "model": "item/compass_03" },
  { "predicate": { "angle": 0.609375 }, "model": "item/compass_04" },
  { "predicate": { "angle": 0.640625 }, "model": "item/compass_05" },
  { "predicate": { "angle": 0.671875 }, "model": "item/compass_06" },
  { "predicate": { "angle": 0.703125 }, "model": "item/compass_07" },
  { "predicate": { "angle": 0.734375 }, "model": "item/compass_08" },
  { "predicate": { "angle": 0.765625 }, "model": "item/compass_09" },
  { "predicate": { "angle": 0.796875 }, "model": "item/compass_10" },
  { "predicate": { "angle": 0.828125 }, "model": "item/compass_11" },
  { "predicate": { "angle": 0.859375 }, "model": "item/compass_12" },
  { "predicate": { "angle": 0.890625 }, "model": "item/compass_13" },
  { "predicate": { "angle": 0.921875 }, "model": "item/compass_14" },
  { "predicate": { "angle": 0.953125 }, "model": "item/compass_15" },
  { "predicate": { "angle": 0.984375 }, "model": "item/compass" }
    ]
}



不难发现"angle"就是上面打在this.addPropertyOverride()里面的参数
而这些0.625526的数字就是apply的回传值,用此值判断所在区间
0.000000~0.015624就跑去读取 "model": "item/compass"
0.015625~0.046874就派去读取 "model": "item/compass_17"
...


3.自制动态贴图
好既然我们已经知道动态贴图的秘密了我们就自己做一个吧
在compass里的apply方法,官方在每一个变数和和方法上面加上
@SideOnly(Side.CLIENT)注解来实现单边读取,而我们可以用之前做的proxy判断法来实现


现在我们回到ItemBloodsave的构造函数里添加一句
  public ItemBloodsave(){
    setUnlocalizedName("itembloodsave");
    setRegistryName("itembloodsave");
    setCreativeTab(CreativeTabs.MATERIALS);
    setMaxStackSize(1);
   
    if(!Main.proxy.isServerSider())this.addPropertyOverride(new ResourceLocation("bloodsave"), new ItemBloodsaveTextures());
  }


这样只有客户端会执行此句话
我们设定参数名为"bloodsave"
new 一个 ItemBloodsaveTextures()这里我们还没创建会报错


我们现在来创建ItemBloodsaveTextures()



ItemBloodsaveTextures里输入
public class ItemBloodsaveTextures implements IItemPropertyGetter{
  @Override
  public float apply(ItemStack stack, World worldIn, EntityLivingBase entityIn) {
    if(worldIn == null && entityIn != null)
   worldIn = entityIn.getEntityWorld();//玩家背包內的物品沒有世界
   if (worldIn != null && stack.getTagCompound() != null && stack.getTagCompound().hasKey("blood")){//阻擋創造模式物品欄
  return stack.getTagCompound().getInteger("bloodsave");
  }
    return 0;
  }
}



这里我来解释一下,apply是每一个ItemBloodsave,不管在地上,手里,箱子里,玩家物品栏里,创造模式物品栏里,
每一tick都会执行一次(20tick=1sec)
经过我的测试,在不同地方的物品的输入值也不一样
玩家物品栏 worldIn == null,entityIn != null
地上 worldIn != null,entityIn == null
手里 worldIn != null,entityIn != null
创造模式物品栏 worldIn == null,entityIn == null


我们的物品必须被玩家右击以后才有nbt资料
而创造模式物品栏里的item是不可能有nbt资料的,如果硬要去读取则会崩溃
所以以上代码让还没有nbt的血瓶以及创造模式物品栏内的血瓶回传值为0
其他则读取nbt资料来回传1~20


接下来就剩下json文件和把贴图放进去了
我们回到models.item.itembloodsave.json里改写
{
    "parent": "item/generated",
    "textures": {
  "layer0": "soa:items/itembloodsave"
    },
"overrides": [
    { "predicate": { "bloodsave": 0 },"model": "soa:item/itembloodsave"    },
    { "predicate": { "bloodsave": 1 },"model": "soa:item/itembloodsave_1"},
    { "predicate": { "bloodsave": 8 }, "model": "soa:item/itembloodsave_2" },
    { "predicate": { "bloodsave": 13 }, "model": "soa:item/itembloodsave_3" },
    { "predicate": { "bloodsave": 20 }, "model": "soa:item/itembloodsave_4" }
]

}



apply回传值↓
0→"model": "soa:item/itembloodsave"
1~7→"model": "soa:item/itembloodsave_1"
8~12→"model": "soa:item/itembloodsave_2"
13~19→ "model": "soa:item/itembloodsave_3"
20→"model": "soa:item/itembloodsave_4"


再来把1,2,3,4models补上



我就写itembloodsave_1.json的内容吧
{
    "parent": "item/generated",
    "textures": {
  "layer0": "soa:items/itembloodsave_1"
    }
}



"layer0": "soa:items/itembloodsave_1"就是导向的贴图文件路径我之前也说过了
其他的json只是导向不同的贴图文件路径而已我就不写出来了


附上贴图文件,应该知道要丢哪里了吧(textures.items里)
itembloodsave_1
itembloodsave_2
itembloodsave_3
itembloodsave_4


好我们进游戏看看









好,物品的高级玩法似乎就剩多态没讲了我
也是尽量希望做一个实用,并且可以把教程融合在一起的物品
不知道这个血瓶你喜不喜欢呢~


源代码




yycpy
666666顶顶顶

cjrsacred
楼主忽略了一种情况:展示框

cjrsacred
我试了一下,不知道对不对,创造物品栏是无世界有实体的(知道打开物品栏时是这样),展示框是无世界无实体,所以第二个 if 那里不用判断 worldln 就行了

尬兹GZ
顶顶顶!!!

egod
没有报错,存血取血功能正常,但就是不回根据血液存储量更新贴图,伤心
物品代码:
  1. public class PandaBlood extends Item{
  2.         private static final String name = "panda_blood";
  3.        
  4.         public PandaBlood() {
  5.                 super();
  6.                 setRegistryName(name);
  7.                 setUnlocalizedName(INFO.MODID+":"+name+"_item");
  8.                 setCreativeTab(CreativeTabs.MATERIALS);
  9.                 setMaxStackSize(1);
  10.                 this.addPropertyOverride(new ResourceLocation("blood_save"),
  11.                                         new IItemPropertyGetter() {
  12.                                                 @SideOnly(Side.CLIENT)
  13.                                                 public float apply(ItemStack stack, World worldIn, EntityLivingBase entityIn) {
  14.                                                         boolean flag = entityIn != null;
  15.                                                         entityIn.sendMessage(new TextComponentString("YOU ARE "+entityIn.getName()+
  16.                                                                         "your panda blood is "+stack.getTagCompound().getInteger("blood_save")));
  17.                                                         Entity entity = (Entity)(flag ? entityIn : stack.getItemFrame());
  18.                                                         if(worldIn == null && entityIn != null) {
  19.                                                                 worldIn = entity.world;
  20.                                                         }
  21.                                                         if(worldIn != null && stack.getTagCompound() != null && stack.getTagCompound().hasKey("blood")) {
  22.                                                                 return (float)stack.getTagCompound().getInteger("blood_save");
  23.                                                         }
  24.                                                         return 0F;
  25.                                                 }
  26.                                         });
  27.         }
  28.        
  29.         @Override
  30.         public void addInformation(ItemStack stack, World worldIn, List<String> tooltip,ITooltipFlag flagIn) {
  31.                 if(flagIn.isAdvanced()) {
  32.                         tooltip.add("This is ");
  33.                         tooltip.add("a Panda Blood");
  34.                 }
  35.                 else {
  36.                         tooltip.add(I18n.format(this.getUnlocalizedName()+".1."+"desc"));
  37.                 }
  38.                 if(org.lwjgl.input.Keyboard.isKeyDown(org.lwjgl.input.Keyboard.KEY_LSHIFT)) {
  39.                         tooltip.add(I18n.format(this.getUnlocalizedName()+".shift.1."+"desc"));
  40.                 }
  41.                 NBTTagCompound nbt = stack.getTagCompound();
  42.                 if(nbt!=null && nbt.hasKey("blood_save")) {
  43.                         tooltip.add("blood:"+nbt.getInteger("blood_save"));
  44.                 }
  45.         }
  46.        
  47.         @Override
  48.         public int getMaxItemUseDuration(ItemStack stack) {
  49.                 return 32;
  50.         }
  51.        
  52.         @Override
  53.         public EnumAction getItemUseAction(ItemStack stack) {
  54.                 return EnumAction.DRINK;
  55.         }
  56.        
  57.         // 血瓶功能
  58.         @Override
  59.         public ActionResult<ItemStack> onItemRightClick(World worldIn,EntityPlayer player,EnumHand hand){
  60.                 player.setActiveHand(hand);
  61.                 if(!worldIn.isRemote) {
  62.                         ItemStack item = player.getHeldItem(hand);
  63.                         // 如果第一次使用,初始化一个内部nbt
  64.                         if(item.getTagCompound()==null) {
  65.                                 player.sendMessage(new TextComponentString("Seems the first time to use...activated!"));
  66.                                 item.setTagCompound(new NBTTagCompound());
  67.                                
  68.                                 NBTTagCompound nbt = new NBTTagCompound();
  69.                                 nbt.setInteger("blood_save", 0);
  70.                                
  71.                                 item.getTagCompound().setTag("blood", nbt);
  72.                         }
  73.                        
  74.                         int bloodSave = item.getTagCompound().getInteger("blood_save");
  75.                         if(player.isSneaking() && bloodSave<20) {
  76.                                 int damage = new Random().nextInt(10)+1;
  77.                                 player.sendMessage(new TextComponentString("health take: "+damage));
  78.                                 player.setHealth(player.isCreative()?player.getHealth()-0:player.getHealth()-damage);
  79.                                 if(bloodSave+damage > 20) {
  80.                                         item.getTagCompound().setInteger("blood_save", 20);
  81.                                         player.sendMessage(new TextComponentString("Panda Blood seems full..."));
  82.                                 }else {
  83.                                         item.getTagCompound().setInteger("blood_save", bloodSave+damage);
  84.                                         player.sendMessage(new TextComponentString("Now it's "+item.getTagCompound().getInteger("blood_save")+"/20"));
  85.                                 }
  86.                                 player.stopActiveHand();
  87.                         }else if(player.isSneaking() && bloodSave == 20) {
  88.                                 player.sendMessage(new TextComponentString("hey! your panda blood is already full!"));
  89.                         }
  90.                 }
  91.                 return super.onItemRightClick(worldIn, player, hand);
  92.         }
  93.        
  94.         @Override
  95.         public ItemStack onItemUseFinish(ItemStack item, World world, EntityLivingBase player) {
  96.                 if(!world.isRemote) {
  97.                         int bloodSave = item.getTagCompound().getInteger("blood_save");
  98.                         float health = player.getHealth();
  99.                         float maxHealth = player.getMaxHealth();
  100.                         float heal = Math.min(maxHealth-health, bloodSave);
  101.                         player.heal(heal);
  102.                         item.getTagCompound().setInteger("blood_save", bloodSave-(int)heal);
  103.                         player.sendMessage(new TextComponentString("Panda Blood heals you "+(int)heal+" health"));
  104.                         player.sendMessage(new TextComponentString("Now it's "+item.getTagCompound().getInteger("blood_save")+"/20"));
  105.                 }
  106.                 return super.onItemUseFinish(item, world, player);
  107.         }
  108. }
复制代码

item 的json 文件
  1. {
  2.     "parent":"item/generated",
  3.     "textures":{
  4.         "layer0":"panda_mod:panda_blood_texture"   
  5.     },
  6.     "Overrides":[
  7.     {"predicate":{"blood_save":0.0},"model":"panda_mod:item/panda_blood_item"},
  8.     {"predicate":{"blood_save":1.0},"model":"panda_mod:item/panda_blood_item_1"},
  9.     {"predicate":{"blood_save":5.0},"model":"panda_mod:item/panda_blood_item_2"},
  10.     {"predicate":{"blood_save":13.0},"model":"panda_mod:item/panda_blood_item_3"},
  11.     {"predicate":{"blood_save":20.0},"model":"panda_mod:item/panda_blood_item_4"}
  12.     ]
  13. }
复制代码

panda_blood_item_1.json
  1. {
  2.     "parent":"item/generated",
  3.     "textures":{
  4.         "layer0":"panda_mod:panda_blood_texture_1"
  5.     }
复制代码



egod
egod 发表于 2019-4-19 22:54
没有报错,存血取血功能正常,但就是不回根据血液存储量更新贴图,伤心
物品代码:

forge 版本 1.12.2