일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |
- 정처기 필기
- 1인 게임 개발
- Unity #Unity2D #Portal
- 퐁
- 1인 게임 제작
- portal
- 유니티 3D
- Pong
- 토이 프로젝트
- 자바스크립트 게임
- FPS
- 1인 게임
- 유니티
- 정보처리기사
- 유니티3d
- 3회차
- Unity
- 필기
- 게임 제작
- 게임
- 게임제작
- unity3d
- 합격
- 1인 개발
- 정처기
- Vampire Survivors
- Unity2D
- 게임 개발
- 자바스크립트
- 프로그래머스 #최소힙 #우선순위 큐
- Today
- Total
Coding Feature.
[Unity 2D] Portal 같은 게임 만들기 #3 포탈 매커니즘 구현하기 2(속도 변환) 본문
[Unity 2D] Portal 같은 게임 만들기 #3 포탈 매커니즘 구현하기 2(속도 변환)
codingfeature 2024. 1. 5. 19:54이전까지 포탈에 들어갈 때 플레이어의 위치만 변경했다면 이제는 플레이어가 들어간 속도 그대로 나오도록 구현해보겠습니다.
포탈에는 관성을 이용해서 퍼즐을 클리어해야 하는 구간이 많습니다.
위 그림처럼 중력을 이용해 포탈에 빠르게 들어가서 빠르게 나오면서 멀리 가도록 하게 구현해야 합니다.
또한 포탈에도 각도가 생겨서 들어간 각도대로 나올 수 있도록 해야 합니다.
우선 플레이어의 속도를 제어할 것이므로 이전에 플레이어를 움직일 때 사용했던 Transform.Translate는 좋은 플레이어 컨트롤 방법이 아닙니다.
대신 플레이어의 속도를 조절하도록 변경하여 물리적 특성을 더 잘 반영할 수 있도록 해줬습니다.
...
if (Input.GetKey(KeyCode.A)){
m_rb.velocity += new Vector2(-1 * playerSpeed * Time.deltaTime, 0);
}
if (Input.GetKey(KeyCode.D))
{
m_rb.velocity += new Vector2(1 * playerSpeed * Time.deltaTime, 0);
}
...
그 다음 사용자가 포탈에 들어갈 때의 속도에서, 속도의 크기(속력)은 그대로 두고, 속도의 방향만 알맞게 바꿀 수 있도록 해줘야 합니다.
아직 유니티에서 각도를 활용하는 방법에는 미숙해서, 저의 미천한 그림실력으로 식을 구해봤습니다.. ㅎㅎ
위 식의 각도는 모두 절대각도를 받아서 사용합니다.
결국 다른 포탈에 나오는 각도는 360 - (플레이어가 포탈에 들어가는 속도의 각도) + (오렌지 포탈 각도) + (블루 포탈 각도) 임을 구했습니다.
플레이어가 포탈에 들어가는 속도의 각도는 다음 코드를 사용해서 구했습니다.
PlayerVelocityAngle = Mathf.Atan2(playerVelocity.y, playerVelocity.x) * Mathf.Rad2Deg;
atan(y/x) = 각도 (라디안)
Rad2Deg = 라디안 값을 Degree로 바꿀 시 사용되는 상수값 (57.29578)
그 다음 앞서 구한 식으로 플레이어가 포탈에 나올때의 각도를 구합니다.
newPlayerVelocityAngle = 360 - PlayerVelocityAngle + orangePortalRotation + bluePortalRotation;
이제 구한 각도를 2차원 벡터(코드에서는 3차원) 값으로 변환합니다.
Vector3 desiredDirection = new Vector3(Mathf.Cos(newPlayerVelocityAngle * Mathf.Deg2Rad), Mathf.Sin(newPlayerVelocityAngle * Mathf.Deg2Rad), 0);
이때 x 성분과 y 성분을 각각 Cos, Sin 함수를 사용해서 구합니다.
Deg2Rad는 Degree를 라디안 값으로 바꾸는 상수 값입니다!
이제 새로 만들어진 속도의 방향 벡터를 구했으니 이 벡터를 정규화(크기가 1)하고 속력을 곱하면 속력이 같지만 방향이 다른 속도가 계산됩니다!
player.GetComponent<Rigidbody2D>().velocity = desiredDirection.normalized * playerVelocity.magnitude;
벡터에 normalized를 통해 정규화하고, magnitue를 통해 플레이어의 속력을 구하게 됩니다.
위 유니티 코드를 작성하는데에는 아래 쓰레드가 매우 큰 도움이 되었습니다! 더 자세한 내용은 참고바랍니다!
change velocity direction and not magnatude - Unity Forum
위 내용을 정리해서 다시 전체 코드를 작성해보면 다음과 같습니다!
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PortalScript : MonoBehaviour
{
public GameObject player;
public GameObject orangePortal;
public GameObject bluePortal;
Vector3 m_playerVelocity; // 플레이어가 포탈에 들어갈 때의 속도.
bool m_EnteredPortal; // 플레이어가 포탈에 들어간 경우를 확인하는 Boolean.
bool isTouchingOrange, isTouchingBlue; // 플레이어가 포탈에 닿은 경우를 확인하는 Boolean.
float m_PlayerVelocityAngle; // 플레이어가 포탈에 들어갈 때의 속도의 각도 Degree
float m_newPlayerVelocityAngle; // 플레이어가 포탈에 나갈 때의 속도의 각도 Degree
float m_orangePortalRotation;
float m_bluePortalRotation;
// Start is called before the first frame update
void Start()
{
m_EnteredPortal = false;
m_orangePortalRotation = orangePortal.transform.rotation.eulerAngles.z;
m_bluePortalRotation = bluePortal.transform.rotation.eulerAngles.z;
}
// Update is called once per frame
void Update()
{
m_playerVelocity = player.GetComponent<Rigidbody2D>().velocity;
m_PlayerVelocityAngle = Mathf.Atan2(m_playerVelocity.y, m_playerVelocity.x) * Mathf.Rad2Deg; // 포탈을 들어갈 때 각도 Degree
m_newPlayerVelocityAngle = 360 - m_PlayerVelocityAngle + m_orangePortalRotation + m_bluePortalRotation; // 포탈을 나갈때 각도 Degree
// 포탈을 나갈 때 방향 벡터.
Vector3 desiredDirection = new Vector3(Mathf.Cos(m_newPlayerVelocityAngle * Mathf.Deg2Rad), Mathf.Sin(m_newPlayerVelocityAngle * Mathf.Deg2Rad), 0);
// 플레이어가 포탈에 닿았는가 확인.
isTouchingOrange = Physics2D.IsTouching(player.GetComponent<BoxCollider2D>(), orangePortal.GetComponent<BoxCollider2D>());
isTouchingBlue = Physics2D.IsTouching(player.GetComponent<BoxCollider2D>(), bluePortal.GetComponent<BoxCollider2D>());
if (isTouchingOrange && !m_EnteredPortal) // 오렌지 포탈에 닿은 경우 + 이미 들어간 적이 없는 경우.
{
m_EnteredPortal = true;
player.transform.position = bluePortal.transform.position; // 오렌지 포탈로 위치 변환.
player.GetComponent<Rigidbody2D>().velocity = desiredDirection.normalized * m_playerVelocity.magnitude; // 포탈을 나갈때 속도의 방향 변환.
}
if (isTouchingBlue && !m_EnteredPortal) // 블루 포탈에 닿은 경우 + 이미 들어간 적이 없는 경우.
{
m_EnteredPortal = true;
player.transform.position = orangePortal.transform.position; // 블루 포탈로 위치 변환.
player.GetComponent<Rigidbody2D>().velocity = desiredDirection.normalized * m_playerVelocity.magnitude; // 포탈을 나갈때 속도의 방향 변환.
}
if (!isTouchingBlue && !isTouchingOrange)
{
m_EnteredPortal = false;
}
}
}
아래는 몇 가지 테스팅한 내용입니다.
다음에 할 일을 다음과 같이 설정했습니다.
- 포탈건 구현 (사용자가 포탈 직접 만들 수 있도록)
- 캐릭터 애니메이션
- 파티클 및 빛 효과
- 플레이어 속도, 점프 속도, 마찰 등 UX 개선
- 퍼즐 스테이지 구성 및 Scene 관리
- 음악, 효과음 추가
- UI 구현 (메뉴 등)
- QA (버그 수정)
'Toy Project > mini-portal [Unity2D]' 카테고리의 다른 글
[Unity 2D] Portal 같은 게임 만들기 #6 포탈, 포탈건, 캐릭터의 버그 해결 (0) | 2024.01.08 |
---|---|
[Unity 2D] Portal 같은 게임 만들기 #5 포탈건 매커니즘 구현하기 2 (포탈 생성하기) (0) | 2024.01.07 |
[Unity 2D] Portal 같은 게임 만들기 #4 포탈건 매커니즘 구현하기 1 (조준선 그리기) (0) | 2024.01.06 |
[Unity 2D] Portal 같은 게임 만들기 #2 포탈 매커니즘 구현하기 1(위치 변환) (0) | 2024.01.05 |
[Unity 2D] Portal 같은 게임 만들기 #1 플레이어 움직임 구현. (1) | 2024.01.05 |