Unity

3D 테스트 프로젝트 8

psb08 2025. 3. 1. 15:51
728x90
반응형

무기랑 적, 체력까지 만든 뒤, 턴제가 만들어 보고 싶어졌습니다.

 

그럼 먼저 우리 팀과 적이 있어야 할 것이죠

 

Player, Enemy를 만들었습니다.

TeamManager, TurnManager, GameManager도 만들었습니다.

 

오늘은 Player와 Enemy를 설명 하겠습니다.

 

Player.cs

using System.Collections;
using UnityEngine;

public class Player : MonoBehaviour
{
    public string CharacterName;
    public int Health = 100;    
    public int AttackPower = 20;
    public float Speed;
    public float AttackMoveSpeed = 3f;
    private Vector3 originalPosition;

    private void Start()
    {
        originalPosition = transform.position;
    }

    private void Update()
    {
        if (Health <= 0)
            Destroy(gameObject);
    }

    public void Attack(Enemy target)
    {
        if (target != null && target.Health > 0)
        {
            MoveTo(target.transform.position, () =>
            {
                target.Health -= AttackPower;
                Debug.Log($"{CharacterName}가 {target.CharacterName}를 공격했습니다! (남은 체력: {target.Health})");
                MoveTo(originalPosition, null);
            }, AttackMoveSpeed);
        }
    }

    public void MoveTo(Vector3 targetPosition, System.Action onComplete = null, float moveSpeed = 5f)
    {
        StartCoroutine(MoveCoroutine(targetPosition, onComplete, moveSpeed));
    }

    private IEnumerator MoveCoroutine(Vector3 targetPosition, System.Action onComplete, float moveSpeed)
    {
        float journeyLength = Vector3.Distance(transform.position, targetPosition);
        float startTime = Time.time;

        while (Vector3.Distance(transform.position, targetPosition) > 0.1f)
        {
            float distCovered = (Time.time - startTime) * moveSpeed;
            float fractionOfJourney = distCovered / journeyLength;
            transform.position = Vector3.Lerp(transform.position, targetPosition, fractionOfJourney);
            yield return null;
        }

        transform.position = targetPosition;
        onComplete?.Invoke();
    }

}

Player 즉 우리 팀 오브젝트에 사용 할 스크립트 입니다.


public string CharacterName;
public int Health = 100;    
public int AttackPower = 20;
public float Speed;
public float AttackMoveSpeed = 3f;
private Vector3 originalPosition;

순서대로 이름, 체력, 공격력, 공격 할 속도, 공격 할 때의 이동 속도, 원래 포지션입니다.

공격 할 속도란 턴제에서 많이 사용되는 속도의 개념입니다.

 

예시 붕괴 : 스타레일의 속도 바

예시로 붕괴 : 스타레일의 속도 바를 가져 왔습니다.

현재 첫 번째 캐릭터가 제일 위에 있으므로 가장 속도가 빠른 것으로 보입니다.

그 다음으로 속도 순서대로 공격 할 것으로 보이며, 캐릭터 초상화 옆에 숫자는 앞으로 공격까지 남은 수를 뜻합니다.

 

private void Start()
{
    originalPosition = transform.position;
}

private void Update()
{
    if (Health <= 0)
        Destroy(gameObject);
}

시작 시, 현재 위치를 저장합니다. 그리고 만약 체력이 0 보다 작아지면 오브젝트를 파괴합니다.

 

public void Attack(Enemy target)
{
    if (target != null && target.Health > 0)
    {
        MoveTo(target.transform.position, () =>
        {
            target.Health -= AttackPower;
            Debug.Log($"{CharacterName}가 {target.CharacterName}를 공격했습니다! (남은 체력: {target.Health})");
            MoveTo(originalPosition, null);
        }, AttackMoveSpeed);
    }
}

공격 메서드입니다. 타겟이 있고, 체력이 0 보다 크면 공격을 합니다.

상대의 체력이 공격력 만큼 깎이며, 디버그로 확인을 할 수 있습니다.

그 다음 이동을 합니다.

 

public void MoveTo(Vector3 targetPosition, System.Action onComplete = null, float moveSpeed = 5f)
{
    StartCoroutine(MoveCoroutine(targetPosition, onComplete, moveSpeed));
}

private IEnumerator MoveCoroutine(Vector3 targetPosition, System.Action onComplete, float moveSpeed)
{
    float journeyLength = Vector3.Distance(transform.position, targetPosition);
    float startTime = Time.time;

    while (Vector3.Distance(transform.position, targetPosition) > 0.1f)
    {
        float distCovered = (Time.time - startTime) * moveSpeed;
        float fractionOfJourney = distCovered / journeyLength;
        transform.position = Vector3.Lerp(transform.position, targetPosition, fractionOfJourney);
        yield return null;
    }

    transform.position = targetPosition;
    onComplete?.Invoke();
}

MoveTo -> 이동 코루틴을 위한 메서드로 봐도 괜찮습니다.

MoveCoroutine은 간단하게 현재 위치를 저장하고 상대에게 이동한 뒤 다시 돌아오는 메서드입니다.


Enemy.cs

using System.Collections;
using UnityEngine;

public class Enemy : MonoBehaviour
{
    public string CharacterName;
    public int Health = 100;
    public int AttackPower = 15;
    public float Speed;
    public float AttackMoveSpeed = 3f;
    public Transform[] playerTransforms;
    private Vector3 originalPosition;

    private void Start()
    {
        originalPosition = transform.position;
        GameObject[] playerObjects = GameObject.FindGameObjectsWithTag("Player");
        playerTransforms = new Transform[playerObjects.Length];

        for (int i = 0; i < playerObjects.Length; i++)
        {
            playerTransforms[i] = playerObjects[i].transform;
        }
    }

    private void Update()
    {
        if (Health <= 0)
            Destroy(gameObject);
    }

    public void AttackRandomPlayer()
    {
        if (playerTransforms.Length > 0)
        {
            int randomIndex = Random.Range(0, playerTransforms.Length);
            Player target = playerTransforms[randomIndex].GetComponent<Player>();
            if (target != null && target.Health > 0)
            {
                MoveTo(target.transform.position, () =>
                {
                    target.Health -= AttackPower;
                    Debug.Log($"{CharacterName}가 {target.CharacterName}를 공격했습니다! (남은 체력: {target.Health})");
                    MoveTo(originalPosition, null);
                }, AttackMoveSpeed);
            }
        }
    }

    public void MoveTo(Vector3 targetPosition, System.Action onComplete = null, float moveSpeed = 5f)
    {
        StartCoroutine(MoveCoroutine(targetPosition, onComplete, moveSpeed));
    }

    private IEnumerator MoveCoroutine(Vector3 targetPosition, System.Action onComplete, float moveSpeed)
    {
        float journeyLength = Vector3.Distance(transform.position, targetPosition);
        float startTime = Time.time;

        while (Vector3.Distance(transform.position, targetPosition) > 0.1f)
        {
            float distCovered = (Time.time - startTime) * moveSpeed;
            float fractionOfJourney = distCovered / journeyLength;
            transform.position = Vector3.Lerp(transform.position, targetPosition, fractionOfJourney);
            yield return null;
        }

        transform.position = targetPosition;
        onComplete?.Invoke();
    }

}

 

이동하는 코드는 똑같으니 설명하지 않을 것이고, 

 

public string CharacterName;
public int Health = 100;
public int AttackPower = 15;
public float Speed;
public float AttackMoveSpeed = 3f;
public Transform[] playerTransforms;
private Vector3 originalPosition;

private void Start()
{
    originalPosition = transform.position;
    GameObject[] playerObjects = GameObject.FindGameObjectsWithTag("Player");
    playerTransforms = new Transform[playerObjects.Length];

    for (int i = 0; i < playerObjects.Length; i++)
    {
        playerTransforms[i] = playerObjects[i].transform;
    }
}

이름, 체력, 공격력, 속도, 이동 속도, 위치 저장은 같으나, 하나 추가된 점이 있습니다.

바로 우리 팀의 위치입니다.

 

시작 시, Player 태그를 가진 오브젝트를 받아와서 그 길이만큼 저장을 합니다.

 

공격을 위한 작업입니다.

 

public void AttackRandomPlayer()
{
    if (playerTransforms.Length > 0)
    {
        int randomIndex = Random.Range(0, playerTransforms.Length);
        Player target = playerTransforms[randomIndex].GetComponent<Player>();
        if (target != null && target.Health > 0)
        {
            MoveTo(target.transform.position, () =>
            {
                target.Health -= AttackPower;
                Debug.Log($"{CharacterName}가 {target.CharacterName}를 공격했습니다! (남은 체력: {target.Health})");
                MoveTo(originalPosition, null);
            }, AttackMoveSpeed);
        }
    }
}

위치의 길이 만큼 랜덤으로 돌려서 타겟이 있으면 공격을 합니다.

 

 

공격 완성 본입니다.

속도에 따라 공격을 할 수있습니다.

플레이어는 직접 적을 터치하면 공격할 수 있고, 적은 우리 팀 중에서 랜덤으로 공격합니다.

'Unity' 카테고리의 다른 글

3D 테스트 프로젝트 10  (0) 2025.03.03
3D 테스트 프로젝트 9  (0) 2025.03.02
3D 테스트 프로젝트 7  (0) 2025.02.28
3D 테스트 프로젝트 6  (0) 2025.02.27
3D 테스트 프로젝트 5  (0) 2025.02.26