【Minecraft java edition 模组开发】(二):通过对岩浆怪和雪傀儡的源码分析,自己制作一个雪球怪

零、什么是实体

  实体(Entity)包括在Minecraft中所有动态的、移动中的对象。例如游戏中的怪物僵尸骷髅等,船和矿车,受重力影响的方块如下落的沙子铁砧等。

  我们今天要加入的东西就是一个雪球怪,它拥有和岩浆怪一样的分裂能力,不同的是,他不能免疫灼烧伤害,和雪傀儡会受到比较热的自然环境的伤害,并且走到哪里哪里有雪。

一、实体继承树

实体继承树
  这张图有点糊,但是没办法,我从网上找不到其他图了。

  从这张继承树中我们可以岩浆怪继承自史莱姆;雪傀儡继承自抽象类傀儡实体(傀儡实体有三个子类,雪傀儡,铁傀儡和凋零。都是非抽象类);再进一步翻阅forge源码,我们还会发现雪傀儡还实现了两个接口:IRangedAttackMo用于实现怪物远程攻击,女巫,骷髅等也实现了这个接口,IShearable用于实现可剪裁,羊雪傀儡都实现了。

  岩浆怪:

public class EntityMagmaCube extends EntitySlime{

	/* codes */

}

  雪傀儡:

public class EntitySnowman extends EntityGolem implements IRangedAttackMob, net.minecraftforge.common.IShearable{

	/* codes */

}

二、编写雪球怪的代码:

  1.首先既然雪球怪要和岩浆怪类似,那肯定也要继承史莱姆

public class EntitySnowCube extends EntitySlime {
	/* codes */
}

  2.然后我们从岩浆怪的源码里面拷一段给雪球怪

public class EntitySnowCube extends EntitySlime {
	
	public EntitySnowCube(World worldIn) {
		super(worldIn);
	}

	public void registerFixesSnowCube(DataFixer fixer) {
		EntityLiving.registerFixesMob(fixer, EntitySnowCube.class);
	}

	/**
	 * 改变了了雪球怪的速度,让他和岩浆怪一样(这个方法是粘贴自岩浆怪的)
	 */
	@Override
	protected void applyEntityAttributes() {
		super.applyEntityAttributes();
		this.getEntityAttribute(SharedMonsterAttributes.MOVEMENT_SPEED).setBaseValue(0.20000000298023224D);
	}

	/**
	 * @return 设置是否能召唤,只要游戏难度不是和平模式就能召唤
	 */
	@Override
	public boolean getCanSpawnHere() {
		return this.world.getDifficulty() != EnumDifficulty.PEACEFUL;
	}

	/**
	 * 这个方法依旧是粘贴的岩浆怪的,他的作用应该是用来设置史莱姆的大小的(大史莱姆,中史莱姆,小史莱姆)
	 * 这个方法中显示调用了超类史莱姆的方法设置好了大小,然后再把生物的护甲值升高,所以岩浆怪才会比普通史莱姆难打。
	 * @param size
	 * @param resetHealth
	 */
	@Override
	protected void setSlimeSize(int size, boolean resetHealth)
	{
		super.setSlimeSize(size, resetHealth);
		this.getEntityAttribute(SharedMonsterAttributes.ARMOR).setBaseValue((double)(size * 3));
	}
	
	/**
	 * 跳跃延迟,直接粘贴岩浆怪的数据了
	 */
	@Override
	protected int getJumpDelay()
	{
		return super.getJumpDelay() * 4;
	}

	/**
	 * @return 能否伤害玩家
	 * 这里和岩浆怪保持一致,无论大小都能伤害,但其实史莱姆这里是return !this.isSmallSlime();小的没有攻击力
	 */
	@Override
	protected boolean canDamagePlayer()
	{
		return true;
	}

	/**
	 * @return 攻击强度,这里和岩浆怪保持一致,是史莱姆攻击强度加二
	 */
	@Override
	protected int getAttackStrength()
	{
		return super.getAttackStrength() + 2;
	}

}

  这样雪球怪就拥有了一部分和岩浆怪一样的属性

  需要注意的是,岩浆怪的构造方法其实比史莱姆和雪球怪的多了一行。

	public EntityMagmaCube(World worldIn)
    {
        super(worldIn);
        this.isImmuneToFire = true;
    }

  这多的一行是的岩浆怪可以免疫火焰,那我们的雪球怪自然要把这一行删掉。

  3.设置一些不一样的属性:

/**
	 * 该方法继承自史莱姆
	 * @return 设置的粒子效果
	 */
	@Override
	protected EnumParticleTypes getParticleType() {
		return EnumParticleTypes.SNOWBALL;
	}

	/**
	 * @return 这个返回值是雪球怪死后会分裂成什么
	 */
	@Override
	protected EntitySlime createInstance()
	{
		return new EntitySnowCube(this.world);
	}

	/**
	 * 这个方法是获得掉落物表,继承自EntityLiving
	 * @return 返回掉落物表
	 */
	@Override
	@Nullable
	protected ResourceLocation getLootTable()
	{
		// 如果是小史莱姆才会掉落雪球
		return this.isSmallSlime() ? LootTableList.ENTITIES_SNOWMAN : LootTableList.EMPTY;
	}

	/**
	 * 被攻击后发出的声音
	 * @return 这里和雪傀儡一致
	 */
	@Override
	protected SoundEvent getHurtSound(DamageSource damageSourceIn)
	{
		return SoundEvents.ENTITY_SNOWMAN_HURT;
	}

	/**
	 * 死亡音效
	 * @return 和雪傀儡一致
	 */
	@Override
	protected SoundEvent getDeathSound()
	{
		return SoundEvents.ENTITY_SNOWMAN_DEATH;
	}

	/**
	 * 被挤压的音效
	 * @return 雪傀儡没有这个音效,所以这里用的是雪傀儡的环境音效
	 */
	@Override
	protected SoundEvent getSquishSound()
	{
		return SoundEvents.ENTITY_SNOWMAN_AMBIENT;
	}

	/**
	 * 跳跃音效
	 * @return 使用扔雪球的音效
	 */
	protected SoundEvent getJumpSound()
	{
		return SoundEvents.ENTITY_SNOWBALL_THROW;
	}

	/*
	 * 此外还有几个方法继承自史莱姆
	 * jump() handleJumpLava() handleJumpWater() 等,
	 * 只知道是关于跳跃,其他具体情况就不知道了
	 * 这里没有拷贝岩浆球的数据,让雪球怪跟史莱姆的这些数据保持一致好了
	 */

  5.让雪球怪具有一部分雪傀儡的属性:

  首先我们翻阅雪傀儡的源码,找到其中令雪傀儡走路留雪,见水死等属性的方法:

	public void onLivingUpdate()
    {
        super.onLivingUpdate();

        if (!this.world.isRemote)
        {
            int i = MathHelper.floor(this.posX);
            int j = MathHelper.floor(this.posY);
            int k = MathHelper.floor(this.posZ);

            if (this.isWet())
            {
                this.attackEntityFrom(DamageSource.DROWN, 1.0F);
            }

            if (this.world.getBiome(new BlockPos(i, 0, k)).getTemperature(new BlockPos(i, j, k)) > 1.0F)
            {
                this.attackEntityFrom(DamageSource.ON_FIRE, 1.0F);
            }

            if (!net.minecraftforge.event.ForgeEventFactory.getMobGriefingEvent(this.world, this))
            {
                return;
            }

            for (int l = 0; l < 4; ++l)
            {
                i = MathHelper.floor(this.posX + (double)((float)(l % 2 * 2 - 1) * 0.25F));
                j = MathHelper.floor(this.posY);
                k = MathHelper.floor(this.posZ + (double)((float)(l / 2 % 2 * 2 - 1) * 0.25F));
                BlockPos blockpos = new BlockPos(i, j, k);

                if (this.world.getBlockState(blockpos).getMaterial() == Material.AIR && this.world.getBiome(blockpos).getTemperature(blockpos) < 0.8F && Blocks.SNOW_LAYER.canPlaceBlockAt(this.world, blockpos))
                {
                    this.world.setBlockState(blockpos, Blocks.SNOW_LAYER.getDefaultState());
                }
            }
        }
    }

  显而易见是这个,这个方法继承自抽象类EntityLiving,而史莱姆也继承自这个抽象类,所以我们完全可以让雪球怪也继承这个方法。

  6.完整的雪球怪代码:

package com.darkill.examplemod.entity;

import net.minecraft.block.material.Material;
import net.minecraft.entity.EntityLiving;
import net.minecraft.entity.SharedMonsterAttributes;
import net.minecraft.entity.monster.EntitySlime;
import net.minecraft.init.Blocks;
import net.minecraft.init.SoundEvents;
import net.minecraft.util.DamageSource;
import net.minecraft.util.EnumParticleTypes;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.SoundEvent;
import net.minecraft.util.datafix.DataFixer;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.MathHelper;
import net.minecraft.world.EnumDifficulty;
import net.minecraft.world.World;
import net.minecraft.world.storage.loot.LootTableList;

import javax.annotation.Nullable;

public class EntitySnowCube extends EntitySlime {

	public EntitySnowCube(World worldIn) {
		super(worldIn);
	}

	public void registerFixesSnowCube(DataFixer fixer) {
		EntityLiving.registerFixesMob(fixer, EntitySnowCube.class);
	}

	/**
	 * 改变了了雪球怪的速度,让他和岩浆怪一样(这个方法是粘贴自岩浆怪的)
	 */
	@Override
	protected void applyEntityAttributes() {
		super.applyEntityAttributes();
		this.getEntityAttribute(SharedMonsterAttributes.MOVEMENT_SPEED).setBaseValue(0.20000000298023224D);
	}

	/**
	 * @return 设置是否能召唤,只要游戏难度不是和平模式就能召唤
	 */
	@Override
	public boolean getCanSpawnHere() {
		return this.world.getDifficulty() != EnumDifficulty.PEACEFUL;
	}

	/**
	 * 从雪傀儡的源码中拷贝了一个函数给雪球怪
	 * 使雪球怪拥有一些雪傀儡的属性。
	 */
	@Override
	public void onLivingUpdate()
	{
		super.onLivingUpdate();

		if (!this.world.isRemote)
		{
			int i = MathHelper.floor(this.posX);
			int j = MathHelper.floor(this.posY);
			int k = MathHelper.floor(this.posZ);

			if (this.isWet())
			{
				this.attackEntityFrom(DamageSource.DROWN, 1.0F);
			}

			if (this.world.getBiome(new BlockPos(i, 0, k)).getTemperature(new BlockPos(i, j, k)) > 1.0F)
			{
				this.attackEntityFrom(DamageSource.ON_FIRE, 1.0F);
			}

			if (!net.minecraftforge.event.ForgeEventFactory.getMobGriefingEvent(this.world, this))
			{
				return;
			}

			for (int l = 0; l < 4; ++l)
			{
				i = MathHelper.floor(this.posX + (double)((float)(l % 2 * 2 - 1) * 0.25F));
				j = MathHelper.floor(this.posY);
				k = MathHelper.floor(this.posZ + (double)((float)(l / 2 % 2 * 2 - 1) * 0.25F));
				BlockPos blockpos = new BlockPos(i, j, k);

				if (this.world.getBlockState(blockpos).getMaterial() == Material.AIR && this.world.getBiome(blockpos).getTemperature(blockpos) < 0.8F && Blocks.SNOW_LAYER.canPlaceBlockAt(this.world, blockpos))
				{
					this.world.setBlockState(blockpos, Blocks.SNOW_LAYER.getDefaultState());
				}
			}
		}
	}

	/**
	 * 这个方法依旧是粘贴的岩浆怪的,他的作用应该是用来设置史莱姆的大小的(大史莱姆,中史莱姆,小史莱姆)
	 * 这个方法中显示调用了超类史莱姆的方法设置好了大小,然后再把生物的护甲值升高,所以岩浆怪才会比普通史莱姆难打。
	 * @param size
	 * @param resetHealth
	 */
	@Override
	protected void setSlimeSize(int size, boolean resetHealth)
	{
		super.setSlimeSize(size, resetHealth);
		this.getEntityAttribute(SharedMonsterAttributes.ARMOR).setBaseValue((double)(size * 3));
	}

	/**
	 * 该方法继承自史莱姆
	 * @return 设置的粒子效果
	 */
	@Override
	protected EnumParticleTypes getParticleType() {
		return EnumParticleTypes.SNOWBALL;
	}

	/**
	 * @return 这个返回值是雪球怪死后会分裂成什么
	 */
	@Override
	protected EntitySlime createInstance()
	{
		return new EntitySnowCube(this.world);
	}

	/**
	 * 这个方法是获得掉落物表,继承自EntityLiving
	 * @return 返回掉落物表
	 */
	@Override
	@Nullable
	protected ResourceLocation getLootTable()
	{
		// 如果是小史莱姆才会掉落雪球
		return this.isSmallSlime() ? LootTableList.ENTITIES_SNOWMAN : LootTableList.EMPTY;
	}

	/**
	 * 跳跃延迟,直接粘贴岩浆怪的数据了
	 */
	@Override
	protected int getJumpDelay()
	{
		return super.getJumpDelay() * 4;
	}

	/*
	 * 此外还有几个方法继承自史莱姆
	 * jump() handleJumpLava() handleJumpWater() 等,
	 * 只知道是关于跳跃,其他具体情况就不知道了
	 * 这里没有拷贝岩浆球的数据,让雪球怪跟史莱姆的这些数据保持一致好了
	 */

	/**
	 * @return 能否伤害玩家
	 * 这里和岩浆怪保持一致,无论大小都能伤害,但其实史莱姆这里是return !this.isSmallSlime();小的没有攻击力
	 */
	@Override
	protected boolean canDamagePlayer()
	{
		return true;
	}

	/**
	 * @return 攻击强度,这里和岩浆怪保持一致,是史莱姆攻击强度加二
	 */
	@Override
	protected int getAttackStrength()
	{
		return super.getAttackStrength() + 2;
	}

	/**
	 * 被攻击后发出的声音
	 * @return 这里和雪傀儡一致
	 */
	@Override
	protected SoundEvent getHurtSound(DamageSource damageSourceIn)
	{
		return SoundEvents.ENTITY_SNOWMAN_HURT;
	}

	/**
	 * 死亡音效
	 * @return 和雪傀儡一致
	 */
	@Override
	protected SoundEvent getDeathSound()
	{
		return SoundEvents.ENTITY_SNOWMAN_DEATH;
	}

	/**
	 * 被挤压的音效
	 * @return 雪傀儡没有这个音效,所以这里用的是雪傀儡的环境音效
	 */
	@Override
	protected SoundEvent getSquishSound()
	{
		return SoundEvents.ENTITY_SNOWMAN_AMBIENT;
	}

	/**
	 * 跳跃音效
	 * @return 使用扔雪球的音效
	 */
	protected SoundEvent getJumpSound()
	{
		return SoundEvents.ENTITY_SNOWBALL_THROW;
	}

}

三、加载雪球怪的材质

雪球怪

  做这一步时,我们需要下载两个模组,tabula和iChunUtil,这个我在CSDN上上传了,点这里下载tabula和iChunUtil

  具体如何使用这两个工具,并把模型导入项目,请参考b站的这个视频

  然后做好材质以后我们就可以运行游戏了。下面是我做的材质:

在这里插入图片描述

四、运行游戏

  呆萌的材质
雪球怪

  能够被雨淋死,还能留下雪迹:
雪球怪
  掉落物
死亡掉落物

  • 8
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 7
    评论
好的,我会尽力回答你的问题。首先,你需要了解以下几个知识点: 1. Minecraft Forge:Minecraft Forge 是一个用于 Minecraft模组框架,可以帮助开发者更轻松地创建和管理模组。 2. Java 编程语言:Java 是一种广泛使用的面向对象编程语言,可以用于编写 Minecraft 模组。 3. Eclipse 集成开发环境:Eclipse 是一个流行的 Java 集成开发环境,可以帮助开发者更轻松地编写、调试和测试 Java 代码。 下面是一个简单的示例代码,它创建了一个新的方块,并且在玩家放置该方块时输出一条信息: ```java package com.example.examplemod; import net.minecraft.block.Block; import net.minecraft.block.material.Material; import net.minecraft.creativetab.CreativeTabs; import net.minecraft.init.Blocks; import net.minecraft.item.Item; import net.minecraft.item.ItemBlock; import net.minecraft.item.ItemStack; import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.common.Mod.EventHandler; import net.minecraftforge.fml.common.event.FMLInitializationEvent; import net.minecraftforge.fml.common.registry.GameRegistry; @Mod(modid = ExampleMod.MODID, version = ExampleMod.VERSION) public class ExampleMod { public static final String MODID = "examplemod"; public static final String VERSION = "1.0"; public static Block exampleBlock; @EventHandler public void init(FMLInitializationEvent event) { exampleBlock = new Block(Material.rock) .setHardness(2.0f) .setResistance(10.0f) .setUnlocalizedName("example_block") .setCreativeTab(CreativeTabs.tabBlock); GameRegistry.registerBlock(exampleBlock, "example_block"); GameRegistry.addShapelessRecipe(new ItemStack(exampleBlock), new ItemStack(Blocks.dirt)); GameRegistry.addSmelting(Blocks.stone, new ItemStack(exampleBlock), 0.1f); ItemBlock itemBlock = new ItemBlock(exampleBlock); itemBlock.setRegistryName(exampleBlock.getRegistryName()); GameRegistry.registerItem(itemBlock, itemBlock.getUnlocalizedName()); } } ``` 这段代码创建了一个名为 "example_block" 的新方块,它的贴图和材质与基岩块相同。在玩家放置该方块时,控制台会输出一条信息。该代码还注册了一个熔炉配方和一个无序合成配方,以及一个用于在创造模式下找到方块的创造标签。最后,该代码还注册了一个 ItemBlock,用于将方块添加到游戏中。 需要注意的是,这只是一个简单的示例代码,实际的 Minecraft 模组开发涉及到更多的知识和技能。如果你想深入了解 Minecraft 模组开发,建议你查阅相关的文档和教程。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

九死九歌

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值