BulletCtrl이라는 스크립트를 하나 만듭니다.
Start() 함수에서 Rigidbody 참조를 rb에 저장한후 Addforce()메서드로 힘을 한번준다.
Update()함수가 없는데도 플레이해보면 총알이 발사된다.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class BulletCtrl : MonoBehaviour
{
public float damage = 20.0f;
public float force = 1500.0f;
private Rigidbody rb;
void Start()
{
rb = GetComponent<Rigidbody>();
rb.AddForce(transform.forward * force);
}
}
스크립트를 하이라키의 Bullet에 끌어다 넣는다. 자식인 lowpolybullet에 넣으면 안됩니다.
플레이 해보면 순식간에 없어져서 확인하기 어렵습니다.
Bullet 인스펙터뷰의 BulletCtrl스크립트컴포넌트의 force를 100으로 하면 천천히 움직이는 걸 볼수 있다. 확인후 다시 1500으로 돌려준다. 플레이중 100을 입력하면 실행이 끝난후 자동으로 1500으로 돌아간다.
플레이전에 값을 바꾸면 영구적으로 바뀌게 되고 스크립트의 초기화 보다 우선하게 된다. 이게 가끔 문제를 일으킨다. 코드에서 초기값을 바꾸어도 변화가 없기 때문에 찾는데 애를 먹는다.
AddForce()의 인자 Vector3는 월드좌표기준으로 힘을 가하므로 게임오브젝트의 Y축이 회전해도 항상 같은 월드좌표의 Z축방향으로 날라간다. 로컬좌표를 기준으로 힘을 주려면 transform.forward * force로 지정하거나 AddRelativeForce()함수를 사용해야 한다.
AddForce(Vector3) : 월드좌표로 힘을준다
AddForce(transform.foward) : 게임오브젝트의 forward로 힘을준다.
AddRelativeForce(Vector3) : 게임오브젝트의 로컬좌표로 힘을준다.
좀 직관적이지 않는데
만일 AddForce(new Vector3(0,0,1f)) 하면 오브젝트의 방향과 상관없이 월드좌표로 앞으로 날라간다.
AddForce(transform.foward) 오브젝트의 로테이션된 방향으로 날라간다. transform.foward 는 객체의 회전을 반영한 앞 방향을 나타닌다. 로컬좌표 앞방향이다.
AddRelativeForce(new Vector3(0,0,1f)) 하면 오브젝트의 로테이션된 방향으로 날라간다.
아래 실험은 책에는 없는건데 개인적으로 해본거다 여러분은 하지 말아주길 바란다. 잘못하면 코드가 꼬인다.
이걸 실험해 볼려고 코드를 한번 짜 봤다.
AddForceCtrl이라는 스크립트를 하나 만들어 하이라키의 Player에 적용한다.
코드는 G:글로벌좌표 F:forward R:Relative 를 누르면 해당 함수가 실행된다. 이 함수는 BulletCtrl에 추가했다. 세 함수를 보면 인자가 조금씩 다르다.
AddForceCtrl.cs 스크립트 다음2개의 글로벌변수에 Bullet,Player오브젝트를 끌어다 연결해준다.
public GameObject bullet; //총알의 life를 참조하기 위함
public Transform playerTr; //player와 총알의 회전을 맞추기 위해 참조
GameManager에서 BulletCtrl의 메서드를 불러서 사용한다. 외부스크립트를 참조하기위해서는 Bullet을 인스펙터창에서 연결해준후 script컴포넌트의 참조를 참조변수에 지정해서 사용하면 된다. 스크립트의 참조는 GameObject가 아닌 스크립트이름이다. 스크립트 이름으로 class가 생성되기 때문이다.
public GameObject bullet; //인스펙터창에서 연결해야함.
private BulletCtrl sc; //BulletCtrl 스크립트 클래스의 참조
void Start()
{
sc = bullet.GetComponent<BulletCtrl>(); //BulletCtrl 스크립트클래스참조를 받아온다
}
using System.Collections;
using System.Collections.Generic;
using Unity.VisualScripting;
using UnityEngine;
public class AddForceCtrl : MonoBehaviour
{
public GameObject bullet; //총알의 life를 참조하기 위함
public Transform playerTr; //player와 총알의 회전을 맞추기 위해 참조
private BulletCtrl sc; //BulletCtrl 스크립트 클래스의 참조
void Start()
{
sc = bullet.GetComponent<BulletCtrl>(); //BulletCtrl 스크립트클래스참조를 받아온다
}
// Update is called once per frame
void Update() {
if (sc.GetLife() == false) {
if (Input.GetKeyDown(KeyCode.G)) {
sc.AddForceG(playerTr);
Debug.Log("g");
}
if (Input.GetKeyDown("f")) {
sc.AddForceF(playerTr);
Debug.Log("F");
}
if (Input.GetKeyDown("r")) {
sc.AddForceR(playerTr);
Debug.Log("R");
}
}
}
}
Bullet에 적용된 BulletCtrl.cs
인스펙터에서 public Transform rifleTr; 에 하이라키뷰의 Player의 라이플을 끌어다 놔준다. Bullet을 총 앞쪽에 놓을려고 총의 위치를 참조하려고 한다.
총알의 발사속도를 빠르게 하기위해 public float force = 1500.0f;로 수정해 힘을 쎄게한다.
GameManager에서 사용한 3개의 함수가 추가되었다. Addforce의 인자가 조금씩 다르다.
rb.AddForce(Vector3.forward*force); //월드좌표로 앞으로만 날라간다.
rb.AddRelativeForce(Vector3.forward * force); //똑같은 Vector3.forward인데 로컬좌표로 앞으로 날라간다
rb.AddForce(transform.forward * force); //로컬좌표로 앞으로 날라간다
Update()함수 안을 보면
총알이 발사되는 life=true로 설정해 관리한다.
총알이 발사된시간을 lastTime에 저장해 1초가 지나면 false로 해준고
코드는 총알의 생명 life를 참조해 2가지 처리를 하는데
총알이 발사되고 1초가 지나면 속도를 0으로 하고 .
if(life && (Time.time > lastTime + 1f)) {
rb.velocity = Vector3.zero;
lastTime = Time.time; // lastTime을 갱신해준다.
life = false;
}
life가 flase라면 위치와 방향을 총을 참조해 초기화 한다
else if(!life){
transform.position = rifleTr.position + rifleTr.forward +rifleTr.up * 0.3f;
transform.rotation = rifleTr.rotation;
}
그리고 bullet에 Rigidbody컴포넌트가 추가되어있어 FixedUpdate()를 사용했는데 실행시 버벅거려서 LateUpdate()를 사용하니 해결되었다 FollowCam도 LateUpdate()를 사용하는 문제가 되는지는 잘 모르겠다.
버벅거리는 이유는 아마 .Bullet이 rifle(총)의 position과 rotation을 참조하는데 이게 같은 Update()에서 이루어지기 때문에 우선순위가 없어 생기는 일인것 같다. 따라서 LateUpdate()로 Player처리후 맨 마지막에 하니 문제가 해결되는것 같다.
using System.Collections;
using System.Collections.Generic;
using Unity.VisualScripting;
using UnityEngine;
using static Unity.VisualScripting.Member;
public class BulletCtrl : MonoBehaviour
{
public Transform rifleTr;
public float damage = 20.0f;
public float force = 1500.0f; //빠르게 하기위해
private bool life = false;
private Rigidbody rb;
private float lastTime=0f;
void Start()
{
transform.position = rifleTr.position;
rb = GetComponent<Rigidbody>();
}
private void LateUpdate() {
if(life && (Time.time > lastTime + 1f)) {
rb.velocity = Vector3.zero;
lastTime = Time.time;
life = false;
} else if(!life){
transform.position = rifleTr.position + rifleTr.forward +rifleTr.up * 0.3f;
transform.rotation = rifleTr.rotation;
}
}
public void AddForceG(Transform tr) {
rb.AddForce(Vector3.forward*force);
life = true;
lastTime = Time.time;
Debug.Log("g");
}
public void AddForceF(Transform tr) {
rb.AddForce(transform.forward * force);
life = true;
lastTime = Time.time;
}
public void AddForceR(Transform tr) {
rb.AddRelativeForce(Vector3.forward * force);
life = true;
lastTime = Time.time;
}
public bool GetLife() {
return life;
}
}
전망을 좋게하기위해 FollowCam.cs의 public float height = 3.0f;로 조금 높혀준다.
실행화면이다.
G, F ,R을 각각 2번씩 눌러 총알을 발사했다.
G를 누르면 캐릭터방향과 상관없이 앞으로만 발사된다.
F와R를 누르면 캐릭터의 방향을 따라 발사된다.
실험때문에 좀 스크립트가 복잡하게 되었다. ㅠㅠ
'유니티게임강좌 > 총 발사 로직' 카테고리의 다른 글
[총발사로직] Collider 컴포넌트 (0) | 2023.02.27 |
---|---|
[총발사로직] 물리 엔진 속성 설정 - Physics Manager (0) | 2023.02.27 |
[총발사로직]Rigidbody 컴포넌트 (0) | 2023.02.26 |
[총발사로직] 총알 모델 준비 (0) | 2023.02.26 |
[총발사로직] 총발사 로직 (0) | 2023.02.26 |