1. 공격 구현 : 근거리(삽)
오브젝트 풀링으로 만들어진 Bullet(삽)을 관리하는 Weapon을 Player에 추가
Weapon 스크립트 추가 및 작성
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Weapon : MonoBehaviour
{
//무기id, 프리팹id, damage, 갯수, 속도
public int id;
public int prefabId;
public float damage;
public int count;
public float speed;
[SerializeField]
private Bullet bullet;
void Start()
{
this.Init();
}
void Update()
{
//id 별로 관리
switch (id)
{
case 0:
//bullet 회전시키기
this.transform.Rotate(Vector3.forward * this.speed * Time.deltaTime);
break;
default:
break;
}
}
//id별로 초기화
private void Init()
{
switch (id)
{
case 0:
this.speed = -150;
this.Batch();
break;
default:
break;
}
}
//bullet 배치하기
void Batch()
{
for(int i = 0; i < this.count; i++)
{
//...bullet 게임오브젝트 생성 후
//Weapon의 자식으로 넣기 위해 transform가져와 지역변수에 넣기
Transform bulletTrans = GameManager.instance.pool.Get(prefabId).transform;
//이 transform을 부모로 설정
bulletTrans.parent = this.transform;
//...회전 각도(z축) 설정
//count(갯수)만큼 회전각 나누어서 배치
Vector3 rot = Vector3.forward * 360 * i / count;
bulletTrans.Rotate(rot);
//Player로 부터 1.5f 거리만큼 떨어져서 위치
bulletTrans.Translate(bulletTrans.up * 1.5f, Space.World);
//bullet 초기화
this.bullet.Init(this.damage, -1); // -1 == 무한, 무한 관통
}
}
}
count(개수)를 5로 설정하고
실행한 결과
count를 10으로 설정하고 실행한 결과
레벨업 추가
- Update 부분에 test구문 추가하여 test하기
- 마우스왼쪽 누르면 damage:20, count: 5로 변경
test로 레벨업한 결과 => 개수 증가 및 배치가 이상함
**문제되는 점들
1. LevelUp을 하면 기존 count에 새로 입력한 count가 추가됨
(ex)
2 --> 5 (O)
2 --> 7 (X)
2. bullet의 위치 조정 필요 : LevelUp할 때 마다 player의 위치로 초기화 되어야함
.
.
.
Weapon - Batch() 부분 스크립트 수정하기
수정 후 실행 결과
2. 공격구현 : 원거리(총알)
- 범위 내에 Player와 거리가 가장 가까운 Monster에게 총알 발사
1) Scanner : 가장 가까운 Monster(target)를 구하는 스크립트 작성
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Rendering;
public class Scanner : MonoBehaviour
{
public float scanRange;
public LayerMask targetLayer;
public RaycastHit2D[] targets;
public Transform nearestTarget;
private void FixedUpdate()
{
//scanRange 내에 해당하는 targetLayer의 위치를 배열에 저장
targets = Physics2D.CircleCastAll(transform.position, scanRange, Vector2.zero, 0,targetLayer);
nearestTarget = GetNearest();
}
//가장 가까운 target 위치 반환 메서드
Transform GetNearest()
{
Transform result = null;
float dis = 100;
foreach(RaycastHit2D target in targets)
{
Vector3 myPos = transform.position;
Vector3 targetPos = target.transform.position;
float curDis = Vector3.Distance(myPos, targetPos);
//더 가까운 위치를 갱신
if (curDis < dis)
{
dis = curDis;
result = target.transform;
}
}
//가장 가까운 target위치 반환
return result;
}
}
2) Player에 스크립트 부착 후 값 넣어주기
(Nearest Targetd은 GetNearest의 값으로 입력되어짐)
3) Bullet 스크립트 수정
- Init의 매개변수에 Vector3 dir(위치) 추가
- per(관통력)에 따라 Bullet(총알) 비활성화하기 추가
- Bullet(총알)에 속도 추가
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Bullet : MonoBehaviour
{
public float damage; //데미지
public int per; //관통
private Rigidbody2D rBody;
private void Awake()
{
this.rBody = this.GetComponent<Rigidbody2D>();
}
public void Init(float damage, int per, Vector3 dir)
{
this.damage = damage;
this.per = per;
if(per > -1)
{
//속도 부여 (위치 * 속력)
this.rBody.velocity = dir * 15f ;
}
}
private void OnTriggerEnter2D(Collider2D collision)
{
//태그가 Monster가 아니거나 관통력이 -1인 경우
if (!collision.CompareTag("Monster")| per == -1)
{
return;
}
//충돌마다 관통력 감소
per--;
//관통력이 -1이 되면
if (per == -1)
{
//속도 = 0 , 오브젝트 비활성화
rBody.velocity = Vector2.zero;
gameObject.SetActive(false);
}
}
}
4) Weapon 스크립트 수정
-원거리 Bullet(총알) Init에 추가
- 총알 발사 메서드 추가
using System.Collections;
using System.Collections.Generic;
using System.Threading;
using UnityEngine;
public class Weapon : MonoBehaviour
{
//무기id, 프리팹id, damage, 갯수, 속도
public int id;
public int prefabId;
public float damage;
public int count;
public float speed;
private float timer;
private Player player;
private void Awake()
{
//부모 오브젝트에 있는 컴포넌트 가져오기
this.player = this.GetComponentInParent<Player>();
}
void Start()
{
this.Init();
}
void Update()
{
//id 별로 관리
switch (id)
{
case 0:
//bullet(삽) 회전시키기
this.transform.Rotate(Vector3.forward * this.speed * Time.deltaTime);
break;
default:
this.timer += Time.deltaTime;
if(this.timer > this.speed)
{
//timer 초기화
this.timer = 0f;
//총알 발사
this.Fire();
}
break;
}
//...TEST...
if (Input.GetMouseButtonDown(0))
{
this.LevelUp(20, 5);
}
}
//id별로 초기화
private void Init()
{
switch (id)
{
case 0:
this.speed = -150;
this.Batch();
break;
default:
//총알 발사 속도
speed = 0.3f;
break;
}
}
//...레벨업 메서드
//레벨업 시 damage와 count 조절하기
public void LevelUp(float damage, int count)
{
this.damage = damage;
this.count = count;
//레벨 = 0 , 근접무기일 경우
if(id == 0)
{
//배치해아함
this.Batch();
}
}
//...근거리 bullet(삽) 배치하기
void Batch()
{
for(int i = 0; i < this.count; i++)
{
//...bullet 게임오브젝트 생성 후
//Weapon의 자식으로 넣기 위해 transform가져와 지역변수에 넣기
Transform bullet;
//...i가 childCount 범위 내라면
if(i < this.transform.childCount)
{
//현재 child를 사용
bullet = this.transform.GetChild(i);
}
else
{
//...i가 범위를 넘어서면
//'모자란 수 만큼' 풀링으로 가져옴
bullet= GameManager.instance.pool.Get(prefabId).transform;
//현재 transform을 부모로 설정
bullet.parent = this.transform;
}
//...bullet위치 player의 위치로 초기화
//levelup 했을때 위치 오류 방지
bullet.localPosition = Vector3.zero;
bullet.localRotation = Quaternion.identity;
//...회전 각도(z축) 설정
//count(갯수)만큼 회전각 나누어서 배치s
Vector3 rot = Vector3.forward * 360 * i / count;
bullet.Rotate(rot);
//Player로 부터 1.5f 거리만큼 떨어져서 위치
bullet.Translate(bullet.up * 1.5f, Space.World);
//bullet 초기화
bullet.GetComponent<Bullet>().Init(this.damage, -1,Vector3.zero); // -1 == 무한, 무한 관통
}
}
//...원거리 Bullet(총알) 발사
void Fire()
{
if(!this.player.scanner.nearestTarget)
{
return;
}
//가장 가까운 몬스터 위치
Vector3 targetPos = this.player.scanner.nearestTarget.position;
//...총알 방향 설정
Vector3 dir = targetPos - transform.position;
//현재 Vector의 방향은 유지, 크기는 1로 변환
dir = dir.normalized;
Transform bullet = GameManager.instance.pool.Get(prefabId).transform;
bullet.position = this.transform.position;
bullet.rotation = Quaternion.FromToRotation(Vector3.up, dir);
//bullet 초기화
bullet.GetComponent<Bullet>().Init(this.damage, count, dir); // -1 == 무한, 무한 관통
}
}
스크립트 수정 후 실행 결과
(Weapon(삽)은 비활성화 상태로 꺼둠)
3. 무기 장착
Player 자식으로 왼손 오른손 추가하고 Hand 스크립트 만들기
Hand 스크립트 : 무기 방향 및 위치, 레이어 관리
using System.Collections;
using System.Collections.Generic;
using Unity.Mathematics;
using Unity.VisualScripting;
using UnityEngine;
public class Hand : MonoBehaviour
{
public bool isLeft;
public SpriteRenderer spriter;
//오른손 위치
private Vector3 rightPos = new Vector3(0.35f, -0.15f, 0);
//오른손 반전 위치
private Vector3 rightPosReverse = new Vector3(-0.15f, -0.1f, 0);
//왼손 각도
private Quaternion leftRot = Quaternion.Euler(0, 0, -35f);
//왼손 반전 각도
private Quaternion leftRotReverse = Quaternion.Euler(0,180f,210f);
private void Awake()
{
this.spriter = this.GetComponent<SpriteRenderer>();
}
private void Update()
{
if (isLeft) //근거리 무기
{
//Player가 왼쪽을 보면
if (GameManager.instance.player.inputVec.x == -1)
{
//반전
this.transform.localRotation = this.leftRotReverse;
//sprite layer 설정
this.spriter.sortingOrder = 4;
}
else if(GameManager.instance.player.inputVec.x == 1)
{
this.transform.localRotation = this.leftRot;
//sprite layer 설정
this.spriter.sortingOrder = 6;
}
}
else //원거리 무기
{
//Player가 왼쪽을 보면
if (GameManager.instance.player.inputVec.x == -1)
{
//반전
this.transform.localPosition = this.rightPosReverse;
//sprite layer 설정
this.spriter.sortingOrder = 6;
}
else if(GameManager.instance.player.inputVec.x == 1)
{
this.transform.localPosition = this.rightPos;
//sprite layer 설정
this.spriter.sortingOrder = 4;
}
}
}
}
** 의문점
나는 Player 방향 전환을 spriter.flip을 안 쓰고 localScale을 사용하여서 Hand 반전을 줘보려고 하였다.
그러나 나머지는 다 잘 되는데, 왼손 반전 각도를 골드메탈님이 설정한 것처럼
Quaternion.Euler(0, 0, -135f);로 설정했지만 이상하게 반전이 되었다..
localRotation은 부모의 영향을 받는다고 하는데
아마도 내가 부모인 Player에서 spriter.flip을 사용하지 않아서 문제가 발생한 것 같다.
(혹시 몰라 this.transform.flipY = GameManager.instance.player.inputVec.x == -1;
이라고 설정해봤는데도 반전되지 않았다.)
따라서 Quaternion.Euler 값을 내가 직접 설정하였더니 좌우 반전이 잘 되었다.
실행 모습
아직 총알 위치를 총 끝으로 잡지 않은 상태!
**잘 이해가 안 갔던 부분들 정리
1. per(관통력)의 의미와 작동 원리
2. Scanner - GetNearest() 작동 원리
++
만약에 다 완성하고 시간이 좀 남으면 가장 가까운 거리를 구하는 로직을 우리가 배웠던 Gizmos를 사용하여 바꿔보려고 한다! 새로운 방식들이 조금 많아 찬찬히 이해하고 넘어가려고 하느라 진도가 조금 느리다..
'2D 콘텐츠 제작 > [언데드 서바이벌] 제작 일지' 카테고리의 다른 글
[언데드 서바이벌 06] 레벨업 시스템 구현 & 오류 수정 (0) | 2023.09.19 |
---|---|
[언데드 서바이벌 05] HUD 구현 & 피격 액션 추가 & 능력 업그레이드 구현 (0) | 2023.09.18 |
[언데드 서바이벌 03] 오브젝트 풀링으로 몬스터 생성 & 몬스터 레벨 적용 (0) | 2023.09.15 |
[언데드 서바이벌 02] 무한맵 생성 & 몬스터 생성 (0) | 2023.09.14 |
[언데드 서바이벌 01] 게임오브젝트 생성, 애니메이션 제작, 이동 구현 (1) | 2023.09.13 |