플레이어, UI에 관한 코드를 조금 수정하고 자기장 역할을 하는 독지대를 만들었음
저번엔 건물을 세우는 UI와 상호작용만 사용했다면 이번엔 메인메뉴 UI와 수리 UI, 건설UI로 분리함
그리고 플레이어의 체력을 100으로 설정하고 SerializeField로 유니티에서 볼 수 있게 설정함
다음은 수정한 코드다
//Player 수정한 부분 중 일부만 나와있는 코드
void Menu()
{
if (Input.GetKeyDown(KeyCode.B))
{
if (isEnabledMenuUI)
{
isEnabledMenuUI = false;
buildUI.SetActive(false);
repairUI.SetActive(false);
selectUI.SetActive(false);
menuUI.SetActive(false);
repairTarget = null;
repairMode = false;
}
else
{
isEnabledMenuUI = true;
menuUI.SetActive(true);
selectUI.SetActive(true);
}
}
if(modeSelect == (int)modeSelection.BuildMode)
{
buildUI.SetActive(true);
selectUI.SetActive(false);
modeSelect = (int)modeSelection.NonSelcet;
}
if(modeSelect == (int)modeSelection.RepairMode)
{
repairUI.SetActive(true);
selectUI.SetActive(false);
repairMode = true;
modeSelect = (int)modeSelection.NonSelcet;
}
}
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 VisualizeStatus()
{
TowerManager targetTowerManager = repairTarget.GetComponent<TowerManager>();
int targetCurHP = targetTowerManager.hp.health;
int targetMaxHP = targetTowerManager.hp.healthCheck;
int targetPower = targetTowerManager.damage;
int targetAttackType = targetTowerManager.damageType;
curHP.text = targetCurHP.ToString();
maxHP.text = targetMaxHP.ToString();
power.text = targetPower.ToString();
attackType.text = targetAttackType.ToString();
if(repairOn)
{
}
}
void RepairMode()
{
if (repairMode)
{
if(Input.GetMouseButton(0))
{
Vector3 mousePos = Input.mousePosition;
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
RaycastHit hit;
if(Physics.Raycast(ray, out hit))
{
repairTarget = hit.transform.gameObject;
}
if(repairTarget != null && repairTarget.tag == "Tower")
{
VisualizeStatus();
}
if (repairOn && repairTarget.tag == "Tower")
{
TowerManager targetTowerManager = repairTarget.GetComponent<TowerManager>();
targetTowerManager.hp.healthCheck = targetTowerManager.hp.health;
//자원 감소 코드
repairOn = false;
}
}
}
}
수정된 부분의 설명은 Menu코드는 UI들을 버튼에 따라 키고 끄는 방식이다
현재 코드에서는 B버튼으로 메인메뉴를 열고 마우스로 UI버튼을 눌러 이동하는 방식이다
그리고 누르는 UI에 따라 활성 UI를 바꿔준다.
그리고 BuildMode 코드는 towerList에 들어가있는 것에 따라 타워를 생성한다.
VisualizeStatus 코드는 Repair 코드에서 타워의 상태를 보여주기 위한 코드이다.
RepairMode에서는 마우스 버튼을 눌렀을 때 Ray를 발생시켜 부딪힌 물체의 정보를 가져와 그 물체의 tag가 Tower라면 정보를 보여주고 Repair 버튼이 눌렸다면 수리를 해주는 코드이다.
플레이어의 전체 코드를 보고 싶다면 아래를 확인하면 된다
더보기
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;
[SerializeField]
int playerHealth;
[SerializeField]
int playerHealthCheck;
//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 repairUI;
bool isEnabledMenuUI;
/*bool isEnabledSelectUI;
bool isEnabledBuildUI;
bool isEnabledRepairUI;*/
public int modeSelect;
public bool buildMode;
public bool repairMode;
enum towerList
{
BasicTower = 0,
PunchTower = 1,
LaserTower = 2
}
enum modeSelection
{
NonSelcet = -1,
BuildMode = 0,
RepairMode = 1,
}
[SerializeField]
GameObject[] towerObjList;
public int choice;
//repair 관련 필드
GameObject repairTarget;
public bool repairOn;
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;
playerHealth = health.health = 100;
playerHealthCheck = health.healthCheck = 100;
//UnBeat에 쓰일 필드 초기화
material = GetComponent<Renderer>().material;
//repair 필드 초기화
repairTarget = null;
repairMode = false;
repairOn = false;
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");
repairUI = GameObject.Find("RepairUI");
buildUI.SetActive(false);
repairUI.SetActive(false);
selectUI.SetActive(false);
menuUI.SetActive(false);
isEnabledMenuUI = false;
/*isEnabledSelectUI = true;
isEnabledBuildUI = false;
isEnabledRepairUI = false;*/
modeSelect = -1;
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는 음수, 양수로 받아 계산
}
//무적 코루틴
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);
repairUI.SetActive(false);
selectUI.SetActive(false);
menuUI.SetActive(false);
repairTarget = null;
repairMode = false;
}
else
{
isEnabledMenuUI = true;
menuUI.SetActive(true);
selectUI.SetActive(true);
}
}
if(modeSelect == (int)modeSelection.BuildMode)
{
buildUI.SetActive(true);
selectUI.SetActive(false);
modeSelect = (int)modeSelection.NonSelcet;
}
if(modeSelect == (int)modeSelection.RepairMode)
{
repairUI.SetActive(true);
selectUI.SetActive(false);
repairMode = true;
modeSelect = (int)modeSelection.NonSelcet;
}
}
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 VisualizeStatus()
{
TowerManager targetTowerManager = repairTarget.GetComponent<TowerManager>();
int targetCurHP = targetTowerManager.hp.health;
int targetMaxHP = targetTowerManager.hp.healthCheck;
int targetPower = targetTowerManager.damage;
int targetAttackType = targetTowerManager.damageType;
curHP.text = targetCurHP.ToString();
maxHP.text = targetMaxHP.ToString();
power.text = targetPower.ToString();
attackType.text = targetAttackType.ToString();
if(repairOn)
{
}
}
void RepairMode()
{
if (repairMode)
{
if(Input.GetMouseButton(0))
{
Vector3 mousePos = Input.mousePosition;
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
RaycastHit hit;
if(Physics.Raycast(ray, out hit))
{
repairTarget = hit.transform.gameObject;
}
if(repairTarget != null && repairTarget.tag == "Tower")
{
VisualizeStatus();
}
if (repairOn && repairTarget.tag == "Tower")
{
TowerManager targetTowerManager = repairTarget.GetComponent<TowerManager>();
targetTowerManager.hp.healthCheck = targetTowerManager.hp.health;
//자원 감소 코드
repairOn = 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();
RepairMode();
}
void LateUpdate()
{
//체력이 변했는지 체크
if(healthBuffer != health.healthCheck)
{
//체력 변환 체크값을 현재 체력으로 바꿔줌
healthBuffer = health.healthCheck;
StartCoroutine("UnBeat");
}
}
}
다음은 메뉴와 건설에 관한 스크립트이다
//Menu
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Menu : MonoBehaviour
{
Player player;
void Start()
{
player = GameObject.Find("Player").GetComponent<Player>();
}
public void BuildMenu()
{
player.modeSelect = 0;
}
public void RepairMenu()
{
player.modeSelect = 1;
}
public void Repair()
{
player.repairOn = true;
}
}
//Build
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;
}
}
이 스크립트들은 UI 버튼을 활용하여 사용하였기 때문에 코드가 간단하다
다음은 자기장 역할을 하는 독이다.
플레이어의 위치로 조금씩 이동하며 x축과 z축 방향으로만 커지는 독이다.
//Posion
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Posion : MonoBehaviour
{
GameObject objPlayer;
Player player;
float moveSpeed = 0.2f;
float growSpeed = 0.005f;
int posionDamage = -5;
// Start is called before the first frame update
void Start()
{
objPlayer = GameObject.Find("Player");
player = objPlayer.GetComponent<Player>();
}
void PosionMove()
{
Vector3 playerPos = new Vector3(objPlayer.transform.position.x, 1, objPlayer.transform.position.z);
transform.position = Vector3.MoveTowards(transform.position, playerPos, Time.deltaTime * moveSpeed);
}
void PosionGrow()
{
transform.localScale = new Vector3(transform.localScale.x + growSpeed, 1, transform.localScale.z + growSpeed); ;
}
private void OnTriggerStay(Collider other)
{
if(other.tag == "Player" && player.canDamaged)
{
player.canDamaged = false;
player.ManageHP(posionDamage);
}
}
// Update is called once per frame
void Update()
{
PosionMove();
PosionGrow();
}
}
다음은 이번에 추가된 기능을 녹화하여 올린 것이다.
'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 |
[타워 디펜스] 플레이어 만들기 (0) | 2022.12.30 |