今天我们在MC中实现一艘可以在水中和岩浆中滑行的船

本期教程之前可以先复习一下生物实体教程,会比较好理解一些。

1.船是一种生物实体,所以我们首先要制作船的模型,这里直接使用了原版的船模型,当然你也可以用Blockbench制作模型。

ModelObBoat.java

package com.joy187.rejoymod.entity.model;import com.joy187.rejoymod.entity.EntityObBoat;
import net.minecraft.client.model.IMultipassModel;
import net.minecraft.client.model.ModelBase;
import net.minecraft.client.model.ModelRenderer;
import net.minecraft.client.renderer.GLAllocation;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.entity.Entity;
import net.minecraft.util.math.MathHelper;public class ModelObBoat extends ModelBase implements IMultipassModel
{public ModelRenderer[] boatSides = new ModelRenderer[5];public ModelRenderer[] paddles = new ModelRenderer[2];public ModelRenderer noWater;private final int patchList = GLAllocation.generateDisplayLists(1);public ModelObBoat(){this.boatSides[0] = (new ModelRenderer(this, 0, 0)).setTextureSize(128, 64);this.boatSides[1] = (new ModelRenderer(this, 0, 19)).setTextureSize(128, 64);this.boatSides[2] = (new ModelRenderer(this, 0, 27)).setTextureSize(128, 64);this.boatSides[3] = (new ModelRenderer(this, 0, 35)).setTextureSize(128, 64);this.boatSides[4] = (new ModelRenderer(this, 0, 43)).setTextureSize(128, 64);int i = 32;int j = 6;int k = 20;int l = 4;int i1 = 28;this.boatSides[0].addBox(-14.0F, -9.0F, -3.0F, 28, 16, 3, 0.0F);this.boatSides[0].setRotationPoint(0.0F, 3.0F, 1.0F);this.boatSides[1].addBox(-13.0F, -7.0F, -1.0F, 18, 6, 2, 0.0F);this.boatSides[1].setRotationPoint(-15.0F, 4.0F, 4.0F);this.boatSides[2].addBox(-8.0F, -7.0F, -1.0F, 16, 6, 2, 0.0F);this.boatSides[2].setRotationPoint(15.0F, 4.0F, 0.0F);this.boatSides[3].addBox(-14.0F, -7.0F, -1.0F, 28, 6, 2, 0.0F);this.boatSides[3].setRotationPoint(0.0F, 4.0F, -9.0F);this.boatSides[4].addBox(-14.0F, -7.0F, -1.0F, 28, 6, 2, 0.0F);this.boatSides[4].setRotationPoint(0.0F, 4.0F, 9.0F);this.boatSides[0].rotateAngleX = ((float)Math.PI / 2F);this.boatSides[1].rotateAngleY = ((float)Math.PI * 3F / 2F);this.boatSides[2].rotateAngleY = ((float)Math.PI / 2F);this.boatSides[3].rotateAngleY = (float)Math.PI;this.paddles[0] = this.makePaddle(true);this.paddles[0].setRotationPoint(3.0F, -5.0F, 9.0F);this.paddles[1] = this.makePaddle(false);this.paddles[1].setRotationPoint(3.0F, -5.0F, -9.0F);this.paddles[1].rotateAngleY = (float)Math.PI;this.paddles[0].rotateAngleZ = 0.19634955F;this.paddles[1].rotateAngleZ = 0.19634955F;this.noWater = (new ModelRenderer(this, 0, 0)).setTextureSize(128, 64);this.noWater.addBox(-14.0F, -9.0F, -3.0F, 28, 16, 3, 0.0F);this.noWater.setRotationPoint(0.0F, -3.0F, 1.0F);this.noWater.rotateAngleX = ((float)Math.PI / 2F);}/*** Sets the models various rotation angles then renders the model.*/public void render(Entity entityIn, float limbSwing, float limbSwingAmount, float ageInTicks, float netHeadYaw, float headPitch, float scale){GlStateManager.rotate(90.0F, 0.0F, 1.0F, 0.0F);EntityObBoat entityboat = (EntityObBoat)entityIn;this.setRotationAngles(limbSwing, limbSwingAmount, ageInTicks, netHeadYaw, headPitch, scale, entityIn);for (int i = 0; i < 5; ++i){this.boatSides[i].render(scale);}this.renderPaddle(entityboat, 0, scale, limbSwing);this.renderPaddle(entityboat, 1, scale, limbSwing);}public void renderMultipass(Entity p_187054_1_, float p_187054_2_, float p_187054_3_, float p_187054_4_, float p_187054_5_, float p_187054_6_, float scale){GlStateManager.rotate(90.0F, 0.0F, 1.0F, 0.0F);GlStateManager.colorMask(false, false, false, false);this.noWater.render(scale);GlStateManager.colorMask(true, true, true, true);}protected ModelRenderer makePaddle(boolean p_187056_1_){ModelRenderer modelrenderer = (new ModelRenderer(this, 62, p_187056_1_ ? 0 : 20)).setTextureSize(128, 64);int i = 20;int j = 7;int k = 6;float f = -5.0F;modelrenderer.addBox(-1.0F, 0.0F, -5.0F, 2, 2, 18);modelrenderer.addBox(p_187056_1_ ? -1.001F : 0.001F, -3.0F, 8.0F, 1, 6, 7);return modelrenderer;}protected void renderPaddle(EntityObBoat boat, int paddle, float scale, float limbSwing){float f = boat.getRowingTime(paddle, limbSwing);ModelRenderer modelrenderer = this.paddles[paddle];modelrenderer.rotateAngleX = (float) MathHelper.clampedLerp(-1.0471975803375244D, -0.2617993950843811D, (double)((MathHelper.sin(-f) + 1.0F) / 2.0F));modelrenderer.rotateAngleY = (float)MathHelper.clampedLerp(-(Math.PI / 4D), (Math.PI / 4D), (double)((MathHelper.sin(-f + 1.0F) + 1.0F) / 2.0F));if (paddle == 1){modelrenderer.rotateAngleY = (float)Math.PI - modelrenderer.rotateAngleY;}modelrenderer.render(scale);}
}

2.我们要让船在岩浆和水上行走,所以我们的EntityObBoat类要继承船实体类,同时让船对岩浆产生免疫:

EntityObBoat.java

package com.joy187.rejoymod.entity;import com.joy187.rejoymod.item.ModItems;
import net.minecraft.block.BlockLiquid;
import net.minecraft.block.material.Material;
import net.minecraft.block.state.IBlockState;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.MoverType;
import net.minecraft.entity.item.EntityBoat;
import net.minecraft.entity.passive.EntityAnimal;
import net.minecraft.entity.passive.EntityWaterMob;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.init.Blocks;
import net.minecraft.init.MobEffects;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.network.datasync.DataParameter;
import net.minecraft.network.datasync.DataSerializers;
import net.minecraft.network.datasync.EntityDataManager;
import net.minecraft.network.play.client.CPacketSteerBoat;
import net.minecraft.potion.PotionEffect;
import net.minecraft.util.*;
import net.minecraft.util.math.*;
import net.minecraft.world.World;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;import java.util.ArrayList;
import java.util.List;public class EntityObBoat extends EntityBoat {private static final DataParameter<Integer> TIME_SINCE_HIT = EntityDataManager.createKey(EntityObBoat.class, DataSerializers.VARINT);private static final DataParameter<Integer> FORWARD_DIRECTION = EntityDataManager.createKey(EntityObBoat.class, DataSerializers.VARINT);private static final DataParameter<Float> DAMAGE_TAKEN = EntityDataManager.createKey(EntityObBoat.class, DataSerializers.FLOAT);private static final DataParameter<Boolean>[] DATA_ID_PADDLE = new DataParameter[]{EntityDataManager.createKey(EntityObBoat.class, DataSerializers.BOOLEAN), EntityDataManager.createKey(EntityObBoat.class, DataSerializers.BOOLEAN)};private final float[] paddlePositions;private float outOfControlCounter;private float deltaRotation;private int lerpSteps;private double boatPitch;private double lerpY;private double lerpZ;private double boatYaw;private double lerpXRot;private boolean leftInputDown;private boolean rightInputDown;private boolean forwardInputDown;private boolean backInputDown;private double lavaLevel;private float boatGlide;private Status status;private Status previousStatus;private double lastYd;public EntityObBoat(World world){super(world);//我们的船对岩浆、火免疫,不然会烧掉this.isImmuneToFire = true;this.paddlePositions = new float[2];this.preventEntitySpawning = true;this.setSize(1.375F, 0.5625F);}public EntityObBoat(World world, double x, double y, double z){this(world);this.motionX = 0.0D;this.motionY = 0.0D;this.motionZ = 0.0D;this.prevPosX = x;this.prevPosY = y;this.prevPosZ = z;this.setPosition(x, y, z);}@Overrideprotected boolean canTriggerWalking(){return false;}@Overrideprotected void entityInit(){this.dataManager.register(TIME_SINCE_HIT, 0);this.dataManager.register(FORWARD_DIRECTION, 1);this.dataManager.register(DAMAGE_TAKEN, 0.0F);for(DataParameter<Boolean> parameter : DATA_ID_PADDLE){this.dataManager.register(parameter, false);}}@Overridepublic AxisAlignedBB getCollisionBox(Entity entity){return entity.canBePushed() ? entity.getEntityBoundingBox() : null;}@Overridepublic AxisAlignedBB getCollisionBoundingBox(){return this.getEntityBoundingBox();}@Overridepublic boolean canBePushed(){return true;}@Overridepublic double getMountedYOffset(){return -0.1D;}@Overridepublic boolean attackEntityFrom(DamageSource source, float amount){if(this.isEntityInvulnerable(source)){return false;}else if(!this.world.isRemote && !this.isDead){if(source instanceof EntityDamageSourceIndirect && source.getTrueSource() != null && this.isPassenger(source.getTrueSource())){return false;}else{this.setForwardDirection(-this.getForwardDirection());this.setTimeSinceHit(10);this.setDamageTaken(this.getDamageTaken() + amount * 10.0F);this.markVelocityChanged();boolean takeDamage = source.getTrueSource() instanceof EntityPlayer && ((EntityPlayer) source.getTrueSource()).capabilities.isCreativeMode;if(takeDamage || this.getDamageTaken() > 40.0F){   //判断我们如果将船打破后会掉落什么物品if(!takeDamage && this.world.getGameRules().getBoolean("doEntityDrops")){this.dropItemWithOffset(ModItems.OBBOAT, 1, 0.0F);}this.setDead();}return true;}}else{return true;}}@Overridepublic void applyEntityCollision(Entity entity){if(entity instanceof EntityObBoat){if(entity.getEntityBoundingBox().minY < this.getEntityBoundingBox().maxY){super.applyEntityCollision(entity);}}else if(entity.getEntityBoundingBox().minY <= this.getEntityBoundingBox().minY){super.applyEntityCollision(entity);}}@Override@SideOnly(Side.CLIENT)public void performHurtAnimation(){this.setForwardDirection(-this.getForwardDirection());this.setTimeSinceHit(10);this.setDamageTaken(this.getDamageTaken() * 11.0F);}@Overridepublic boolean canBeCollidedWith(){return !this.isDead;}@Override@SideOnly(Side.CLIENT)public void setPositionAndRotationDirect(double x, double y, double z, float yaw, float pitch, int posRotationIncrements, boolean teleport){this.boatPitch = x;this.lerpY = y;this.lerpZ = z;this.boatYaw = yaw;this.lerpXRot = pitch;this.lerpSteps = 10;}@Overridepublic EnumFacing getAdjustedHorizontalFacing(){return this.getHorizontalFacing().rotateY();}@Overridepublic void onUpdate(){this.previousStatus = this.status;this.status = this.getBoatStatus();if(this.status != Status.UNDER_LAVA && this.status != Status.UNDER_FLOWING_LAVA){this.outOfControlCounter = 0.0F;}else{this.outOfControlCounter++;}if(!this.world.isRemote && this.outOfControlCounter >= 60.0F){this.removePassengers();}if(this.getTimeSinceHit() > 0){this.setTimeSinceHit(this.getTimeSinceHit() - 1);}if(this.getDamageTaken() > 0.0F){this.setDamageTaken(this.getDamageTaken() - 1.0F);}this.prevPosX = this.posX;this.prevPosY = this.posY;this.prevPosZ = this.posZ;if(!this.world.isRemote){this.setFlag(6, this.isGlowing());}this.onEntityUpdate();this.tickLerp();if(this.canPassengerSteer()){if(this.getPassengers().size() == 0 || !(this.getPassengers().get(0) instanceof EntityPlayer)){this.setPaddleState(false, false);}this.updateMotion();if(this.world.isRemote){this.controlBoat();this.world.sendPacketToServer(new CPacketSteerBoat(this.getPaddleState(0), this.getPaddleState(1)));}this.move(MoverType.SELF, this.motionX, this.motionY, this.motionZ);}else{this.motionX = 0.0D;this.motionY = 0.0D;this.motionZ = 0.0D;}for(int i = 0; i <= 1; i++){if(this.getPaddleState(i)){if(!this.isSilent() && (double) (this.paddlePositions[i] % ((float) Math.PI * 2F)) <= (Math.PI / 4D) && ((double) this.paddlePositions[i] + 0.39269909262657166D) % (Math.PI * 2D) >= (Math.PI / 4D)){SoundEvent event = this.getPaddleSound();if(event != null){Vec3d look = this.getLook(1.0F);double lookX = i == 1 ? -look.z : look.z;double lookZ = i == 1 ? look.x : -look.x;this.world.playSound(null, this.posX + lookX, this.posY, this.posZ + lookZ, event, this.getSoundCategory(), 1.0F, 0.8F + 0.4F * this.rand.nextFloat());}}this.paddlePositions[i] = (float) ((double) this.paddlePositions[i] + 0.39269909262657166D);}else{this.paddlePositions[i] = 0.0F;}}this.doBlockCollisions();List<Entity> entities = this.world.getEntitiesInAABBexcluding(this, this.getEntityBoundingBox().expand(0.20000000298023224D, -0.009999999776482582D, 0.20000000298023224D), EntitySelectors.getTeamCollisionPredicate(this));if(!entities.isEmpty()){boolean flag = !this.world.isRemote && !(this.getControllingPassenger() instanceof EntityPlayer);for(Entity entity : entities){if(!entity.isPassenger(this)){if(flag && this.getPassengers().size() < 2 && !entity.isRiding() && entity.width < this.width && entity instanceof EntityLivingBase && !(entity instanceof EntityWaterMob) && !(entity instanceof EntityPlayer)){entity.startRiding(this);}else{this.applyEntityCollision(entity);}}}}}//船被打破之后掉落的物品@Overridepublic ItemStack getPickedResult(RayTraceResult target){return new ItemStack(ModItems.OBBOAT, 1, 0);}private void tickLerp(){if(this.lerpSteps > 0 && !this.canPassengerSteer()){double posX = this.posX + (this.boatPitch - this.posX) / (double) this.lerpSteps;double posY = this.posY + (this.lerpY - this.posY) / (double) this.lerpSteps;double posZ = this.posZ + (this.lerpZ - this.posZ) / (double) this.lerpSteps;double yaw = MathHelper.wrapDegrees(this.boatYaw - (double) this.rotationYaw);this.rotationYaw = (float) ((double) this.rotationYaw + yaw / (double) this.lerpSteps);this.rotationPitch = (float) ((double) this.rotationPitch + (this.lerpXRot - (double) this.rotationPitch) / (double) this.lerpSteps);this.lerpSteps--;this.setPosition(posX, posY, posZ);this.setRotation(this.rotationYaw, this.rotationPitch);}}@Overridepublic void setPaddleState(boolean leftPaddle, boolean rightPaddle){this.dataManager.set(DATA_ID_PADDLE[0], leftPaddle);this.dataManager.set(DATA_ID_PADDLE[1], rightPaddle);}@Override@SideOnly(Side.CLIENT)public float getRowingTime(int side, float limbSwing){return this.getPaddleState(side) ? (float) MathHelper.clampedLerp((double) this.paddlePositions[side] - 0.39269909262657166D, this.paddlePositions[side], limbSwing) : 0.0F;}private Status getBoatStatus(){Status status = this.getUnderLavaStatus();if(status != null){this.lavaLevel = this.getEntityBoundingBox().maxY;return status;}else if(this.checkInLava()){return Status.IN_LAVA;}else{float f = this.getBoatGlide();if(f > 0.0F){this.boatGlide = f;return Status.ON_LAND;}else{return Status.IN_AIR;}}}private float getLavaLevelAbove(){AxisAlignedBB boundingBox = this.getEntityBoundingBox();int minX = MathHelper.floor(boundingBox.minX);int maxX = MathHelper.ceil(boundingBox.maxX);int minY = MathHelper.floor(boundingBox.maxY);int maxY = MathHelper.ceil(boundingBox.maxY - this.lastYd);int minZ = MathHelper.floor(boundingBox.minZ);int maxZ = MathHelper.ceil(boundingBox.maxZ);BlockPos.PooledMutableBlockPos mutableBlockPos = BlockPos.PooledMutableBlockPos.retain();try{label78:for(int y = minY; y < maxY; y++){float liquidHeight = 0.0F;int x = minX;while(true){if(x >= maxX){if(liquidHeight < 1.0F){return (float) mutableBlockPos.getY() + liquidHeight;}break;}for(int z = minZ; z < maxZ; z++){mutableBlockPos.setPos(x, y, z);IBlockState state = this.world.getBlockState(mutableBlockPos);//判断船是否在岩浆或者水上if(state.getMaterial() == Material.LAVA || state.getMaterial() == Material.WATER){liquidHeight = Math.max(liquidHeight, BlockLiquid.getBlockLiquidHeight(state, this.world, mutableBlockPos));}if(liquidHeight >= 1.0F){continue label78;}}x++;}}return (float) (maxY + 1);}finally{mutableBlockPos.release();}}@Overridepublic float getBoatGlide(){AxisAlignedBB entityBoundingBox = this.getEntityBoundingBox();AxisAlignedBB boundingBox = new AxisAlignedBB(entityBoundingBox.minX, entityBoundingBox.minY - 0.001D, entityBoundingBox.minZ, entityBoundingBox.maxX, entityBoundingBox.minY, entityBoundingBox.maxZ);int minX = MathHelper.floor(boundingBox.minX) - 1;int maxX = MathHelper.ceil(boundingBox.maxX) + 1;int minY = MathHelper.floor(boundingBox.minY) - 1;int maxY = MathHelper.ceil(boundingBox.maxY) + 1;int minZ = MathHelper.floor(boundingBox.minZ) - 1;int maxZ = MathHelper.ceil(boundingBox.maxZ) + 1;List<AxisAlignedBB> list = new ArrayList<>();float slipperiness = 0.0F;int friction = 0;BlockPos.PooledMutableBlockPos mutableBlockPos = BlockPos.PooledMutableBlockPos.retain();try{for(int x = minX; x < maxX; x++){for(int z = minZ; z < maxZ; z++){int offset = (x != minX && x != maxX - 1 ? 0 : 1) + (z != minZ && z != maxZ - 1 ? 0 : 1);if(offset != 2){for(int y = minY; y < maxY; y++){if(offset <= 0 || y != minY && y != maxY - 1){mutableBlockPos.setPos(x, y, z);IBlockState state = this.world.getBlockState(mutableBlockPos);state.addCollisionBoxToList(this.world, mutableBlockPos, boundingBox, list, this, false);if(!list.isEmpty()){slipperiness += state.getBlock().getSlipperiness(state, this.world, mutableBlockPos, this);friction++;}list.clear();}}}}}}finally{mutableBlockPos.release();}return slipperiness / (float) friction;}private boolean checkInLava(){AxisAlignedBB entityBoundingBox = this.getEntityBoundingBox();int minX = MathHelper.floor(entityBoundingBox.minX);int maxX = MathHelper.ceil(entityBoundingBox.maxX);int minY = MathHelper.floor(entityBoundingBox.minY);int maxY = MathHelper.ceil(entityBoundingBox.minY + 0.001D);int minZ = MathHelper.floor(entityBoundingBox.minZ);int maxZ = MathHelper.ceil(entityBoundingBox.maxZ);boolean flag = false;this.lavaLevel = Double.MIN_VALUE;BlockPos.PooledMutableBlockPos mutableBlockPos = BlockPos.PooledMutableBlockPos.retain();try{for(int x = minX; x < maxX; x++){for(int y = minY; y < maxY; y++){for(int z = minZ; z < maxZ; z++){mutableBlockPos.setPos(x, y, z);IBlockState state = this.world.getBlockState(mutableBlockPos);//判断岩浆是否在岩浆或水中滑行if(state.getMaterial() == Material.LAVA || state.getMaterial() == Material.WATER){float liquidHeight = BlockLiquid.getLiquidHeight(state, this.world, mutableBlockPos);this.lavaLevel = Math.max(liquidHeight, this.lavaLevel);flag |= entityBoundingBox.minY < (double) liquidHeight;}}}}}finally{mutableBlockPos.release();}return flag;}private Status getUnderLavaStatus(){AxisAlignedBB entityBoundingBox = this.getEntityBoundingBox();double entityHeight = entityBoundingBox.maxY + 0.001D;int minX = MathHelper.floor(entityBoundingBox.minX);int maxX = MathHelper.ceil(entityBoundingBox.maxX);int minY = MathHelper.floor(entityBoundingBox.maxY);int maxY = MathHelper.ceil(entityHeight);int minZ = MathHelper.floor(entityBoundingBox.minZ);int maxZ = MathHelper.ceil(entityBoundingBox.maxZ);boolean flag = false;BlockPos.PooledMutableBlockPos mutableBlockPos = BlockPos.PooledMutableBlockPos.retain();try{for(int x = minX; x < maxX; x++){for(int y = minY; y < maxY; y++){for(int z = minZ; z < maxZ; z++){mutableBlockPos.setPos(x, y, z);IBlockState state = this.world.getBlockState(mutableBlockPos);if((state.getMaterial() == Material.LAVA || state.getMaterial() == Material.WATER) && entityHeight < (double) BlockLiquid.getLiquidHeight(state, this.world, mutableBlockPos)){if(state.getValue(BlockLiquid.LEVEL) != 0){return Status.UNDER_FLOWING_LAVA;}flag = true;}}}}}finally{mutableBlockPos.release();}return flag ? Status.UNDER_LAVA : null;}private void updateMotion(){double gravity = this.hasNoGravity() ? 0.0D : -0.03999999910593033D;double position = 0.0D;float momentum = 0.05F;if(this.previousStatus == Status.IN_AIR && this.status != Status.IN_AIR && this.status != Status.ON_LAND){this.lavaLevel = this.getEntityBoundingBox().minY + (double) this.height;this.setPosition(this.posX, (double) (this.getLavaLevelAbove() - this.height) + 0.101D, this.posZ);this.motionY = 0.0D;this.lastYd = 0.0D;this.status = Status.IN_LAVA;}else{if(this.status == Status.IN_LAVA){position = (this.lavaLevel - this.getEntityBoundingBox().minY) / (double) this.height;momentum = 0.9F;}else if(this.status == Status.UNDER_FLOWING_LAVA){gravity = -7.0E-4D;momentum = 0.9F;}else if(this.status == Status.UNDER_LAVA){position = 0.009999999776482582D;momentum = 0.45F;}else if(this.status == Status.IN_AIR){momentum = 0.9F;}else if(this.status == Status.ON_LAND){momentum = this.boatGlide;if(this.getControllingPassenger() instanceof EntityPlayer){this.boatGlide /= 2.0F;}}this.motionX *= momentum;this.motionZ *= momentum;this.deltaRotation *= momentum;this.motionY += gravity;if(position > 0.0D){this.motionY += position * 0.06153846016296973D;this.motionY *= 0.75D;}}}private void controlBoat(){if(this.isBeingRidden()){float speed = 0.0F;if(this.leftInputDown){this.deltaRotation += -1.0F;}if(this.rightInputDown){this.deltaRotation++;}if(this.rightInputDown != this.leftInputDown && !this.forwardInputDown && !this.backInputDown){speed += 0.005F;}this.rotationYaw += this.deltaRotation;if(this.forwardInputDown){speed += 0.04F;}if(this.backInputDown){speed -= 0.005F;}this.motionX += (MathHelper.sin(-this.rotationYaw * 0.017453292F) * speed);this.motionZ += (MathHelper.cos(this.rotationYaw * 0.017453292F) * speed);this.setPaddleState(this.rightInputDown && !this.leftInputDown || this.forwardInputDown, this.leftInputDown && !this.rightInputDown || this.forwardInputDown);}}@Overridepublic void updatePassenger(Entity passenger){//当玩家进入船中,防止其着火,就赋予其防火效果((EntityLivingBase)passenger).addPotionEffect(new PotionEffect(MobEffects.FIRE_RESISTANCE, 100));if(this.isPassenger(passenger)){float x = 0.0F;float height = (float) ((this.isDead ? 0.009999999776482582D : this.getMountedYOffset()) + passenger.getYOffset());if(this.getPassengers().size() > 1){int index = this.getPassengers().indexOf(passenger);if(index == 0){x = 0.2F;}else{x = -0.6F;}if(passenger instanceof EntityAnimal){x = (float) ((double) x + 0.2D);}}Vec3d pos = (new Vec3d(x, 0.0D, 0.0D)).rotateYaw(-this.rotationYaw * 0.017453292F - ((float) Math.PI / 2F));passenger.setPosition(this.posX + pos.x, this.posY + (double) height, this.posZ + pos.z);passenger.rotationYaw += this.deltaRotation;passenger.setRotationYawHead(passenger.getRotationYawHead() + this.deltaRotation);this.applyYawToEntity(passenger);if(passenger instanceof EntityAnimal && this.getPassengers().size() > 1){int rotation = passenger.getEntityId() % 2 == 0 ? 90 : 270;passenger.setRenderYawOffset(((EntityAnimal) passenger).renderYawOffset + (float) rotation);passenger.setRotationYawHead(passenger.getRotationYawHead() + (float) rotation);}if(this.isInsideOfMaterial(Material.WATER)){passenger.dismountRidingEntity();}}}@Overrideprotected void applyYawToEntity(Entity entityToUpdate){entityToUpdate.setRenderYawOffset(this.rotationYaw);float yaw = MathHelper.wrapDegrees(entityToUpdate.rotationYaw - this.rotationYaw);float clampedYaw = MathHelper.clamp(yaw, -105.0F, 105.0F);entityToUpdate.prevRotationYaw += clampedYaw - yaw;entityToUpdate.rotationYaw += clampedYaw - yaw;entityToUpdate.setRotationYawHead(entityToUpdate.rotationYaw);}@Override@SideOnly(Side.CLIENT)public void applyOrientationToEntity(Entity entityToUpdate){this.applyYawToEntity(entityToUpdate);}@Overrideprotected void writeEntityToNBT(NBTTagCompound compound){}@Overrideprotected void readEntityFromNBT(NBTTagCompound compound){}@Overridepublic boolean processInitialInteract(EntityPlayer player, EnumHand hand){if(player.isSneaking()){return false;}else{if(!this.world.isRemote && this.outOfControlCounter < 60.0F && !this.isInsideOfMaterial(Material.WATER)){player.startRiding(this);}return true;}}@Overrideprotected void updateFallState(double y, boolean onGround, IBlockState state, BlockPos pos){this.lastYd = this.motionY;if(!this.isRiding()){if(onGround){if(this.fallDistance > 3.0F){if(this.status != Status.ON_LAND){this.fallDistance = 0.0F;return;}this.fall(this.fallDistance, 1.0F);if(!this.world.isRemote && !this.isDead){this.setDead();if(this.world.getGameRules().getBoolean("doEntityDrops")){for(int i = 0; i < 3; i++){this.entityDropItem(new ItemStack(Blocks.OBSIDIAN, 1, 0), 0.0F);}}}}this.fallDistance = 0.0F;}else if(this.world.getBlockState((new BlockPos(this)).down()).getMaterial() != Material.LAVA && y < 0.0D ||this.world.getBlockState((new BlockPos(this)).down()).getMaterial() != Material.WATER && y < 0.0D){this.fallDistance = (float) ((double) this.fallDistance - y);}}}@Overridepublic boolean getPaddleState(int state){return this.dataManager.get(DATA_ID_PADDLE[state]) && this.getControllingPassenger() != null;}@Overridepublic void setDamageTaken(float damageTaken){this.dataManager.set(DAMAGE_TAKEN, damageTaken);}@Overridepublic float getDamageTaken(){return this.dataManager.get(DAMAGE_TAKEN);}@Overridepublic void setTimeSinceHit(int timeSinceHit){this.dataManager.set(TIME_SINCE_HIT, timeSinceHit);}@Overridepublic int getTimeSinceHit(){return this.dataManager.get(TIME_SINCE_HIT);}@Overridepublic void setForwardDirection(int forwardDirection){this.dataManager.set(FORWARD_DIRECTION, forwardDirection);}@Overridepublic int getForwardDirection(){return this.dataManager.get(FORWARD_DIRECTION);}@Overrideprotected boolean canFitPassenger(Entity passenger){return this.getPassengers().size() < 2;}@Overridepublic Entity getControllingPassenger(){List<Entity> passengers = this.getPassengers();return passengers.isEmpty() ? null : passengers.get(0);}@Override@SideOnly(Side.CLIENT)public void updateInputs(boolean left, boolean right, boolean forward, boolean back){this.leftInputDown = left;this.rightInputDown = right;this.forwardInputDown = forward;this.backInputDown = back;}//枚举船的几种状态public enum Status{IN_LAVA,UNDER_LAVA,UNDER_FLOWING_LAVA,ON_LAND,IN_AIR}
}

3.新建船的渲染类RenderObBoat.java,这里直接使用原版的船渲染类。

RenderObBoat.java

package com.joy187.rejoymod.entity.render;import com.joy187.rejoymod.entity.EntityObBoat;
import com.joy187.rejoymod.entity.model.ModelObBoat;
import com.joy187.rejoymod.util.Reference;
import net.minecraft.client.model.IMultipassModel;
import net.minecraft.client.model.ModelBase;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.client.renderer.entity.Render;
import net.minecraft.client.renderer.entity.RenderManager;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.math.MathHelper;public class RenderObBoat extends Render<EntityObBoat> {//这个要对应我们的船的皮肤贴图文件路径public static final ResourceLocation TEXTURES = new ResourceLocation(Reference.Mod_ID + ":textures/entity/obboat.png");protected ModelBase modelBoat = new ModelObBoat();public RenderObBoat(RenderManager renderManagerIn){super(renderManagerIn);this.shadowSize = 0.5F;this.modelBoat = new ModelObBoat();}public void doRender(EntityObBoat entity, double x, double y, double z, float entityYaw, float partialTicks){GlStateManager.pushMatrix();this.setupTranslation(x, y, z);this.setupRotation(entity, entityYaw, partialTicks);this.bindEntityTexture(entity);if (this.renderOutlines){GlStateManager.enableColorMaterial();GlStateManager.enableOutlineMode(this.getTeamColor(entity));}this.modelBoat.render(entity, partialTicks, 0.0F, -0.1F, 0.0F, 0.0F, 0.0625F);if (this.renderOutlines){GlStateManager.disableOutlineMode();GlStateManager.disableColorMaterial();}GlStateManager.popMatrix();super.doRender(entity, x, y, z, entityYaw, partialTicks);}public void setupRotation(EntityObBoat p_188311_1_, float p_188311_2_, float p_188311_3_){GlStateManager.rotate(180.0F - p_188311_2_, 0.0F, 1.0F, 0.0F);float f = (float)p_188311_1_.getTimeSinceHit() - p_188311_3_;float f1 = p_188311_1_.getDamageTaken() - p_188311_3_;if (f1 < 0.0F){f1 = 0.0F;}if (f > 0.0F){GlStateManager.rotate(MathHelper.sin(f) * f * f1 / 10.0F * (float)p_188311_1_.getForwardDirection(), 1.0F, 0.0F, 0.0F);}GlStateManager.scale(-1.0F, -1.0F, 1.0F);}public void setupTranslation(double p_188309_1_, double p_188309_3_, double p_188309_5_){GlStateManager.translate((float)p_188309_1_, (float)p_188309_3_ + 0.375F, (float)p_188309_5_);}/*** Returns the location of an entity's texture. Doesn't seem to be called unless you call Render.bindEntityTexture.*/protected ResourceLocation getEntityTexture(EntityObBoat entity){return TEXTURES;}public boolean isMultipass(){return true;}public void renderMultipass(EntityObBoat p_188300_1_, double p_188300_2_, double p_188300_4_, double p_188300_6_, float p_188300_8_, float p_188300_9_){GlStateManager.pushMatrix();this.setupTranslation(p_188300_2_, p_188300_4_, p_188300_6_);this.setupRotation(p_188300_1_, p_188300_8_, p_188300_9_);this.bindEntityTexture(p_188300_1_);((IMultipassModel)this.modelBoat).renderMultipass(p_188300_1_, p_188300_9_, 0.0F, -0.1F, 0.0F, 0.0F, 0.0625F);GlStateManager.popMatrix();}
}

RenderHandler.java中的registerEntityRenders()中添加船的渲染注册:

RenderHandler.java

public class RenderHandler {public static void registerEntityRenders() {RenderingRegistry.registerEntityRenderingHandler(EntityObBoat.class, new IRenderFactory<EntityObBoat>(){@Overridepublic Render<? super EntityObBoat> createRenderFor(RenderManager manager){return new RenderObBoat(manager);}});}
}

4.在EntityInit.java中添加我们的船的注册信息:

        registerEntity("obboat", EntityObBoat.class, ENTITY_NEXT_ID, 20);

5.生物实体部分完成,我们要制作一个专门生成船的物品,新建ItemObBoat类。

ItemObBoat.java

package com.joy187.rejoymod.item;import com.joy187.rejoymod.entity.EntityObBoat;
import net.minecraft.block.Block;
import net.minecraft.creativetab.CreativeTabs;
import net.minecraft.entity.Entity;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.init.Blocks;
import net.minecraft.item.ItemStack;
import net.minecraft.stats.StatList;
import net.minecraft.util.ActionResult;
import net.minecraft.util.EnumActionResult;
import net.minecraft.util.EnumHand;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.MathHelper;
import net.minecraft.util.math.RayTraceResult;
import net.minecraft.util.math.Vec3d;
import net.minecraft.world.World;import java.util.List;public class ItemObBoat extends ItemBase{public ItemObBoat(String name, CreativeTabs tab) {super(name,tab);this.maxStackSize=1;}private EntityObBoat.Type type= EntityObBoat.Type.OAK;public ItemObBoat(EntityObBoat.Type typeIn){this.type = typeIn;this.maxStackSize = 1;this.setCreativeTab(CreativeTabs.TRANSPORTATION);this.setUnlocalizedName("boat." + "ob");}/*** Called when the equipped item is right clicked.*/public ActionResult<ItemStack> onItemRightClick(World worldIn, EntityPlayer playerIn, EnumHand handIn){ItemStack itemstack = playerIn.getHeldItem(handIn);float f = 1.0F;float f1 = playerIn.prevRotationPitch + (playerIn.rotationPitch - playerIn.prevRotationPitch) * 1.0F;float f2 = playerIn.prevRotationYaw + (playerIn.rotationYaw - playerIn.prevRotationYaw) * 1.0F;double d0 = playerIn.prevPosX + (playerIn.posX - playerIn.prevPosX) * 1.0D;double d1 = playerIn.prevPosY + (playerIn.posY - playerIn.prevPosY) * 1.0D + (double)playerIn.getEyeHeight();double d2 = playerIn.prevPosZ + (playerIn.posZ - playerIn.prevPosZ) * 1.0D;Vec3d vec3d = new Vec3d(d0, d1, d2);float f3 = MathHelper.cos(-f2 * 0.017453292F - (float)Math.PI);float f4 = MathHelper.sin(-f2 * 0.017453292F - (float)Math.PI);float f5 = -MathHelper.cos(-f1 * 0.017453292F);float f6 = MathHelper.sin(-f1 * 0.017453292F);float f7 = f4 * f5;float f8 = f3 * f5;double d3 = 5.0D;Vec3d vec3d1 = vec3d.addVector((double)f7 * 5.0D, (double)f6 * 5.0D, (double)f8 * 5.0D);RayTraceResult raytraceresult = worldIn.rayTraceBlocks(vec3d, vec3d1, true);if (raytraceresult == null){return new ActionResult<ItemStack>(EnumActionResult.PASS, itemstack);}else{Vec3d vec3d2 = playerIn.getLook(1.0F);boolean flag = false;List<Entity> list = worldIn.getEntitiesWithinAABBExcludingEntity(playerIn, playerIn.getEntityBoundingBox().expand(vec3d2.x * 5.0D, vec3d2.y * 5.0D, vec3d2.z * 5.0D).grow(1.0D));for (int i = 0; i < list.size(); ++i){Entity entity = list.get(i);if (entity.canBeCollidedWith()){AxisAlignedBB axisalignedbb = entity.getEntityBoundingBox().grow((double)entity.getCollisionBorderSize());if (axisalignedbb.contains(vec3d)){flag = true;}}}if (flag){return new ActionResult<ItemStack>(EnumActionResult.PASS, itemstack);}else if (raytraceresult.typeOfHit != RayTraceResult.Type.BLOCK){return new ActionResult<ItemStack>(EnumActionResult.PASS, itemstack);}else{Block block = worldIn.getBlockState(raytraceresult.getBlockPos()).getBlock();boolean flag1 = block == Blocks.WATER || block == Blocks.FLOWING_WATER || block == Blocks.LAVA || block == Blocks.FLOWING_LAVA;//这里声明我们要召唤的船的实体类(第2步中的实体类)EntityObBoat entityboat = new EntityObBoat(worldIn, raytraceresult.hitVec.x, flag1 ? raytraceresult.hitVec.y - 0.12D : raytraceresult.hitVec.y, raytraceresult.hitVec.z);//entityboat.setBoatType(this.type);entityboat.rotationYaw = playerIn.rotationYaw;if (!worldIn.getCollisionBoxes(entityboat, entityboat.getEntityBoundingBox().grow(-0.1D)).isEmpty()){return new ActionResult<ItemStack>(EnumActionResult.FAIL, itemstack);}else{if (!worldIn.isRemote){worldIn.spawnEntity(entityboat);}if (!playerIn.capabilities.isCreativeMode){itemstack.shrink(1);}playerIn.addStat(StatList.getObjectUseStats(this));return new ActionResult<ItemStack>(EnumActionResult.SUCCESS, itemstack);}}}}
}

ModItems.java中添加该物品的注册信息:

                                                    //物品名称  放入哪个物品栏public static final Item OBBOAT = new ItemObBoat("obboat",IdlFramework.ITEM_TAB);

6.在resources包中的assets\rejoymod\models\item中新建物品模型文件:

obboat.json

{"parent": "item/generated","textures": {"layer0": "rejoymod:items/obboat"}
}

en_us.lang中添加船物品和船实体的英文名称:

item.obboat.name=Example Boat
entity.obboat.name=Example Boat

textures\item中添加物品的贴图:

textures\entity中添加船实体的皮肤贴图:

7.保存所有文件 -> 进入游戏测试:

岩浆中行船

水中行船

Minecraft 1.12.2模组开发(四十五) 水火两用船相关推荐

  1. Minecraft 1.12.2模组开发(四十九) 维度空间

    1.18.2维度空间教程 1.16.5维度空间教程 我们今天在1.12.2的模组中实现一个自定义维度的生成: 1.在Java包的init包中新建一个InitDimension类注册我们所有的维度: I ...

  2. Minecraft 1.12.2模组开发(四十) buff效果(Potion Effect)

    今天我们在1.12.2的模组中尝试实现几种特殊的buff效果 1.在开发包中新建potion包 -> potion包中新建一个BaseSimplePotion类作为我们药水效果的基类: Base ...

  3. Minecraft 1.12.2模组开发(二十) 导出模组

    模组制作完成后,我们就可以将其导出成为.jar文件,进行发布,供全世界的玩家进行下载游玩了 1.进入模组开发的文件夹 -> 起动cmd控制台 2.输入构建指令等待其构建模组 Windows系统: ...

  4. Minecraft 1.16.5模组开发(四十八) 传送门

    Minecraft 1.18.2模组 传送门教程 我们今天在模组中实现一个传送门,让我们可以传送到自己的维度中.(文末附数据包下载链接) 1.在src\main\resources\data中新建一个 ...

  5. Minecraft 1.12.2模组开发(四十三) 自定义盾牌(Shield)

    今天我们在模组中实现一个自定义盾牌 1.新建一个接口类IHasModel: IHasModel.java public interface IHasModel {public void registe ...

  6. Minecraft 1.12.2模组开发(三十九) 反应器(TileEntity方块实体)

    说到方块实体(TileEntity),可以理解为一种功能性方块,比如熔炉,箱子,附魔台等. 我们今天来做一个类似于熔炉的反应器 熔炉逻辑: 放入燃料-> 放入物品 -> 获取产出物品 1. ...

  7. Minecraft 1.16.5模组开发(三十八) 3D盔甲(新)

    Minecraft升级到1.16.5后,3D盔甲的制作方法也跟之前版本稍有不同(主要在第二步.第四步),建议先复习一下往期教程: Minecraft 1.12.2模组开发(三十七) 3D盔甲 1.在b ...

  8. Minecraft 1.16.5模组开发(三十二) 自定义投掷物品实体

    如果你了解过之前我们的实体开发教程,那么本次的教程会相对比较好理解. Minecraft 1.12.2模组开发(七) 实体(魔改Zombie) 我们本次将参考雪球在MC中制作一个属于我们自己的可投掷实 ...

  9. Minecraft 1.12.2模组开发(一) 配置ForgeMDK环境

    我的世界1.12.2 IDEA开发包构建教程已出,更加方便快捷~ 1.12.2Forge模组开发 配置ForgeMDK环境 开发环境:eclipse 1. 我的世界模组开发首先需要配置Forge MD ...

最新文章

  1. 大道至简:软件工程实践者的思想——第七、八章感想
  2. Powershell 邮件发送
  3. TensorFlow配置日志等级
  4. 关于Beta分布、二项分布与Dirichlet分布、多项分布的关系
  5. 无盘服务器 双镜像盘,镜像(无盘柜)-双活集群解决方案
  6. SAP CRM product hierarchy和category的三个问题问答
  7. 手机app 服务器 网页同步,手机app接入云服务器
  8. Kafka源码解析 - 副本迁移任务提交流程
  9. 基础知识—函数-函数概述
  10. linux 脚本中的push,在Linux系统下实现ServerPush(转)
  11. 设定MyEclipse编辑代码区域文字的大小及非关键字的字体、字形和颜色
  12. pads9.5在win10中选项字体显示不全问题解决补丁下载(网盘免费下载)
  13. pmp考试有题库么?
  14. 架构之美–开放环境下的网络架构
  15. Unity3D中使用Projector生成阴影
  16. 上传图片到淘宝接口调用展示
  17. 关于阿里云的直播API开发
  18. Codeforces 868C - Qualification Rounds 思维
  19. Python 魔术方法指南
  20. 如何修改计算机系统的网络最大连接数?

热门文章

  1. JAVA:二进制与十进制转换
  2. 【CF446B】 DZY Loves Modification
  3. android ae动画教程,AE动画转Web代码工具指北-Lottie
  4. 智能家居之ESP8266接继电器接线方式
  5. VMware安装苹果系统
  6. 普通云硬盘,高性能云硬盘和SSD云硬盘三者之间有什么区别?
  7. zabbix应用之详细的拓扑图标签--链路流量
  8. 计算机应用专业职业价值观,计算机应用技术专业大学生职业生涯规划书.doc
  9. 启动docker 报ERROR: failed to register layer: symlink
  10. ubuntu上mysql端口3306无法远程连接