想在MC中开车吗?今天我们在MC中制作一辆车。
由于车辆是一个生物实体,所以要首先了解MC中的实体:我的世界实体教程
1.首先我们要制作一个车辆实体的模型(blockbench) 下载地址:
将模型导出(本教程在1.16.5下使用Mojmaps格式)
导数模型的.java文件:
将该文件文件放入开发包中
2.Entity包中新建一个汽车类HeisenCarEntity.java:
我们的汽车默认以马类为父类,但取消了马年龄和可驯服的特征,使其更加符合一个载具的设定:
package com.joy187.re8joymod.common.entity;
import com.joy187.re8joymod.common.init.EntityInit;
import com.joy187.re8joymod.common.init.ModItems;
import net.minecraft.entity.*;
import net.minecraft.entity.ai.attributes.AttributeModifierMap;
import net.minecraft.entity.ai.attributes.Attributes;
import net.minecraft.entity.ai.goal.*;
import net.minecraft.entity.item.BoatEntity;
import net.minecraft.entity.passive.PigEntity;
import net.minecraft.entity.passive.horse.AbstractHorseEntity;
import net.minecraft.entity.passive.horse.HorseEntity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.ItemStack;
import net.minecraft.item.Items;
import net.minecraft.item.crafting.Ingredient;
import net.minecraft.network.IPacket;
import net.minecraft.network.datasync.DataParameter;
import net.minecraft.network.datasync.DataSerializers;
import net.minecraft.network.datasync.EntityDataManager;
import net.minecraft.particles.ParticleTypes;
import net.minecraft.potion.Effects;
import net.minecraft.util.ActionResultType;
import net.minecraft.util.Hand;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.math.MathHelper;
import net.minecraft.util.math.vector.Vector3d;
import net.minecraft.world.World;
import net.minecraftforge.fml.network.NetworkHooks;
//继承马类生物
public class HeisenCarEntity extends HorseEntity {
// private static final DataParameter<String> WOOD_TYPE
// = EntityDataManager.defineId(HeisenCarEntity.class, DataSerializers.STRING);
public HeisenCarEntity(EntityType<? extends HeisenCarEntity> p_i50250_1_, World p_i50250_2_) {
super(p_i50250_1_, p_i50250_2_);
}
// public HeisenCarEntity(World worldIn, double x, double y, double z) {
// //this(EntityInit.HEISENCAR.get(), worldIn);
// this.setPos(x, y, z);
// this.setDeltaMovement(Vector3d.ZERO);
// this.xo = x;
// this.yo = y;
// this.zo = z;
// }
public void aiStep() {
super.aiStep();
}
protected void registerGoals() {
this.goalSelector.addGoal(7, new LookAtGoal(this, PlayerEntity.class, 6.0F));
this.addBehaviourGoals();
}
//设置车辆的相关属性,如生命值、移动速度等
public static AttributeModifierMap.MutableAttribute setAttributes() {
return MobEntity.createMobAttributes().add(Attributes.MAX_HEALTH, 100.0D)
.add(Attributes.MOVEMENT_SPEED, 0.4D);
}
public boolean canBeControlledByRider() {
Entity entity = this.getControllingPassenger();
if (!(entity instanceof PlayerEntity)) {
return false;
} else {
//可直接被玩家骑乘,无需驯服
PlayerEntity playerentity = (PlayerEntity)entity;
return true;
}
}
public ActionResultType mobInteract(PlayerEntity p_230254_1_, Hand p_230254_2_) {
this.doPlayerRide(p_230254_1_);
return ActionResultType.sidedSuccess(this.level.isClientSide);
}
//该函数是开车时的速度等控制,可以自行调整
public void travel(Vector3d p_213352_1_) {
if (this.isAlive()) {
if (this.isVehicle() && this.canBeControlledByRider()) {
LivingEntity livingentity = (LivingEntity)this.getControllingPassenger();
this.yRot = livingentity.yRot;
this.yRotO = this.yRot;
this.xRot = livingentity.xRot * 0.5F;
this.setRot(this.yRot, this.xRot);
this.yBodyRot = this.yRot;
this.yHeadRot = this.yBodyRot;
float f = livingentity.xxa * 0.5F;
float f1 = livingentity.zza;
if (f1 <= 0.0F) {
f1 *= 0.25F;
this.gallopSoundCounter = 0;
}
if (this.onGround && this.playerJumpPendingScale == 0.0F && this.isStanding()) {
f = 0.0F;
f1 = 0.0F;
}
if (this.playerJumpPendingScale > 0.0F && !this.isJumping() && this.onGround) {
double d0 = this.getCustomJump() * (double)this.playerJumpPendingScale * (double)this.getBlockJumpFactor();
double d1;
if (this.hasEffect(Effects.JUMP)) {
d1 = d0 + (double)((float)(this.getEffect(Effects.JUMP).getAmplifier() + 1) * 0.1F);
} else {
d1 = d0;
}
Vector3d vector3d = this.getDeltaMovement();
this.setDeltaMovement(vector3d.x, d1, vector3d.z);
this.setIsJumping(true);
this.hasImpulse = true;
net.minecraftforge.common.ForgeHooks.onLivingJump(this);
if (f1 > 0.0F) {
float f2 = MathHelper.sin(this.yRot * ((float)Math.PI / 180F));
float f3 = MathHelper.cos(this.yRot * ((float)Math.PI / 180F));
this.setDeltaMovement(this.getDeltaMovement().add((double)(-0.4F * f2 * this.playerJumpPendingScale), 0.0D, (double)(0.4F * f3 * this.playerJumpPendingScale)));
}
this.playerJumpPendingScale = 0.0F;
}
this.flyingSpeed = this.getSpeed() * 0.1F;
if (this.isControlledByLocalInstance()) {
this.setSpeed((float)this.getAttributeValue(Attributes.MOVEMENT_SPEED));
super.travel(new Vector3d((double)f, p_213352_1_.y, (double)f1));
} else if (livingentity instanceof PlayerEntity) {
this.setDeltaMovement(Vector3d.ZERO);
}
if (this.onGround) {
this.playerJumpPendingScale = 0.0F;
this.setIsJumping(false);
}
this.calculateEntityAnimation(this, false);
} else {
this.flyingSpeed = 0.02F;
super.travel(p_213352_1_);
}
}
}
public float getSteeringSpeed() {
return (float)this.getAttributeValue(Attributes.MOVEMENT_SPEED) * 1.15F;
}
}
新建一个EntityInit.java,将我们刚刚设定好的车辆在这个类中统一放置:
package com.joy187.re8joymod.common.init;
import com.joy187.re8joymod.Utils;
import com.joy187.re8joymod.common.entity.*;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityClassification;
import net.minecraft.entity.EntityType;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.passive.PigEntity;
import net.minecraft.entity.projectile.AbstractArrowEntity;
import net.minecraft.entity.projectile.ArrowEntity;
import net.minecraft.entity.projectile.SpectralArrowEntity;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.fml.RegistryObject;
import net.minecraftforge.registries.DeferredRegister;
import net.minecraftforge.registries.ForgeRegistries;
public class EntityInit {
public static final DeferredRegister<EntityType<?>> ENTITY_TYPES = DeferredRegister.create(ForgeRegistries.ENTITIES,
Utils.MOD_ID);
//我们的车辆
public static final RegistryObject<EntityType<HeisenCarEntity>> HEISENCAR = ENTITY_TYPES.register("heisencar",
() -> EntityType.Builder.of(HeisenCarEntity::new, EntityClassification.MISC).sized(2f,0.8f).setTrackingRange(30)
.build(new ResourceLocation(Utils.MOD_ID, "heisencar").toString()));
//其他的生物实体也在这里
// public static final RegistryObject<EntityType<EntityRose>> ROSE = ENTITY_TYPES.register("rose",
// () -> EntityType.Builder.of(EntityRose::new, EntityClassification.MONSTER).sized(2f,0.8f).setTrackingRange(30)
// .build(new ResourceLocation(Utils.MOD_ID, "rose").toString()));
}
3.新建一个渲染类RenderHeisenCar.java用于车辆在游戏中的模型渲染:
package com.joy187.re8joymod.common.entity.render;
import com.joy187.re8joymod.Utils;
import com.joy187.re8joymod.common.entity.HeisenCarEntity;
import com.joy187.re8joymod.common.entity.model.ModelHeisenCar;
import net.minecraft.client.renderer.entity.EntityRendererManager;
import net.minecraft.client.renderer.entity.MobRenderer;
import net.minecraft.util.ResourceLocation;
public class RenderHeisenCar extends MobRenderer<HeisenCarEntity, ModelHeisenCar<HeisenCarEntity>> {
public static final ResourceLocation TEXTURE = new ResourceLocation(Utils.MOD_ID, "textures/entity/heisenberg2.png");
public RenderHeisenCar(EntityRendererManager manager) {
super(manager, new ModelHeisenCar<HeisenCarEntity>(), 0.7f);
}
@Override
public ResourceLocation getTextureLocation(HeisenCarEntity p_110775_1_) {
return TEXTURE;
}
}
新建一个ClientModEventSubscriber.java文件用于对渲染文件进行处理
package com.joy187.re8joymod.common;
import com.joy187.re8joymod.Utils;
import com.joy187.re8joymod.common.entity.render.*;
import com.joy187.re8joymod.common.init.EntityInit;
import com.joy187.re8joymod.common.init.ModItems;
import com.joy187.re8joymod.common.items.ItemGM79B;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.entity.SpriteRenderer;
import net.minecraftforge.fml.client.registry.RenderingRegistry;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import net.minecraft.client.gui.ScreenManager;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.common.Mod.EventBusSubscriber;
import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent;
/**
* Subscribe to events from the MOD EventBus that should be handled on the PHYSICAL CLIENT side in this class
*
* @author Sinhika
*/
@EventBusSubscriber(modid= Utils.MOD_ID, bus=EventBusSubscriber.Bus.MOD, value=Dist.CLIENT)
public class ClientModEventSubscriber
{
private static final Logger LOGGER = LogManager.getLogger(Utils.MOD_ID + " Client Mod Event Subscriber");
/**
* We need to register our renderers on the client because rendering code does not exist on the server
* and trying to use it on a dedicated server will crash the game.
* <p>
* This method will be called by Forge when it is time for the mod to do its client-side setup
* This method will always be called after the Registry events.
* This means that all Blocks, Items, TileEntityTypes, etc. will all have been registered already
*/
//将我们的载具渲染在这个函数中调用
@SubscribeEvent
public static void onFMLClientSetupEvent(final FMLClientSetupEvent event)
{
RenderingRegistry.registerEntityRenderingHandler(EntityInit.HEISENCAR.get(), RenderHeisenCar::new);
}
} // end class
4.在我们的Main.java中的setup函数中添加实体的属性信息:
private void setup(final FMLCommonSetupEvent event) {
DeferredWorkQueue.runLater(() -> GlobalEntityTypeAttributes.put(EntityInit.HEISENCAR.get(), HeisenCarEntity.setAttributes().build()));
}
5.在.lang文件中添加我们的物品名称信息,将贴图放入textures/entity文件夹:
"entity.re8joymod.heisencar": "Heisen Car",
6.我们同时设计一个召唤载具的物品,物品具体教程可参照物品教程:
新建一个ItemVehicleCore.java文件用于召唤载具
package com.joy187.re8joymod.common.items;
import com.joy187.re8joymod.common.entity.EntityDoll1;
import com.joy187.re8joymod.common.entity.EntityGM79B;
import com.joy187.re8joymod.common.entity.HeisenCarEntity;
import com.joy187.re8joymod.common.init.EntityInit;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.IItemTier;
import net.minecraft.item.ItemStack;
import net.minecraft.potion.EffectInstance;
import net.minecraft.potion.Effects;
import net.minecraft.util.ActionResult;
import net.minecraft.util.Hand;
import net.minecraft.world.World;
import java.util.Random;
public class ItemVehicleCore extends ItemPickaxe {
public ItemVehicleCore(IItemTier toolMaterial, int attackDamage, float attackSpeed, Properties itemProperties) {
super(toolMaterial,attackDamage, attackSpeed, itemProperties);
}
@Override //这里我们设置按右键就可以召唤我们的载具
public ActionResult<ItemStack> use(World p_77659_1_, PlayerEntity p_77659_2_, Hand p_77659_3_) {
ItemStack itemstack = p_77659_2_.getItemInHand(p_77659_3_);
//生成我们的载具
HeisenCarEntity e = new HeisenCarEntity(EntityInit.HEISENCAR.get(), p_77659_2_.level);
e.setPos(p_77659_2_.position().x,p_77659_2_.position().y,p_77659_2_.position().z);
p_77659_2_.level.addFreshEntity(e);
if (!p_77659_2_.abilities.instabuild) {
itemstack.shrink(10000);
if (itemstack.isEmpty()) {
p_77659_2_.inventory.removeItem(itemstack);
}
}
return ActionResult.success(itemstack);
}
}
在ItemInit中声明该物品:
public static final RegistryObject<ItemPickaxe> HCKEY = ITEMS.register("vehicle_core",
() -> new ItemVehicleCore(CustomItemTier.TOOL_KEY3,2,-1.5F,new Item.Properties().tab(RegistryEvents.RE8GROUP)));
在.lang文件添加该物品的名称,在models/item中新建该物品.json文件,绑定其贴图路径,贴图放入textures/items文件夹中:
en_us.lang
"item.re8joymod.vehicle_core":"Heisen Car Control",
vehicle_core.json
{
"parent": "item/generated",
"textures": {
"layer0": "re8joymod:items/factoryg" //和你在textures/items中的名称保持一致
}
}
7.OK,载具和召唤物都制作完成,进入游戏进行测试:
可以按WASD键位对载具操控进行移动:
nb!新年快乐!
新年快乐!