[Bullet 오브젝트 풀링]
● 게임에서 자주 생성되고 제거되는 오브젝트(예: 이펙트, 총알, 몬스터 등)는 매번 Instantiate/Destroy를 호출하면 성능에 큰 영향을 준다.
● 이를 해결하기 위해 오브젝트 풀링 기법을 적용하여 메모리 재사용성을 높이고 GC(가비지 컬렉션) 비용을 줄이는 것이 목적
■ 구조 요약
● Pool 클래스: 하나의 프리팹을 위한 오브젝트 풀을 관리
● TowerPoolManager 클래스: 싱글톤 기반으로 여러 Pool을 관리
■ Pool 클래스 설명
● 역할: 하나의 프리팹(GameObject)에 대한 풀을 구성
● 핵심 변수
○ _prefab: 풀의 원형 프리팹
○ _pool: ObjectPool<T>로 실제 오브젝트 풀을 관리
○ Root: 생성된 풀 오브젝트들을 묶는 부모 transform
■ 생성자
● 전달된 프리팹을 기반으로 오브젝트 풀을 초기화
■ 오브젝트 생명주기 콜백
● OnCreate: 오브젝트를 처음 생성할 때 실행
● OnGet: 풀에서 꺼낼 때 실행 (SetActive(true))
● OnRelease: 풀에 반환할 때 실행 (SetActive(false))
● OnDestroy: 풀 자체를 제거할 때 실행
■ TowerPoolManager 클래스
● 싱글톤 패턴을 이용하여 어디서든 접근 가능
● _pools 딕셔너리로 프리팹 이름을 키로 각 Pool을 관리
● 주요 메서드
○ Pop(GameOjbect prefab)
○ 프리팹 이름으로 풀을 찾고 없으면 새로 생성
○ 해당 풀에서 오브젝트를 꺼내 반환
○ Push(GameObject go)
○ 오브젝트를 해당 이름의 풀로 반환
○ 이름이 일치하는 풀이 없으면 false 반환
■ 장점
● 런타임 성능 향상: Instantiate/Destroy를 반복하지 않아 성능 저하 및 GC 비용 최소화
● 메모리 재사용: 이미 생성된 오브젝트를 재활용
● 확장 용이성: 여러 종류의 프리팹을 관리한느 구조 (TowerPoolManager)
[Bullet]
● 발사체(총알)가 적을 향해 날아가고 충돌 시 피해를 입힌 뒤 오브젝트 풀링 시스템으로 반환되는 투사체 로직을 담당
■ 핵심 기능
● 이동: 지정된 방향으로 일정 속도로 이동
● 수명 관리: duration 이상 살아 있으면 자동 파괴
● 충돌 처리: 적(EnemyController)과 충돌 시 데미지 부여 후 파괴
● 풀 반환: 파괴 시 TowerPoolManager를 통해 오브젝트 풀에 반환
■ 발사 정보 설정
● 총알의 시작 위치, 방향, 데미지를 설정
● transform.rotation을 설정해 시각적으로 발사 방향과 일치
public void SetInfo(Vector3 startPos, Vector3 dir, int damage)
■ 이동 및 수명 제어
● 수명이 다 되었는지 확인하고 파괴
● 설정된 방향으로 일정 속도로 이동
private void Update()
{
//일정 시간이 지나면 자연스럽게 파괴
currentDuration += Time.deltaTime;
if (currentDuration > duration)
{
DestroyProjectile();
}
//bullet 위치 이동
transform.position += dir.normalized * (speed * Time.deltaTime);
}
■ 충돌 처리
● targetLayer에 포함된 적과 충돌했을 경우 EnemyController를 가져와 데미지 부여 후 오브젝트 풀로 되돌림
private void OnTriggerEnter(Collider other)
{
if (targetLayer.value == (targetLayer.value | (1 << other.gameObject.layer)))
{
EnemyController enemy = other.GetComponent<EnemyController>();
if (enemy != null)
{
enemy.OnDamaged(damage);
DestroyProjectile();
}
}
}
■ 파괴 및 반환
● 실제로는 Destroy() 하지 않고 오브젝트 풀에 반환
private void DestroyProjectile()
{
TowerPoolManager.Instance.Push(gameObject);
}
■ 장점
● 성능 최적화: Destroy()가 아닌 풀링을 통해 GC 비용 절감
● 모듈화된 구조: SetInfo()만 호출하면 재사용 가능
● 정확한 충돌 감지: LayerMask 기반으로 타겟 필터링
● 비주얼 정렬: 방향 회전 자동 설정으로 자연스러운 발사
[타워 설치 시스템]
● 플레이어가 마우스로 타워를 설치할 수 있도록 돕는 시스템
● 프리뷰(반투명 타워)를 통해 설치 위치를 시각적으로 안내
● 충돌 여부와 자원을 기반으로 설치 가능 여부를 판단
● 설치 후 실제 타워를 배치하고 자원을 차감
■ 주요 기능
● 타워 프리뷰 표시: 설치 전 마우스를 따라다니는 투명한 프리뷰 표시
● 충돌 판정: OverlapBox로 설치 가능 여부 계산
● 설치 회전: 마우스 휠로 프리뷰 회전
● 자원 확인 및 차감: ResourceController로 자원 체크 및 소비
● 타워 설치: 인게임 타워 실제 생성 및 리스트 등록
■ 설치 준비
● 프리뷰 오브젝트를 생성하고 반투명 머터리얼 적용
● 기존 프리뷰는 제거하고 새로 생성
● UI에서 호출되는 인터페이스
public void SetSelectedTower(int prefabIndex)
{
if (prefabIndex < 0 || prefabIndex >= towerPrefabList.Count)
{
Debug.Log("잘못된 프리팹 인덱스");
return;
}
if (currentPreview != null)
{
Destroy(currentPreview);
}
selectedPrefab = towerPrefabList[prefabIndex];
currentPreview = Instantiate(previewPrefabList[prefabIndex]);
previewRenderers = currentPreview.GetComponentsInChildren<Renderer>();
SetMaterialTransparent();
}
■ 설치 처리 흐름
● 프리뷰 위치 이동
○ 마우스 위치를 Raycast로 추적 → transform.position 적용
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
if (Physics.Raycast(ray, out RaycastHit hit, 100f, LayerMask.GetMask("Ground")))
{
//1. 위치 이동 (마우스 위치)
Vector3 pos = hit.point;
currentPreview.transform.position = pos;
● 프리뷰 회전
○ 마우스 휠 입력 → previewRotationY 축적 → Quaternion.Euler 적용
//2. 회전 (마우스 휠)
float scroll = Input.mouseScrollDelta.y;
if (scroll != 0)
{
previewRotationY += scroll * 15f;
currentPreview.transform.rotation = Quaternion.Euler(0, previewRotationY, 0);
}
● 충돌 여부 판단
○ Physics.OverlapBox()를 통해 현재 프리뷰가 buildableLayer와 겹치는지 검사
//3. 충돌 판정
Vector3 halfSize = GetBoundsExtents();
Vector3 centerPos = pos + Vector3.up * halfSize.y;
//현재 centerPos 위치에 halfSize의 박스 크기를 만들어 buildableLayer에 속한 기존 오브젝트들과 겹치면 true를 반환
Collider[] overlapped = Physics.OverlapBox(centerPos, halfSize, Quaternion.identity, buildableLayer);
canPlace = true;
foreach (Collider col in overlapped)
{
if (col.gameObject == currentPreview || col.transform.IsChildOf(currentPreview.transform))
{
continue;
}
canPlace = false;
}
● 프리뷰 색상 업데이트
○ 설치 가능 → 초록색, 불가능 → 빨간색
//프리뷰 색상 설정 (설치 가능: 초록, 설치 불가능: 빨강)
SetPreviewColor(canPlace ? Color.green : Color.red);
● 마우스 클릭 시 설치
○ 자원 확인 → 설치 위치에 타워 생성 → 자원 차감
//4. 타워 설치
if (Input.GetMouseButtonDown(0) && canPlace)
{
//자원 비교
if (CanBuild())
{
//자원 소모
SpendResource();
//타워 건설
BuildTower(pos);
}
}
■ 자원 확인과 소비
● 설치하려는 타워의 TowerData → TowerLevelData를 참조
● UpgradeCost 기준으로 자원이 충분한지 판단
private bool CanBuild()
{
towerData = selectedPrefab.GetComponent<Tower>().towerData;
towerLevelData = towerData.towerLevelDatas[0];
foreach (UpgradeCost cost in towerLevelData.upgradeCosts)
{
if (playerResource.GetResourceAmount(cost.itemType) < cost.amount)
{
return false;
}
}
return true;
}
● 충분하면 자원 소비
private void SpendResource()
{
foreach (UpgradeCost cost in towerLevelData.upgradeCosts)
{
playerResource.SpendResource(cost.itemType, cost.amount);
}
}
■ 타워 설치
● 실제 타워 프리팹을 설치 위치에 인스턴스화
private void BuildTower(Vector3 pos)
{
AudioManager.Instance.PlaySFX(SFX.TOWER);
GameObject go = Instantiate(selectedPrefab, pos, currentPreview.transform.rotation);
towers.Add(go.GetComponent<Tower>());
Destroy(currentPreview);
currentPreview = null;
selectedPrefab = null;
}
■ 설치 영역 충돌 체크
● 설치 위치에 대한 Bounds 크기를 렌더러 기준으로 계산
● OverlapBox()에 활용하여 설치 가능 여부 판단
private Vector3 GetBoundsExtents()
{
Bounds bounds = new Bounds(currentPreview.transform.position, Vector3.zero);
foreach (Renderer rend in previewRenderers)
{
bounds.Encapsulate(rend.bounds);
}
return bounds.extents;
}
■ 시각적 피드백: 프리뷰 색상
● 설치 가능 시 초록색, 불가능 시 빨간색으로 반투명 컬러 적용
private void SetPreviewColor(Color color)
{
foreach (Renderer rend in previewRenderers)
{
foreach (Material mat in rend.materials)
{
mat.color = new Color(color.r, color.g, color.b, 0.5f); // 반투명
}
}
}
■ 장점
● 유저 피드백 우수: 프리뷰 + 색상으로 직관적인 설치 가능 여부를 전달
● 자원 시스템과 통합: 타워 설치 시 자원 조건 확인 및 차감
● 유연한 구조: 다양한 종류의 타워 및 프리뷰 모델 대응 가능
● 충돌 방지 정확성: OverlapBox로 타워 간 간섭 없이 설치 가능
'내일 배움 캠프 > 따봉Ib' 카테고리의 다른 글
| [따봉Ib 👍] ASTROWARD (4) 최종 (0) | 2025.06.20 |
|---|---|
| [따봉Ib 👍] ASTROWARD (3) 트러블 슈팅 (0) | 2025.06.17 |
| [따봉Ib 👍] ASTROWARD (1) (0) | 2025.06.17 |