970 words
5 minutes
09 吐口水的羊驼
09 吐口水的羊驼
对于吐口水的羊驼,我们需要一个物品,右键生成一个吐口水的羊驼的实体.
代码的主要功能就是生成一个口水的羊驼的实体.
public class LlamaItem extends Item {
public LlamaItem(Properties properties) {
super(properties);
}
@Override
public InteractionResultHolder<ItemStack> use(Level level, Player player, InteractionHand usedHand) {
level.playSound(null,player.getX(),player.getY(),player.getZ(), SoundEvents.LLAMA_SPIT, SoundSource.NEUTRAL,0.5f,0.4f/(level.getRandom().nextFloat() * 0.4f + 0.8f));
if (!level.isClientSide){
CustomLlamaSpitEntity llamaSpitEntity = new CustomLlamaSpitEntity(level,player);
llamaSpitEntity.shootFromRotation(player,player.getXRot(),player.getYRot(),0f,1.5f,1.0f);
level.addFreshEntity(llamaSpitEntity);
}
return super.use(level, player, usedHand);
}
}
下面我添加一个自己的口水的类,直接继承于原版的类,并修改了一些细节.
// 自定义羊驼唾液实体类,继承自Projectile
public class CustomLlamaSpitEntity extends Projectile {
// 构造函数,初始化实体类型和所在世界
protected CustomLlamaSpitEntity(EntityType<? extends Projectile> entityType, Level level) {
super(entityType, level);
}
// 构造函数,初始化世界和所有者
public CustomLlamaSpitEntity(Level world, Player owner) {
this(EntityType.LLAMA_SPIT, world); // 这里使用了原版的type所以,所以渲染和模型都是对应的原版的口水的渲染和模型
this.setOwner(owner);
this.setPos(owner.getX() - (double)(owner.getBbWidth() + 1.0F) * 0.5 * (double)Math.sin(owner.yBodyRot * 0.017453292F), owner.getEyeY() - 0.10000000149011612, owner.getZ() + (double)(owner.getBbWidth() + 1.0F) * 0.5 * (double)Math.cos(owner.yBodyRot * 0.017453292F));
}
// 每 tick 更新逻辑
@Override
public void tick() {
super.tick();
Vec3 vec3d = this.getDeltaMovement();
HitResult hitResult = ProjectileUtil.getHitResultOnMoveVector(this,this::canHitEntity);
this.onHit(hitResult);
double d = this.getX() + vec3d.x;
double e = this.getY() + vec3d.y;
double f = this.getZ() + vec3d.z;
this.updateRotation();
float g = 0.99F;
float h = 0.06F;
//检查是否碰撞到非空气方块或进入水中
if (this.level().getBlockStates(this.getBoundingBox()).noneMatch(BlockBehaviour.BlockStateBase::isAir)) {
this.discard();
} else if (this.isInWaterOrBubble()) {
this.discard();
} else {
//新运动向量和位置
this.setDeltaMovement(vec3d.scale(0.9900000095367432));
if (!this.isNoGravity()) {
this.setDeltaMovement(this.getDeltaMovement().add(0.0, -0.05999999865889549, 0.0));
}
this.setPos(d, e, f);
}
}
// 击中实体时的处理逻辑
@Override
protected void onHitEntity(EntityHitResult result) {
super.onHitEntity(result);
Entity owner = this.getOwner();
if (owner instanceof LivingEntity livingEntity){
result.getEntity().hurt(this.damageSources().mobProjectile(this,livingEntity),1f);
}
}
// 击中方块时的处理逻辑
@Override
protected void onHitBlock(BlockHitResult result) {
super.onHitBlock(result);
if (!this.level().isClientSide){
this.discard();
}
}
// 定义同步数据
@Override
protected void defineSynchedData(SynchedEntityData.Builder builder) {
}
// 从数据包中重新创建实体
@Override
public void recreateFromPacket(ClientboundAddEntityPacket packet) {
super.recreateFromPacket(packet);
double d = packet.getX();
double e = packet.getY();
double f = packet.getZ();
for(int i =0;i<7;i++){
double g = 0.4 + 0.1 * (double)i;
this.level().addParticle(ParticleTypes.SPIT,this.getX(),this.getY(),this.getZ(),d*g,e,f*g);
}
this.setPos(d,e,f);
}
}
其他代码请查看之前的自行完成.
我们看下对应的如何实现将实体的渲染作为物品的渲染.使用mixin对renderitem进行了修改,如果renderitem的目标item是我们添加的羊驼的物品,.我们就取消这个渲染,然后写上自己的渲染代码
/**
* 这个类继承自ItemRenderer,并使用Mixin注解标记,表示它将修改ItemRenderer的行为。
*/
@Mixin(ItemRenderer.class)
public class ItemRendererMixin {
/**
* 使用Unique注解标记的成员变量,用于获取Minecraft实例,以便在渲染过程中使用。
*/
@Unique
private final Minecraft mc = Minecraft.getInstance();
/**
* 使用Inject注解标记的方法,用于在ItemRenderer的render方法执行前注入自定义代码。
* 这个方法会检查要渲染的物品是否是特定的物品(例如MOD中新增的羊驼项),如果是,则使用自定义的渲染逻辑。
*
* @param itemStack 要渲染的物品栈
* @param displayContext 显示上下文,定义了物品的展示方式
* @param leftHand 是否在左手中
* @param poseStack 用于追踪和修改渲染状态的矩阵堆栈
* @param bufferSource 提供渲染缓冲区的源
* @param combinedLight 组合光照值
* @param combinedOverlay 组合覆盖值
* @param p_model 要渲染的模型
* @param ci 回调信息,可以通过设置cancel()来取消原本的渲染逻辑
*/
@Inject(method = "render", at = @At("HEAD"), cancellable = true)
public void renderItem(ItemStack itemStack, ItemDisplayContext displayContext, boolean leftHand, PoseStack poseStack, MultiBufferSource bufferSource, int combinedLight, int combinedOverlay, BakedModel p_model, CallbackInfo ci) {
// 检查是否是MOD中新增的羊驼项
if (BuiltInRegistries.ITEM.getKey(itemStack.getItem()).equals(ResourceLocation.fromNamespaceAndPath(NeoMafishMod.MODID, "llama_item"))) {
// 取消默认渲染
ci.cancel();
// 创建一个新的羊驼实体实例
Llama llama = new Llama(EntityType.LLAMA, mc.level);
poseStack.pushPose();
// 使用org.joml.Quaternionf进行旋转
Quaternionf rotation = new Quaternionf().rotateY((float) Math.toRadians(180));
poseStack.mulPose(rotation);
// 调整渲染的羊驼模型的缩放比例
poseStack.scale(0.5F, 0.5F, 0.5F);
// 调用Minecraft的渲染系统来渲染羊驼模型
mc.getEntityRenderDispatcher().render(llama, 0, 0, 0, 0.0F, 1.0F, poseStack, bufferSource, combinedLight);
poseStack.popPose();
}
}
}
记得添加对应的类到mixin的json