티스토리 뷰
게임클라이언트 프로그래밍/3D Project
3D 러닝게임 터치슬라이드, 포물선운동, FollowingCam
Game Client Lee Hwanguk 2023. 8. 3. 00:51# 터치슬라이드를 이용한 오브잭트 제어를 공부중이다. 먼저 이전에 오브잭트를 이동하는 방식에서 변경할 부분들이 있었다.
1. x 축을 기준으로 회전하면서 z축 방향으로 이동, 오브잭트가 지면보다 낮은 위치로 떨어지면 GameOver
*Script
private void Update()
{
this.transform.position += Vector3.forward * this.moveSpeed * Time.deltaTime; //z축(앞으로) 이동
this.transform.Rotate(Vector3.right * this.rotateSpeed * Time.deltaTime); // 회전 (x축을 기준으로)
if(this.transform.position.y<this.limitY) //떨어지면? 게임오버
{
Debug.Log("GameOver");
}
}
2. x축(좌,우) 로 이동 하는 중이라면 같은 방향으로 1번 이상 이동 불가(이중 이동 방지), 자연스러운 이동 연출을 위하여
Mathf.Lerp(start, end, percent); 로 현재위치(start)에서 목표위치(end)까지 일정한비율(percent)로 값을 보간
*Script
public void MoveToX(int x)
{
if (this.isXMove) return; //이중 이동 방지
if (x > 0 && this.transform.position.x < this.moveXWidth) //우로 이동
{
this.StartCoroutine(OnMoveToX(x));
}
else if(x<0&&this.transform.position.x>-this.moveXWidth) //좌로 이동
{
StartCoroutine(OnMoveToX(x));
}
}
private IEnumerator OnMoveToX(int direction)
{
float current = 0;
float percent = 0;
float start = this.transform.position.x;
float end = this.transform.position.x + direction * this.moveXWidth;
this.isXMove= true;
while(percent < 1)
{
current += Time.deltaTime;
percent = current / this.moveTimeX;
float x=Mathf.Lerp(start, end, percent);
this.transform.position=new Vector3(x, this.transform.position.y, this.transform.position.z);
yield return null;
}
this.isXMove= false;
}
3. 자연스러운 jump 연출을 위하여 포물선운동 공식 적용
*Script
private IEnumerator OnMveToY()
{
float current = 0;
float percent = 0;
float v0 = -this.gravity; //y방향의 초기 속도
this.isJump= true;
this.rb.useGravity = false;
while(percent < 1)
{
current += Time.deltaTime;
percent = current / this.moveTimeY;
//시간경과에 따라 오브잭트의 y위치를 변경
//포물선 운동 : 시작위치+초기속도*시간+중력*시간제곱
float y = this.originY + (v0 * percent) + (this.gravity * percent * percent);
this.transform.position=new Vector3(this.transform.position.x,y,this.transform.position.z);
yield return null;
}
this.isJump= false;
this.rb.useGravity = true;
}
*포물선 공식?
https://namu.wiki/w/%ED%8F%AC%EB%AC%BC%EC%84%A0%20%EC%9A%B4%EB%8F%99
=>포물선 운동 : 시작위치+초기속도*시간+중력*시간제곱
4.터치 슬라이드를 이용한 오브잭트 제어
* PC환경 모두 적용 (Application.isMobilePlatform)
private void Update()
{
//모바일 환경? PC환경?
if (Application.isMobilePlatform)
{
Debug.Log("Mobile");
OnMobilePlatform();
}
else
{
Debug.Log("PC");
OnPCPlatform();
}
}
/// <summary>
/// PC환경
/// </summary>
private void OnPCPlatform()
{
if(Input.GetMouseButtonDown(0))
{
Debug.Log("PC Touch");
this.touchStart = Input.mousePosition;
}
else if (Input.GetMouseButton(0))
{
this.touchEnd = Input.mousePosition;
this.OnDragXY();
}
}
* Mobile환경(터치 슬라이드 적용)
/// <summary>
/// 모바일 환경에서는 터치&드레그로 조작
/// </summary>
private void OnMobilePlatform()
{
//현제 화면을 터치하고 있지않다면? return
if (Input.touchCount == 0) return;
//첫번째 터치 정보
Touch touch=Input.GetTouch(0);
//터치시작
if(touch.phase==TouchPhase.Began)
{
this.touchStart = touch.position;
}
//터치 & 드레그
else if (touch.phase==TouchPhase.Moved)
{
this.touchEnd = touch.position;
this.OnDragXY();
}
}
* 터치상태로 x/y축 드래그 범위 감지
private void OnDragXY()
{
//터치 상태로 x축 드래그 범위가 dragDistance보다 클때
if(Mathf.Abs(this.touchEnd.x-this.touchStart.x)>=this.dragDistance)
{
this.movement.MoveToX((int)Mathf.Sign(this.touchEnd.x - this.touchStart.x));
return;
}
//터치 상태로 y축 양의 방향으로 드래그 범위가 dragDistance보다 클떄
if (this.touchEnd.y - touchStart.y >= this.dragDistance)
{
this.movement.MoveToY();
return;
}
}
5. FollingCam
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class FollowingCam : MonoBehaviour
{
public Transform target; //카메라가 따라갈 대상 (플레이어)
private Vector3 offset = new Vector3(0f, 5f, -9f); //카메라와 대상 사이의 오프셋
private float smoothSpeed = 0.125f; //카메라 이동 스무딩 정도
private void Start()
{
}
private void LateUpdate()
{
//target이 null이면? return
if (this.target == null) return;
//플레이어의 위치에 오프셋을 더한 위치로 카메라 이동
Vector3 desiredPosition = target.position + offset;
Vector3 smoothedPosition = Vector3.Lerp(transform.position, desiredPosition, smoothSpeed);
transform.position = smoothedPosition;
//카메라가 항상 대상을 바라보도록 설정
transform.LookAt(target);
//카메라의 Rotation을 (30, 0, 0)으로 설정
transform.rotation = Quaternion.Euler(30f, transform.rotation.eulerAngles.y, transform.rotation.eulerAngles.z);
}
}
* Test
* 전체 Script
using System.Collections;
using System.Collections.Generic;
using System.Linq.Expressions;
using Unity.VisualScripting;
using UnityEngine;
public class PlayerController : MonoBehaviour
{
[SerializeField]
private float dragDistance = 50f; //드레그 거리
private Vector3 touchStart; //터치 시작 위치
private Vector3 touchEnd; //터치 끝 위치
private Movement movement;
private void Awake()
{
movement = GetComponent<Movement>();
}
private void Update()
{
//모바일 환경? PC환경?
if (Application.isMobilePlatform)
{
Debug.Log("Mobile");
OnMobilePlatform();
}
else
{
Debug.Log("PC");
OnPCPlatform();
}
}
/// <summary>
/// 모바일 환경에서는 터치&드레그로 조작
/// </summary>
private void OnMobilePlatform()
{
//현제 화면을 터치하고 있지않다면? return
if (Input.touchCount == 0) return;
//첫번째 터치 정보
Touch touch=Input.GetTouch(0);
//터치시작
if(touch.phase==TouchPhase.Began)
{
this.touchStart = touch.position;
}
//터치 & 드레그
else if (touch.phase==TouchPhase.Moved)
{
this.touchEnd = touch.position;
this.OnDragXY();
}
}
/// <summary>
/// PC환경
/// </summary>
private void OnPCPlatform()
{
if(Input.GetMouseButtonDown(0))
{
Debug.Log("PC Touch");
this.touchStart = Input.mousePosition;
}
else if (Input.GetMouseButton(0))
{
this.touchEnd = Input.mousePosition;
this.OnDragXY();
}
}
private void OnDragXY()
{
//터치 상태로 x축 드래그 범위가 dragDistance보다 클때
if(Mathf.Abs(this.touchEnd.x-this.touchStart.x)>=this.dragDistance)
{
this.movement.MoveToX((int)Mathf.Sign(this.touchEnd.x - this.touchStart.x));
return;
}
//터치 상태로 y축 양의 방향으로 드래그 범위가 dragDistance보다 클떄
if (this.touchEnd.y - touchStart.y >= this.dragDistance)
{
this.movement.MoveToY();
return;
}
}
}
using System.Collections;
using System.Collections.Generic;
using Unity.VisualScripting;
using UnityEngine;
public class Movement : MonoBehaviour
{
//x축
private float moveXWidth = 1.5f; // 1회 이동시 이동거리(x축)
private float moveTimeX = 0.1f; //1회 이동시 소요시간 (x축)
private bool isXMove=false; //true : 이동중
//y축
private float originY = 0.55f; //점프 및 착지하는 y축 값
private float gravity = -9.81f; //중력
private float moveTimeY = 0.3f; //1회 이동에 소요 시간 (y축)
private bool isJump=false; //true : 점프 중 (2중 점프 방지)
//z축
[SerializeField]
private float moveSpeed = 20.0f; //(이동속도 (z축)
//회전
private float rotateSpeed = 300f; //회전 속도
private float limitY = -1.0f; //플레이어가 사망하는 y위치
private Rigidbody rb;
private void Awake()
{
this.rb=GetComponent<Rigidbody>();
}
private void Update()
{
this.transform.position += Vector3.forward * this.moveSpeed * Time.deltaTime; //z축(앞으로) 이동
this.transform.Rotate(Vector3.right * this.rotateSpeed * Time.deltaTime); // 회전 (x축을 기준으로)
if(this.transform.position.y<this.limitY) //떨어지면? 게임오버
{
Debug.Log("GameOver");
}
}
/// <summary>
/// 현재 x축 이동 중으로 이동 불가(같은 방향으로 연속 이동 방지)
/// </summary>
/// <param name="x"></param>
public void MoveToX(int x)
{
if (this.isXMove) return; //이중 이동 방지
if (x > 0 && this.transform.position.x < this.moveXWidth) //우로 이동
{
this.StartCoroutine(OnMoveToX(x));
}
else if(x<0&&this.transform.position.x>-this.moveXWidth) //좌로 이동
{
StartCoroutine(OnMoveToX(x));
}
}
/// <summary>
/// 오브잭트 점프
/// 이중 점프 방지
/// </summary>
public void MoveToY()
{
if (this.isJump)
{
return; //이중 점프 방지
}
StartCoroutine(this.OnMveToY());
}
/// <summary>
/// x축으로 오브잭트 이동
/// 이동 중에는 중복 이동을 할 수 없음
/// </summary>
/// <param name="direction"></param>
/// <returns></returns>
private IEnumerator OnMoveToX(int direction)
{
float current = 0;
float percent = 0;
float start = this.transform.position.x;
float end = this.transform.position.x + direction * this.moveXWidth;
this.isXMove= true;
while(percent < 1)
{
current += Time.deltaTime;
percent = current / this.moveTimeX;
float x=Mathf.Lerp(start, end, percent);
this.transform.position=new Vector3(x, this.transform.position.y, this.transform.position.z);
yield return null;
}
this.isXMove= false;
}
private IEnumerator OnMveToY()
{
float current = 0;
float percent = 0;
float v0 = -this.gravity; //y방향의 초기 속도
this.isJump= true;
this.rb.useGravity = false;
while(percent < 1)
{
current += Time.deltaTime;
percent = current / this.moveTimeY;
//시간경과에 따라 오브잭트의 y위치를 변경
//포물선 운동 : 시작위치+초기속도*시간+중력*시간제곱
float y = this.originY + (v0 * percent) + (this.gravity * percent * percent);
this.transform.position=new Vector3(this.transform.position.x,y,this.transform.position.z);
yield return null;
}
this.isJump= false;
this.rb.useGravity = true;
}
}
'게임클라이언트 프로그래밍 > 3D Project' 카테고리의 다른 글
Coin, 장애물 배치 (1) | 2023.08.06 |
---|---|
무한으로 생성되는 오브잭트, Random.Range / System.Random (0) | 2023.08.05 |
Rigidbody 와 Collider로 캐릭터 이동 / Character Controller로 캐릭터 이동 (0) | 2023.07.31 |