저번에 이어서 오버워치2 게임 요소를 간단하게나마 구현해보도록 하겠다. 저번 포스트에서 구상해봤던 Ally 회복 시스템, 데미지 이펙트 및 애니메이션, 투사체 조준 시스템 등을 구현해볼 생각이다.
UI > Image를 생성, Crosshair라고 지정한다.Crosshair에 에셋 스토어에서 받은 이미지를 넣었다.Crosshair.cs 스크립트를 작성한다.public class Crosshair : MonoBehaviour
{
void Start()
{
}
void Update()
{
Vector2 mousePos = Input.mousePosition;
transform.position = mousePos;
}
}
void Start()
{
Cursor.visible = false;
}
Shooter.cs에서 Space bar 입력을 좌클릭(Input.GetMouseButtonDown(0))으로 변경한다. void Update()
{
if (Input.GetMouseButtonDown(0)) << 마우스 좌클릭
{
Fire();
}
}
Vector3 mouseWorldPos = Camera.main.ScreenToWorldPoint(Input.mousePosition);
mouseWorldPos.z = 0f;
Vector3 direction = (mouseWorldPos - transform.position).normalized;
rb.AddForce(direction * shootForce, ForceMode2D.Impulse);

다음으로 투사체를 아군이 맞았을 때, 아군을 회복시켜주는 스크립트를 추가해보겠다.
Ally.cs에 heal()함수를 추가했으므로, bullet.cs에서 이를 가져오기만 하면 된다.bullet.cs에서 Ally의 체력이 가득 차있을 경우 관통하는 기능을 이미 넣어놨기 때문에, bullet.cs에서 healAmount값을 설정하고 이를 구현하기만 하면 된다. public int healAmount = 1;
ally의 hp가 가득 차있지 않을 경우 ally를 회복한다. if (ally.hp < ally.maxHp)
{
ally.Heal(healAmount);
Destroy(gameObject);
}

Enemy가 공격을 하고, 공격을 Ally가 맞았을 때 Ally의 체력이 닳는 시스템을 구현하고자 한다.Ally.cs에 Takedamage()함수를 추가한다. public void TakeDamage(int amount)
{
hp -= amount;
if (hp < 0)
{
hp = 0;
}
if (hp <= 0)
{
Destroy(gameObject);
}
}
bullet.cs에 적에게서 발사된 투사체인지 플레이어에게서 발사된 투사체인지를 판별하는 기능을 추가한다. public bool isFromEnemy = false;
isFromEnemy라는 bool을 선언한다.Ally는 damage를 입는다. if (isFromEnemy && collision.CompareTag("Ally"))
{
Ally ally = collision.GetComponent<Ally>();
if (ally != null)
{
ally.TakeDamage(damage);
Destroy(gameObject);
}
}
Enemy는 damage를 입는다. else if (!isFromEnemy && collision.CompareTag("Enemy"))
{
Enemy enemy = collision.GetComponent<Enemy>();
if (enemy != null)
{
enemy.OnHit(this);
Destroy(gameObject);
}
}
Ally는 heal이 된다. else if (!isFromEnemy && collision.CompareTag("Ally"))
{
Ally ally = collision.GetComponent<Ally>();
if (ally != null && ally.hp < ally.maxHp)
{
ally.Heal(healAmount);
Destroy(gameObject);
}
}
Enemy.cs에 공격 기능을 추가한다.Enemy.cs에 발사할 총알 프리팹을 가져오고, 공격 주기와 발사 속도를 지정한다. public GameObject bulletPrefab;
public float attackInterval = 2f;
public float shootForce = 10f;
fire()함수를 추가한다. Enemy오브젝트의 위치를 불러와서, 발사 위치를 지정한다. void Fire()
{
Vector3 spawnPos = transform.position;
GameObject bullet = Instantiate(bulletPrefab, spawnPos, Quaternion.identity);
Vector2 direction = Vector2.left;
Rigidbody2D rb = bullet.GetComponent<Rigidbody2D>();
rb.AddForce(direction * shootForce, ForceMode2D.Impulse);
Bullet.cs에서 이 총알이 Enemy로부터 왔음을 판별하도록 한다. Bullet bulletScript = bullet.GetComponent<Bullet>();
if (bulletScript != null)
{
bulletScript.isFromEnemy = true;
}
}
Enemy 오브젝트에서 투사체는 발사됐지만, Ally오브젝트와 충돌했을 때 Ally의 체력이 닳지 않았다. 디버그를 위해 코드를 추가해서 확인해보았다. Debug.Log("적 총알이 아군에 명중!");

Ally.cs를 확인해보았다. public void Heal(int amount)
{
hp = Mathf.Min(hp + amount, maxHp);
if (hpSlider != null)
{
hpSlider.value = hp;
}
}
heal()함수에는 hpSlider값을 갱신하는 코드가 있지만, TakeDamage()함수에는 존재하지 않았다. public void TakeDamage(int amount)
{
hp -= amount;
if (hp < 0)
{
hp = 0;
}
if (hp <= 0)
{
Destroy(gameObject);
}
}
hpSlider값을 hp에 맞게 갱신해주었다. if (hpSlider != null)
{
hpSlider.value = hp;
}
결과를 확인해보았다.

Bullet이 Ally에게 맞을 경우와 Enemy에게 맞을 경우를 구분하고, Player에게서 발사될 경우, Enemy에게서 발사될 경우에 따라 작용되는 효과가 다르도록 구현이 되었다.
Bullet이 Enemy나 Ally에 충돌하면 피격 이펙트를 재생하고자 한다.
먼저, 에셋 스토어에서 적절한 Effects를 다운로드했다.
다음으로 Bullet.cs에 이펙트 생성 코드를 추가하였다.
public GameObject hitEffectPrefab;
void OnTriggerEnter2D(Collider2D collision)
{
{
if (collision.CompareTag("Enemy") || collision.CompareTag("Ally"))
{
if (hitEffectPrefab != null)
{
GameObject effect = Instantiate(hitEffectPrefab, transform.position, Quaternion.identity);
Destroy(effect, 0.3f);
}
}
}

C#이나 Unity 사전 강의에서 배웠던 내용들이 굉장히 많이 사용된다. 모르는 것들은 구글링해가며 구현해나가고 있는데, 오류가 생길 때마다 많이 당황하게 되는 것 같다. 또, 스크립트들을 단순화할 수 있는 방법이 분명 있을 것 같은데, 이를 알아내는 눈이 아직 많이 부족한 것 같다. 반복 연습을 통해 그런 능력을 길러야겠다는 생각이 든다.