만들기 시작한지는 좀 되었지만 이제와서 윤곽이 잡혀서 올림
만들고자 하는 타워 디펜스의 아이디어들
굳이 비슷한 게임을 찾자면 몬스터 아웃브레이크와 비슷하다고 생각함
팀 프로젝트로 맡은 부분이 플레이어 부분이기 때문에 플레이어에 대해서만 다룰 것임
플레이어의 기능은 위의 기능과 이동이 있음
아래는 여태껏 구현해온 코드임
//Player.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Player : MonoBehaviour
{
//IMove 관련 필드
float moveSpeed;
Vector3 inputDir;
Vector3 moveDir;
CharacterController controller;
//Health 관련 필드
Health health;
int healthBuffer;
//Pick 관련 필드
GameObject Hand = null;
float standardDistance = 1.2f;
//피격 관련 필드
bool canDamaged = true;
float unBeatTime = 1.0f;
Material material;
//Build 관련 필드
GameObject buildUI;
bool isEnabledUI;
public bool buildMode;
enum towerList
{
BasicTower = 0,
PunchTower = 1,
LaserTower = 2
}
[SerializeField]
GameObject[] towerObjList;
public int choice;
void Start()
{
//Move 필드 초기화
controller = GetComponent<CharacterController>();
moveSpeed = 0.07f;
//Health 필드 초기화
health = GetComponent<Health>();
healthBuffer = health.healthCheck;
//UnBeat에 쓰일 필드 초기화
material = GetComponent<Renderer>().material;
//Build에 쓰일 필드 초기화
buildUI = GameObject.Find("BuildUI");
buildUI.SetActive(false);
isEnabledUI = false;
buildMode = false;
}
void Pick()
{
//플레이어 안에 게임 오브젝트를 하나 둠
//주울 수 있는 오브젝트 List인 PickList 안에 있는 물체에서 제일 가까운 물체의 거리와 Target 오브젝트를 찾음
float closeDistance = float.PositiveInfinity;
GameObject Target = null;
//손에 들고 있지 않은 경우
if(Hand == null)
{
/*foreach (GameObject i in GameManager.PickList)
//distance에 값을 두기
{
//PickList에 있는 물체들로 거리 측정 반복문
Vector3 targetPos = i.transform.position;
Vector3 playerPos = this.transform.position;
float nowDistacne = Vector3.Magnitude(playerPos - targetPos);
if (closeDistance > nowDistacne)
{
closeDistance = nowDistacne;
Target = i;
}
}*/
//PickList 사용 안한 충돌 물체 구하기
//기준 거리 내에 있는 Collider 추출해서 목록에 넣기
Collider[] collider = Physics.OverlapSphere(this.transform.position, standardDistance);
foreach(Collider i in collider)
{
Vector3 targetPos = i.gameObject.transform.position;
Vector3 playerPos = this.transform.position;
float nowDistacne = Vector3.Magnitude(playerPos - targetPos);
if (closeDistance > nowDistacne && (i.gameObject.tag =="Tower"||i.gameObject.tag =="Resource"))
{
closeDistance = nowDistacne;
Target = i.gameObject;
}
}
//collider가 IsTrigger든 아니든 줍고 내려놓을 수 있음, 단 플레이어의 위치에 내려놓는다면
//Trigger가 아닐시 플레이어가 움직일시 밀릴 수 있음
//기준 거리 안에 있다면(주울 수 있는 거리라면)
if(closeDistance <= standardDistance)
{
//Target의 이름별로 실행
if (Target.tag == "Tower")
{
Hand = Target;
Hand.transform.SetParent(this.transform);
Hand.SetActive(false);
//renderer가 자식한테도 있어서 타워가 포신이 안지워짐(그거까지 넣기)
/*TowerAttackType HandScript = Hand.GetComponentInChildren<TowerAttackType>();
TowerManager HandScript2 = Hand.GetComponentInChildren<TowerManager>();
HandScript.enabled = false;
HandScript2.enabled = false;
Renderer Handrenderer = Hand.GetComponent<Renderer>();
Handrenderer.enabled = false;*/
//오브젝트 콜라이더 제외 비활성화
//상속
}
else if (Target.tag == "Resource")
{
GameManager.resource++;
//GameManager.PickList.Remove(Target);
Destroy(Target);
//자원 추가
}
}
else
{
//기준 거리 밖에 있다면
//거리가 멀다고 메세지 띄우기?
}
}
else
{
//물체를 들고 있는 경우(들 수 있는 물체가 타워만 우선 구현)
//타워 내려놓기, 설치방법에 따라 함수호출
//임시로 플레이어 위치에 내려놓기로 설정
Hand.transform.position = this.transform.position;
Hand.SetActive(true);
/*TowerAttackType HandScript = Hand.GetComponentInChildren<TowerAttackType>();
TowerManager HandScript2 = Hand.GetComponentInChildren<TowerManager>();
HandScript.enabled = true;
HandScript2.enabled = true;
Renderer Handrenderer = Hand.GetComponent<Renderer>();
Handrenderer.enabled = true;*/
Hand.transform.SetParent(null);
Hand = null;
}
}
void OnPick()
{
//space가 눌리면 Pick 함수 실행
if (Input.GetKeyDown(KeyCode.Space))
{
Pick();
}
}
public void ManageHP(int amount)
{
health.healthCheck += amount;
// amount는 음수, 양수로 받아 계산
}
private void OnTriggerStay(Collider collider)
{
//체력 깎는거 Enemy에서 공격력 수치만 불러올 수 있게 설정
if(canDamaged && collider.name == "Enemy")
{
canDamaged = false;
Debug.Log("Hit");
health.healthCheck--;
}
else
{
return;
}
}
//무적 코루틴
IEnumerator UnBeat()
{
int blinkTime = (int)(unBeatTime/0.25f);
for(int i = 0; i < blinkTime; i++)
{
if(i%2 == 0)
{
material.color = new Color32(255, 100, 0, 255);
}
else
{
material.color = new Color32(255, 142, 0, 255);
}
yield return new WaitForSeconds(0.25f);
}
material.color = new Color32(255, 142, 0, 255);
canDamaged = true;
yield return null;
}
void RepairMenu()
{
//혹은 한번에 1씩 수리
//타워 스크립트 안에서 인수를 만들거나 체력 인수로 조합하여 필요 자원값 설정 필요
if (Input.GetKeyDown(KeyCode.R))
{
if (isEnabledUI)
{
isEnabledUI = false;
buildUI.SetActive(false);
}
else
{
isEnabledUI = true;
buildUI.SetActive(true);
}
}
}
void BuildMenu()
{
if(Input.GetKeyDown(KeyCode.B))
{
if(isEnabledUI)
{
isEnabledUI = false;
buildUI.SetActive(false);
}
else
{
isEnabledUI = true;
buildUI.SetActive(true);
}
}
}
void BuildMode()
{
if(buildMode)
{
switch(choice)
{
case (int)towerList.BasicTower:
buildMode = false;
Instantiate(towerObjList[(int)towerList.BasicTower],transform.position,new Quaternion(0, 0, 0, 0));
choice = -1;
break;
case (int)towerList.PunchTower:
buildMode = false;
Instantiate(towerObjList[(int)towerList.PunchTower], transform.position, new Quaternion(0, 0, 0, 0));
choice = -1;
break;
case (int)towerList.LaserTower:
buildMode = false;
Instantiate(towerObjList[(int)towerList.LaserTower], transform.position, new Quaternion(0, 0, 0, 0));
choice = -1;
break;
}
}
}
void Move()
{
inputDir = Vector3.zero;
if (Input.GetKey(KeyCode.A)) inputDir += Vector3.left;
if (Input.GetKey(KeyCode.D)) inputDir += Vector3.right;
if (Input.GetKey(KeyCode.S)) inputDir += Vector3.back;
if (Input.GetKey(KeyCode.W)) inputDir += Vector3.forward;
inputDir.Normalize();
moveDir = Vector3.MoveTowards(moveDir, inputDir, Time.deltaTime * 5);
controller.Move(moveDir * moveSpeed);
}
void Update()
{
Move();
OnPick();
BuildMenu();
BuildMode();
}
void LateUpdate()
{
//체력이 변했는지 체크
if(healthBuffer != health.healthCheck)
{
//체력 변환 체크값을 현재 체력으로 바꿔줌
healthBuffer = health.healthCheck;
StartCoroutine("UnBeat");
}
}
}
현재 플레이어의 이동, 무적, 타워의 이동과 건설까지는 구현이 되었음
다음은 이와 연관되는 UI에 들어가는 스크립트임
버튼을 누르면 동작하게 간단히 구현하였음
//Build.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Build : MonoBehaviour
{
Player player;
void Start()
{
player = GameObject.Find("Player").GetComponent<Player>();
}
public void BuildBasic()
{
IsBuildMode();
player.choice = 0;
}
public void BuildPunch()
{
IsBuildMode();
player.choice = 1;
}
public void BuildLaser()
{
IsBuildMode();
player.choice = 2;
}
void IsBuildMode()
{
player.buildMode = true;
}
}
버튼에 따라 타워의 종류를 0~2로 주고 enum으로 player 안에서는 타워의 종류를 개발자가 알기 쉽게 만듦
아래는 구현된 현재 상황을 동영상으로 찍어봄
'Unity' 카테고리의 다른 글
[TowerDefence] 타워 디펜스 게임 마무리 및 코드 정리 (0) | 2023.04.17 |
---|---|
[턴제 생존 게임] We Mustn't Die Here (0) | 2023.04.14 |
[타워디펜스] 타워 철거기능 구현 (0) | 2023.02.03 |
[타워디펜스] 몹 스포너(Spawner)와 웨이브(Wave) (0) | 2023.01.16 |
[타워디펜스] 메뉴UI와 자기장 (0) | 2023.01.13 |