Firing Shells
발사키를 누르고 있으면 포신이 향하는 방향으로 화살표가 생겨나 오래 누르면 더 길어져서 멀리 발사하는 것을 표시할 수 있는 시스템을 표현하려고 합니다.
그것을 위해 Hierarchy의 Tank에 우클릭 하고 Create Empty를 선택하여 빈 오브젝트를 탱크의 자식으로 추가한 후 이름을 FireTransform이라고 해 줍니다. 그리고 탱크의 포신 바로 앞에 위치하도록 Position을 (0, 1.7, 1.35)로, Rotation은 (350, 0, 0)으로 합니다.
그리고 화살표 UI를 표현하기 위해 Canvas에 우클릭 하고 UI>Slider를 선택하여 슬라이더를 하나 추가하고 이름을 AimSlider로 정합니다.
화면에 거대한 슬라이더가 하나 생겼습니다. 이제 Hierarchy의 AimSlider를 Alt+ 클릭해서 펼쳐 보면, 여러 개의 자식들이 있습니다. 손잡이를 잡고 슬라이더를 움직일 것이 아니므로 Handle Slide Area를 지우고, Background 역시 지웁니다. 결과적으로 아래의 그림과 같이 Fill Area, Fill만 남게 됩니다.
다시 AimSlider를 선택하고 인스펙터를 보면 여러가지 프로퍼티들이 있습니다.
Interactable은 체크 해제하고, Transition은 None으로 바꿔줍시다. 방향은 Bottom to Top, Min 15, Max 30으로 정합니다.
이제 이 슬라이더의 크기를 먼저 부모인 Canvas에 맞게 바꾼 다음 세부 조절을 하려 합니다. AimSlider를 선택한 상태에서 Shift를 누르고 FIll Area까지 동시 선택합니다.
그런후 인스펙터의 Anchor Presets을 누르고 ALT 키를 누른 상태에서 우하방을 선택하여 크기를 부모에 맞게 조절합니다.
그러면 슬라이더가 탱크 하방에 대략 적당한 크기로 조절된 것을 볼 수 있습니다.
다음으로 Fill Area의 자식인 Fill을 선택하고 인스펙터에서 Height는 0, Source Image는 Aim Arrow로 바꿉니다.
AimSlider가 선택된 상태에서 기즈모의 y축을 눌러 상단에서 본 뷰를 만들어 봅시다. 그리고 화면 좌상단의 Rect tool을 눌러 Rect를 조절 가능하게 만들고 좌우를 좁혀 대략 탱크의 폭 정도로 만들어 봅시다.
그리고 위아래 길이를 조금 늘려주고,
통째로 위로 잡아 올립니다.
그 다음 기즈모의 y축으로 살짝 끌어올려 지상으로 조금 올라오게 합니다.
이렇게 대략적으로 조절해 둔 뒤 인스펙터에서 좀 더 정확히 숫자를 정해주겠습니다.
대략적인 준비가 끝났으니 이제 스크립트를 작성합니다.
Assets>Scripts>Tank 폴더에 TankShooting이라는 스크립트가 준비되어 있습니다. 이것을 Hierarchy의 Tank에 연결한 후 에디터로 엽니다.
public int m_PlayerNumber = 1;
public Rigidbody m_Shell;
public Transform m_FireTransform;
public Slider m_AimSlider;
public AudioSource m_ShootingAudio;
public AudioClip m_ChargingClip;
public AudioClip m_FireClip;
public float m_MinLaunchForce = 15f;
public float m_MaxLaunchForce = 30f;
public float m_MaxChargeTime = 0.75f;
| cs |
여느 때와 마찬가지로 각종 레퍼런스와 초기값으로 쓰일 퍼블릭 변수들이 선언됩니다.
private string m_FireButton;
private float m_CurrentLaunchForce;
private float m_ChargeSpeed;
private bool m_Fired;
| cs |
프라이빗 변수들도 선언되고,
OnEnable()에서
private void OnEnable()
{
m_CurrentLaunchForce = m_MinLaunchForce;
m_AimSlider.value = m_MinLaunchForce;
}
| cs |
탱크가 스폰되었을 때의 발사강도와 슬라이더 크기를 초기화합니다.
private void Start()
{
m_FireButton = "Fire" + m_PlayerNumber;
m_ChargeSpeed = (m_MaxLaunchForce - m_MinLaunchForce) / m_MaxChargeTime;
}
| cs |
Update()에서는 발사버튼의 상태에 따라 발사와 관련된 작업을 처리합니다.
private void Update()
{
m_AimSlider.value = m_MinLaunchForce;
if (m_CurrentLaunchForce >= m_MaxLaunchForce && !m_Fired)
{
// 최고 파워에서 발사되지 않았을 때
m_CurrentLaunchForce = m_MaxLaunchForce;
Fire();
}
else if(Input.GetButtonDown(m_FireButton))
{
// 발사 버튼이 이제 막 눌러지기 사작했을 때
m_Fired = false;
m_CurrentLaunchForce = m_MinLaunchForce;
m_ShootingAudio.clip = m_ChargingClip;
m_ShootingAudio.Play();
}
else if (Input.GetButton(m_FireButton) && !m_Fired)
{
// 발사 버튼이 눌러지고 있고 아직 발사되지 않았을 때
m_CurrentLaunchForce += m_ChargeSpeed * Time.deltaTime;
m_AimSlider.value = m_CurrentLaunchForce;
}
else if (Input.GetButtonUp(m_FireButton) && !m_Fired)
{
// 눌렸던 발사버튼이 놓아졌지만 아직 발사되지 않았을 때
Fire();
}
}
| cs |
Fire()에서 실제 발사를 처리합니다.
private void Fire()
{
m_Fired = true;
// 포탄 인스턴스를 생성 후 저장
Rigidbody shellInstance = Instantiate(
m_Shell, m_FireTransform.position,m_FireTransform.rotation) as Rigidbody;
// 포탄 속도 지정
shellInstance.velocity = m_CurrentLaunchForce * m_FireTransform.forward;
// 소리를 발사 소리로 변경
m_ShootingAudio.clip = m_FireClip;
m_ShootingAudio.Play();
// 발사 파워 초기화
m_CurrentLaunchForce = m_MinLaunchForce;
}
| cs |
스크립트를 저장하고 다시 유니티로 돌아가서 프로퍼티들을 연결합니다.
실행하여 발사 버튼을 눌러보면 노란 화살표가 길어지면서 포탄의 세기가 잘 조절되어 발사됩니다!...라고 한번에 적었으면 좋았겠지만 실제로는 잘 안되어서 몇 시간 삽질했습니다.
알고보니
else if(Input.GetButtonDown(m_FireButton)) 부분을
else if(Input.GetButton(m_FireButton)) 이라고 적었더라고요.
이거 알아내는데 몇시간 걸렸군요. 이런 건 어찌나 눈에 안 띄는지.
어쨌거나 잘 작동된다면 반드시! Apply를 눌러 프리팹에 탱크 변경사항을 적용하고 Hierarchy에서 탱크를 지우고 씬을 저장합니다.
댓글 없음:
댓글 쓰기