NeoForge 26.1 Docs
  • 문서
  • 노트
NeoForge 26.1
NeoForge 26.1
v26.1
학습 진도
0 / 77 챕터 완료방문 0
BlockEntity 기초 — CounterBlockEntityBlockEntityRenderer 구현Entity 등록과 AttributeSupplierEntityRenderer와 EntityModelAI Goal 시스템CustomPacketPayload — 클라이언트/서버 패킷 통신AttachmentTypes — 엔티티·블록에 데이터 부착WorldGen Feature 기초 — 광물 생성
고급 시스템

AI Goal 시스템

registerGoals 오버라이드로 커스텀 Mob에 FloatGoal, MeleeAttackGoal, WaterAvoidingRandomStrollGoal 등 Vanilla Goal을 추가하고, goalSelector와 targetSelector의 우선순위 체계를 이해합니다.

AI Goal 시스템이란?

Minecraft의 Mob AI는 Goal 기반 행동 트리로 동작합니다. 각 Goal은 독립적인 행동 단위이며, 매 틱마다 canUse() 조건을 평가해 실행 여부를 결정합니다. 우선순위(priority) 숫자가 낮을수록 먼저 평가됩니다.

두 개의 셀렉터가 협력합니다.

  • goalSelector — 행동 결정 (이동, 공격, 대기, 시선 처리)
  • targetSelector — 타겟 선정 (누구를 공격할지)

1단계 — registerGoals 오버라이드

Mob 하위 클래스에서 registerGoals()를 오버라이드해 Goal을 등록합니다. 이 메서드는 생성자 호출 시 한 번만 실행됩니다.

examplemod-template-26.1.2/src/main/java/com/example/examplemod/entity/RubyGolemEntity.java

public class RubyGolemEntity extends Mob {
 
    public RubyGolemEntity(EntityType<? extends Mob> type, Level level) {
        super(type, level);
    }
 
    @Override
    protected void registerGoals() {
        this.goalSelector.addGoal(0, new FloatGoal(this));                     // 물에 뜸 (최우선)
        this.goalSelector.addGoal(1, new MeleeAttackGoal(this, 1.2D, false));  // 근접 공격
        this.goalSelector.addGoal(2, new WaterAvoidingRandomStrollGoal(this, 1.0D)); // 무작위 이동
        this.goalSelector.addGoal(3, new LookAtPlayerGoal(this, Player.class, 6.0f)); // 플레이어 바라보기
        this.goalSelector.addGoal(4, new RandomLookAroundGoal(this));          // 무작위 둘러보기
 
        this.targetSelector.addGoal(0, new HurtByTargetGoal(this));
        this.targetSelector.addGoal(1, new NearestAttackableTargetGoal<>(this, Zombie.class, true));
    }
 
    public static AttributeSupplier.Builder createAttributes() {
        return Mob.createMobAttributes()
                .add(Attributes.MAX_HEALTH, 30.0)
                .add(Attributes.MOVEMENT_SPEED, 0.25)
                .add(Attributes.ATTACK_DAMAGE, 4.0)
                .add(Attributes.ARMOR, 2.0);
    }
}

2단계 — 우선순위 체계

addGoal(priority, goal)의 첫 번째 인자가 우선순위입니다. 낮은 숫자 = 높은 우선순위.

priorityGoal설명
0FloatGoal물에 빠지면 수면으로 올라옴 (최우선)
1MeleeAttackGoal타겟이 있으면 근접 공격
2WaterAvoidingRandomStrollGoal물을 피하며 무작위 이동
3LookAtPlayerGoal6블록 이내 플레이어를 바라봄
4RandomLookAroundGoal아무것도 없으면 무작위 방향 바라봄

높은 priority Goal이 canUse() == true이면 낮은 priority Goal은 실행되지 않습니다. FloatGoal이 0인 이유는 물속에서도 다른 행동보다 수면 복귀가 먼저여야 하기 때문입니다.


3단계 — goalSelector vs targetSelector

두 셀렉터는 역할이 다릅니다.

goalSelector — 엔티티가 무엇을 할지 결정합니다.

this.goalSelector.addGoal(1, new MeleeAttackGoal(this, 1.2D, false));
//                         ^priority  ^Goal 인스턴스

targetSelector — 엔티티가 누구를 공격할지 결정합니다.

this.targetSelector.addGoal(0, new HurtByTargetGoal(this));
// 공격받으면 공격자를 타겟으로 설정
 
this.targetSelector.addGoal(1, new NearestAttackableTargetGoal<>(this, Zombie.class, true));
// 가장 가까운 Zombie를 자동 타겟

MeleeAttackGoal은 targetSelector가 타겟을 설정해야 실제로 동작합니다. 두 셀렉터가 협력해야 공격 AI가 완성됩니다.


4단계 — 주요 Vanilla Goal 목록

이동 관련

Goal설명
FloatGoal물에서 수면으로 올라옴
WaterAvoidingRandomStrollGoal물을 피하며 무작위 이동
RandomStrollGoal물 무시하고 무작위 이동
MoveTowardsTargetGoal타겟 방향으로 이동

공격 관련

Goal설명
MeleeAttackGoal근접 공격 (속도 배율, 장애물 무시 여부)
RangedAttackGoal원거리 공격 (투사체 발사)

시선 관련

Goal설명
LookAtPlayerGoal지정 클래스 엔티티를 바라봄
RandomLookAroundGoal무작위 방향 바라봄

타겟 관련

Goal설명
HurtByTargetGoal공격받으면 공격자를 타겟으로
NearestAttackableTargetGoal가장 가까운 지정 타입 엔티티를 타겟으로
DefendVillageTargetGoal마을 주민 방어 (Iron Golem 패턴)

5단계 — 커스텀 Goal 구현

Vanilla Goal로 부족하면 Goal을 직접 상속합니다. 세 메서드가 핵심입니다.

examplemod-template-26.1.2/src/main/java/com/example/examplemod/entity/goal/FleeFromRainGoal.java

public class FleeFromRainGoal extends Goal {
 
    private final Mob mob;
 
    public FleeFromRainGoal(Mob mob) {
        this.mob = mob;
        this.setFlags(EnumSet.of(Goal.Flag.MOVE));
    }
 
    /**
     * 이 Goal을 시작할 수 있는지 매 틱 평가.
     * true를 반환하면 Goal이 활성화됩니다.
     */
    @Override
    public boolean canUse() {
        return this.mob.level().isRaining()
                && this.mob.level().canSeeSky(this.mob.blockPosition());
    }
 
    /**
     * Goal이 활성화된 동안 매 틱 호출.
     * 실제 행동 로직을 여기에 작성합니다.
     */
    @Override
    public void tick() {
        // 비를 피해 가장 가까운 지붕 아래로 이동하는 로직
        BlockPos shelter = findNearestShelter();
        if (shelter != null) {
            this.mob.getNavigation().moveTo(shelter.getX(), shelter.getY(), shelter.getZ(), 1.2D);
        }
    }
 
    /**
     * Goal이 중단될 때 호출 (canUse() == false 또는 canContinueToUse() == false).
     * 상태 초기화를 여기서 처리합니다.
     */
    @Override
    public void stop() {
        this.mob.getNavigation().stop();
    }
 
    private BlockPos findNearestShelter() {
        // 구현 생략 — 실제로는 BlockPos 탐색 로직
        return null;
    }
}

Goal.Flag는 동시에 실행될 수 없는 Goal 그룹을 정의합니다. MOVE 플래그를 가진 Goal은 동시에 하나만 활성화됩니다.


안티패턴

⚠️ 같은 priority 두 Goal

// ❌ 두 Goal 모두 priority 1 → 무작위 한 쪽만 동작
goalSelector.addGoal(1, new MeleeAttackGoal(this, 1.2D, false));
goalSelector.addGoal(1, new RandomStrollGoal(this, 1.0D));

같은 priority를 가진 Goal은 동시에 동작을 시도해 충돌합니다. 어느 쪽이 실행될지 예측할 수 없습니다. 항상 고유한 priority 값을 사용하세요.

⚠️ 매 틱 새 Goal 등록

// ❌ tick() 안에서 Goal 등록 — 절대 금지
@Override
public void tick() {
    this.goalSelector.addGoal(1, new MeleeAttackGoal(this, 1.2D, false));
}

registerGoals()는 생성자에서 한 번만 호출됩니다. tick() 안에서 Goal을 추가하면 매 틱 중복 등록이 발생해 메모리 누수와 예측 불가능한 AI 동작을 유발합니다.


체크리스트

  • registerGoals()가 Mob 하위 클래스에서 오버라이드됨
  • 모든 goalSelector Goal의 priority가 고유한 값
  • MeleeAttackGoal 사용 시 targetSelector에 타겟 Goal도 등록됨
  • 커스텀 Goal의 stop()에서 상태 초기화 처리됨
  • /summon examplemod:ruby_golem ~ ~ ~ 후 AI 동작 확인

정리

  • registerGoals()를 오버라이드해 goalSelector와 targetSelector에 Goal을 등록합니다.
  • priority 숫자가 낮을수록 먼저 평가됩니다. 같은 priority는 충돌을 유발하므로 항상 고유한 값을 사용합니다.
  • goalSelector는 행동을, targetSelector는 타겟을 결정합니다. 공격 AI는 두 셀렉터가 협력해야 완성됩니다.
  • 커스텀 Goal은 Goal을 상속해 canUse(), tick(), stop()을 구현합니다.
  • registerGoals()는 생성자에서 한 번만 실행됩니다. tick() 안에서 Goal을 추가하지 마세요.

다음 챕터에서는 커스텀 엔티티에 렌더러와 모델을 연결하는 방법을 다룹니다.

EntityRenderer와 EntityModel

MobRenderer와 EntityModel을 상속해 커스텀 Mob의 3D 렌더러와 모델 레이어를 구현하고, 클라이언트 이벤트로 안전하게 등록하는 방법을 배웁니다.

CustomPacketPayload — 클라이언트/서버 패킷 통신

NeoForge 26의 CustomPacketPayload record와 StreamCodec으로 클라이언트↔서버 패킷을 정의하고, RegisterPayloadHandlersEvent와 PacketDistributor로 전송하는 전체 과정을 학습합니다.

On this page

AI Goal 시스템이란?1단계 — registerGoals 오버라이드2단계 — 우선순위 체계3단계 — goalSelector vs targetSelector4단계 — 주요 Vanilla Goal 목록이동 관련공격 관련시선 관련타겟 관련5단계 — 커스텀 Goal 구현안티패턴체크리스트정리
NeoForge 26.1 Docs

NeoForge 26.1 모딩 개발 문서 사이트

GitHubDiscord

문서

  • 문서
  • 노트

GitHub

  • GitHub
  • Discord

© 2026 NeoForge 26.1 Docs. 콘텐츠는 MIT 라이선스로 제공됩니다.

Built with Next.js · Tailwind CSS · shadcn/ui