924 words
5 minutes
10 可以抛掷的斧头
10 可以抛掷的斧头
先添加一个投掷物实体.和之前的雪球类似,不过我们需要修改一个内容实现投掷的斧头特有的功能.
我们复用了之前的STONE_PROJECTILE的entitytype,由于STONE_PROJECTILE是使用的物品作为投掷物渲染,所以这里直接复用了.
public class FuProjectileEntity extends ThrowableItemProjectile {
/**
* 构造函数,初始化FuProjectileEntity实例。
*
* @param entityType 实体类型
* @param level 所属的世界实例
*/
public FuProjectileEntity(EntityType<? extends ThrowableItemProjectile> entityType, Level level) {
super(entityType, level);
}
/**
* 另一个构造函数,用于从LivingEntity(如玩家或怪物)投掷FuProjectileEntity。
*
* @param livingEntity 投掷实体
* @param world 所属的世界实例
*/
public FuProjectileEntity(LivingEntity livingEntity, Level world) {
super(ModEntities.STONE_PROJECTILE.get(), livingEntity, world);
}
/**
* 覆盖ThrowableItemProjectile类的getDefaultItem方法,返回此投掷物的默认物品。
*
* @return 返回的默认物品
*/
@Override
protected Item getDefaultItem() {
return ModItems.STONE_BALL.get();
}
/**
* 当投掷物击中方块时调用的方法。
* 如果服务器端执行并且击中的是木头方块,则会移除方块并生成相应的物品实体。
* 无论击中什么方块,都会生成投掷物本身的物品实体并丢弃这个实体。
*
* @param result 击中结果,包含击中的方块位置等信息
*/
@Override
protected void onHitBlock(BlockHitResult result) {
Level level = level();
BlockPos blockPos = result.getBlockPos();
BlockState blockState = level.getBlockState(blockPos);
boolean isWoodenBlock = blockState.is(BlockTags.LOGS);
if (!this.level().isClientSide) {
level.broadcastEntityEvent(this, (byte) 3);
if (isWoodenBlock) {
level.removeBlock(blockPos, false);
spawnAtLocation(blockState.getBlock());
}
ItemStack itemStack = this.getItem();
ItemEntity itemEntity = new ItemEntity(this.level(), this.getX(), this.getY(), this.getZ(), itemStack);
itemEntity.setThrower(getOwner());
this.level().addFreshEntity(itemEntity);
}
this.discard();
super.onHitBlock(result);
}
/**
* 当投掷物击中实体时调用的方法。
* 如果服务器端执行,则会对该实体造成伤害,并生成投掷物本身的物品实体。
* 然后丢弃这个投掷物实体。
*
* @param result 击中结果,包含击中的实体信息
*/
@Override
protected void onHitEntity(EntityHitResult result) {
if (!this.level().isClientSide) {
Entity entity = result.getEntity();
Entity owner = this.getOwner();
entity.hurt(this.damageSources().thrown(this, owner), 4.0f);
ItemEntity itemEntity = new ItemEntity(this.level(), this.getX(), this.getY(), this.getZ(), this.getItem());
itemEntity.setThrower(getOwner());
this.level().addFreshEntity(itemEntity);
this.discard();
}
}
}
好了我们需要让斧头右键使用的时候可以投掷出去,这里直接用了mixin,mixin了斧头的use方法.
/**
* 该类使用Mixin技术扩展了AxeItem的行为,添加了投掷斧头的功能。
*/
@Mixin(AxeItem.class)
public class AxeItemMixin extends DiggerItem {
/**
* 构造函数,初始化AxeItemMixin实例。
*
* @param tier 斧头的材质等级
* @param blocks 斧头可以挖掘的方块类型
* @param properties 斧头的其他属性
*/
public AxeItemMixin(Tier tier, TagKey<Block> blocks, Properties properties) {
super(tier, blocks, properties);
}
/**
* 当玩家使用斧头时调用的方法,覆盖了DiggerItem类的use方法。
* 如果配置允许,玩家可以像投掷雪球一样投掷斧头。
*
* @param level 玩家所在的世界实例
* @param player 使用斧头的玩家
* @param usedHand 使用斧头的手(主手或副手)
* @return InteractionResultHolder<ItemStack> 表示交互结果和使用后的物品栈
*/
@Override
public InteractionResultHolder<ItemStack> use(Level level, Player player, InteractionHand usedHand) {
boolean CFG_isFuThrowable = Config.isFuThrowable(); // 从配置文件获取是否允许投掷斧头
ItemStack itemStack = player.getItemInHand(usedHand); // 获取玩家手中的斧头
if (CFG_isFuThrowable) {
level.playSound(null, player.getX(), player.getY(), player.getZ(),
SoundEvents.SNOWBALL_THROW, SoundSource.NEUTRAL, 0.5f, 0.4f / (level.getRandom().nextFloat() * 0.4f + 0.8f)); // 播放投掷声音
player.awardStat(Stats.ITEM_USED.get(this)); // 给玩家添加使用此物品的统计
if (!level.isClientSide) {
player.awardStat(Stats.ITEM_USED.get(this)); // 在服务器端给玩家添加统计
if (!player.getAbilities().invulnerable) {
itemStack.hurtAndBreak(1, (ServerLevel) level, player, p -> {
// 斧头损坏时调用
});
player.getInventory().removeItem(itemStack); // 从玩家的背包中移除损坏的斧头
}
FuProjectileEntity fuProjectileEntity = new FuProjectileEntity(player, level); // 创建投掷物实体
fuProjectileEntity.setItem(itemStack); // 设置投掷物实体的物品栈
fuProjectileEntity.shootFromRotation(player, player.getXRot(), player.getYRot(), 0.0f, 1.5f, 1.0f); // 设置投掷物的发射角度和速度
level.addFreshEntity(fuProjectileEntity); // 将投掷物实体添加到世界中
}
itemStack.consume(1, player); // 消耗一个斧头
return InteractionResultHolder.success(itemStack); // 返回交互成功
}
return InteractionResultHolder.fail(itemStack); // 如果不允许投掷,返回交互失败
}
}
实现总成