Flandre923
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;
            }
        }
    }
}
30 望远镜实现标记
https://fuwari.vercel.app/posts/minecraft1_21_0/30_望远镜实现标记/
Author
Flandre923
Published at
2024-08-24