타워 디펜스에서 타워를 철거하는 기능과 한 종류의 타워만 사용을 방지하여 게임의 재미를 올리기 위해 타워 건설의 자원 값에 가중치를 두었음
#철거 기능 구현
#예전에 RepairMode였던 함수를 ManageMode로 수정하고 UI에서 먼저 수리인지 철거인지 정하고 실행
void ManageMode()
{
if (manageMode)
{
if(Input.GetMouseButton(0))
{
Vector3 mousePos = Input.mousePosition;
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
RaycastHit hit;
if(Physics.Raycast(ray, out hit))
{
manageTarget = hit.transform.gameObject;
}
if(manageTarget != null && manageTarget.tag == "Tower")
{
VisualizeStatus();
}
if (manageOn && manageTarget.tag == "Tower")
{
if(manageSelectBuffer == (int)manageSelection.RepairMode)
{
TowerManager targetTowerManager = manageTarget.GetComponent<TowerManager>();
targetTowerManager.hp.healthCheck = targetTowerManager.hp.health;
//자원 감소 코드
//타워 매니저 데미지 타입으로 설정하면 될듯
}
if(manageSelectBuffer == (int)manageSelection.RemoveMode)
{
int targetAttackType = manageTarget.GetComponent<TowerManager>().damageType;
switch(targetAttackType)
{
case (int)towerAttackType.기본:
GameManager.resource += (int)((towerCostAdder[targetAttackType - 1] + 6) * 0.7);
break;
case (int)towerAttackType.밀기:
GameManager.resource += (int)((towerCostAdder[targetAttackType - 1] + 9) * 0.7);
break;
case (int)towerAttackType.광역:
GameManager.resource += (int)((towerCostAdder[targetAttackType - 1] + 18) * 0.7);
break;
case (int)towerAttackType.슬로우:
GameManager.resource += (int)((towerCostAdder[targetAttackType - 1] + 15) * 0.7);
break;
}
GameObject.Destroy(manageTarget);
}
manageOn = false;
}
}
}
}
수리와 철거 중 선택한 이후 철거라면 비용의 70% 반환 후 해당 게임 오브젝트 파괴, 수리라면 체력을 최대 체력으로 설정해주는 코드로 바뀌었다.
#건설 기능
void BuildMode()
{
if(buildMode)
{
switch(choice)
{
case (int)towerList.BasicTower:
buildMode = false;
if (GameManager.resource >= towerCostAdder[choice] + 6)
{
Instantiate(towerObjList[(int)towerList.BasicTower], transform.position, new Quaternion(0, 0, 0, 0));
GameManager.resource -= towerCostAdder[choice] + 6;
towerCostAdder[choice] += 3;
}
choice = -1;
break;
case (int)towerList.PunchTower:
buildMode = false;
if(GameManager.resource >= towerCostAdder[choice] + 15)
{
Instantiate(towerObjList[(int)towerList.PunchTower], transform.position, new Quaternion(0, 0, 0, 0));
GameManager.resource -= towerCostAdder[choice] + 15;
towerCostAdder[choice] += 5;
}
choice = -1;
break;
case (int)towerList.RangeTower:
buildMode = false;
if(GameManager.resource >= towerCostAdder[choice] + 9)
{
Instantiate(towerObjList[(int)towerList.RangeTower], transform.position, new Quaternion(0, 0, 0, 0));
GameManager.resource -= towerCostAdder[choice] + 9;
towerCostAdder[choice] += 4;
}
choice = -1;
break;
case (int)towerList.SlowTower:
buildMode = false;
if (GameManager.resource >= towerCostAdder[choice] + 18)
{
Instantiate(towerObjList[(int)towerList.SlowTower], transform.position, new Quaternion(0, 0, 0, 0));
GameManager.resource -= towerCostAdder[choice] + 18;
towerCostAdder[choice] += 6;
}
choice = -1;
break;
}
}
}
건설 기능은 towerCostAdder라는 배열을 하나 생성하여 해당 배열마다 추가된 값을 가지고 있어서 그 자원을 참고하여 설치가 가능한지 판단하도록 수정하였음
따로 Manage 버튼을 클릭하면 위와 같이 Repair와 Remove중 선택하게 수정하였음
아래는 Player의 전체 소스코드
더보기
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
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;
//피격 관련 필드
public bool canDamaged = true;
float unBeatTime = 1.0f;
Material material;
//Menu 관련 필드
GameObject menuUI;
GameObject selectUI;
GameObject buildUI;
GameObject manageUI;
GameObject manageSelectUI;
bool isEnabledMenuUI;
/*bool isEnabledSelectUI;
bool isEnabledBuildUI;
bool isEnabledRepairUI;*/
public int modeSelect;
public int manageSelect;
int manageSelectBuffer;
public bool buildMode;
public bool manageMode;
enum towerList
{
BasicTower = 0,
PunchTower = 1,
RangeTower = 2,
SlowTower = 3,
}
enum modeSelection
{
NonSelect = -1,
BuildMode = 0,
ManageMode = 1,
}
enum manageSelection
{
NonSelect = -1,
RepairMode = 0,
RemoveMode = 1,
}
enum towerAttackType
{
기본 = 1,
밀기 = 2,
광역 = 3,
슬로우 = 4,
}
[SerializeField]
GameObject[] towerObjList;
public int choice;
public int[] towerCostAdder;
//repair 관련 필드
GameObject manageTarget;
public bool manageOn;
Text lv;
Text attackType;
Text maxHP;
Text curHP;
Text power;
void Start()
{
//Move 필드 초기화
controller = GetComponent<CharacterController>();
moveSpeed = 0.07f;
//Health 필드 초기화
health = GetComponent<Health>();
healthBuffer = health.healthCheck;
//UnBeat에 쓰일 필드 초기화
material = GetComponent<Renderer>().material;
//repair 필드 초기화
manageTarget = null;
manageMode = false;
manageOn = false;
manageSelectBuffer = (int)manageSelection.NonSelect;
lv = GameObject.Find("Lv").GetComponent<Text>();
attackType = GameObject.Find("AttackType").GetComponent<Text>();
maxHP = GameObject.Find("Max").GetComponent<Text>();
curHP = GameObject.Find("Cur").GetComponent<Text>();
power = GameObject.Find("Power").GetComponent<Text>();
//Menu에 쓰일 필드 초기화
menuUI = GameObject.Find("MenuUI");
selectUI = GameObject.Find("SelectUI");
buildUI = GameObject.Find("BuildUI");
manageUI = GameObject.Find("ManageUI");
manageSelectUI = GameObject.Find("ManageSelectUI");
buildUI.SetActive(false);
manageUI.SetActive(false);
selectUI.SetActive(false);
manageSelectUI.SetActive(false);
menuUI.SetActive(false);
isEnabledMenuUI = false;
/*isEnabledSelectUI = true;
isEnabledBuildUI = false;
isEnabledRepairUI = false;*/
modeSelect = -1;
manageSelect = -1;
buildMode = false;
towerCostAdder = new int[4];
}
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는 음수, 양수로 받아 계산
}
//무적 코루틴
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 Menu()
{
if (Input.GetKeyDown(KeyCode.B))
{
if (isEnabledMenuUI)
{
isEnabledMenuUI = false;
buildUI.SetActive(false);
manageUI.SetActive(false);
selectUI.SetActive(false);
manageSelectUI.SetActive(false);
menuUI.SetActive(false);
manageTarget = null;
manageMode = false;
modeSelect = (int)modeSelection.NonSelect;
manageSelectBuffer = (int)manageSelection.NonSelect;
}
else
{
isEnabledMenuUI = true;
menuUI.SetActive(true);
selectUI.SetActive(true);
}
}
if(modeSelect == (int)modeSelection.BuildMode)
{
buildUI.SetActive(true);
selectUI.SetActive(false);
modeSelect = (int)modeSelection.NonSelect;
}
if(modeSelect == (int)modeSelection.ManageMode)
{
selectUI.SetActive(false);
manageSelectUI.SetActive(true);
if(manageSelect != (int)manageSelection.NonSelect)
{
manageSelectUI.SetActive(false);
manageUI.SetActive(true);
manageMode = true;
modeSelect = (int)modeSelection.NonSelect;
manageSelectBuffer = manageSelect;
manageSelect = (int)manageSelection.NonSelect;
}
}
}
void BuildMode()
{
if(buildMode)
{
switch(choice)
{
case (int)towerList.BasicTower:
buildMode = false;
if (GameManager.resource >= towerCostAdder[choice] + 6)
{
Instantiate(towerObjList[(int)towerList.BasicTower], transform.position, new Quaternion(0, 0, 0, 0));
GameManager.resource -= towerCostAdder[choice] + 6;
towerCostAdder[choice] += 3;
}
choice = -1;
break;
case (int)towerList.PunchTower:
buildMode = false;
if(GameManager.resource >= towerCostAdder[choice] + 15)
{
Instantiate(towerObjList[(int)towerList.PunchTower], transform.position, new Quaternion(0, 0, 0, 0));
GameManager.resource -= towerCostAdder[choice] + 15;
towerCostAdder[choice] += 5;
}
choice = -1;
break;
case (int)towerList.RangeTower:
buildMode = false;
if(GameManager.resource >= towerCostAdder[choice] + 9)
{
Instantiate(towerObjList[(int)towerList.RangeTower], transform.position, new Quaternion(0, 0, 0, 0));
GameManager.resource -= towerCostAdder[choice] + 9;
towerCostAdder[choice] += 4;
}
choice = -1;
break;
case (int)towerList.SlowTower:
buildMode = false;
if (GameManager.resource >= towerCostAdder[choice] + 18)
{
Instantiate(towerObjList[(int)towerList.SlowTower], transform.position, new Quaternion(0, 0, 0, 0));
GameManager.resource -= towerCostAdder[choice] + 18;
towerCostAdder[choice] += 6;
}
choice = -1;
break;
}
}
}
void VisualizeStatus()
{
TowerManager targetTowerManager = manageTarget.GetComponent<TowerManager>();
int targetCurHP = targetTowerManager.hp.health;
int targetMaxHP = targetTowerManager.hp.healthCheck;
int targetPower = targetTowerManager.damage;
int targetAttackType = targetTowerManager.damageType;
int targetLv = targetTowerManager.towerLevel;
lv.text = targetLv.ToString();
curHP.text = targetCurHP.ToString();
maxHP.text = targetMaxHP.ToString();
power.text = targetPower.ToString();
switch(targetAttackType)
{
case (int)towerAttackType.기본:
attackType.text = "기본";
break;
case (int)towerAttackType.밀기:
attackType.text = "밀기";
break;
case (int)towerAttackType.광역:
attackType.text = "광역";
break;
case (int)towerAttackType.슬로우:
attackType.text = "슬로우";
break;
}
if(manageOn)
{
}
}
void ManageMode()
{
if (manageMode)
{
if(Input.GetMouseButton(0))
{
Vector3 mousePos = Input.mousePosition;
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
RaycastHit hit;
if(Physics.Raycast(ray, out hit))
{
manageTarget = hit.transform.gameObject;
}
if(manageTarget != null && manageTarget.tag == "Tower")
{
VisualizeStatus();
}
if (manageOn && manageTarget.tag == "Tower")
{
if(manageSelectBuffer == (int)manageSelection.RepairMode)
{
TowerManager targetTowerManager = manageTarget.GetComponent<TowerManager>();
targetTowerManager.hp.healthCheck = targetTowerManager.hp.health;
//자원 감소 코드
//타워 매니저 데미지 타입으로 설정하면 될듯
}
if(manageSelectBuffer == (int)manageSelection.RemoveMode)
{
int targetAttackType = manageTarget.GetComponent<TowerManager>().damageType;
switch(targetAttackType)
{
case (int)towerAttackType.기본:
GameManager.resource += (int)((towerCostAdder[targetAttackType - 1] + 6) * 0.7);
break;
case (int)towerAttackType.밀기:
GameManager.resource += (int)((towerCostAdder[targetAttackType - 1] + 9) * 0.7);
break;
case (int)towerAttackType.광역:
GameManager.resource += (int)((towerCostAdder[targetAttackType - 1] + 18) * 0.7);
break;
case (int)towerAttackType.슬로우:
GameManager.resource += (int)((towerCostAdder[targetAttackType - 1] + 15) * 0.7);
break;
}
GameObject.Destroy(manageTarget);
}
manageOn = false;
}
}
}
}
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();
Menu();
BuildMode();
ManageMode();
}
void LateUpdate()
{
//체력이 변했는지 체크
if(healthBuffer != health.healthCheck)
{
//체력 변환 체크값을 현재 체력으로 바꿔줌
healthBuffer = health.healthCheck;
StartCoroutine("UnBeat");
}
}
}
'Unity' 카테고리의 다른 글
[TowerDefence] 타워 디펜스 게임 마무리 및 코드 정리 (0) | 2023.04.17 |
---|---|
[턴제 생존 게임] We Mustn't Die Here (0) | 2023.04.14 |
[타워디펜스] 몹 스포너(Spawner)와 웨이브(Wave) (0) | 2023.01.16 |
[타워디펜스] 메뉴UI와 자기장 (0) | 2023.01.13 |
[타워 디펜스] 플레이어 만들기 (0) | 2022.12.30 |