NeoForge 26.1 Docs
  • 문서
  • 노트
NeoForge 26.1
NeoForge 26.1
v26.1
학습 진도
0 / 77 챕터 완료방문 0
캡스톤 통합 설계 + 의존 구조차원에 보석 광물 배치 (WorldGen)기계 가공 통합 — Crusher로 광물 → 보석 정제차원 전용 새 몹 — GemGuardian이벤트로 모듈 연결사운드·파티클 폴리시마무리와 통합 빌드
마스터캡스톤

사운드·파티클 폴리시

SoundEvent와 ParticleType을 DeferredRegister로 등록하고, 포탈 진입·기계 완료·보스 처치·보석 사용 4가지 시점에 효과를 트리거하는 방법을 다룹니다.

사운드·파티클 폴리시

모드에 기능을 추가하면 동작은 완성됩니다. 그러나 플레이어 경험 품질은 사운드와 파티클에서 크게 갈립니다. 포탈을 밟았을 때 아무 소리가 없으면 입장했는지 모르고, 보스를 처치했을 때 파티클이 없으면 성취감이 반감됩니다.

이 챕터에서는 두 가지 레지스트리(SOUND_EVENTS, PARTICLE_TYPES)를 MasterCapstoneMod에 추가하고, CapstoneEventHandler를 확장해 4가지 시점에 효과를 연결합니다.


1. SoundEvent DeferredRegister

DeferredRegister.create(Registries.SOUND_EVENT, MOD_ID)로 레지스트리를 만들고, createVariableRangeEvent로 거리 감쇠 사운드를 등록합니다.

examplemod-master-projects/capstone/src/main/java/com/example/master/capstone/MasterCapstoneMod.java

// ── 사운드 레지스트리 ─────────────────────────────────────────────────────
public static final DeferredRegister<SoundEvent> SOUND_EVENTS =
        DeferredRegister.create(Registries.SOUND_EVENT, MOD_ID);
 
public static final Supplier<SoundEvent> PORTAL_ENTER = SOUND_EVENTS.register(
        "portal_enter",
        () -> SoundEvent.createVariableRangeEvent(
                Identifier.fromNamespaceAndPath(MOD_ID, "portal_enter")));

createVariableRangeEvent vs createFixedRangeEvent
createVariableRangeEvent는 거리에 따라 볼륨이 자동으로 줄어듭니다. volume 파라미터로 최대 감쇠 거리를 조정할 수 있습니다. 고정된 특정 거리(예: 16블록)만 들리게 하려면 createFixedRangeEvent(rl, 16.0f)를 사용하세요.


2. ParticleType DeferredRegister

커스텀 파티클 타입을 정의합니다. SimpleParticleType은 별도 데이터 없이 단순 스프라이트를 렌더링하는 가장 기본적인 파티클 타입입니다.

// ── 파티클 레지스트리 ──────────────────────────────────────────────────────
public static final DeferredRegister<ParticleType<?>> PARTICLE_TYPES =
        DeferredRegister.create(Registries.PARTICLE_TYPE, MOD_ID);
 
public static final Supplier<SimpleParticleType> MAGIC_SPARKLE = PARTICLE_TYPES.register(
        "magic_sparkle",
        () -> new SimpleParticleType(false));

overrideLimiter 인자
SimpleParticleType(false) — 두 번째 인자 overrideLimiter를 true로 두면 파티클 표시 한도를 무시합니다. 일반 연출 파티클에는 false가 맞습니다. 하드코어 이펙트처럼 항상 보여야 하는 경우에만 true를 사용하세요.

2.1 생성자에서 레지스트리 등록

두 레지스트리를 modEventBus에 등록해야 게임 시작 시 레지스트리 시스템이 인식합니다.

public MasterCapstoneMod(IEventBus modEventBus, ModContainer container) {
    LOGGER.info("Master Capstone Mod 로드 — 4개 모드 통합");
 
    SOUND_EVENTS.register(modEventBus);
    PARTICLE_TYPES.register(modEventBus);
}

3. 4가지 트리거 구현

CapstoneEventHandler에 4가지 효과 트리거를 추가합니다.

트리거 A — 포탈 진입

포탈 블록에서 엔티티가 진입할 때 MagicPortalBlock.entityInside()에서 직접 호출합니다.

public static void triggerPortalEnterEffects(Level level, BlockPos pos) {
    level.playSound(
            null, pos,
            MasterCapstoneMod.PORTAL_ENTER.get(),
            SoundSource.AMBIENT,
            1.0f, 1.0f
    );
 
    if (level instanceof ServerLevel serverLevel) {
        serverLevel.sendParticles(
                MasterCapstoneMod.MAGIC_SPARKLE.get(),
                pos.getX() + 0.5,
                pos.getY() + 1.0,
                pos.getZ() + 0.5,
                20, 0.3, 0.5, 0.3, 0.1
        );
    }
}

playSound의 첫 번째 인자 null은 "이 사운드를 트리거한 플레이어에게도 들리게 하라"는 의미입니다. Player 인스턴스를 넘기면 그 플레이어에게는 들리지 않습니다.

트리거 B — 기계 가공 완료

Crusher BlockEntity의 tick 메서드에서 progress == MAX_PROGRESS 조건 도달 시 1회 호출합니다.

public static void triggerMachineCompleteEffects(Level level, BlockPos pos) {
    level.playSound(
            null, pos,
            SoundEvents.ANVIL_USE,
            SoundSource.BLOCKS,
            1.0f, 1.2f
    );
 
    if (level instanceof ServerLevel serverLevel) {
        serverLevel.sendParticles(
                ParticleTypes.CRIT,
                pos.getX() + 0.5,
                pos.getY() + 1.2,
                pos.getZ() + 0.5,
                15, 0.3, 0.3, 0.3, 0.05
        );
    }
}

Crusher tick에서 호출하는 방법:

if (progress >= MAX_PROGRESS) {
    progress = 0;
    CapstoneEventHandler.triggerMachineCompleteEffects(level, worldPosition);
    produceOutput();
}

트리거 C — GemGuardian 사망 시 SCRAPE 파티클

기존 onMobDeath 핸들러에 파티클 버스트를 추가합니다.

@SubscribeEvent
public static void onMobDeath(LivingDeathEvent event) {
    if (!(event.getEntity() instanceof GemGuardianEntity guardian)) return;
 
    Level level = guardian.level();
    if (level.isClientSide()) return;
 
    // ... 기존 드롭 로직 ...
 
    // 챕터 05 추가: SCRAPE 파티클 버스트
    if (level instanceof ServerLevel serverLevel) {
        serverLevel.sendParticles(
                ParticleTypes.SCRAPE,
                guardian.getX(),
                guardian.getY() + 0.5,
                guardian.getZ(),
                30, 0.5, 0.5, 0.5, 0.2
        );
    }
}

ParticleTypes.SCRAPE는 긁히는 느낌의 반짝이 파티클로, 보석 파편이 흩날리는 효과에 적합합니다.

트리거 D — 보석 사용 시 ENCHANT 파티클

onUseGem 핸들러에 enchant 파티클 샤워를 추가합니다.

if (purity >= 75) {
    player.sendSystemMessage(Component.literal("§a고순도 보석 — 차원 입장 강화"));
 
    // 챕터 05 추가: ENCHANT 파티클 샤워
    if (player.level() instanceof ServerLevel serverLevel) {
        serverLevel.sendParticles(
                ParticleTypes.ENCHANT,
                player.getX(),
                player.getY() + 1.0,
                player.getZ(),
                50, 0.5, 1.0, 0.5, 1.0
        );
    }
}

ParticleTypes.ENCHANT는 마법 부여 시 흩날리는 글자 파티클입니다. 보석에 마법이 주입되는 느낌을 줍니다.


4. sounds.json 작성

SoundEvent만 등록해서는 게임이 오디오 파일을 어디서 찾아야 할지 알 수 없습니다. assets/master_capstone/sounds.json으로 경로를 명시해야 합니다.

examplemod-master-projects/capstone/src/main/resources/assets/master_capstone/sounds.json

{
  "portal_enter": {
    "category": "ambient",
    "subtitle": "subtitles.master_capstone.portal_enter",
    "sounds": [
      {
        "name": "master_capstone:portal_enter",
        "stream": false
      }
    ]
  }
}
필드값설명
category"ambient"게임 볼륨 설정의 "주변 소리" 슬라이더와 연결
subtitle"subtitles.master_capstone.portal_enter"자막 표시 시 lang 파일에서 읽을 키
streamfalse반복 배경음이 아닌 짧은 효과음은 false

4.1 OGG 파일 배치

src/main/resources/assets/master_capstone/sounds/
└── portal_enter.ogg

NeoForge는 OGG Vorbis 포맷만 지원합니다. MP3·WAV·FLAC은 지원하지 않습니다.

4.2 lang 파일에 자막 추가

assets/master_capstone/lang/ko_kr.json

{
  "subtitles.master_capstone.portal_enter": "마법의 종소리"
}

5. 성능 — 파티클 throttling

⚠️ 매 tick 파티클 → TPS 급감

// ❌ 매 tick 50개 파티클
public static void tick(...) {
    serverLevel.sendParticles(..., 50, ...);  // 매 tick 실행
}
 
// ✅ 조건부 throttling
if (level.getGameTime() % 20 == 0) {  // 1초마다
    serverLevel.sendParticles(..., 5, ...);
}

파티클은 서버→클라이언트 패킷 + 클라이언트 렌더 비용을 모두 씁니다. 기계 idle 상태처럼 반복이 필요한 경우 20틱(1초)마다 소량을 보내는 패턴을 사용하세요.

이 챕터의 4가지 트리거는 모두 이벤트 발생 시 1회만 호출되므로 throttling이 필요하지 않습니다.


6. 이 챕터의 완료 기준

  • MasterCapstoneMod에 SOUND_EVENTS·PARTICLE_TYPES DeferredRegister와 PORTAL_ENTER·MAGIC_SPARKLE 인스턴스가 추가됩니다.
  • CapstoneEventHandler가 4가지 시점에 사운드·파티클을 트리거합니다.
  • sounds.json과 portal_enter.ogg가 올바른 경로에 배치됩니다.
  • lang 파일에 자막 키 subtitles.master_capstone.portal_enter가 등록됩니다.
  • 매 tick 파티클 안티패턴 없이 throttling이 올바르게 적용됩니다.

다음 챕터에서는 캡스톤 모드의 최종 빌드와 배포 패키징을 다룹니다.

이벤트로 모듈 연결

NeoForge 이벤트 시스템을 활용해 GemGuardian 처치 시 MagicCore를 드롭하고, Ruby 아이템 우클릭으로 PURITY 기반 차원 입장 강화를 표시하는 CapstoneEventHandler를 구현합니다.

마무리와 통합 빌드

마스터 트랙 캡스톤을 README로 정리하고, tools·dimension·machine·capstone 4개 JAR을 함께 로드해 End-to-End 흐름을 검증합니다.

On this page

사운드·파티클 폴리시1. SoundEvent DeferredRegister2. ParticleType DeferredRegister2.1 생성자에서 레지스트리 등록3. 4가지 트리거 구현트리거 A — 포탈 진입트리거 B — 기계 가공 완료트리거 C — GemGuardian 사망 시 SCRAPE 파티클트리거 D — 보석 사용 시 ENCHANT 파티클4. sounds.json 작성4.1 OGG 파일 배치4.2 lang 파일에 자막 추가5. 성능 — 파티클 throttling6. 이 챕터의 완료 기준
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