코딩inf
#5 적 이동 스크립트 구현 / 타워설치(돈 감소) (6/24) 본문
일단 스크립트 이다.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Enemy : MonoBehaviour
{
public Transform[] waypoints;
public Transform targetWaypoint;
public int targetWaypointIndex = 0;
public float minDistance = 0.001f;
public float movementSpeed = 3.0f;
public float rotationSpeed = 1.0f;
// Start is called before the first frame update
void Start()
{
targetWaypoint = waypoints[targetWaypointIndex];
}
// Update is called once per frame
void Update()
{
float movementStep = movementSpeed * Time.deltaTime;
float rotationStep = rotationSpeed * Time.deltaTime;
Vector3 directionToTarget = targetWaypoint.position - transform.position;
Quaternion rotationToTarget = Quaternion.LookRotation(directionToTarget);
transform.rotation = rotationToTarget;
float distance = Vector3.Distance(transform.position, targetWaypoint.position);
CheckDistanceToWayPoint(distance);
transform.position = Vector3.MoveTowards(transform.position, targetWaypoint.position, movementStep);
}
void CheckDistanceToWayPoint(float currentDistance)
{
if(currentDistance <= minDistance && waypoints.Length < targetWaypointIndex)
{
targetWaypointIndex++;
UpdateTargetWaypoint();
}
}
void UpdateTargetWaypoint()
{
targetWaypoint = waypoints[targetWaypointIndex];
}
}
public Transform[] waypoints;
적이 이동할 다음 위치를 정해두는 transform 배열 입니다.
public Transform targetWaypoint;
현재 적이 목표로 두고 있는 위치의 정보를 저장하는 변수 입니다.
public int targetWaypointIndex = 0;
목표 위치의 순서를 컨트롤 하는 정수형 변수 입니다.
public float minDistance = 0.001f;
현재 목표 위치와의 거리가 최소 거리(0.001)보다 작으면 도착했다라고 판별하는 변수 입니다.
public float movementSpeed = 3.0f;
적의 속도를 저장하는 변수 입니다.
public float rotationSpeed = 1.0f;
적의 회전 속도를 저장하는 변수 입니다.
void Start()
{
targetWaypoint = waypoints[targetWaypointIndex];
}
여기부터는 update함수이다.
목표 좌표를 다음 위치를 정하는 배열[targetWaypoint(0)]으로 지정
float movementStep = movementSpeed * Time.deltaTime;
float rotationStep = rotationSpeed * Time.deltaTime;
이동속도와 회전속도에 델타 타임을 곱해서 프레임당이 아닌
초당으로 계산해 공정하게 플레이 할 수 있도록 설정했습니다.
Vector3 directionToTarget = targetWaypoint.position - transform.position;
Quaternion rotationToTarget = Quaternion.LookRotation(directionToTarget);
transform.rotation = rotationToTarget;
Vector3 directionToTarget을 만들고 그 값을 목표좌표에서 현재 좌표를 뺀 만큼으로 해 줍니다.
directionToTarget을 rotationToTarget의 회전값으로 한다.
rotationToTarget을 적 오브젝트의 회전값으로 한다.
float distance = Vector3.Distance(transform.position, targetWaypoint.position);
distance변수를 현재 좌표부터 목표좌표까지의 거리로 정한다. 즉 distance변수는 목표 좌표까지의 거리이다.
CheckDistanceToWayPoint(distance);
구한 distance를 CheckDistanceToWayPoint로 호출한다.
transform.position = Vector3.MoveTowards(transform.position, targetWaypoint.position, movementStep);
위치를 현재 좌표(transform.position)부터
목표 좌표(targetWaypoint.position)까지 deltaTime을 곱한 변수(movementStep)만끔씩 이동한다.
여기부터는 CheckDistanceToWayPoint 함수이다.
void CheckDistanceToWayPoint(float currentDistance)
일단 목표좌표까지의 거리(currentDistance)를 반환받는다.
if(currentDistance <= minDistance && waypoints.Length < targetWaypointIndex)
만일 목표좌표까지의 거리가(currentDistance) 최소거리(minDistance 현재 값은 0.001이다)보다 작고
배열의 크기(.Length를 하면 배열의 크기를 알 수 있다.)가 목표위치 순서보다 작으면 실행
배열의 크기는 적이이동할 좌표의 개수를 의미한다. 그리고 목표위치 순서(targetWaypointIndex)가 현재 3이면
적이 이동한 좌표의 개수는 총 4개가 되는것이다.
그러니 목표위치 순서(targetWaypointIndex)가 무한 증가하는것을 방지하려고 구현한 코드이다.
그러므로 이 if문은 적이 도착하였는가를 체크해주는 알고리즘이다.
targetWaypointIndex++;
자 그럼 위에 조건을 충족시키면
목표위치 순서(targetWaypointIndex)를 1만큼 증가시킨다.
UpdateTargetWaypoint();
그리고 UpdateTargetWaypoint함수를 실행 시킨다.
여기부터는 UpdateTargetWaypoint함수이다.
targetWaypoint = waypoints[targetWaypointIndex];
적이 도착했을때 다음 목표좌표로 변경해주기 위해 구현했다.
현재 목표좌표는 여러 목표좌표가 있는 배열(waypoints[])중 현재 있는 목표위치 순서(targetWaypointIndex)
로 바꿔주는거다.
그런데 여기서 근데 지금있는 순서로 바꾸면 그대로 아니냐 할 수 있다.
근데 CheckDistanceToWayPoint 함수에서 targetWaypointIndex에 1을 더했으니 다음 순서로 변수가 지정이 된것이다.
변수 세팅은 적이 이동할 좌표를 순서대로 waypoints[]배열에 넣고
targetWaypointIndex는 0으로 지정한뒤 나머지는 개개인에 따라 잘 설정하면 된다.
-----------------------------------------------------------------------------------------------------------------------------------
이제 타워 설치 구현 코드이다.
코드는 전에 작성한 Ray 파일이고 수정부분은 색처리함.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using TMPro;
public class Ray : MonoBehaviour
{
private RaycastHit hit;
public TextMeshProUGUI look;
public GameObject[] before;
public Material[] MA;
public bool[] isTower;
public GameObject EnemyPrefab;
public GameObject TowerPrefab;
public TextMeshProUGUI money;
public TextMeshProUGUI Error;
public int have_money = 1000;
public GameObject[] TowerPointPosition;
void Start()
{
money.text = ("Money : " + have_money);
}
void Update()
{
Raycast(); // ray를 쏘아주고 text(look)에 맞은 위치, 거리, 이름을 출력해주는 함수
TowerPointMeshRenderer(); //맞은 오브젝트의 색을 바꿔주는 함수이다.
}
void Raycast()
{
if (Physics.Raycast(this.transform.position, transform.forward, out hit)) //ray를 쏘아서 맞았을때
{
//Debug.Log("hit point : " + hit.point + ", distance : " + hit.distance + ", name : " + hit.collider.name+ ", tag : " +hit.collider.tag);
look.text = ("hit point : " + hit.point + ", distance: " + hit.distance + ", name: " + hit.collider.name + ", hit object position : " + hit.collider.transform.position ); // look.text에 맞은 좌표와, 현재 지점부터의 거리, 맞은 오브젝트, 맞은 오브젝트의 position를 출력
Debug.DrawRay(this.transform.position, transform.forward * 100000f, Color.red); //scene창에 ray를 출력해주어서 시각적으로 볼 수 있게 해준다. game 창에는 표시 안됨
//hit.collider.gameObject.GetComponent<Renderer>().material.color = Color.red;
}
else {
Debug.DrawRay(this.transform.position, transform.forward * 100000f, Color.red); //scene창에 ray를 출력해주어서 시각적으로 볼 수 있게 해준다. game 창에는 표시 안됨
}
}
void TowerPointMeshRenderer()
{
int i = 0; //tower point의 색을 일일히 변경하려면 30줄 가량 써야해서 for문으로 구성하기위해 만든 변수
for(i = 0; i < 32; i++) //총 32번 반복
{
if (hit.collider.name == before[i].name)
{
hit.collider.GetComponent<Renderer>().material = MA[1];
if(isTower[i] == false && Input.GetMouseButtonDown(0) && have_money >= 100)
{
Instantiate(TowerPrefab, TowerPointPosition[i].transform.position, TowerPrefab.transform.rotation);
have_money -= 100;
money.text = ("Money : " + have_money);
isTower[i] = true;
}
if (isTower[i] == false && Input.GetMouseButtonDown(0) && have_money < 100)
{
StartCoroutine("Error_Coroutine_0001");
}
} //그 맞은 오브젝트의 색 맞은 상태의 색(MA[1])로 바꾸기
else { before[i].GetComponent<Renderer>().material = MA[0]; } //아니면 안맞은 상태의 색(MA[0])로 바꾸기
}
}
IEnumerator Error_Coroutine_0001()
{
Error.text = ("Not Enough Money (Code 0001)");
yield return new WaitForSeconds(3f);
Error.text = ("");
}
}
public bool[] isTower;
현재 보는 위치에 tower가 있으면 재설치가 되지않도록 구현하기 위해 만든bool형 배열이다.
public GameObject TowerPrefab;
설치할 타워의 프리펩이다.
public TextMeshProUGUI money;
현재 가지고 있는 돈을 표시하기위해 만든 변수이다.
public TextMeshProUGUI Error;
여러 경고, 에러등을 표시하기위해 만든 변수이다.
public int have_money = 1000;
현재 가지고 있는 돈을 저장하는 변수이다.
public GameObject[] TowerPointPosition;
타워가 설치될 위치를 모두 저장하는 GameObject배열이다.
if(isTower[i] == false && Input.GetMouseButtonDown(0) && have_money >= 100)
만일 현재 타워를 설치할 자리가 비어있고 마우스 좌클을 했고 돈이 100보다 많거나 같으면
Instantiate(TowerPrefab, TowerPointPosition[i].transform.position, TowerPrefab.transform.rotation);
Instantiate는 복제하는 변수이다. 여기서는 생성하는데 쓸거다.
첫번째 인수는 복제할 오브젝트 두번째는 위치 세번째는 회전값이다.
여기서는 타워오브젝트(TowerPrefab)를 복사하고 타워생성위치(TowerPosintPosition)의
위치(position)와 회전값(rotation)을 사용할 것이다.
have_money -= 100;
설치를 했으니 돈을 깎는다.
money.text = ("Money : " + have_money);
현재 남은 돈을 출력
isTower[i] = true;
현재 자리에 이미 타워가 있다고 bool값을 True로 바꾸기
if (isTower[i] == false && Input.GetMouseButtonDown(0) && have_money < 100)
만일 타워가 현재 시선이 향하는 위치에 없고 좌클을 했고 돈이 100보자 작으면
StartCoroutine("Error_Coroutine_0001");
[Error_Coroutine_0001]코루틴을 시작한다.
여기부터는 [Error_Coroutine_0001] 코루틴 속의 내용이다.
Error.text = ("Not Enough Money (Code 0001)");
돈이 부족하다고 출력하기
yield return new WaitForSeconds(3f);
3초 기다리기
Error.text = ("");
3초후에 지우기
영상
'Unity > TowerDiffence' 카테고리의 다른 글
#4 에임 위에 있는 오브젝트 색 변화시키기(6/8) (0) | 2021.06.08 |
---|---|
#3 에임위에 있는 오브젝트 이름 출력 [Raycast] (6/6) (0) | 2021.06.06 |
#2 입력키 출력--------------------------[6/5] (0) | 2021.06.05 |
#0 기획하기 (0) | 2021.06.04 |
#1 오브젝트 세팅 및 카메라 이동 --------------------[6/3] (0) | 2021.06.03 |