2025年1月25日土曜日

forge MOD で武器を作ってみた

forge MOD で武器を作ってみた

概要

アイテムを持った状態で右クリックを押すと魔法弾のような光線が飛び出しあたったエンティティを炎上させるような武器を作ってみました

環境

  • macOS 15.2
  • Java 21.0.5
  • forrge MDK 1.20.6-50.1.32
  • minecraft 1.20.6

武器アイテムの作成

Item クラスを継承し作成します
use メソッドをオーバライドすることでアイテム(武器)としての処理を実装できます

クライアント側では右クリック時にエフェクトを表示しサーバ側ではレイトレースでターゲットを検出し衝突したエンティティのタイプに応じて処理を分岐しています
このあたりのサーバ側の処理は自由に変更して OK です

  • vim src/main/java/com/example/examplemod/LaserGunItem.java
package com.example.examplemod;

import net.minecraft.core.BlockPos;
import net.minecraft.core.particles.ParticleTypes;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.InteractionResultHolder;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.item.ItemEntity;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.entity.projectile.ProjectileUtil;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.ClipContext;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.phys.BlockHitResult;
import net.minecraft.world.phys.EntityHitResult;
import net.minecraft.world.phys.HitResult;
import net.minecraft.world.phys.Vec3;

public class LaserGunItem extends Item {

    public LaserGunItem(Properties properties) {
        super(properties);
    }

    @Override
    public InteractionResultHolder<ItemStack> use(
            Level world, Player player, InteractionHand hand) {
        // クライアント側のみでエフェクトを表示
        if (world.isClientSide()) {
            // ビームエフェクトを生成
            spawnLaserBeam(player);
        } else {
            // サーバー側でダメージ処理
            fireLaser(world, player);
        }
        return InteractionResultHolder.sidedSuccess(
                player.getItemInHand(hand), world.isClientSide());
    }

    @Override
    public boolean onEntityItemUpdate(ItemStack stack, ItemEntity entity) {
        // 特殊な処理が必要であればここで行う(今回は不要なのでデフォルト動作に任せます)
        // アイテムが q で捨てられたときにアイテムとして残すための設定
        return super.onEntityItemUpdate(stack, entity);
    }

    private void spawnLaserBeam(Player player) {
        // クライアント側エフェクト(例:パーティクル)
        player.level()
                .addParticle(
                        ParticleTypes.END_ROD,
                        player.getX(),
                        player.getEyeY(),
                        player.getZ(),
                        player.getLookAngle().x,
                        player.getLookAngle().y,
                        player.getLookAngle().z);
    }

    private void fireLaser(Level world, Player player) {
        Vec3 start = player.getEyePosition(1.0F);
        Vec3 direction = player.getLookAngle();
        double range = 50.0D; // 50ブロック先をターゲット
        Vec3 end = start.add(direction.scale(range));

        // ブロックとのヒット判定
        HitResult blockHit =
                world.clip(
                        new ClipContext(
                                start,
                                end,
                                ClipContext.Block.OUTLINE,
                                ClipContext.Fluid.NONE,
                                player));
        // エンティティとのヒット判定
        EntityHitResult entityHit =
                ProjectileUtil.getEntityHitResult(
                        world,
                        player,
                        start,
                        end,
                        player.getBoundingBox().expandTowards(direction.scale(range)).inflate(1.0D),
                        entity -> entity instanceof LivingEntity && entity != player);
        // 優先的にエンティティを処理
        if (entityHit != null) {
            System.out.println("Hit entity!");
            Entity hitEntity = entityHit.getEntity();
            if (hitEntity instanceof LivingEntity livingEntity) {
                // 敵にダメージを与える
                livingEntity.hurt(livingEntity.damageSources().playerAttack(player), 10.0F);
            }
        } else if (blockHit != null && blockHit.getType() == HitResult.Type.BLOCK) {
            // ブロックにヒットした場合
            System.out.println("Hit block at: " + ((BlockHitResult) blockHit).getBlockPos());
            BlockHitResult blockResult = (BlockHitResult) blockHit;
            BlockPos hitPos = blockResult.getBlockPos();
            // ヒット位置に火をつける例
            world.setBlockAndUpdate(hitPos, Blocks.FIRE.defaultBlockState());
        } else {
            // 何にも当たらなかった場合
            System.out.println("Missed!");
        }
    }
}

作成したアイテムをMODに登録

Mod 本体側のクラスに先ほど作成した LaserGunItem を登録します
長いので登録する部分だけ紹介します
コード全体は前回紹介しているのでそちらを参照してください

  • vim src/main/java/com/example/examplemod/ExampleMod.java
@Mod(ExampleMod.MODID)
public class ExampleMod {
    // レーザガンアイテムの追加
    public static final RegistryObject<Item> LASER_GUN =
            ITEMS.register("laser_gun", () -> new LaserGunItem(new Item.Properties().stacksTo(1)));

    // レーザガンをCombatタブに追加
    private void addCreative(BuildCreativeModeTabContentsEvent event) {
        if (event.getTabKey() == CreativeModeTabs.COMBAT) event.accept(LASER_GUN);
    }
}

動作確認

  • ./gradlew build && ./gradlew runClient

で確認しクリエイティブモードのワールドでインベントリを開き武器の一覧の最後にMOD武器が追加されていることを確認しましょう
そして武器を持ち右クリックすると光線が飛ぶことを確認します

最後に

forge MOD で武器を作ってみました
テクスチャがデフォルトなので次回はテクスチャを作ってみたいと思います

参考サイト

0 件のコメント:

コメントを投稿