코드네임 :
#7 싱글톤패턴 & 오브젝트 풀 본문
옵젝풀부터 설명좀 다시 들으삼
정적변수가지고 싱그론 패턴 객체 만듦
ScoreManager.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
// 여기 써있는 Start()과 Update()는 private이므로 ScoreManager에서만 사용가능
//SetScore(int value)는 외부에서 쓸 수 있음
public class ScoreManager : MonoBehaviour
{
public Text currentScoreUI;
public int currentScore;
public Text bestScoreUI;
public int bestScore;
public static ScoreManager Instance = null; // 공용 정적변수
// static은 이 클래스에서 딱 하나만 쓸 수 있는 변수가 됨
// 자기 자신의 이름으로 변수를 하나 만듦
public int Score
{
get //받음
{
return currentScore;
}
set // 보냄
{
currentScore = value;
currentScoreUI.text = "현재점수 : " + currentScore;
if (currentScore > bestScore)
{
bestScore = currentScore;
bestScoreUI.text = "최고점수 : " + bestScore;
PlayerPrefs.SetInt("Best Score", bestScore); // 갱신된 최고점수 저장
}
}
}
private void Awake() //싱글톤 객체
// 이 Awake 함수는 Start보다 더 먼저 실행 됨
// + Unity가 실행될때 바로 Awake 호출됨 (즉 object가 활성화/비활성화에 관계없이 항상 호출됨
{
if(Instance == null)
{
Instance = this; // Find 사용 안했으므로 빠르게 처리 가능
}
}
void Start()
{
bestScore = PlayerPrefs.GetInt("Best Score", 0);
// 여기에 있는 0은 디폴트 값으로 게임을 처음 시작했을때 최고점수에 아무것도 들어있지 않으므로 0값을 넣어주는 역할을 함
bestScoreUI.text = "최고점수 : " + bestScore;
// 자기 자신의 멤버변수이기 때문에 bestScore앞에 sm. 필요없음 !
}
void Update()
{
}
public void SetScore(int value) // 자기꺼한테 가져왔으니까 앞에 sm 안 써두 됨
{
currentScore++;
// ScoreManager안에 들어있는 currentScore의 값을 1 증가
currentScoreUI.text = "현재점수 : " + currentScore;
// str + int = 결과는 str(문자열)형으로
if (currentScore > bestScore) // 최고점수 갱신
{
bestScore = currentScore;
bestScoreUI.text = "최고점수 : " + bestScore;
PlayerPrefs.SetInt("Best Score", bestScore); // 갱신된 최고점수 저장
}
}
public int GetScore()
{
return currentScore; // 현재 스코어를 되돌려준다
}
}
Enemy.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Enemy : MonoBehaviour
{
public float speed = 5;
Vector3 dir; // 전역변수 dir
// Start() 함수에 있던 걸 Update()함수에 적용하기 위해 전역변수로!
public GameObject explosionFactory; // 폭발을 위한 PreFab
// GameObject smObject; //느려진다는 그 충돌처리함수의 Find 의 해결책
void Start()
{
int randValue = Random.Range(0,10); // ()에 들어가 있는 숫자가 실수인 경우 마지막 숫자까지 포함하지만
// 정수인 경우 포함 X
// 즉 위의 경우 0~9 사이의 숫자만 나옴
// int randValue = UnityEngine.Random.Range(0,10);
if (randValue < 3) // 30%의 확률로
{
GameObject target = GameObject.Find("Player");
// Find : Hierarchy창의 모든 이름 중에서 해당하는거("Player") 찾기
// GameObject.Find("Player") : Player 오브젝트를 반환
// GameObject target = GameObject.Find("Player"); : 반환된 Player 오브젝트를 target에다가 지역변수로 넣어주기
// 즉 target이 Player가 됨
dir = target.transform.position - transform.position;
// 적이 현재 주인공이 있는 방향으로 고개(?)를 향하게 됨 !!!
// target.transform.position : Player의 포지션 (주인공의 위치)
// transform.position : 적의 위치
// - : " 현재 위치레서 목표 위치쪽 방향으로 틀어라 "라고 하고 싶을 때 '벡터'의 뺄셈 이용
// 벡터A - 벡터B = 목표 위치A - 현재 위치B
// (근데 벡터이므로 방향만.. 걍 고개 돌리는거 생각하삼)
dir.Normalize();
// dir.Normalize : 정규화 (단위 벡터)
// Player와 적의 거리가 멀 경우 그 거리를 1로 만들어버림 (방향은 동일)
// 이걸 해줌으로써 나중에 speed 곱할 때 동일한 방향, 동일한 속도로 움직일 수 있게 해줌
}
else // 30% 확률 안에 못 들었다면
{
dir = Vector3.down; // 적을 자기가 떨어지는 위치 그대로에서 떨어지게 함 (;; 말이 이상한디
}
// smObject = GameObject.Find("ScoreManager"); //느려진다는 그 충돌처리함수의 Find 의 해결책
}
void Update()
{
transform.position += dir * speed * Time.deltaTime;
}
void OnCollisionEnter(Collision other) // 충돌 처리 함수
{
////GameObject smObject = GameObject.Find("ScoreManager"); // Find는 Hierarchy창 전체를 훑고 지나가니까 느려진다고 많이 쓰지 말래
// // 따라서 여기에다가 쓴 이 Find는 충돌이 일어날떄마다 호출되기 떄문에 일케 쓰는 건 좋지 않은 방법
// ScoreManager sm = smObject.GetComponent<ScoreManager>(); // ScoreManager 안에 있는 Script를 얻어올수 있게 됨
//sm.SetScore(sm.GetScore() + 1); // 현재 값보다 하나 더 증가한 값을 SetScore에 저장
//위 3 줄 대신 써주기 (Find는 비효율적이니!)
//ScoreManager.Instance.SetScore(ScoreManager.Instance.GetScore() + 1);
// 이렇게 쓰는 것만으로도 Find 안 써도 해당 스크립트에 접근할수 있음 (효율적이고 간단해짐)
/* 다시 위에 있는 코드한줄을 아래에 있는 한줄로도 바꿔쓰기 가능 */
ScoreManager.Instance.Score++; // ScoreManager.Instance.Score = ScoreManager.Instance.Score + 1;
// Score을 불러준 순간 get이 되어서
// Scoremanager의 Get함수에 있는 currentscore을 가져오게 됨 (바로 위에 주석처리한 코드에서 ScoreManager.Instance.GetScore() 보면 이해 잘 됨)
// 그럼 ScoreManager.Instance.Score은 currentscore가 됨
// 그후 거기에 +1을 하고
// 그럼 ScoreManager.Instance.Score에 대입 하면 set 호출됨 ~~~
GameObject explosion = Instantiate(explosionFactory); //여기서 오류나면 이제 아래있는 코드들이 실행이 안되므로 꼬옥 enemy의 explosionFactory 프리팹에 효과 넣어주기!!
// Instantiate() : ()안에 있는 원본을 복사
// 요 코드는 그 복사한거를 explosion에다가 넘겨주는 것
explosion.transform.position = transform.position;
// 폭발 이펙트의 위치를 설정
// 폭발 위치는 = 이 스크립트가 현재가지고 있는 위치
// transform의 의미는 : 이 스크립트를 포함하고 있는 옵젝이 갖고 있는 위치값
Destroy(other.gameObject); // 다른 게임 오브젝트 파괴
Destroy(gameObject); // 자기 자신 파괴
}
}
미사일 오브젝트풀
- 메모리 아끼기!! (모바일 컨텐츠에서)
playerfire.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
// 버튼을 누르는 순간 총알오브젝트(Bullet)를 생성하는 메소드 - 인스턴시에이트 ?
// 총알이 여러발 나가야 함으로 총알을 복사해주는 프리팹??
public class PlayerFire : MonoBehaviour
{
public GameObject bulletFactory; // 총알 원본
// bulletFactory : 총알의 프리팹 ..?
// 이걸 복제해서 계속 똑같은 총알을 만들거래
public GameObject firePosition; // 발사 위치
public int poolSize = 10; //10개의 배열
GameObject[] bulletObjectPool; // 이 배열에다가 총알 집어넣음
void Start()
{
bulletObjectPool = new GameObject[poolSize];
for (int i=0; i < poolSize; i++)
{
GameObject bullet = Instantiate(bulletFactory);
bulletObjectPool[i] = bullet;
bullet.SetActive(false); // 안보이게 '비활성화' 해주는 기능 (시작하자마자 총알이 10발 갑자기 발사되면 안되니)
}
}
void Update()
{
if (Input.GetButtonDown("Fire1")) // GetButtonDown : 어떤 버튼이 눌러져 있는가?(마우스 버튼) (버튼을 누른 그 순간에 한번만 작동)
{
//GameObject bullet = Instantiate(bulletFactory); // Instantiate : 프리탭옵젝()을 복제 (즉 여기서는 bulletFactory를 복제)
// // 이렇게 복제된 옵젝은 return값으로 들어오게 되는데 그거를 이제 지역변수인 bullet에다가 넣어줌
//bullet.transform.position = firePosition.transform.position; // bullet의 초기 위치
// // bullet옵젝의 위치를 FirePosition옵젝의 위치(0,1,0)로 이동
/*위에꺼 대신에 아래처럼 쓰기*/
for (int i=0; i < poolSize; i++)
{
GameObject bullet = bulletObjectPool[i]; // 비어있는 총알 오브젝트 하나에
if (bullet.activeSelf == false) // 현재 총알이 발사중인 상태가 아니라면
{
bullet.SetActive(true); //활성화
bullet.transform.position = transform.position; //bullet의 위치 = player의 위치가 됨
break; //총알을 발사했기떄문에 더이상 반복문을 돌 필요 없으므로 break
}
}
}
}
}
enemy.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Enemy : MonoBehaviour
{
public float speed = 5;
Vector3 dir;
public GameObject explosionFactory;
void Start()
{
int randValue = Random.Range(0,10);
if (randValue < 3) // 30%의 확률로
{
GameObject target = GameObject.Find("Player");
dir = target.transform.position - transform.position;
dir.Normalize();
// dir.Normalize : 정규화 (단위 벡터)
}
else // 30% 확률 안에 못 들었다면
{
dir = Vector3.down;
}
}
void Update()
{
transform.position += dir * speed * Time.deltaTime;
}
void OnCollisionEnter(Collision other) // 충돌 처리 함수
{
ScoreManager.Instance.Score++;
GameObject explosion = Instantiate(explosionFactory);
explosion.transform.position = transform.position;
if (other.gameObject.name.Contains("Bullet"))
//Bullet이라면
{
other.gameObject.SetActive(false); //비활성화
}
else //Bullet이 아니라면
{
Destroy(other.gameObject); //제거
}
Destroy(gameObject); // 자기 자신 파괴
}
}
destroyzone.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
//충돌 영역 설정
public class DestroyZone : MonoBehaviour
{
void Start()
{
}
void Update()
{
}
private void OnTriggerEnter(Collider other)
{
// Destroy(other.gameObject);
if (other.gameObject.name.Contains("Bullet"))
//Bullet이라면
{
other.gameObject.SetActive(false); //비활성화
}
else //Bullet이 아니라면
{
Destroy(other.gameObject); //제거
}
}
}
bullet 프리팹에서 리짓바디에서 Freeze ~~~ 두개 다 켜주기
'프로그래밍 > Unity(C#)' 카테고리의 다른 글
쿠키런 유니티 모작 (0) | 2023.07.25 |
---|---|
유니티 게임화면 기획 (0) | 2023.07.21 |
#6 점수 추가 & 저장 및 불러오기 (0) | 2023.07.09 |
#5 폴리싱 & 이펙트 & 배경 & 사운드 (0) | 2023.07.08 |
슈팅게임 #4 충돌처리 (0) | 2023.07.07 |