안녕하세요. 인텔리원스튜디오(IntelliOneStudio)입니다.
오늘은 ChatGPT를 활용하여 Unity 플랫포머 게임에서 적을 공격하는 기능을 추가해볼께요.
참고로 공격 처리는 총 3회에 걸쳐 게시될거에요.
제목 | 내용 |
[챗GPT게임개발21] ChatGPT를 활용하여 적 공격 처리 추가하기(1) | OnCollisionEnter2D를 활용한 충동 감지 기능 개발 |
[챗GPT게임개발22] ChatGPT를 활용하여 적 공격 처리 추가하기(2) | OnCollisionEnter2D를 활용한 충동 감지 기능 개발 |
[챗GPT게임개발23] ChatGPT를 활용하여 적 공격 처리 추가하기(3) | Physics2D.OverlapCircleAll을 이용한 충돌 감지 |
[오늘의 목표] OnCollisionEnter2D를 활용한 충동 감지 기능 개발
1. 적을 공격하는 스크립트 개발
2. 실행 결과 살펴 보기
※ ChatGPT 답변 내용 중 제가 별도로 표시한 파란색 내용을 기준으로 읽으시면 좀 더 이해가 쉽게 될거예요.
기존 공격은 어떻게 했을까? : 답은 OnCollisionEnter2D 를 통한 충돌 감지
아래 영상과 같이 기존 Platformer Microgame 에서의 공격은 위로 점프하는 방식이였어요.
위로 점프 후 착지 시 충돌하게 되는 방식이예요.
이런 방식으로 적을 공격하고 스크립트는 OnCollisionEnter2D -> PlayerEnemyCollision 로 순서대로 실행되요.
using System.Collections;
using System.Collections.Generic;
using Platformer.Gameplay;
using UnityEngine;
using static Platformer.Core.Simulation;
namespace Platformer.Mechanics
{
/// <summary>
/// A simple controller for enemies. Provides movement control over a patrol path.
/// </summary>
[RequireComponent(typeof(AnimationController), typeof(Collider2D))]
public class EnemyController : MonoBehaviour
{
public PatrolPath path;
public AudioClip ouch;
internal PatrolPath.Mover mover;
internal AnimationController control;
internal Collider2D _collider;
internal AudioSource _audio;
SpriteRenderer spriteRenderer;
public Bounds Bounds => _collider.bounds;
void Awake()
{
control = GetComponent<AnimationController>();
_collider = GetComponent<Collider2D>();
_audio = GetComponent<AudioSource>();
spriteRenderer = GetComponent<SpriteRenderer>();
}
void OnCollisionEnter2D(Collision2D collision)
{
var player = collision.gameObject.GetComponent<PlayerController>();
if (player != null)
{
var ev = Schedule<PlayerEnemyCollision>();
ev.player = player;
ev.enemy = this;
}
}
void Update()
{
if (path != null)
{
if (mover == null) mover = path.CreateMover(control.maxSpeed * 0.5f);
control.move.x = Mathf.Clamp(mover.Position.x - transform.position.x, -1, 1);
}
}
}
}
그리고 PlayerEnemyCollision은 적의 헬스 상태에 따라 <EnemyDeath>를 처리해요.
using Platformer.Core;
using Platformer.Mechanics;
using Platformer.Model;
using UnityEngine;
using static Platformer.Core.Simulation;
namespace Platformer.Gameplay
{
/// <summary>
/// Fired when a Player collides with an Enemy.
/// </summary>
/// <typeparam name="EnemyCollision"></typeparam>
public class PlayerEnemyCollision : Simulation.Event<PlayerEnemyCollision>
{
public EnemyController enemy;
public PlayerController player;
PlatformerModel model = Simulation.GetModel<PlatformerModel>();
public override void Execute()
{
var willHurtEnemy = player.Bounds.center.y >= enemy.Bounds.max.y;
if (willHurtEnemy)
{
var enemyHealth = enemy.GetComponent<Health>();
if (enemyHealth != null)
{
enemyHealth.Decrement();
if (!enemyHealth.IsAlive)
{
Schedule<EnemyDeath>().enemy = enemy;
player.Bounce(2);
}
else
{
player.Bounce(7);
}
}
else
{
Schedule<EnemyDeath>().enemy = enemy;
player.Bounce(2);
}
}
else
{
Schedule<PlayerDeath>();
}
}
}
}
그래서 먼저 OnCollisionEnter2D를 이용해서,
공격 애니메이션이 동작할 때 적에게 피해를 주는 기능을 추가해봤어요.
[챗GPT게임개발20] ChatGPT를 활용하여 공격 애니메이션 추가하기
OnCollisionEnter2D 활용해서 적에게 피해주기
기존 PlayerEnemyCollision 스크립트를 주고 원하는 기능을 추가해달라고 했어요.
[질문] 안녕 ChatGPT, 다음의 코드에 플레이어가 공격할 때 적에게 피해를 주는 기능을 추가해줘
using Platformer.Core; using Platformer.Mechanics; using Platformer.Model; using UnityEngine; using static Platformer.Core.Simulation; namespace Platformer.Gameplay { /// <summary> /// Fired when a Player collides with an Enemy. /// </summary> /// <typeparam name="EnemyCollision"></typeparam> public class PlayerEnemyCollision : Simulation.Event<PlayerEnemyCollision> { public EnemyController enemy; public PlayerController player; PlatformerModel model = Simulation.GetModel<PlatformerModel>(); public override void Execute() { var willHurtEnemy = player.Bounds.center.y >= enemy.Bounds.max.y; if (willHurtEnemy) { var enemyHealth = enemy.GetComponent<Health>(); if (enemyHealth != null) { enemyHealth.Decrement(); if (!enemyHealth.IsAlive) { Schedule<EnemyDeath>().enemy = enemy; player.Bounce(2); } else { player.Bounce(7); } } else { Schedule<EnemyDeath>().enemy = enemy; player.Bounce(2); } } else { Schedule<PlayerDeath>(); } } } }
[답변]
기존의 PlayerEnemyCollision 클래스 코드를 유지하면서 새로운 기능을 추가하려면, 플레이어의 공격 상태를 검사하여 추가적인 충돌 처리 로직을 실행하는 부분을 삽입해야 합니다. 플레이어가 공격 중일 때 적과 충돌하는 경우를 처리하기 위해 추가적인 조건문과 디버깅 정보를 기존 코드에 통합하겠습니다.
using Platformer.Core; using Platformer.Mechanics; using Platformer.Model; using UnityEngine; using static Platformer.Core.Simulation; namespace Platformer.Gameplay { /// <summary> /// Fired when a Player collides with an Enemy. /// </summary> /// <typeparam name="EnemyCollision"></typeparam> public class PlayerEnemyCollision : Simulation.Event<PlayerEnemyCollision> { public EnemyController enemy; public PlayerController player; PlatformerModel model = Simulation.GetModel<PlatformerModel>(); public override void Execute() { Debug.Log("Collision detected between player and enemy."); if (player.attackState == PlayerController.AttackState.Attacking) { Debug.Log("Player is attacking. Handling attack collision."); HandleAttackCollision(); } else { Debug.Log("Handling regular collision based on player position."); HandleRegularCollision(); } } void HandleAttackCollision() { var enemyHealth = enemy.GetComponent<Health>(); if (enemyHealth != null) { enemyHealth.Decrement(); Debug.Log("Enemy health decremented by player attack."); if (!enemyHealth.IsAlive) { Debug.Log("Enemy has died from player attack."); Schedule<EnemyDeath>().enemy = enemy; player.Bounce(2); } else { Debug.Log("Enemy hurt but still alive; player bounces higher."); player.Bounce(7); } } else { Debug.Log("No Health component found on enemy during attack."); Schedule<EnemyDeath>().enemy = enemy; player.Bounce(2); } } void HandleRegularCollision() { var willHurtEnemy = player.Bounds.center.y >= enemy.Bounds.max.y; if (willHurtEnemy) { Debug.Log("Player is positioned to hurt the enemy."); var enemyHealth = enemy.GetComponent<Health>(); if (enemyHealth != null) { enemyHealth.Decrement(); Debug.Log("Enemy health decremented by player jump attack."); if (!enemyHealth.IsAlive) { Debug.Log("Enemy has died from player jump attack."); Schedule<EnemyDeath>().enemy = enemy; player.Bounce(2); } else { Debug.Log("Enemy hurt by jump attack but still alive."); player.Bounce(7); } } else { Debug.Log("No Health component found on enemy for jump attack."); Schedule<EnemyDeath>().enemy = enemy; player.Bounce(2); } } else { Debug.Log("Player will be hurt and possibly die due to collision."); Schedule<PlayerDeath>(); } } } }
설명
- HandleAttackCollision: 공격 중에 발생한 충돌을 처리합니다. 적의 Health 컴포넌트를 찾아 건강을 감소시키고, 적이 살아있지 않다면 사망 처리를 합니다.
- HandleRegularCollision: 기존 로직을 유지하되, 플레이어의 위치에 따라 적을 다치게 할 수 있는 조건을 검사합니다.
- 디버깅 메시지: 각 처리 단계에서 적절한 디버그 정보를 로그로 출력하여 개발자가 상황을 이해하고 문제를 추적할 수 있도록 합니다.
이 코드를 통해 게임의 다양한 상호작용 상황을 더 잘 관리하고 추적할 수 있습니다.
역시 깔끔하게 잘 만들어주네요.
수정 사항을 저장하고 플레이모드를 실행해서 결과가 잘 나오는 지를 확인했어요.
OnCollisionEnter2D ? 충돌이 생기지 않아요.
플레이어가 공격할 때 아래 영상처럼 적과 충돌이 생기지 않았어요.
원인이 무엇인지 궁금했어요.
챗GPT에게 왜 이런 문제가 생기는 지 물었어요.
[질문] 안녕 ChatGPT, 공격은 애니메이션 클립으로 처리되고 있어. 왜 충돌이 발생하지 않는지 확인해줘
[답변]
공격이 애니메이션으로 구현되어 있으나 실제로 적과의 충돌 이벤트가 발생하지 않는 문제에 대한 해결 방안을 제공해 드리겠습니다. 이는 애니메이션에 의한 시각적인 표현이 있음에도 불구하고 충돌 감지 로직이 제대로 구현되어 있지 않을 가능성이 있습니다. 충돌을 감지하도록 코드를 추가하거나 개선하는 몇 가지 방법을 아래에 설명합니다.
1. 애니메이션 이벤트 사용하기
Unity의 Animator 컴포넌트는 애니메이션 중 특정 시점에 코드를 실행할 수 있는 애니메이션 이벤트 기능을 제공합니다. 공격 애니메이션이 가장 강렬한 순간에 Animation Event를 추가하여 적과의 충돌을 체크하는 메소드를 호출할 수 있습니다.
애니메이션 이벤트 설정
- Unity 에디터에서 Animator 윈도우를 열고 공격 애니메이션 클립을 선택합니다.
- 애니메이션 타임라인에서 적절한 프레임에 마우스 오른쪽 버튼을 클릭하고 Add Event를 선택합니다.
- 추가된 이벤트에서 Function 필드에 호출할 함수 이름을 입력합니다(예: CheckHit)
PlayerController 스크립트에 충돌 검사 메소드 추가
void CheckHit() { // 공격 범위 내에 적이 있는지 검사 Collider2D[] hits = Physics2D.OverlapCircleAll(transform.position, attackRange, enemyLayer); foreach (var hit in hits) { if (hit.gameObject.CompareTag("Enemy")) { Debug.Log("Hit an enemy!"); // 적에게 피해를 주는 로직 var enemyHealth = hit.GetComponent<Health>(); if (enemyHealth != null) { enemyHealth.Decrement(); } } } }
여기서 attackRange는 공격 범위를, enemyLayer는 적 캐릭터가 속한 레이어를 나타냅니다.
2. 트리거를 사용한 충돌 감지
플레이어 캐릭터의 공격 부위에 트리거(Collider2D 컴포넌트의 Is Trigger 옵션 활성화)를 설정하고, 공격 애니메이션 동안 이 트리거를 활성화하여 적과의 충돌을 감지할 수 있습니다.
트리거 활성화 및 비활성화
void StartAttack() { attackTrigger.enabled = true; } void EndAttack() { attackTrigger.enabled = false; }
StartAttack과 EndAttack 메소드는 각각 공격 시작과 끝에서 호출되어야 합니다. 이를 애니메이션 이벤트나 UpdateAttackState 메소드에서 관리할 수 있습니다.3. 물리 엔진 설정 점검
- Rigidbody2D 설정: 플레이어나 적의 Rigidbody2D 설정이 적절한지 확인합니다. 예를 들어, Rigidbody의 Body Type이 Kinematic이면 충돌이 제대로 감지되지 않을 수 있습니다.
- Layer 충돌 매트릭스: Project Settings -> Physics 2D에서 다양한 레이어 간의 충돌 가능성을 확인하고 필요에 따라 조정합니다.
이러한 접근 방법을 통해 애니메이션에 따른 공격 처리가 실제 게임 내에서도 정확히 반영될 수 있도록 조정할 수 있습니다.
동영상에서 자세히 보면 공격 애니메이션이 진행될 때 플레이어의 Collider 영역이 바뀌지 않네요.
플레이어의 Collider 영역이 적의 Collider 영역과 충돌이 되어야 하는데...
이런 문제로 원하는 결과가 나오지 않았어요.
다음 시간에 챗GPT가 알려준 방식에서 애니메이션 이벤트를 사용해서 구현해볼까요.
오늘은 ChatGPT를 활용하여 OnCollisionEnter2D를 활용한 충동 감지 기능 개발을 해봤어요.
원하는 결과가 나오지 않아서 조금 속상하지만,
챗GPT가 개선 방안이라고 알려준 방식으로 수정하면 좋은 결과가 나올 것 같아요.
지금까지,
언제나 성장하는 인텔리원스튜디오(IntelliOneStudio)입니다.
감사합니다.
'디지털노마드' 카테고리의 다른 글
[챗GPT게임개발23] ChatGPT를 활용하여 적 공격 처리 추가하기(3) (55) | 2024.05.12 |
---|---|
[챗GPT게임개발22] ChatGPT를 활용하여 적 공격 처리 추가하기(2) (63) | 2024.05.12 |
[챗GPT게임개발20] ChatGPT를 활용하여 공격 애니메이션 추가하기 (68) | 2024.05.10 |
[챗GPT게임개발19] ChatGPT를 활용하여 가속 패드와 Jiggler 추가하기 (65) | 2024.05.09 |
[챗GPT게임개발18] ChatGPT를 활용하여 트리거와 이벤트 시스템을 활용 (60) | 2024.05.09 |