858 words
4 minutes
30 望远镜实现标记
30 望远镜实现标记
效果是你可以再望远镜中点击鼠标左键,进行标记,再对应的位置会生成粒子效果,然后回再对应的位置生成tnt
package com.mafuyu33.neomafishmod.mixin.itemmixin.spyglass;
@Mixin(Player.class)
public abstract class SpyglassMixin extends LivingEntity {
// 构造函数,继承自LivingEntity
protected SpyglassMixin(EntityType<? extends LivingEntity> entityType, Level level) {
super(entityType, level);
}
// Shadow方法,允许访问Player类中的私有方法
@Shadow
public abstract boolean isScoping(); // 检查玩家是否正在使用窥镜
// Shadow方法,获取玩家手上的物品
@Shadow
public abstract Iterable<ItemStack> getHandSlots();
// Unique字段,用于记录最后一次命中方块的位置
@Unique
BlockPos lastHitBlockPos;
// 在Player类的tick方法中注入代码
@Inject(at = @At("HEAD"), method = "tick")
private void init(CallbackInfo ci) {
boolean isSpyglassCanPin = Config.isSpyglassCanPin(); // 从配置文件读取是否启用窥镜定位功能
if (isSpyglassCanPin) {
// 如果启用窥镜定位功能
if (this.isScoping() && BowDashMixinHelper.isAttackKeyPressed()) { // 如果玩家正在使用窥镜并且攻击键被按下
// 获取玩家眼睛位置和视线方向
Vec3 playerPos = this.getEyePosition(1.0F);
Vec3 playerLook = this.getViewVector(1.0F);
// 设置射线起点和方向,射线长度为25565(这里可能是为了演示,实际应用中这个值会根据需求调整)
Vec3 rayEnd = playerPos.add(playerLook.scale(25565));
// 进行射线投射
BlockHitResult blockHitResult = level().clip(new ClipContext(playerPos, rayEnd, ClipContext.Block.OUTLINE, ClipContext.Fluid.NONE, this));
// 检查是否击中方块
if (blockHitResult.getType() == HitResult.Type.BLOCK) {
// 获取方块坐标
BlockPos currentHitBlockPos = blockHitResult.getBlockPos();
// 如果当前坐标和上一次点击的坐标在y轴上相同,则清除存储的坐标值
if (lastHitBlockPos != null && currentHitBlockPos.getY() == lastHitBlockPos.getY()) {
lastHitBlockPos = null;
} else {
// 否则,存储当前坐标值
lastHitBlockPos = currentHitBlockPos;
if (level().isClientSide) { // 如果是客户端
level().playSound((Player) (Object) this, this.blockPosition(), ModSounds.PIN.value(), SoundSource.PLAYERS);
System.out.println("击中方块坐标:" + currentHitBlockPos.getX() + ", " + currentHitBlockPos.getY() + ", " + currentHitBlockPos.getZ());
}
}
}
}
// 如果存在记录的坐标
if (lastHitBlockPos != null) {
// 在hitBlockPos为原点,竖直向上延伸20格生成末地烛粒子
for (float yOffset = 0; yOffset < 20; yOffset += 0.1f) {
double particleX = lastHitBlockPos.getX() + 0.5 + (random.nextFloat() - 0.5) * 0.1; // 加入随机性模拟波动
double particleY = lastHitBlockPos.getY() + yOffset + 0.5;
double particleZ = lastHitBlockPos.getZ() + 0.5 + (random.nextFloat() - 0.5) * 0.1; // 加入随机性模拟波动
// 计算粒子密度,可以根据需要调整指数底数和系数
double density = Math.exp(-yOffset / 20); // 使用指数衰减模拟密度减少
// 根据粒子密度生成粒子
if (level().isClientSide && random.nextFloat() < density) {
level().addParticle(ParticleTypes.COMPOSTER, true, particleX, particleY, particleZ, 0, 0.05, 0);
}
}
}
// 如果玩家手持山羊角并且正在使用它,并且存在记录的坐标
if (this.isHolding(Items.GOAT_HORN) && this.isUsingItem() && lastHitBlockPos != null) {
if (!level().isClientSide) { // 如果不是客户端
for (int i = 0; i < 20; i++) {
double xOffset = random.nextDouble() * 16 - 8; // 在-5到5之间生成随机偏移量
double zOffset = random.nextDouble() * 16 - 8;
double x = lastHitBlockPos.getX() + 0.5 + xOffset;
double y = lastHitBlockPos.getY() + 100 + random.nextDouble() * 4 - 2; // 在lastHitBlockPos上空20格附近随机生成Y坐标
double z = lastHitBlockPos.getZ() + 0.5 + zOffset;
PrimedTnt tnt = new PrimedTnt(EntityType.TNT, level());
tnt.setPos(x, y, z);
// 设置不同的向下速度
double downwardVelocity = random.nextDouble() * 1 - 0.5; // 随机生成一个向下速度,范围在-0.5到0.5之间
tnt.setDeltaMovement(0, downwardVelocity, 0);
// 根据向下速度的大小确定引爆时间
int fuse = (int) (downwardVelocity * -50) + 120; // 根据向下速度计算引爆时间,速度越小,引爆时间越长
tnt.setFuse(fuse); // 设置TNT的引爆时间
level().addFreshEntity(tnt);
}
}
lastHitBlockPos = null;
}
}
}
}