모딩/마인크래프트 모드 개발 일지

마크 모딩) "천사강림"

kimchangmin02 2025. 12. 26. 16:54

 

 

 

 

📘 목차

1. 신규 엔티티 및 기본 기능 구현

  • [신규] 다이아 좀비: 새로운 엔티티 정의 및 특징
  • 물속 투사체 시스템: 수중 발사 메커니즘 최적화
  • 그래픽 체력 표시(Health Bar): 문자열 방식을 탈피한 실시간 게이지 구현

2. 투사체 물리 및 기술 분석 (V3 vs V4)

  • 결정적 코드 차이: getWaterInertia() 메소드 오버라이드 여부
  • 마인크래프트 내부 로직: AbstractArrow 클래스의 틱(Tick) 처리 분석
  • 수중 감속 메커니즘: 기본값(0.6F)과 강제 고정값(1.0F)의 속도 차이 원인

3. GUI 및 렌더링 시스템 최적화

  • 직접적인 그래픽 출력: drawSolidRect  VertexConsumer를 이용한 면(Quad) 렌더링
  • 트러블슈팅: RenderType.gui() 해결 및 버전별 렌더러 환경 대응
  • 부모 클래스 활용: AbstractAllyEntity를 통한 읽기 전용 데이터 접근 및 메서드 호출

4. 아군 엔티티(Ally) 데이터 관리 시스템

  • 데이터 엔진: AbstractAllyEntity의 경험치 및 레벨업 로직
  • 데이터 저장소(Capability): AllyDataProvider를 이용한 영구 데이터 저장
  • 동기화: 패킷 전송(S2CAllySyncPacket)을 통한 서버-클라이언트 실시간 갱신
  • 이벤트 기반 UI: @SubscribeEvent를 활용한 범용 UI 렌더링 및 복잡성 관리

5. 투사체 공격력 및 커스텀 로직 (V5)

  • 데미지 설정: baseDamage 변수 활용과 생성자 설정 방식
  • 확실한 타격 판정: onHitEntity 오버라이드를 통한 고정 데미지 부여
  • 상속의 이점: AbstractArrow vs ThrowableItemProjectile 선택 가이드
  • 마법 효과 극대화: 중력 제거(setNoGravity) 및 블록 박힘 방지 로직

6. 지능형 AI 및 팀 시스템 구축

  • 팀킬 방지 시스템: @Mod.EventBusSubscriber @SubscribeEvent를 이용한 아군 보호
  • 중앙 제어형 AI 핸들러: ZombieEnemyHandler를 통한 특수 좀비(침묵, 안개, 은신) 대처
  • 인터페이스 활용: IWizard 인터페이스를 통한 타겟팅 차단 및 반격 방지 로직

7. 공중 포격 및 고급 기동 (V6)

  • 시즈 모드(Siege): 천장 높이 감지, 고도 상승 및 중력 무시 포격
  • 전략적 하강: 대각선 사선 하강(Diagonal Glide) 벡터 계산
  • 평균 반발력(Average Repulsion): 다수의 적을 피하는 안전 착륙 지점 스캔 로직

8. 블록벤치(Blockbench)와 애니메이션 (V6~V7)

  • 모델링 기초: 피벗 포인트(Pivot Point) 설정과 그룹 종속 관계
  • 동적 애니메이션: setupAnim을 이용한 머리 회전 및 부유(Floating) 효과
  • 가짜 투사체 렌더링: 성능 최적화를 위한 렌더러 기반 시각 효과(홀로그램) 구현
  • 초월 상태 연출: 법사 주변 궤도 구체(Gate of Heaven) 및 구 형태의 궤도 계산

9. 외부 리소스 활용 및 라이선스

  • 모델 확보: mcmodels.net 및 Sketchfab 무료 리소스 활용법
  • 저장권 및 라이선스: CC0, CC BY 등 라이선스 준수 및 출처 표기 에티켓
  • 플러그인 활용: Minecraft Asset Browser를 이용한 모델 라이브러리 구축

10. 특수 무기 투사체 구현

  • 투척용 다이아 검: 아이템 모델을 재활용한 새로운 투사체 엔티티
  • 렌더링 보정: 검의 방향성(Yaw/Pitch) 동기화 및 칼날 방향 정렬 해결
  • 추가 컨셉 제안: 문도/유나라 스타일의 둔화 및 특수 효과 투사체 설계

 

 

 

[  ]다이아좀비

 새로운 엔티티로 만들기 

 

[ ㅇㅋ ]물속 투사체

[ ㅇㅋ ]체력표시

 


 

 

물속에도 투사체가 잘날아가는모습

 

 

법사3(V3)와 법사4(V4)의 투사체 속도 차이가 발생하는 결정적인 이유는 getWaterInertia()라는 메소드의 오버라이드(Override) 여부에 있습니다.

제공해주신 코드상에서 구체적인 이유는 다음과 같습니다.

1. 결정적인 코드 차이

법사4 (MagicProjectileV4)의 코드:

V4의 코드에는 물속에서의 관성(저항)을 제어하는 코드가 명시적으로 포함되어 있습니다.

    @Override
protected float getWaterInertia() {
    // 물속에서도 감속 없이 100% 속도 유지
    return 1.0F; // 1.0F는 속도 손실이 0%라는 의미입니다.
}
  

법사3 (MagicProjectileV3)의 코드:

V3의 코드를 보면 이 메소드가 존재하지 않습니다. 즉, 부모 클래스인 AbstractArrow의 기본 동작을 그대로 따르게 됩니다.

2. 마인크래프트 내부 로직상의 이유

V3와 V4 모두 AbstractArrow를 상속받고 있습니다. 마인크래프트의 AbstractArrow 클래스 내부 tick() 메소드는 투사체가 물속에 있을 때 다음과 같은 로직을 수행합니다.

  1. 물 체크: 투사체가 물(Water) 블록 안에 있는지 확인합니다.
  2. 속도 감소: 물 안에 있다면 현재 속도에 getWaterInertia() 값을 곱합니다.
  3. 기본값: AbstractArrow에서 getWaterInertia()의 기본값은 **0.6F**입니다.

법사3(V3)가 물속에서 안 나가는 이유:

  • V3는 이 메소드를 건드리지 않았기 때문에 매 틱마다 속도가 60%로 줄어듭니다. (40%씩 감속)
  • 마인크래프트에서 0.6의 감속은 매우 강력하기 때문에, 발사되자마자 물의 저항을 이기지 못하고 바로 멈추거나 바닥으로 가라앉게 됩니다.

법사4(V4)가 물속에서도 잘 나가는 이유:

  • V4는 이 값을 **1.0F**로 강제 고정했습니다.
  • 매 틱마다 속도에 1.0을 곱하므로, 물속에서도 속도가 전혀 줄어들지 않고 공기 중에서와 동일한 속도로 날아가는 것입니다.

이유:
V3는 AbstractArrow의 기본 물 저항(40% 감속)을 그대로 받고 있고, V4는 저항을 0으로 설정했기 때문입니다.

 

 

 

 

 

 

문자열을 출력하는 방식이 아닌, 그래픽 라이브러리를 사용해 직접 색상이 채워진 사각형을 그리는 방식을 사용

 

drawSolidRect 메소드 추가:

  • 폰트를 써서 문자(---)를 출력하는 대신, 마이크래프트의 VertexConsumer를 이용해 실제 **면(Quad)**을 그립니다.
  • 이를 통해 끊어짐이 없는 매끄러운 막대기 바를 구현했습니다.

 

 

 

 

 

 

RenderType'의 메서드 'gui'을(를) 해결할 수 없습니다
WizardEntityV4'의 메서드 'getCurrentLevel'을(를) 해결할 수 없습니다
'WizardEntityV4'의 메서드 'getExperience'을(를) 해결할 수 없습니다

부모는 읽기전용일때 어떻게 이문제를 해결할까

 

자체적으로 경험치 로직을 추가하려나 

ㄴㄴ

걍 변수명을 몰랏던거네 

 

 

 

  1. RenderType 관련: RenderType.gui()는 주로 마인크래프트 1.18 이상의 GUI 시스템에서 사용되지만, 월드에 렌더링되는 엔티티 렌더러(EntityRenderer) 환경에서는 접근이 제한적이거나 환경에 따라 없을 수 있습니다.

RenderType.gui() 대신 월드 공간에서 색상을 채워 그릴 수 있는 가장 안정적인 방식인 RenderType.lightning() 또는 직접적인 VertexConsumer 설정을 사용하도록 수정했습니다.

 

 

 

 

AbstractAllyEntity

내 파일이엇네 ㅋ

 

 

 

 

부모 클래스에는 이미 **getAllyLevel()**과 **getAllyExperience()**라는 이름으로 메서드가 구현되어 있습니다. 따라서 자식 클래스(WizardEntityV4)에서 따로 오버라이딩할 필요 없이, 렌더러에서 이 이름들을 직접 호출하면 됩니다.

자식도 부모 메소드 호출가능함 

 

 

 

 

 

 

법사2에 레벨 표시하는 부분잇나 

 

 

 

사용자님이 말씀하신 대로 법사4와 법사2는 서로 상속 관계가 아닙니다. 그런데 왜 법사4 머리 위에 이 UI가 뜰까요?

이유: 이 클래스가 **이벤트 기반(@SubscribeEvent)**으로 작동하기 때문입니다.

  • 이 코드는 게임 내의 모든 생명체가 렌더링될 때(RenderLivingEvent) 실행됩니다.
  • 만약 사용자님이 이 파일의 if (!(event.getEntity() instanceof WizardEntity wizard)) return; 부분을 WizardEntityV4 도 포함되도록 수정했거나, 혹은 AbstractAllyEntity 같은 공통 부모를 체크하도록 수정했다면 법사4에게도 이 UI가 나타나게 됩니다.

 

 

괜히, event구독방식쓰니깐 너무 복잡해지네 

그렇다고 법사2 다 삭제하자니, 괜히 에러생길까봐좀 

 

 

 

 

 

제공해주신 AbstractAllyEntity 클래스는 모든 아군 엔티티(법사 V2, V4 등)의 '두뇌'와 '저장소' 역할을 하는 부모 클래스입니다.

질문하신 "어떻게 관계되어 있는가"에 대한 핵심적인 답변은 다음과 같습니다.


1. 경험치 처리의 핵심 엔진 (연결 고리)

이전 질문에서 **wizard.addExperience(1.0f)**를 호출했을 때, 실제로 그 숫자를 더하고 레벨업을 시킬지 판단하는 실제 로직이 바로 이 AbstractAllyEntity에 들어있습니다.

  • 관계: WizardEntityV4는 이 클래스를 상속받았기 때문에, 별도의 코드를 작성하지 않아도 이 부모 클래스의 addExperience 로직을 그대로 사용합니다.
  • 로직: 현재 경험치를 확인하고, getMaxExperienceForLevel에서 설정한 값(V4에서는 level + 1)보다 많아지면 레벨을 올립니다.

2. 데이터 저장소: Capability (가장 중요한 부분)

코드의 이 부분을 주목해야 합니다.

    @Override public int getAllyLevel() { 
    return this.getCapability(AllyDataProvider.ALLY_DATA).map(AllyData::getLevel).orElse(1); 
}
  
  • 관계: 법사의 레벨과 경험치 데이터는 엔티티 자체가 아니라 **AllyDataProvider.ALLY_DATA**라는 "데이터 주머니(Capability)"에 담겨 있습니다.
  • UI와의 관계: 아까 사진에서 본 Kills: 0/2 같은 UI 렌더러는 화면을 그릴 때 이 주머니(ALLY_DATA)를 열어서 숫자를 읽어옵니다.
  • 결론: V4가 이 클래스를 상속받는 순간, UI 렌더러는 "아, 얘도 ALLY_DATA 주머니를 차고 있네? 그럼 정보를 그려줘야지!"라고 판단하게 되는 것입니다.

3. 서버와 클라이언트의 통신 (동기화)

    @Override public void syncDataToClients() {
    if (!this.level.isClientSide) 
        AllyNetwork.sendToTracking(new S2CAllySyncPacket(this.getId(), ...), this);
}
  
  • 관계: 서버에서 몬스터를 죽여서 경험치가 올라도, 클라이언트(내 컴퓨터 화면)가 모르면 UI가 변하지 않습니다.
  • 이 부모 클래스는 경험치가 변할 때마다 패킷(S2CAllySyncPacket)을 쏴서 화면상의 UI 숫자를 갱신해주는 역할을 합니다.

4. 체력 및 속성 관리

    private void updateMaxHealth(int level) {
    attr.setBaseValue(getBaseMaxHealth() + (level - 1) * getHealthBonusPerLevel());
}
  
  • 관계: 레벨업을 할 때 체력이 자동으로 늘어나는 공식도 여기서 관리합니다. V4에서 설정한 getHealthBonusPerLevel()(5.0D) 값이 이 공식에 대입되어 체력이 계산됩니다.

요약하자면

AbstractAllyEntity는 **"규격"**입니다.

  1. 데이터: AllyData라는 공통 주머니를 사용함 → 그래서 UI가 V4를 인식함.
  2. 동작: addExperience라는 공통 함수를 사용함 → 그래서 V4가 경험치를 얻음.
  3. 통신: syncDataToClients를 사용함 → 그래서 우리 눈에 실시간으로 보임.

사진에서 UI가 두 번 나왔던 이유는,
하나는 이 클래스가 제공하는 **"공통 데이터(Kills/Level)"**를 보고 그려지는 공통 UI이고,
다른 하나는 WizardEntityRendererV4에서 직접 추가한 **"전용 텍스트"**였던 것입니다. 둘 다 이 부모 클래스가 관리하는 데이터를 기반으로 하고 있습니다.

 

 

 

 

[  ]

아니, ui수정하는게 이렇게 복잡할줄이야

뭐지금은 프로토타입만드는중이니깐, 

걍 법사이름 ui에 추가만 해주면 될것같은데 

무슨 법사인지 구분하기 위해서 

 

 

 

 

[  ]

투사체 공격력 

private double baseDamage = 2.0D;

이거 final은 아닌데 

private은 자식에서 바꿀수잇엇던가 

 

 

 

걍모습만 화살 모습으로 되는건가 

 

 

 

 

현재 코드에서 MagicProjectileV4AbstractArrow를 상속받고 있기 때문에, 공격력 설정 방식과 위치는 다음과 같습니다.

1. 공격력이 어디에 있나요?

AbstractArrow 클래스 내부에는 baseDamage라는 변수가 숨겨져 있습니다. 별도로 설정하지 않으면 기본값이 매우 낮게 책정됩니다.

2. 공격력을 10으로 수정하는 방법 (두 가지 방식)

방법 A: 생성자에서 기본 데미지 설정 (추천)

가장 간단한 방법입니다. 투사체가 생성될 때 setBaseDamage 메서드를 사용하여 값을 고정합니다.

    public class MagicProjectileV4 extends AbstractArrow {

    public MagicProjectileV4(EntityType<? extends AbstractArrow> type, Level level) {
        super(type, level);
        this.setBaseDamage(10.0D); // 여기서 10으로 설정 (하트 5칸 분량)
    }

    public MagicProjectileV4(Level level, LivingEntity shooter) {
        super(WizardEntityTypeInitV4.MAGIC_PROJECTILE_V4.get(), shooter, level);
        this.setBaseDamage(10.0D); // 여기서 10으로 설정
    }
    
    // ... 나머지 코드
}
  

주의사항: AbstractArrow의 실제 데미지는 속도(Velocity) * baseDamage 공식으로 계산됩니다. 현재 WizardSkirmishGoalV4에서 속도를 0.2F로 매우 느리게 쏘고 계시기 때문에, baseDamage를 10으로 해도 실제 들어가는 데미지는 2(10 * 0.2) 정도밖에 안 될 수 있습니다.


방법 B: 속도와 상관없이 무조건 10 데미지 주기 (확실한 방법)

마법 화살이므로 속도와 상관없이 맞으면 무조건 10의 피해를 입히고 싶다면, onHitEntity를 오버라이드하여 직접 데미지를 주면 됩니다.

    @Override
protected void onHitEntity(EntityHitResult result) {
    Entity target = result.getEntity();
    Entity owner = this.getOwner();

    // 데미지 소스 생성 (마법 또는 투사체 판정)
    DamageSource source = DamageSource.thrown(this, owner == null ? this : owner);
    
    // 대상에게 직접 10.0F(하트 5칸)의 데미지를 입힘
    target.hurt(source, 10.0F);

    // 맞았으므로 투사체 제거
    this.discard();
}
  

3. 상속을 하면 안 되나요?

상속을 하셔도 됩니다. AbstractArrow를 상속받는 것은 화살의 물리 법칙(중력, 포물선 등)을 그대로 쓸 수 있어 매우 편리합니다. 다만, "마법" 느낌을 내기 위해 중력을 없애거나(setNoGravity(true)), 속도에 상관없는 고정 데미지를 주고 싶을 때는 위에서 언급한 방법 B처럼 직접 데미지 로직을 작성하는 것이 더 정확합니다.

 

 

 

 

 

 

 

 

네, 정확한 통찰입니다. AbstractArrow를 상속받는 이유는 **"바닥부터 새로 만드는 게 훨씬 복잡하고 번거롭기 때문"**이 맞습니다.

왜 굳이 화살을 상속받아 사용하는지, 그리고 진짜 "순수 커스텀 투사체"를 만들려면 무엇이 필요한지 쉽게 설명해 드릴게요.


1. 왜 AbstractArrow를 상속받나요? (편의성)

투사체를 처음부터(Entity 클래스부터) 만들려면 아래 기능들을 직접 수학적으로 계산해서 코딩해야 합니다.

  • 충돌 판정(Raytracing): 투사체가 매 틱마다 어디로 이동하는지, 그 사이에 벽이나 몹이 있었는지 선을 그어 확인하는 로직.
  • 물리 엔진: 중력, 공기 저항, 물속에서의 감속 등.
  • 네트워크 패킷: 서버에서 날아가는 투사체 위치를 클라이언트(화면)에 실시간으로 동기화하는 로직.
  • 회전 각도: 날아가는 방향에 맞춰 투사체 모델이 회전하게 하는 계산.

AbstractArrow는 이 어려운 기능들을 이미 다 가지고 있습니다. 그래서 겉모습(모델)만 바꾸고 속성(데미지, 중력 유무)만 살짝 수정해서 쓰는 것이 훨씬 효율적입니다.


2. "진짜" 화살 같지 않게 만들려면? (커스터마이징)

현재 코드에서 "화살 느낌"을 지우고 "마법 탄환"처럼 보이게 하려면 몇 가지만 더 손보면 됩니다.

① 땅에 꽂히지 않게 하기 (화살의 가장 큰 특징 제거)

화살은 블록에 맞으면 박히지만, 마법은 보통 터지거나 사라져야 합니다. onHit 부분에서 이미 discard()를 쓰셨지만, 더 확실하게 하려면 아래 코드를 추가합니다.

    @Override
protected void onHitBlock(BlockHitResult result) {
    // 블록에 박히지 않고 바로 사라지게 함
    this.discard();
}
  

② 중력 없애기 (직선으로 날아가는 마법)

화살은 포물선을 그리며 떨어집니다. 마법처럼 직선으로 날아가게 하려면 생성자나 tick에서 설정합니다.

    this.setNoGravity(true);
  

3. 더 나은 대안: ThrowableItemProjectile

만약 화살의 느낌(활 시위 당기는 소리, 박히는 판정 등)이 너무 싫다면, **눈덩이(Snowball)**나 **엔더 진주(Ender Pearl)**의 조상인 ThrowableItemProjectile을 상속받는 방법도 있습니다.

  • AbstractArrow: 활 공격 기반 (데미지 계산이 복잡함, 블록에 박힘)
  • ThrowableProjectile: 던지는 물체 기반 (데미지 설정이 자유로움, 맞으면 바로 사라짐)

4. 만약 "순수 커스텀 클래스"를 만든다면?

상속을 아예 안 하거나 최상위 Entity만 상속받는다면 아래와 같은 코드를 전부 직접 짜야 합니다

    public void tick() {
    Vec3 movement = this.getDeltaMovement();
    double nextX = this.getX() + movement.x;
    double nextY = this.getY() + movement.y;
    double nextZ = this.getZ() + movement.z;

    // 1. 직접 레이트레이싱 (충돌 확인)
    HitResult hitresult = ProjectileUtil.getHitResult(this, this::canHitEntity);
    
    // 2. 직접 충돌 처리
    if (hitresult.getType() != HitResult.Type.MISS) {
        this.onHit(hitresult);
    }

    // 3. 직접 위치 업데이트
    this.setPos(nextX, nextY, nextZ);
    
    // 4. 직접 마찰력/중력 계산... (끝도 없음)
}
  

 

 

 

 

 

 

 

 

지금 하시는 방식(AbstractArrow 상속)이 가장 정석입니다. 다만 부모의 로직 중에서 **"내가 바꾸고 싶은 부분(데미지 계산)"**만 위 코드처럼 **오버라이드(@Override)**해서 가로채는 방식이 가장 효율적입니다.

 

아 그래서 

자바 프로그래밍때, 기존에 잇던 코드를 바꿀일이 더 많다고 한게 이런거엿나

느낌이

마크 원본은 읽기전용이니깐 

 

 

 

 

onhit은 필요한게 엔티티에 안맞아도 삭제시켜야하니깐

 

 

 

  1. onHit(HitResult)의 역할:
    • 이 메서드는 투사체가 세상의 무언가에 "닿는 순간" 무조건 실행됩니다.
    • 여기에 this.discard()를 넣으면, 화살이 땅바닥(블록)에 박히지 않고 바로 사라지게 됩니다. (마법 탄환처럼 보임)
  2. onHitEntity(EntityHitResult)의 역할:
    • 이 메서드는 onHit이 실행되는 과정 중에 "상대가 엔티티일 때만" 추가로 호출됩니다.
    • 여기에 데미지 로직을 넣으면, 땅에 맞았을 때는 조용히 사라지고 몹에 맞았을 때만 10의 데미지를 정확히 입힙니다.

 

[  ]

ui에 몹이름 나오도록

 

뭔가 버그잡고

기존  코드수정하는건, 그렇게 재미잇는일은 아니네

물론 ai가 다하기는 하지만, 

결국 새로운 기능만들때가 재미잇는거고, 유지보수는 그렇게까지 가슴뛰는 일은 아닐수도 잇는건가 

 

 

 

 

 

일단 레벨업 잘되니깐 이건 패스하고 

 

 

 

 

 

 

 

 

 

if문을 계속 추가하는 방식은 나중에 새로운 좀비가 10마리, 20마리로 늘어날수록 코드가 지저분해지고 관리가 불가능해집니다. 이를 소프트웨어 설계에서는 **"결합도가 높다"**고 하며, 피해야 할 방식입니다.

대신 말씀하신 **"중앙 제어 방식"**이나 **"상태 기반 방식"**을 사용하는 것이 훨씬 스마트합니다. 몇 가지 효율적인 구현 전략을 제안해 드립니다.


1. 상태 효과(MobEffect) 활용 (침묵 좀비용)

가장 마인크래프트다운 방식입니다. 좀비가 법사에게 **'침묵(Silence)'**이라는 커스텀 디버프를 걸게 만드세요.

  • 구현 방법:
    • SilenceEffect라는 클래스를 만듭니다.
    • 법사의 canUse() 또는 tick()에서 현재 자신에게 이 효과가 있는지 체크합니다.
    • if (this.hasEffect(ModEffects.SILENCE.get())) return false;
  • 장점: 좀비 코드를 법사가 알 필요가 없습니다. 어떤 좀비든, 어떤 함정이든 '침묵 효과'만 걸면 법사는 마법을 못 쓰게 됩니다.

2. 중앙 타겟팅 핸들러 확장 (안개/은신 좀비용)

이미 사용 중인 ZombieEnemyHandler::isEnemyZombie를 더 똑똑하게 만드는 방식입니다.

  • 구현 방법:
    • ZombieEnemyHandlercanBeTargeted(LivingEntity target, LivingEntity attacker) 라는 메서드를 만듭니다.
    • 이 메서드 안에서 안개 효과, 은신 여부, 거리 등을 한 번에 계산합니다.
          // WizardEntity 내 Goal 등록 시
      new NearestAttackableTargetGoal<>(this, LivingEntity.class, 10, true, false, 
          (target) -> ZombieEnemyHandler.isValidTarget(this, target))
        
  • 장점: 법사의 AI 코드는 건드릴 필요 없이, ZombieEnemyHandler만 업데이트하면 모든 법사(V3, V4, V5...)에게 새로운 좀비 대처법이 적용됩니다.

3. 인터페이스(Interface) 활용 (특수 능력 좀비용)

좀비들에게 특정 '능력'을 부여하는 인터페이스를 만듭니다.

  • 구현 방법:
    • IStealthZombie, IReflectProjectile 같은 인터페이스를 만듭니다.
    • 안개 좀비는 IStealthZombie를 구현(implements)합니다.
    • 법사는 if (target instanceof IStealthZombie stealth && stealth.isHidden()) 정도만 확인하면 됩니다.
  • 장점: 새로운 좀비를 만들 때 인터페이스만 붙여주면 법사가 알아서 인식합니다.

4. 엔티티 태그(Entity Tags) 활용

코드 수정 없이 JSON 설정만으로도 조절할 수 있는 방식입니다.

  • 구현 방법:
    • tags/entity_types/mirage_zombies.json 같은 파일을 만듭니다.
    • 법사 코드에서 target.getType().is(ModTags.MIRAGE_ZOMBIES) 인지 확인합니다.
  • 장점: 나중에 다른 모드의 좀비도 태그에만 등록하면 법사가 똑같이 반응하게 할 수 있습니다.

요약: 어떤 방식을 쓸까요?

  1. 침묵/무력화와 같이 법사 자체가 변하는 경우 → 상태 효과(MobEffect)
  2. 안개/은신과 같이 타겟을 못 찾게 되는 경우 → 중앙 핸들러(ZombieEnemyHandler)
  3. 반사/회피와 같이 특정 좀비의 고유 특성인 경우 → 인터페이스(Interface)

이렇게 분리하면 if문 지옥에서 벗어나 "법사는 법사의 일만 하고, 좀비는 좀비의 일만 하는" 아주 깔끔한 코드가 됩니다. README에 쓸 때도 "확장 가능한 AI 구조를 가졌다"라고 자랑할 수 있겠죠!

 

 

 

로직상으로는 실수(float) 데이터이지만, String.format("%.0f", ...)을 사용하면 화면에 표시할 때 반올림되어 정수처럼 보이게 됩니다.

체력표시

굳이 실수말고

 

몹종류+체력내용 출력되게 

 

 

[  ]

isallywizrd인터페이스가 현재잇는가

다른 종류의 법사가 공격해도, 반격안하고 데미지 안닳는 

 

좀비에 잇던 아군 인식기능 가져오면 될듯 

 


 

 

  • AbstractAllyEntity (뼈대): 법사가 가져야 할 공통 기능(경험치 추가, 레벨업 시 체력 증가)이 들어있습니다. 법사 코드를 짧게 만들어주는 고마운 클래스입니다.
  • AllyData & AllyDataProvider (저장소): 마인크래프트가 꺼져도 법사의 레벨과 경험치가 사라지지 않게 저장해주는 "가방" 같은 역할입니다. (Capability 시스템)
  • AllyNetwork & S2CAllySyncPacket (통신): 서버에만 있는 레벨 정보를 당신의 화면(클라이언트)으로 보내주는 무전기 역할을 합니다. 이게 없으면 머리 위에 레벨이 0으로 보이거나 갱신되지 않습니다.
  • CommonAllyHUD (화면 표시): 법사 머리 위에 Lv.1, 경험치 바, 초록색 체력 바를 그려주는 코드입니다. 법사 코드에는 렌더링 관련 내용이 없는데도 바가 뜨는 이유가 바로 이 클래스 때문입니다.
  • IMyModProjectile: 화살이나 마법 구체가 "누가 쐈는지"를 쉽게 알 수 있게 해주는 도구입니다

 

 

 

근데 항상 코드에 저렇게 추가해야하나, 어쩔수없는건가 

근데 이러면 모든 법사에 다 추가해야하잖아, 

좀비는 

 

 

 

  1. 데미지 0 (무효화): MagicProjectileV4에 있는 onWizardTeamHurt 이벤트가 작동합니다. 공격자와 피해자가 모두 IWizard 인터페이스를 가지고 있다면, 데미지 이벤트 자체를 취소(setCanceled)하여 체력이 깎이지 않게 합니다.
  2. 반격 안 함 (타겟팅 차단): WizardEventsV4에 있는 onWizardChangeTarget 이벤트가 작동합니다. 법사가 법사를 타겟으로 잡으려는 순간을 포착해 취소시키므로, 아무리 맞아도 반격 모드로 전환되지 않습니다.
  3. 먼저 공격 안 함 (탐색 차단): NearestAttackableTargetGoal에 들어간 조건문이 주변에 법사(IWizard)가 있으면 적으로 인식하지 않고 무시합니다.

 

 

 

1. @SubscribeEvent란? (기능 정의)

이 어노테이션은 "이 메서드는 특정 사건(이벤트)이 발생했을 때 실행될 코드다"라고 표시하는 것입니다.

  • 예: "누군가 데미지를 입었을 때(LivingHurtEvent) 이 코드를 실행해줘!"

2. @Mod.EventBusSubscriber란? (자동 등록)

이 어노테이션은 포지(Forge) 시스템에게 이 클래스를 훑어보라고 명령하는 역할을 합니다.

  • 마인크래프트가 켜질 때, 포지는 모드 안에 있는 수천 개의 클래스를 다 뒤져볼 수 없습니다(너무 느려지니까요).
  • 그래서 @Mod.EventBusSubscriber가 붙은 클래스만 골라서 "오, 여기 이벤트 처리하는 코드가 있네? 내가 등록해줄게!" 하고 시스템에 연결(Register)해줍니다.

 

 

 

3. 왜 이걸 추가해야 했나요? (중요!)

사용자님이 처음에 주신 MagicProjectileV5 클래스 안에는 onWizardInternalHurt라는 아주 중요한 팀킬 방지 코드가 있었습니다.

@SubscribeEvent
public static void onWizardInternalHurt(LivingHurtEvent event) { ... }

하지만 클래스 상단에 @Mod.EventBusSubscriber가 없으면:

  1. 포지는 이 클래스 안에 @SubscribeEvent가 있는지 아예 모릅니다.
  2. 결국 게임 속에서 법사가 아군을 때려도 이 메서드는 절대로 호출되지 않습니다. (코드는 작성되어 있지만, 실행 스위치가 꺼져 있는 상태)

결과적으로: 이 어노테이션이 없으면 팀킬 방지 로직이 아예 작동하지 않아 법사들끼리 서로 죽이게 됩니다.


4. 사용 시 주의사항

@Mod.EventBusSubscriber를 사용하여 자동으로 이벤트를 등록할 때는 반드시 지켜야 할 규칙이 있습니다.

  1. 메서드는 반드시 static이어야 합니다:
    • 포지가 클래스를 인스턴스화(new)하지 않고도 바로 접근해야 하기 때문입니다.
  2. modid를 명시해야 합니다:
    • modid = MyMod.MODID를 적어줘야 포지가 어느 모드에서 보낸 신호인지 정확히 파악합니다.

요약

  • @SubscribeEvent: "이벤트가 발생하면 이 일을 할 거야!" (행동 정의)
  • @Mod.EventBusSubscriber: "포지야, 여기 이벤트 처리할 애들 있으니까 가서 확인해!" (연결 통로 개방)

이게 있어야만 "아군 법사 타격 시 데미지 무효화" 로직이 게임 내 시스템에 정상적으로 등록되어 작동하게 됩니다.

 

 


 

  1. 감지: 적 발견!
  2. 검사: 위를 본다. 몇 칸까지 올라갈 수 있는가? (예: 7칸 확인)
  3. 상승: 7칸 높이까지 초속 1의 속도로 이동. (공격 X)
  4. 고정: 중력 무시 설정. 위치 고정.
  5. 포격: 10초간 포격. (예측 샷)
  6. 하강: 중력 서서히 복구. 천천히 지면으로 착륙. (공격 X)
  7. 휴식: 5~10초간 지상 이동 모드. (이때 다시 위로 올라가면 너무 사기니까요.)

 

 

1. 천장 높이에 따른 목표값 수정, 2. 하강 시 낙하 데미지 방지, 3. 타겟 소실 시 즉시 복귀

 

 

 

 

 

[  ]

이렐처럼, 공이 주변을 돌아다니도록 

투사체면역

 

뭔가 아리 궁극기(롤 트레일러에서 보이는것처럼)

그런 초월상태를 표현하고싶엇는데 그럴려면 좀 애니메이션을 추가해야겟는데 

 

 

 

 

 

 

 

지금 착지후 도망로직이 추가되어잇지만, 

착지하는 순간 묵사발되어버림 

 

 

적들이 밑에서 기다리는 문제를 해결하기 위한 **'대각선 사선 하강(Diagonal Glide)'**의 이론적 구현 방법과 속도 조절 전략을 설명해 드릴게요.


1. 핵심 원리: '벡터(Vector)의 합성'

마인크래프트에서 엔티티의 움직임은 [X(가로), Y(높이), Z(세로)] 세 방향의 힘을 합쳐서 결정됩니다.

  • 기존 방식: Y축으로만 -0.1의 힘을 줌 (수직 낙하)
  • 사선 방식: Y축으로 내리는 힘 + 적의 반대 방향으로 미는 X, Z축의 힘을 동시에 줌

2. 적의 위치를 이용한 방향 계산

하강이 시작되는 순간, 법사는 수학적으로 다음과 같이 판단합니다.

  1. 적의 위치나의 위치를 비교합니다.
  2. "적 → 나" 방향의 직선 화살표(벡터)를 그립니다.
  3. 이 화살표 방향 그대로 법사에게 **'밀어내는 힘'**을 지속적으로 줍니다. 이렇게 하면 아래로 떨어지는 동시에 뒤로 밀려나게 됩니다.

3. "적들이 따라오지 못할까?" (속도와 거리의 문제)

말씀하신 대로 떨어지는 속도가 너무 느리면 좀비들이 법사의 낙하지점을 예측해서 따라옵니다. 이를 해결하기 위한 전략은 다음과 같습니다.

  • 낙하 속도 상향 (Y축): 현재 -0.1은 깃털처럼 천천히 떨어지는 속도입니다. 이를 -0.25 ~ -0.4 정도로 높여야 합니다. (이미 낙하 피해 면제 로직을 넣었기 때문에 빠르게 떨어져도 안전합니다.)
  • 수평 추진력 추가 (X, Z축): 단순히 떨어지는 것보다 뒤로 밀려나는 속도를 더 빠르게 설정합니다.
    • 즉, "아래로 떨어지는 속도 < 뒤로 밀려나는 속도"가 되면 좀비가 뛰어오는 속도보다 법사가 뒤로 날아가는 속도가 더 빨라져서 물리적으로 닿을 수 없게 됩니다.

4. 시각적인 궤적 (Trajectory)

이 로직이 적용되면 법사는 다음과 같이 움직입니다.

  1. 포격 종료: 중력이 서서히 작동함.
  2. 슬라이딩: 바닥을 향해 수직으로 꽂히는 게 아니라, 비행기가 활주로에 착륙하듯 대각선으로 미끄러지며 내려옵니다.
  3. 착지: 좀비들이 원래 법사가 있던 곳(수직 아래)으로 모여들 때, 법사는 이미 그곳에서 10~15칸 떨어진 안전한 곳에 착지하게 됩니다.

5. 추가적인 예외 처리 (이론)

대각선으로 밀려나다 보면 벽에 부딪히거나 낭떠러지로 떨어질 위험이 있습니다.

  • 벽 감지: 뒤로 밀려나는 도중 뒤에 블록이 있다면 추진력을 멈추고 수직 하강으로 전환해야 합니다.
  • 착지 즉시 정지: 땅에 닿는 순간(isOnGround), 뒤로 밀려나던 힘(X, Z)을 즉시 0으로 만들어야 합니다. 그러지 않으면 빙판 위를 미끄러지듯 계속 가다가 구덩이에 빠질 수 있습니다.

요약하자면:
낙하 속도(Y)를 지금보다 2.5배 정도 빠르게 올리고, 그와 동시에 적 반대 방향으로 강력한 수평 힘을 주어 "뒤로 날아가며 착륙"하게 만드는 것이 핵심입니다.

 

 

 

 

 

 

 

정확한 지적입니다! 타겟 한 명만 기준으로 삼으면, 타겟 뒤에 숨어있던 다른 좀비들이나 옆에서 몰려온 좀비들에게 둘러싸일 위험이 큽니다.

이런 **'다수 적 포위 상황'**을 해결하기 위한 이론적 계산 방식은 [평균 반발력(Average Repulsion)] 개념을 사용하는 것입니다.


1. 타겟이 아닌 '집단'으로부터 도망치기

단순히 타겟 - 나를 계산하는 게 아니라, 내 주변(예: 반경 10칸 내)에 있는 모든 적대적 유닛을 계산기에 넣습니다.

  • 작동 방식: 내 주변 모든 좀비들의 위치를 파악합니다.
  • 벡터 합산:
    • A 좀비가 내 북쪽에 있고, B 좀비가 내 동쪽에 있다면, 나는 그 반대인 **'남서쪽'**으로 밀려나도록 힘을 합칩니다.
    • 좀비가 한쪽에 몰려있을수록 그 반대 방향으로 밀려나는 힘은 더 강해집니다.
  • 결과: 좀비들이 없는 '가장 한적한 곳'을 수학적으로 찾아내어 그곳으로 미끄러지듯 착륙하게 됩니다.

2. 가중치 설정 (타겟 vs 일반 좀비)

모든 좀비를 똑같이 취급하지 않고 중요도를 나눌 수 있습니다.

  • 타겟 가중치: 나를 직접적으로 위협하는 메인 타겟으로부터는 더 멀리 떨어지려고 합니다.
  • 거리 가중치: 나랑 물리적으로 가까운 좀비일수록 나를 밀어내는 힘을 더 강하게 계산합니다. (내 바로 밑에 있는 놈이 가장 강력하게 나를 옆으로 밀어내게 됩니다.)

3. 착륙 지점 '안전 스캔' (Landing Zone Scan)

하강을 시작하기 전에 미리 착륙할 수 있는 바닥 블록들을 스캔하는 논리를 추가할 수 있습니다.

  • 논리: "내 반경 10칸 내의 바닥 중 좀비 숫자가 0인 지점이 어디인가?"를 찾습니다.
  • 이동: 그 지점을 목표로 대각선 활강을 시작합니다. 단순히 적을 피하는 게 아니라 **'안전한 착륙장'**을 향해 날아가는 개념입니다.

 

이건 성능때문에 이렇게 하기가 좀 그렇네, 

걍 순간이동 로직 쓰는게 

 

일단 프로토 타입이니깐 

 

일단 이렇게 하도록 하고 애니메이션 부분을 좀 건들여볼까 

 

 

 

일단 로직은 된거같고, 

애니메이션 추가하기 위해 법사6만들자 

 

진짜 천사의 강림이다. 

 


 

애니메이션은 좀 복잡한거같고 

 

 

 

블록벤치(Blockbench)로 만든 모델에 애니메이션을 넣는 방법은 크게 두 가지가 있습니다.

  1. 자바 코드 방식 (추천): 머리 회전, 팔 흔들기 등 단순한 움직임은 코드로 계산합니다. (가장 가볍고 관리가 편함)
  2. GeckoLib 방식: 복잡한 애니메이션(걷기, 마법 캐스팅 포즈 등)을 블록벤치에서 직접 제작하여 JSON으로 내보냅니다. (전문적인 애니메이션 가능)

현재 상황에서는 **"타겟을 바라보게 고개를 숙이는 기능"**이 우선이므로, 자바 코드로 애니메이션을 제어하는 방법을 알려드리겠습니다.


1. 모델 클래스 수정 (WizardVer2.java)

모델 클래스의 setupAnim 메서드가 바로 애니메이션을 담당하는 곳입니다. 블록벤치에서 모델을 Export할 때 이 부분이 비어있거나 기본값일 텐데, 아래와 같이 수정해 주세요.

(※ 모델 파일 내의 Part 이름이 head, body, right_arm 등이라고 가정합니다.)

    // WizardVer2.java (또는 사용 중인 모델 클래스)

@Override
public void setupAnim(T entity, float limbSwing, float limbSwingAmount, float ageInTicks, float netHeadYaw, float headPitch) {
    // 1. 머리 회전: 타겟을 바라보게 함 (상하좌우)
    // netHeadYaw는 도리도리(좌우), headPitch는 끄덕끄덕(상하)입니다.
    this.head.yRot = netHeadYaw * ((float)Math.PI / 180F); // 라디안 변환
    this.head.xRot = headPitch * ((float)Math.PI / 180F);

    // 2. 부유 애니메이션 (공중에 떠 있을 때 몸이 살짝 위아래로 출렁임)
    if (entity.isNoGravity()) { // V6가 비행 중일 때
        float floater = (float) Math.sin(ageInTicks * 0.1F) * 0.05F;
        this.body.y = 20.0F + floater; // 기본 위치에서 약간씩 변동
    } else {
        this.body.y = 24.0F; // 지상 위치
    }

    // 3. 팔 애니메이션 (마법 발사 포즈 예시)
    // 법사가 공격 대상이 있다면 팔을 앞으로 뻗게 할 수 있습니다.
    if (entity.getTarget() != null) {
        this.right_arm.xRot = -1.5F + (float)Math.sin(ageInTicks * 0.2F) * 0.1F; // 팔을 앞으로 들고 미세하게 떨림
        this.left_arm.xRot = -1.5F;
    } else {
        // 평상시: 걷기 애니메이션 (팔다리 교차)
        this.right_arm.xRot = (float)Math.cos(limbSwing * 0.6662F + (float)Math.PI) * 2.0F * limbSwingAmount * 0.5F;
        this.left_arm.xRot = (float)Math.cos(limbSwing * 0.6662F) * 2.0F * limbSwingAmount * 0.5F;
    }
}
  

2. 블록벤치에서 체크할 점

블록벤치에서 모델을 만들 때 피벗 포인트(Pivot Point) 설정이 매우 중요합니다.

  • 머리(Head): 피벗 포인트가 목 부분(회전축)에 있어야 합니다. 피벗이 정중앙에 있으면 머리가 공중에서 굴러다니는 것처럼 보입니다.
  • 팔(Arms): 어깨 부분에 피벗 포인트가 있어야 합니다.
  • 이름 확인: 위 코드의 this.head, this.right_arm 등은 블록벤치에서 설정한 Group 이름과 일치해야 합니다.

3. 더 정교한 애니메이션을 원한다면? (회전률/저장)

질문하신 **"회전률을 만들어 애니메이션을 저장해둬야 하나"**에 대한 답변입니다.

  • 코드 방식: 따로 저장할 필요 없습니다. setupAnim에서 실시간으로 계산합니다. 위에서 아래로 공격할 때 headPitch 값이 자동으로 커지기 때문에, 모델의 피벗 포인트만 잘 잡혀 있다면 코드가 알아서 머리를 숙이게 만듭니다.
  • 블록벤치 애니메이션 탭 이용: 만약 법사가 "공중으로 솟구칠 때 몸을 뒤로 젖히는" 등의 복잡한 동작을 원한다면, 블록벤치 왼쪽 상단의 'Animate' 탭에서 애니메이션을 만듭니다.
    • 하지만 이 방식은 표준 Minecraft Entity 모델 방식(HierarchicalModel)으로는 적용하기 까다롭고, GeckoLib이라는 라이브러리를 사용해야 합니다.

4. V6 법사를 위한 팁 (위에서 아래로 보기)

V6 법사는 공중에 높이 떠 있으므로 headPitch 값이 꽤 크게 나옵니다(예: 45도 이상).

만약 머리만 숙이는 게 아니라 몸 전체를 약간 앞으로 기울이고 싶다면 아래 코드를 setupAnim에 추가하세요:

    // 타겟이 아래에 있을수록 몸을 더 앞으로 기울임
if (headPitch > 10.0F) { 
    this.body.xRot = (headPitch - 10.0F) * 0.5F * ((float)Math.PI / 180F);
} else {
    this.body.xRot = 0;
}
  

이렇게 하면 법사가 아래에 있는 적을 내려다볼 때 훨씬 자연스럽게 몸을 숙이는 느낌이 납니다.


결론:

  1. 블록벤치에서 목, 어깨의 피벗 포인트를 회전축에 맞게 재설정한다.
  2. WizardVer2.javasetupAnim 메서드에 위 코드를 복사해서 넣는다.
  3. 게임을 켜서 법사가 공중에서 아래를 잘 쳐다보는지 확인한다!

 

 

 

 

법사가 공중에 떴을 때(SIEGE 상태) 주위에 투사체가 빙글빙글 도는 효과는 **"초월 상태"**를 표현하기에 아주 멋진 아이디어입니다!

이것을 구현할 때 가장 중요한 점은 실제 엔티티 투사체를 소환하면 안 된다는 것입니다. 말씀하신 대로 충돌 문제, 성능 문제, 그리고 주인을 따라다니게 하는 로직이 매우 복잡해지기 때문입니다.

가장 깔끔한 해결책은 WizardEntityRendererV6에서 가짜 투사체(시각적 효과)를 직접 그려주는 것입니다.


구현 전략

  1. 상태 동기화: 서버에서 법사가 SIEGE 상태인지 확인하고, 클라이언트(렌더러)에게 알려줘야 합니다. (EntityData 사용)
  2. 가짜 투사체 렌더링: 법사 렌더러에서 실제 투사체 모델을 법사 주위 궤도에 맞춰 여러 개 그립니다.
  3. 충돌 방지: 이건 그냥 '그림'일 뿐이므로 물리적인 충돌이 전혀 발생하지 않습니다.

 

이해안됨

[  ]

 

 

 

 

 

 

 

 

 

1. "코드 없이 어떻게 가짜를 그리나?" (환상술사의 원리)

가장 쉽게 비유하자면 **'인형극'**과 **'홀로그램'**의 차이입니다.

  • 실제 투사체(엔티티): 실제로 살아있는 배우를 무대 위에 한 명 더 세우는 것과 같습니다. 그 배우는 무대 위에서 다른 사람과 부딪힐 수도 있고(충돌), 대본(AI)도 따로 필요합니다.
  • 렌더러에서 그리는 가짜(시각 효과): 법사라는 배우가 **'홀로그램 발생기'**를 들고 있는 것과 같습니다.
    • 마인크래프트 시스템은 법사라는 캐릭터를 화면에 그릴 때, "법사의 몸을 그려라"라는 명령만 내리는 게 아니라 **"법사 몸 주변에 투사체 그림 4개를 더 그려라"**라고 추가 명령을 내리는 것입니다.
    • 이 그림들은 실제 생명체(엔티티)가 아니기 때문에 연산량이 거의 없고, 다른 투사체와 물리적으로 부딪히는 일도 발생하지 않습니다. 그냥 법사에 딱 붙어있는 장식품(스킨) 같은 존재라고 보시면 됩니다.

2. "궤도(원)는 어떻게 그려지는가?" (수학적 원리)

공중에서 법사를 중심으로 투사체가 도는 것은 **'시계 바늘'**의 원리를 이용합니다.

  1. 기준점: 항상 법사의 발바닥이나 허리 위치를 (0, 0)으로 잡습니다.
  2. 각도: 시간이 흐를 때마다(게임 틱) 각도를 0도에서 360도까지 계속 올립니다.
  3. 위치 계산: 수학의 **사인(Sin)**과 **코사인(Cos)**이라는 삼각함수를 사용합니다.
    • 코사인은 좌우(X) 위치를 결정합니다.
    • 사인은 앞뒤(Z) 위치를 결정합니다.
  4. 반지름: 법사로부터 얼마나 멀리 떨어질지 숫자를 정하면(예: 1.5미터), 그 거리만큼 떨어진 채로 시간이 흐를수록 각도가 변하며 뱅글뱅글 돌게 됩니다.

3. "3D 구 형태로 그리려면?" (평면에서 입체로)

지금 설명한 방식은 법사의 허리 주변을 평면으로 도는 '토성 고리' 같은 형태입니다. 이것을 구(Sphere) 형태로 바꾸려면 높이(Y축)에도 변화를 주어야 합니다.

구 형태를 만드는 방법은 크게 두 가지입니다.

  1. 나선형 방식 (용이 몸을 감싸듯):
    • 투사체가 단순히 옆으로만 도는 게 아니라, 위아래로도 계속 움직이게 만듭니다.
    • 예를 들어, 1번 투사체는 머리 위에서 발끝까지 내려오면서 돌고, 2번 투사체는 반대로 올라가면서 돌게 설정하면 전체적으로 법사를 감싸는 구 형태처럼 보입니다.
  2. 기울어진 궤도 방식 (원자 모형):
    • 평면 궤도를 여러 개 만드는데, 각 궤도를 비딱하게 기울이는 것입니다.
    • 하나는 가로로 돌고, 하나는 세로로 돌고, 하나는 대각선으로 돌게 하면, 멀리서 봤을 때 법사가 투사체로 이루어진 '보호막 구' 안에 갇혀 있는 것처럼 보이게 됩니다.

4. 정리하자면

  • 충돌이 없는 이유: 눈에 보이는 '그림'일 뿐, 서버가 계산하는 '물체'가 아니기 때문입니다.
  • 법사를 따라다니는 이유: 법사의 위치를 기준으로 "거기서 1미터 옆에 그려라"라고 명령하기 때문에 법사가 순간이동을 해도 그림은 즉시 따라옵니다.
  • 구 형태의 비결: 좌우(X), 앞뒤(Z)뿐만 아니라 위아래(Y) 위치까지 각도에 따라 출렁이게 만들면 입체적인 구 모양의 궤도가 완성됩니다.

이 방식은 마인크래프트에서 화려한 스킬 효과나 보스 몬스터의 아우라를 표현할 때 가장 많이 사용하는 표준적인 테크닉입니다.

 

 

 

 

 

 

투사체를 실제 **'객체(Entity)'**로 만들어서 돌리는 것이 왜 연산량이 많은지, 코드 없이 아주 쉬운 비유로 설명해 드릴게요.

마인크래프트에서 **실제 투사체(객체)**와 **가짜 그림(렌더링)**의 차이는 **'살아있는 배우'**와 **'배우가 든 풍선'**의 차이와 같습니다.


1. "생각"의 양이 다릅니다 (물리 연산)

  • 실제 객체: 마인크래프트의 모든 엔티티는 매 순간(1초에 20번) 주변을 확인합니다. "나 지금 블록에 부딪혔나?", "지나가는 소랑 부딪혔나?", "중력 때문에 떨어져야 하나?" 같은 계산을 끊임없이 합니다. 투사체가 4개면 이 계산을 4배로 해야 합니다.
  • 가짜 그림: 아무런 생각을 하지 않습니다. 그냥 "법사 몸에서 1미터 옆에 그려져라"라는 공식 하나만 따릅니다. 벽에 부딪히는지, 땅에 닿는지 고민조차 안 하기 때문에 연산이 거의 '0'에 가깝습니다.

2. "편지"를 계속 보내야 합니다 (네트워크 통신)

마인크래프트는 서버와 클라이언트가 나누어져 있습니다.

  • 실제 객체: 서버가 "투사체 1번이 (10, 60, 10) 위치로 옮겨졌어!"라고 내 컴퓨터(클라이언트)에 계속 **편지(데이터 패킷)**를 보내야 합니다. 투사체가 뱅글뱅글 돌면 위치가 계속 변하니까 편지를 엄청나게 많이 보내야 하고, 인터넷이 느려지거나 렉이 걸릴 수 있습니다.
  • 가짜 그림: 서버는 투사체가 있는지조차 모릅니다. 그냥 내 컴퓨터가 혼자서 "법사가 초월 상태네? 그럼 내 마음대로 그림 좀 그려야지" 하고 계산해서 보여주는 것입니다. 주고받는 편지가 아예 없으니 렉이 생길 이유가 없습니다.

3. "서류 작업"이 복잡합니다 (메모리 관리)

  • 실제 객체: 엔티티 하나를 만들면 게임은 "이 투사체의 주인은 누구인가?", "태어난 지 얼마나 됐나?", "데미지는 얼마인가?" 같은 정보를 담은 **두꺼운 서류철(데이터)**을 메모리에 만들어 관리합니다.
  • 가짜 그림: 서류가 없습니다. 그냥 화면에 점을 찍는 것과 비슷해서, 다 그리고 나면 바로 잊어버립니다. 다음 화면을 그릴 때 다시 계산하면 끝입니다.

4. "따라다니기"가 힘듭니다 (위치 동기화)

  • 실제 객체: 법사가 빠르게 움직이면, 투사체 객체들도 법사의 속도에 맞춰서 따라가려고 애를 써야 합니다. 가끔 법사는 저기 가 있는데 투사체는 뒤늦게 따라오는 '끌림 현상'이 생기기도 합니다.
  • 가짜 그림: 법사의 몸에 **'문신'**을 새긴 것과 같습니다. 법사가 움직이면 그림은 그 위치를 기준으로 그려지기 때문에 0.0001초의 오차도 없이 자석처럼 딱 붙어있게 됩니다.

요약하자면:

  • 실제 객체로 돌리기: 법사 주변에 진짜 드론 4대를 띄우는 것과 같습니다. 배터리도 들고, 조종사도 필요하고, 서로 부딪히지 않게 조절도 해야 합니다.
  • 가짜 그림으로 그리기: 법사 주변에 **조명(홀로그램)**을 쏘는 것과 같습니다. 실체는 없지만 눈에는 똑같이 보이고, 조종할 필요도 없이 법사만 따라다니면 되니 훨씬 가볍고 효율적입니다.

그래서 복잡한 궤도를 그리거나 화려한 효과를 줄 때는 가짜 그림(렌더링) 방식을 사용하는 것이 훨씬 똑똑한 방법입니다!

 

 

 

 

 

 

 

뭔가 유나라 만들수잇을것같은데 

 

 

법사 V7의 핵심 아이디어인 **'가짜로 보여주되, 실제 데이터와 연동하는 방식'**은 아주 영리한 설계입니다. 게임 개발에서 흔히 **"시각적 동기화"**라고 부르는 기법입니다.

이 시스템이 코드 없이 어떻게 돌아가는지 그 원리를 4단계로 설명해 드릴게요.


1. "탄창" 역할을 하는 숫자 (데이터 관리)

먼저 법사에게 **'현재 구체 개수'**라는 이름의 작은 메모장을 하나 쥐여줍니다.

  • 처음 소환되면 이 메모장에는 **'6'**이라고 적혀 있습니다.
  • 이 숫자는 서버(법사의 머리)와 클라이언트(우리의 눈)가 실시간으로 공유합니다.

2. 공격: "바꿔치기 마술" (발사 로직)

적을 만났을 때, 법사는 다음과 같은 행동을 동시에 합니다.

  1. 메모장 수정: '현재 구체 개수'에서 1을 뺍니다. (6 -> 5)
  2. 실제 탄환 생성: 법사의 몸 위치에서 적을 향해 날아가는 **'진짜 투사체 객체'**를 하나 새로 만듭니다.

이때, 우리 눈에는 **"주변을 돌던 구체 중 하나가 슥 빠져나와서 적에게 날아가는 것"**처럼 보입니다. 하지만 사실은 돌고 있던 가짜 그림 하나가 사라지는 순간, 그 자리에서 진짜 탄환이 튀어나가는 착시 현상을 이용하는 것입니다.

3. 재생: "투명 타이머" (충전 로직)

법사 내부에서는 눈에 보이지 않는 시계가 계속 돌아가고 있습니다.

  • 구체가 6개 미만(0~5개)일 때만 시계가 작동합니다.
  • 예를 들어 '5초'가 지날 때마다 메모장의 숫자를 +1 시킵니다.
  • 숫자가 다시 6이 되면 시계는 멈춥니다.

4. 렌더링: "그려라, 적힌 숫자만큼만" (그리기 로직)

이 부분이 가장 중요합니다. 렌더러(그림 그리는 장치)는 이제 무조건 6개를 그리는 게 아니라, 법사의 메모장에 적힌 숫자를 먼저 확인합니다.

  • 숫자가 6이면: 60도 간격으로 6개를 다 그립니다.
  • 숫자가 3이면: 똑같은 궤도상에 3개만 그립니다.
  • 숫자가 0이면: 아무것도 그리지 않습니다.

요약하자면:

  1. 보여주는 것(가짜): 법사 주위의 구체는 그냥 **'현재 남은 화살 개수'**를 시각적으로 보여주는 화려한 **UI(인터페이스)**일 뿐입니다.
  2. 발사하는 것(진짜): 구체가 발사되는 순간에만 아주 잠깐 **'진짜 투사체'**가 생성되어 날아갑니다.
  3. 충돌 걱정 없는 이유: 주위를 도는 6개는 여전히 '그림'이기 때문에 법사 몸이나 다른 물체에 부딪히지 않습니다. 발사되어 나가는 그 '한 발'만 진짜 물체이기 때문입니다.

사용자 경험: 플레이어 입장에서는 "오, 법사가 기를 모아서 구체를 하나씩 날리네? 다 쓰니까 구체가 없어졌다가 다시 생기네!"라고 느끼게 됩니다.

실제로는 **숫자 놀이(데이터)**와 **그림 그리기(렌더링)**를 교묘하게 섞은 아주 효율적인 시스템인 것이죠!

 

 

 

 

 

 

결국 좀만 복잡한거 하려고 하면, 애니메이션과의 연관성을 뗄수는 없나보네 

 

 

아니면 블록벤치, 다른 사람이 만든거 가져올수도잇나 

 

 

 

블록벤치(Blockbench)로 다른 사람이 만든 모델을 가져오는 것은 기술적으로는 매우 쉽지만, 저작권(라이선스) 문제는 매우 중요합니다. 하나씩 꼼꼼하게 설명해 드릴게요.


1. 기술적으로 가져오는 방법 (How-to)

다른 사람이 만든 모델 파일(.bbmodel, .json, .obj 등)이 있다면 블록벤치에서 아주 쉽게 불러올 수 있습니다.

  • 파일 열기: File -> Open Model을 누르거나 파일을 블록벤치 화면으로 드래그하면 됩니다.
  • 파일 형식:
    • .bbmodel: 블록벤치 전용 파일 (가장 추천, 모든 정보 보존)
    • .json: 마인크래프트 자바 에디션 엔티티/블록 모델 (가장 흔함)
    • .obj: 일반적인 3D 모델 파일 (텍스처 연결이 끊길 수 있음)

2. 저작권 문제 (Copyright) ⚠️ 매우 중요

남이 만든 모델을 내 모드에 넣어 배포할 때는 반드시 **라이선스(사용 허가 범위)**를 확인해야 합니다.

  • 라이선스가 명시되지 않은 경우: 저작권법상 원칙적으로 사용 불가입니다. 제작자에게 직접 허락을 받아야 합니다.
  • CC0 (Public Domain): 아무런 제한 없이 누구나 수정하고 상업적으로 사용할 수 있습니다. (가장 안전)
  • CC BY (Attribution): 사용은 가능하지만, 내 모드의 설명란이나 크레딧에 원작자의 이름과 출처를 반드시 적어야 합니다.
  • CC BY-NC (Non-Commercial): 영리 목적으로 사용할 수 없습니다. (모드에 광고를 넣거나 후원을 받는다면 문제될 수 있음)

3. 안전하게 모델을 구하는 곳 (추천 사이트)

저작권 걱정을 덜고 모델을 구할 수 있는 곳들입니다.

  1. Sketchfab (스케치팹):
    • 검색 필터에서 Downloadable을 체크하면 무료 모델을 찾을 수 있습니다.
    • 각 모델 하단에 라이선스(예: CC BY)가 적혀 있으니 확인하고 가져오면 됩니다.
  2. Planet Minecraft (플래닛 마인크래프트):
    • 마인크래프트 유저들이 모델을 공유하는 곳입니다. 보통 설명란에 "내 이름을 언급해달라"거나 "자유롭게 써라"는 내용이 적혀 있습니다.
  3. Blockbench Library (블록벤치 내장 라이브러리):
    • 블록벤치 실행 첫 화면의 Plugins 탭에서 Minecraft Title Generator나 다른 모델 관련 플러그인을 보면 공개된 무료 리소스들이 있습니다.

4. 저작권 문제를 피하는 가장 좋은 방법: '참고'와 '변형'

남의 것을 그대로 가져다 쓰는 것보다 **"아이디어만 빌려오기"**를 추천합니다.

  • 방법: 남이 만든 모델을 블록벤치로 열어서 "아, 이 사람은 레이어를 이렇게 겹쳤구나!", "이런 색감을 썼구나!" 하고 공부한 뒤, 본인만의 스타일로 새로 만드는 것입니다.
  • 이렇게 하면 저작권 문제도 전혀 없고, 내 모드만의 고유한 색깔(Wizard V6만의 정체성)이 생깁니다.

5. '게이트 오브 헤븐' 모델링 팁 (재사용 시)

만약 누군가 만든 '포탈' 모델을 가져왔는데 마음에 쏙 들지 않는다면?

  • 가져온 모델의 **구조(뼈대)**만 남기고, 텍스처를 아까 보여드린 이미지 프롬프트로 생성한 화려한 그림으로 교체해 보세요. 이것만으로도 완전히 새로운 창작물이 됩니다.

결론:
개인적으로 연습용 모드를 만드는 거라면 상관없지만, 인터넷에 배포할 예정이라면 반드시 라이선스를 확인하세요! 웬만하면 아까 말씀드린 '2D 평면 레이어 겹치기' 방식으로 직접 만들어보시는 걸 추천합니다. 생각보다 훨씬 쉽고 결과물도 만족스러우실 거예요.

 

 

 

 

에픽게임즈, 

본인인증해야해서 귀찮음

 

 

블록벤치 내장 라이브러리와 플러그인에서 제공하는 리소스, 그리고 개인적인 사용 범위에 대해 명확하게 정리해 드릴게요.


1. 블록벤치 플러그인/라이브러리 저작권

블록벤치 플러그인 스토어에 올라와 있는 도구들이나 리소스들은 기본적으로 **'커뮤니티 공유'**를 목적으로 합니다.

  • 일반적인 도구(Title Generator 등): 이 플러그인들은 결과물을 만드는 '도구'입니다. 여기서 만든 결과물(글자 모델 등)은 제작자가 자유롭게 쓸 수 있도록 허용하는 경우가 대부분입니다.
  • 주의점 (마인크래프트 타이틀): Minecraft Title Generator로 만든 로고는 마인크래프트의 공식 폰트 스타일을 따라합니다. 이는 모장(Mojang)의 상표권 가이드라인을 따릅니다. (개인 모드나 비영리 블로그에 쓰는 건 문제없지만, '마치 공식 게임인 것처럼' 속여서 팔거나 광고하는 건 안 됩니다.)
  • 라이브러리 모델: 플러그인을 통해 제공되는 샘플 모델들은 대부분 MIT 라이선스나 **CC0(공유 저작물)**인 경우가 많아 매우 자유롭습니다. 하지만 플러그인 설명란에 제작자 이름(Credit)을 적어달라는 문구가 있는지 한 번쯤 확인하는 것이 좋습니다.

2. "배포 안 하고 혼자 만드는 것"

이건 100% 안전합니다.

  • 저작권은 '복제'와 '전송(배포)'에 관한 권리입니다. 내 컴퓨터 안에서 다른 사람의 모델을 가져와 수정하고, 나만 보는 모드를 만드는 행위는 저작권법 위반이 될 수 없습니다. 공부용이나 개인 만족용으로 만드시는 건 아무 제약 없이 마음껏 하셔도 됩니다.

3. "블로그에 올리는 것"

블로그에 올리는 것은 '공개'하는 행위지만, 상황에 따라 다릅니다.

  • 스샷이나 영상만 올리는 경우 (OK): "내가 이런 모드를 만들고 있다"며 개발 일지를 올리는 것은 '공정 이용(Fair Use)' 범위에 해당할 확률이 매우 높습니다. 특히 영리 목적이 아니라면 원작자들도 홍보 효과가 있어 문제 삼지 않습니다.
  • 파일을 공유하는 경우 (주의): 남이 만든 모델 파일 자체를 내 블로그에 직접 올려서 남들이 다운로드하게 하는 건 저작권 문제가 될 수 있습니다. 이때는 "모델 출처: 블록벤치 OO 플러그인"이라고 적어주면 훨씬 안전하고 매너 있는 행동이 됩니다.

4. 결론 및 행동 요령

  1. 공부 및 개인 소장: 걱정 말고 모든 소스를 다 가져다 써보세요. 실력을 키우는 데 가장 좋습니다.
  2. 블로그 포스팅: "이 모델은 어떤 플러그인을 참고해서 만들었다" 혹은 "출처는 어디다"라고 한 줄만 적어주면 저작권 시비에서 거의 100% 자유롭습니다.
  3. 에티켓: 만약 나중에 이 모드를 정식으로 배포하게 된다면, 그때는 사용한 모델들의 제작자에게 이메일을 보내거나, 설명란에 크레딧(이름)을 명시하면 됩니다.

요약:
혼자 만들고 블로그에 자랑하는 건 전혀 문제없습니다! 오히려 그런 기록들이 나중에 본인의 멋진 포트폴리오가 됩니다. 마음 편히 '게이트 오브 헤븐' 모델링에 집중하셔도 됩니다. :)

 

 

 

 

 

https://mcmodels.net/

 

 

 

 

 

블록벤치(Blockbench)를 처음 사용하실 때 가장 많이 헷갈려 하시는 부분입니다. 사실 블록벤치 안에는 마인크래프트의 기본 몹(좀비, 소, 법사 등)들이 들어있는 '자체 모델 라이브러리'라는 버튼은 따로 없습니다.

원하시는 목적에 따라 아래 3가지 방법 중 하나를 선택해서 '라이브러리'처럼 사용하셔야 합니다.


1. 외부 모델 가져오기 (가장 일반적인 방법)

마인크래프트의 기본 몹 모델을 수정하고 싶다면, 블록벤치 안에서 찾는 게 아니라 마인크래프트 게임 파일이나 공식 리소스팩에서 모델 파일(.json 또는 .bbmodel)을 가져와서 열어야 합니다.

  • 추천 사이트: MC Models 같은 곳에서 무료 모델을 받거나, 마인크래프트 공식 **'Vanilla Resource Pack'**을 구글에서 검색해 다운로드하면 그 안에 모든 몹의 기본 모델이 들어있습니다.

2. 플러그인(Plugins) 활용 (기능 라이브러리)

도구나 추가 기능을 찾으시는 거라면 '플러그인' 메뉴를 보셔야 합니다.

  1. 상단 메뉴에서 File(파일) -> **Plugins...(플러그인)**을 클릭합니다.
  2. Available(사용 가능) 탭을 누르면 전 세계 사람들이 만든 수백 개의 추가 기능들이 나옵니다.
    • 예를 들어 'Minecraft Asset Browser' 같은 플러그인을 설치하면, 게임 내 아이템이나 블록을 라이브러리처럼 바로 불러올 수 있는 기능이 생깁니다.

3. Sketchfab 라이브러리 (3D 모델 검색)

다른 사람들이 만든 3D 모델을 구경하거나 가져오고 싶다면:

  1. 플러그인에서 Sketchfab을 검색해 설치합니다.
  2. 그러면 블록벤치 화면에 Sketchfab 탭이 생기며, 거기서 수만 개의 3D 모델을 검색해서 라이브러리처럼 쓸 수 있습니다.

4. 이미 만든 모델 (최근 항목)

보내주신 사진 중앙의 Recent(최근) 섹션이 현재 질문자님이 작업하신 모델들의 '개인 라이브러리' 역할을 합니다. magic_projectile1.bbmodel이 보이는데, 이전에 작업한 파일을 여기서 바로 열 수 있습니다.


결론:
만약 **"마인크래프트 법사 모델을 불러오고 싶다"**는 의미로 라이브러리를 찾으시는 거라면, **"Minecraft Vanilla Assets"**를 인터넷에서 다운로드하여 그 안에 있는 모델 파일을 Open Model로 불러오는 것이 정석입니다!

 

 

 

 

 

결론부터 말씀드리면, 네, 당연히 라이선스가 있습니다. 세상에 존재하는 모든 창작물은 가격이 0원(Free)이라고 해서 저작권이 없는 것이 아닙니다.

mcmodels.net에서 제공하는 무료 제품들은 보통 다음과 같은 라이선스 규칙을 따릅니다.


1. "무료(Free)"의 의미: 가격이 0원일 뿐, 소유권은 작가에게 있음

mcmodels.net의 이용 약관(Terms of Service)과 개별 제품 페이지를 보면 라이선스 범위가 정해져 있습니다. 보통 무료 모델은 **"개인적 사용 및 서버 적용"**은 허용하지만, **"재배포 및 재판매"**는 엄격히 금지합니다.

  • 허용되는 범위 (보통):
    • 자신이 운영하는 마인크래프트 서버에 적용.
    • 개인적으로 만드는 모드에 포함시켜 플레이.
    • 유튜브 영상이나 블로그 리뷰에서 해당 모델이 포함된 화면을 보여주는 것.
  • 금지되는 범위 (보통):
    • 무료로 받은 파일을 다른 사이트에 다시 올리는 행위(재배포).
    • 모델의 일부를 수정해서 자신이 만든 것처럼 판매하는 행위.
    • 모델 파일을 유료 모드 패키지에 포함시켜 파는 행위.

2. 라이선스 확인 방법

제품마다 작가가 설정한 규칙이 다를 수 있습니다.

  • Product Description (제품 설명): 하단에 "License" 또는 "Terms of Use" 섹션이 있는지 확인하세요.
  • 파일 안의 ReadMe.txt: 압축 파일을 풀었을 때 라이선스 관련 텍스트 파일이 들어있는 경우가 많습니다.
  • 사이트 공통 약관: 별도의 설명이 없다면 mcmodels.net의 표준 라이선스를 따르며, 이는 보통 '비상업적 이용 및 재배포 금지'를 골자로 합니다.

3. 질문하신 상황에 대입해 보면 (블로그 & 개발)

  1. 모드 개발에 사용하는 것:
    • OK. 무료 제품의 목적 자체가 유저들이 자기 컨텐츠에 써보라고 올린 것이기 때문에 개발 단계에서 쓰는 건 아무 문제 없습니다.
  2. 블로그에 스크린샷/영상을 올리는 것:
    • OK. 오히려 작가들이 좋아할 일입니다. 단, 매너상 **"모델 출처: mcmodels.net (작가 이름)"**이라고 적어주는 것이 좋습니다.
  3. 블로그에 모드 파일(jar)을 배포하는 것:
    • 주의 필요. 만약 그 모드 안에 mcmodels.net에서 받은 모델 데이터(json, png 등)가 그대로 들어있다면, 라이선스에 따라 "재배포 금지"에 걸릴 수 있습니다.
    • 해결책: 배포할 때 "이 모드에 사용된 일부 모델은 mcmodels.net의 OO 작가님의 무료 리소스를 사용했습니다"라고 명시하세요. 대부분의 무료 리소스 작가들은 출처만 밝혀주면 배포를 허용해 줍니다.

4. 가장 안전한 방법

무료 모델을 다운로드할 때 **작가의 이름(Artist Name)**을 꼭 기억해두세요. 그리고 나중에 블로그에 올리거나 모드를 공유할 때 아래와 같이 한 줄만 적어주면 완벽합니다.

"사용한 포탈 모델 출처: mcmodels.net의 [작가이름]님 무료 배포 리소스"

이렇게 하면 저작권 문제도 해결되고, 나중에 실력이 늘어 직접 만든 모델과 외부 모델을 구분해서 관리하기에도 좋습니다. mcmodels.net은 퀄리티가 높은 곳이니 좋은 소스 찾으셔서 '게이트 오브 헤븐' 멋지게 만드시길 바랍니다!

 

 

 

 

 

 

 

 

근데 유저가 사용할수잇는것도 투척용으로 가능한가 

그러면 굳이 새로운 검을 넣을필요는 없긴하지 

 

 

 

네, 당연히 가능합니다! 질문의 의도를 정확히 파악했습니다. **"내가 만든 새로운 몹이 공격할 때, 화살 대신 다이아몬드 검을 날리게 할 수 있는가"**에 대한 답변은 **"YES"**입니다.

이것을 구현하기 위한 논리적인 핵심 단계는 다음과 같습니다.


1. 투척용 '검 엔티티' 만들기

마인크래프트에서 몹이 무언가를 던지려면, 그 '날아가는 물체' 자체가 하나의 엔티티여야 합니다. (마치 화살이나 화염구처럼요.)

  • 외형 설정 (렌더링): 이 엔티티의 겉모습을 결정할 때, 새로 텍스처를 그릴 필요 없이 **게임 시스템에 "다이아몬드 검의 아이템 모델을 그대로 가져와서 써라"**라고 명령할 수 있습니다.
  • 회전 효과: 검이 그냥 뻣뻣하게 날아가면 어색하겠죠? 엔티티가 날아가는 동안 X축이나 Z축으로 계속 회전하게 설정하면, 실제로 검을 휙휙 던지는 느낌을 줄 수 있습니다.

2. 몹의 공격 패턴(AI) 설정

새로 만드신 몹에게 "적을 발견하면 이 '검 엔티티'를 생성해서 발사해라"라는 인공지능(AI)을 넣어줘야 합니다.

  • 발사 위치: 몹의 손 위치에서 검 엔티티가 나타나도록 설정합니다.
  • 조준: 플레이어(혹은 대상)의 위치를 계산해서 그 방향으로 검 엔티티에 추진력(Velocity)을 줍니다.

3. 검 엔티티의 충돌 로직 (데미지)

이 날아가는 검이 누군가에게 부딪혔을 때 어떤 일이 일어날지 정의합니다.

  • 데미지 결정: 다이아몬드 검의 기본 공격력(예: 7)만큼 데미지를 주도록 설정합니다.
  • 특수 효과: 만약 그 몹이 '마법이 부여된 검'을 던지는 컨셉이라면, 맞았을 때 불이 붙거나 뒤로 밀려나게(넉백) 할 수도 있습니다.

4. 충돌 후의 처리

검이 목표물에 맞거나 땅에 떨어졌을 때 어떻게 될지 정해야 합니다.

  • 회수 가능형: 땅에 꽂히게 하고, 나중에 플레이어나 몹이 주울 수 있게 합니다.
  • 소멸형: 맞추자마자 펑 하고 사라지게 합니다.
  • 튕겨나감: 벽이나 방패에 맞으면 팅! 하고 튕겨져 바닥에 떨어지게 합니다.

요약하자면:

  1. "다이아몬드 검의 모양을 한 화살" 같은 개념의 전용 엔티티를 하나 정의합니다. (렌더러에서 기존 아이템 모델을 재활용)
  2. 몹이 공격할 때 화살 대신 그 전용 엔티티를 소환하게 합니다.
  3. 그 엔티티가 맞았을 때 다이아몬드 검급 데미지를 주도록 설정합니다.

이렇게 하면 유저는 "와, 저 몹은 다이아몬드 검을 던져서 공격하네?"라고 느끼게 됩니다. 코드상으로는 **'아이템 모델을 빌려온 새로운 투사체'**를 만드는 셈입니다.

 

 

 

 

 

유나라 만들려고햇는데, 앞엣거랑 비슷한거같아서 좀 지겨워지는듯 

 

 

 

 

 

둘다 다운하면 되나 

뭘 다운받게 되는거지 

 

 

 

이미지에 있는 **'Free Mini Sword Pack'**은 법사 V6의 '게이트 오브 헤븐' 투사체로 쓰기에 아주 딱 좋은 디자인이네요! 질문하신 내용에 대해 하나씩 설명해 드릴게요.

1. 어떤 버튼을 눌러야 하나요?

  • 이미지에 있는 주황색 [Download for Free] 버튼은 둘 다 똑같은 링크일 가능성이 높습니다. (보통 페이지 상단과 본문에 하나씩 배치해둔 것입니다.)
  • 아무거나 누르시면 됩니다. 누르면 바로 압축 파일(.zip)이 다운로드되거나, 외부 사이트(예: Google Drive, Mediafire)로 연결될 것입니다.

2. 무엇을 다운로드하게 되나요?

보통 이런 "Raw Model" 팩을 받으면 압축 파일 안에 다음과 같은 파일들이 들어있습니다.

  1. .bbmodel 파일: 블록벤치 전용 원본 파일입니다. (이게 있으면 수정하기 가장 좋습니다.)
  2. .json 파일: 마인크래프트 아이템/블록 모델 파일입니다.
  3. .png 파일: 가장 중요한 텍스처(색상) 파일입니다.

3. ".java 파일이 필요한데 없으면 어떡하죠?"

현재 작성하신 코드(MagicProjectileV6, ProjectileRendererV6)를 보면, 투사체의 형태를 정의하는 **MagicProjectileModel**이라는 자바 클래스가 이미 있을 겁니다.

하지만 다운로드받은 파일에는 .java가 없을 거예요. 그 이유는 다음과 같습니다.

  • 방법 A (추천): 다운로드받은 .bbmodel 파일을 블록벤치로 엽니다. 그 다음 **File -> Export -> Export Java Entity**를 누르면 마인크래프트 코드 형태(.java)로 저장할 수 있습니다.
    • 이렇게 생성된 코드를 기존의 MagicProjectileModel 클래스 내용과 교체하시면 됩니다.
  • 방법 B: 만약 단순히 아이템 형태의 투사체를 날리고 싶다면 모델 파일 없이 텍스처(.png)만 ProjectileRendererV6에서 사용하면 됩니다. (하지만 '검' 형태를 제대로 보이게 하려면 방법 A가 훨씬 퀄리티가 좋습니다.)

4. 법사 V6에 적용하기 위한 순서

  1. 다운로드: 압축 파일을 풉니다.
  2. 블록벤치 실행: .bbmodel 파일을 불러옵니다.
  3. 검토: 모델이 너무 크거나 작지 않은지 확인합니다.
  4. 내보내기 (Java): Export Java Entity를 통해 자바 코드를 얻습니다.
  5. 텍스처 저장: .png 파일을 본인의 모드 폴더(src/main/resources/assets/mymod/textures/entity/...)에 넣습니다.
  6. 코드 수정:
    • MagicProjectileModel 클래스에 블록벤치에서 복사한 코드를 붙여넣습니다.
    • ProjectileRendererV6에서 TEXTURE 경로를 새로 넣은 .png 파일 경로로 수정합니다.

팁: 이 검 모델을 '게이트 오브 헤븐' 공격 때 등 뒤의 마법진에서 튀어나오게 하면 정말 멋질 것 같습니다. 다운로드 받아서 블록벤치로 먼저 열어보세요! 궁금한 게 생기면 또 물어봐 주세요.

 

 

 

 

에이 칼자체가 떨어지게 되네 

 

 

 

 

 

 

 

문제의 핵심은 **"기존의 구체 모델(MagicProjectileModel)"**과 **"새로운 검 모델(sword)"**을 동시에 사용하는 것입니다.

기존 투사체 엔티티(MagicProjectileV7)의 **렌더러(Renderer)**만 교체하면, 법사 주변에 떠다니는 구체 모델은 그대로 유지하면서 날아가는 투사체만 검으로 바꿀 수 있습니다.

 

 

 

 

 

 

뭔가 아이스크림 하드 바 같기도 하고 

 

 

 

 

[  ]

거대한 검은 대상과 부딪혀도 안자라지고 면초가 유지 할수잇게 

 

 

검의 방향이 다르고, 좀더 거대햇으면 좋겟는데, 

더 느리게 돌격하고 

 

 

  • 적에게 맞았을 때: onHitEntity 로직에 의해 적에게 10의 데미지(하트 5칸)를 입힌 즉시 this.discard() 명령어가 실행되어 투사체가 사라집니다.
  • 바닥이나 벽에 맞았을 때: onHit 로직에 의해 블록에 닿는 순간 즉시 사라지도록 설정되어 있습니다. (화살처럼 꽂혀 있지 않고 펑 하고 소멸함)

 

 

 

 

 

뭔가 근데 칼 던지는거 이용해서 문도 만들수도 잇을것같기도하고, 칼 아주 느리게 던지록

대신 맞으면 둔화 지속 5초

회전시키면서 

 

문도, 유나라

구현 

 

 

 

 

 

 

 

네, 당연히 가능합니다! 마인크래프트의 엔티티는 **"상태(State)"**에 따라 겉모습을 자유자재로 바꿀 수 있습니다.

사용자께서 걱정하시는 **'충돌 처리(히트박스) 문제'**와 **'모델 교체 방식'**에 대해 코드 없이 논리적으로 설명해 드릴게요.


1. 모델 전체를 갈아끼우는 게 아닙니다 (Layer 방식)

보통은 모델 전체를 다른 파일로 바꾸는 것이 아니라, **"투명 망토를 입었다 벗었다 하는 것"**과 비슷한 방식을 사용합니다.

  • 기본 모델: 법사 몸체 (항상 보임)
  • 추가 모델 (레이어): 날개 (평소에는 숨겨져 있음)
  • 논리: 렌더러(Renderer)가 그림을 그릴 때, 법사에게 물어봅니다. "너 지금 날아오르는 중이니?" 법사가 "응!"이라고 대답하면 그때만 날개 부분을 화면에 그려줍니다.

2. 충돌 처리(히트박스)는 별개입니다

마인크래프트에서 눈에 보이는 모델실제 부딪히는 히트박스는 완전히 별개의 시스템입니다.

  • 히트박스: 보이지 않는 단단한 상자입니다. 코딩할 때 크기를 고정해두면, 법사에게 날개가 달리든, 몸이 2배로 커지든 이 상자의 크기는 변하지 않습니다.
  • 충돌 걱정: 날개를 달아준다고 해서 날개 끝에 화살이 맞거나 벽에 끼지는 않습니다. 날개는 그냥 '환영' 같은 것이고, 실제 몸체(히트박스)만 물리 법칙의 영향을 받습니다.
  • 즉, 충돌 처리가 복잡해질 일은 전혀 없습니다.

3. "상태"를 전달하는 방법

법사가 날아갈 때만 날개를 보여주려면, 두 가지가 필요합니다.

  1. 데이터 전송: 법사 엔티티 내부에 "현재 날고 있는가?"라는 정보를 담는 변수(Flag)를 하나 만듭니다. (이미 만드신 isTranscendent 같은 것을 활용할 수 있습니다.)
  2. 렌더러의 판단: 렌더러는 매 순간 법사를 그릴 때 이 변수를 체크합니다.
    • 변수가 true면? -> 법사 몸 그리고 + 그 위에 날개 모델을 겹쳐서 그린다.
    • 변수가 false면? -> 법사 몸만 그린다.

4. 애니메이션 효과

날개가 생기기만 하는 게 아니라, 날아갈 때 날개가 퍼덕거리게 하고 싶을 때도 충돌 걱정은 안 하셔도 됩니다.

  • 모델 데이터에서 날개 부분에 "시간이 흐를 때마다 각도를 조절해라"라는 수식만 넣어두면 됩니다.
  • 이 퍼덕거림 역시 시각적인 효과일 뿐이라 물리 엔진에는 아무런 부담을 주지 않습니다.

요약

  • 상태에 따라 모델을 다르게 그릴 수 있습니다. (보여주기/숨기기 방식)
  • 충돌 처리와는 아무런 상관이 없습니다. 히트박스는 날개가 있든 없든 그대로 유지됩니다.
  • 구현 방법: 법사에게 "비행 상태"라는 체크 표시를 만들고, 렌더러가 그 표시를 보고 날개를 그릴지 말지 결정하게만 하면 됩니다.

이렇게 하면 훨씬 역동적인 법사를 만드실 수 있습니다! 가령 기를 모을 때만 몸 주변에 오라가 생기거나, 체력이 낮아지면 옷이 찢어진 모델로 변하는 식의 연출도 모두 같은 원리입니다.

 

 

 

 

 

 

 

 

 

블록벤치에서 날개를 만들고 움직이게 하는 과정을 논리적인 단계로 설명해 드릴게요.


1. 날개를 어떻게 만드나요? (구조)

결론부터 말씀드리면, "한 쪽을 정성 들여 만든 뒤 복사해서 반대편에 붙이는 방식"이 가장 좋습니다.

  • 그룹(Group) 나누기: 블록벤치에서 왼쪽 날개용 그룹(left_wing)과 오른쪽 날개용 그룹(right_wing)을 각각 만듭니다.
  • 몸체에 종속시키기: 이 두 그룹을 법사의 '몸통(Body)' 그룹 안에 넣습니다. 그래야 법사가 몸을 돌릴 때 날개도 몸에 붙어서 같이 돌아갑니다.
  • 좌우 대칭: 왼쪽 날개를 먼저 다 만든 뒤, 그대로 복사(Duplicate)해서 X축 방향으로 반전(Mirror)시키면 완벽하게 대칭인 오른쪽 날개가 됩니다.

2. 가장 중요한 "피벗 포인트(Pivot Point)" 설정

날개가 자연스럽게 움직이려면 회전축(피벗 포인트) 설정이 제일 중요합니다.

  • 문지방 원리: 날개의 회전축이 날개 한가운데 있으면 날개가 제자리에서 헬리콥터처럼 돕니다.
  • 날개 뿌리: 회전축을 **날개가 등에 붙어 있는 지점(뿌리)**으로 옮겨야 합니다. 그래야 그 축을 중심으로 날개가 위아래로 혹은 앞뒤로 '퍼덕'거릴 수 있습니다.

3. 날개를 어떻게 움직이게 하나요? (애니메이션)

움직임을 만드는 방법은 크게 두 가지가 있습니다.

방법 A: 수학적 수식을 이용한 자동 움직임 (간단함)

코드에서 날개의 각도를 제어하는 부분에 **"사인(Sin) 곡선"**이라는 개념을 사용합니다.

  • 시간이 흐름에 따라 숫자가 -1 -> 0 -> 1 -> 0 -> -1로 반복되게 만듭니다.
  • 그러면 날개가 이 숫자에 맞춰서 자동으로 위아래로 부드럽게 왕복 운동을 하게 됩니다. 별도의 애니메이션 파일 없이 "날고 있을 때만 이 수식을 적용해라"라고 설정하면 됩니다.

방법 B: 블록벤치 애니메이션 기능 사용 (정교함)

블록벤치의 상단 탭 중 'Animate' 모드에서 직접 움직임을 녹화하는 방식입니다.

  1. 0초일 때 날개 위치, 1초일 때 날개가 펴진 위치 등을 키프레임으로 찍습니다.
  2. 이 애니메이션을 wing_flap 같은 이름으로 저장합니다.
  3. 게임 내에서 법사의 상태가 날아오름일 때 이 wing_flap 애니메이션을 재생(Play)하라고 명령합니다.

4. "날 때만 생기게" 하는 논리

날개가 평소엔 없다가 날 때만 나오게 하는 것은 **'투명도'**나 **'그리기 조건'**의 문제입니다.

  • 평상시: 렌더러가 "날개 모델은 그리지 마"라고 무시합니다.
  • 날아오를 때: 법사가 "나 지금 날아!"라고 신호를 주면, 렌더러가 그때부터 날개 모델을 화면에 그리기 시작하고, 위에서 만든 퍼덕이는 움직임을 적용합니다.

요약하자면:

  1. 블록벤치에서 몸통 그룹 안에 좌/우 날개 그룹을 따로 만듭니다.
  2. 날개의 회전축을 등에 붙은 부분으로 옮깁니다.
  3. 사인 함수를 쓰거나 애니메이션 파일을 만들어 퍼덕임을 구현합니다.
  4. 법사의 isTranscendent 상태true일 때만 이 날개가 화면에 보이도록 렌더러에서 설정합니다.

이렇게 하면 충돌 판정은 그대로이면서, 시각적으로만 화려하게 변신하는 법사를 만들 수 있습니다!

 

 

 

 

 

 

 

 

해결된 원리를 코드 없이 직관적으로 설명해 드릴게요.

핵심은 **"검의 '앞'이 어디인지 다시 정의해준 것"**입니다.

1. 180도 뒤로 돌리기 (좌우 회전)

원래 코드는 검의 모델을 가져와서 특정 방향(Yaw)으로 90도만 틀어서 배치하고 있었습니다. 그런데 이 상태가 하필 손잡이가 진행 방향을 향하는 상태였습니다.

  • 수정된 코드에서는 이 각도를 반대 방향으로 180도 돌렸습니다. (수학적으로 +90에서 -90으로 바꾼 것이 한 바퀴의 절반인 180도 차이를 만듭니다.)
  • 이 과정에서 검의 손잡이가 뒤로 가고, 칼날이 앞(바닥 쪽)을 향하게 되었습니다.

2. 기울기 방향 동기화 (상하 회전)

검을 180도 뒤로 돌려놓고 나면, 위아래로 끄덕이는 방향(Pitch)도 반대가 됩니다.

  • 만약 이 부분을 수정하지 않았다면, 검이 아래로 떨어질 때 칼날은 하늘을 향해 꺾였을 것입니다.
  • 그래서 검이 진행 방향에 맞춰 자연스럽게 머리부터 떨어지도록 기울기 값의 부호(+/-)를 반전시켜 칼날의 각도를 떨어지는 궤적에 딱 맞게 정렬한 것입니다.

[참고용 수정 코드 비교]

혹시 나중에 참고하실 수 있도록 바뀐 부분만 표시해 드립니다.

  • 기존 (손잡이 방향):
  • Java
        poseStack.mulPose(Vector3f.YP.rotationDegrees(fYaw + 90.0F)); // 90도 회전
    poseStack.mulPose(Vector3f.XP.rotationDegrees(-fPitch));     // 마이너스 기울기
      
  • 수정후 (칼날 방향):
  • Java
        poseStack.mulPose(Vector3f.YP.rotationDegrees(fYaw - 90.0F)); // 반대편으로 90도 (총 180도 차이)
    poseStack.mulPose(Vector3f.XP.rotationDegrees(fPitch));      // 플러스 기울기로 보정
      

결과적으로 "뒤로 돌린 뒤(Yaw), 그에 맞춰 고개를 숙이게(Pitch)" 해서 해결된 것입니다!