1. 이동 구현하기
public partial struct MovableSystem : ISystem
{
public void OnUpdate(ref SystemState state)
{
foreach (var (transform, movable) in SystemAPI.Query<RefRW<LocalTransform>, RefRO<MovableComponent>>())
{
Vector3 dir = Vector3.zero;
if (Input.GetKey(KeyCode.UpArrow)) dir += Vector3.forward;
if (Input.GetKey(KeyCode.DownArrow)) dir += Vector3.back;
if (Input.GetKey(KeyCode.LeftArrow)) dir += Vector3.left;
if (Input.GetKey(KeyCode.RightArrow)) dir += Vector3.right;
if (dir == Vector3.zero) continue;
dir = dir.normalized;
var transformValue = transform.ValueRW;
transformValue.Rotation = Quaternion.Euler(0f, 90f - Mathf.Atan2(dir.z, dir.x) * Mathf.Rad2Deg, 0f);
transformValue = transformValue.Translate(dir * movable.ValueRO.moveSpeed * SystemAPI.Time.DeltaTime);
transform.ValueRW = transformValue;
}
}
}
이전에 간단하게 Input 클래스 참조해서 이동시키는 코드를 만들었습니다.
키 입력으로 이동은 어렵지 않게 구현했습니다.
2. InputSystem으로 이동 구현하기
https://docs.unity3d.com/Packages/com.unity.inputsystem@1.4/manual/index.html
Input System | Input System | 1.4.4
Input System The Input System package implements a system to use any kind of Input Device to control your Unity content. It's intended to be a more powerful, flexible, and configurable replacement for Unity's classic Input Manager (the UnityEngine.Input cl
docs.unity3d.com
https://coding-paper.tistory.com/15
유니티로 "젤다의 전설: 꿈꾸는 섬" 모작 2일차
1. 캐릭터 이동 구현 https://docs.unity3d.com/Packages/com.unity.inputsystem@1.0/manual/index.html Input System | Input System | 1.0.2 Input System The Input System package implements a system to use any kind of Input Device to control your Unity con
coding-paper.tistory.com
이전에 기본 세팅은 꿈꾸는 섬 모작 때 했던 링크만 남겨두겠습니다.
InputAction 에셋에 Generate C# Class 체크박스가 있는데 이 부분을 체크하고 Apply버튼을 눌러서 C#클래스로 만들어줄 겁니다.
public partial struct MovableSystem : ISystem, MainInputAction.IPlayerActions
{
// ...
}
그리고 이렇게 System에 상속받아서 구현을 하면 됩니다.
public partial struct MovableSystem : ISystem, MainInputAction.IPlayerActions
{
static Vector2 moveDir;
public void OnCreate(ref SystemState state)
{
var mainInputAction = new MainInputAction();
mainInputAction.Enable();
mainInputAction.Player.SetCallbacks(this);
}
public void OnUpdate(ref SystemState state)
{
foreach (var (transform, movable) in SystemAPI.Query<RefRW<LocalTransform>, RefRO<MovableComponent>>())
{
Vector3 dir = new Vector3(moveDir.x, 0f, moveDir.y);
if (dir == Vector3.zero) continue;
dir = dir.normalized;
var transformValue = transform.ValueRW;
transformValue.Rotation = Quaternion.Euler(0f, 90f - Mathf.Atan2(dir.z, dir.x) * Mathf.Rad2Deg, 0f);
transformValue = transformValue.Translate(dir * movable.ValueRO.moveSpeed * SystemAPI.Time.DeltaTime);
transform.ValueRW = transformValue;
}
}
public void OnMove(InputAction.CallbackContext context)
{
moveDir = context.ReadValue<Vector2>();
}
}
OnMove로 값을 받아와서 저장해뒀다가 OnUpdate에서 적용하도록 작업했습니다.
3. Cinemachine으로 타겟 카메라 구현하기
https://docs.unity3d.com/Packages/com.unity.cinemachine@2.9/manual/index.html
About Cinemachine | Cinemachine | 2.9.4
About Cinemachine Cinemachine is a suite of modules for operating the Unity camera. Cinemachine solves the complex mathematics and logic of tracking targets, composing, blending, and cutting between shots. It is designed to significantly reduce the number
docs.unity3d.com
타겟카메라 구현을 위해 Cinemachine을 추가했습니다.
Main Camera에 Brain을 추가하고 Virtual Camera를 새로 만들었습니다.
그리고 Cinemachine Virtual Camera Target이라든 스크립틀 만들어서 붙였습니다.
[RequireComponent(typeof(Cinemachine.CinemachineVirtualCameraBase))]
public class CinemachineVirtualCameraTarget : MonoBehaviour
{
Cinemachine.CinemachineVirtualCameraBase m_VCam;
public Cinemachine.CinemachineVirtualCameraBase VCam
{
get
{
if (m_VCam == null) m_VCam = GetComponent<Cinemachine.CinemachineVirtualCameraBase>();
return m_VCam;
}
}
Transform m_DummyTransform;
private void Start()
{
VCam.LookAt = null;
VCam.Follow = null;
}
private void LateUpdate()
{
var entityManager = World.DefaultGameObjectInjectionWorld.EntityManager;
EntityQuery query = entityManager.CreateEntityQuery(typeof(MovableComponent));
if (query.IsEmpty == false)
{
var entity = query.GetSingletonEntity();
var localTransform = entityManager.GetComponentData<LocalTransform>(entity);
if (m_DummyTransform == null)
{
var newObj = new GameObject("DummyTransform");
m_DummyTransform = newObj.transform;
VCam.LookAt = m_DummyTransform;
VCam.Follow = m_DummyTransform;
}
m_DummyTransform.position = localTransform.Position;
}
}
}
EntityManager를 참조해서 Entity의 위치를 가져오도록 작업했습니다.
Cinemachine Virtual Camera의 Follow, LookAt 프로퍼티가 Transform을 참조하고 있어서 Dummy Transform을 만들어서 설정하도록 구현했습니다.
Cinemachine에서 개선해주지 않는 이상 이렇게가 한계일 것 같네요.
4. 총알 발사, 이동 구현하기
https://assetstore.unity.com/packages/3d/props/ball-pack-446
Ball Pack | 3D 소품 | Unity Asset Store
Elevate your workflow with the Ball Pack asset from YounGen Tech. Find this & other 소품 options on the Unity Asset Store.
assetstore.unity.com
이번에는 이 에셋을 써봤습니다.
URP에 맞게 셰이더를 일일이 바꿔주었습니다.
public partial struct ShootableSystem : ISystem, MainInputAction.IPlayerActions
{
static bool m_OnKeyFire = false;
public void OnUpdate(ref SystemState state)
{
foreach (var (transform, shootable) in SystemAPI.Query<RefRO<LocalTransform>, RefRW<ShootableComponent>>())
{
//Reloading
if (shootable.ValueRO.BulletCount < shootable.ValueRO.BulletCountMax)
{
if (shootable.ValueRO.BulletReloadTime < shootable.ValueRO.BulletReloadTimeMax)
{
shootable.ValueRW.BulletReloadTime += SystemAPI.Time.DeltaTime;
}
else
{
shootable.ValueRW.BulletReloadTime -= shootable.ValueRO.BulletReloadTimeMax;
shootable.ValueRW.BulletCount++;
Debug.Log("On Reload " + shootable.ValueRO.BulletCount);
if (shootable.ValueRO.BulletCount >= shootable.ValueRO.BulletCountMax)
{
shootable.ValueRW.BulletReloadTime = 0f;
}
}
}
//Fire
if (m_OnKeyFire == true)
{
if (shootable.ValueRW.BulletCount > 0 &&
SystemAPI.Time.ElapsedTime >= shootable.ValueRO.BulletLastShotTime + shootable.ValueRO.BulletShotCooltime)
{
shootable.ValueRW.BulletCount--;
shootable.ValueRW.BulletLastShotTime = (float)SystemAPI.Time.ElapsedTime;
if (shootable.ValueRO.BulletPrefab != Entity.Null)
{
var bulletEntity = state.EntityManager.Instantiate(shootable.ValueRO.BulletPrefab);
var bulletTransform = new LocalTransform() { Position = transform.ValueRO.Position , Scale = 1f, Rotation = transform.ValueRO.Rotation };
bulletTransform.Position += math.mul(transform.ValueRO.Rotation, shootable.ValueRO.ShootOffset);
state.EntityManager.SetComponentData(bulletEntity, bulletTransform);
}
}
m_OnKeyFire = false;
}
}
}
public void OnFire(InputAction.CallbackContext context)
{
m_OnKeyFire = true;
}
}
Shootable System 구현입니다.
리로드 하고 발사하는 부분인데, 이전에 했던 내용의 반복이라 어렵지 않게 구현했습니다.
public partial struct BulletSystem : ISystem
{
public void OnUpdate(ref SystemState state)
{
foreach (var (transform, bullet) in SystemAPI.Query<RefRW<LocalTransform>, RefRO<BulletComponent>>())
{
var transformValue = transform.ValueRW;
transformValue = transformValue.Translate(math.mul(transformValue.Rotation, Vector3.forward) * bullet.ValueRO.Speed * SystemAPI.Time.DeltaTime);
transform.ValueRW = transformValue;
}
}
}
Bullet관련도 이전에 했던 내용 들고 구현했습니다.
발사체를 발사하는 것까지는 문제없이 구현되었습니다.
https://docs.unity3d.com/Packages/com.unity.physics@1.0/manual/index.html
Unity Physics overview | Unity Physics | 1.0.0-pre.15
Unity Physics overview The Unity Physics package, part of Unity's Data-Oriented Technology Stack (DOTS), provides a deterministic rigid body dynamics system and spatial query system. See the Unity Physics Samples for introductory material, including tutori
docs.unity3d.com
다음에는 Physics를 추가해서 발사체 충돌을 구현해 보겠습니다.
Hybrid Renderer도 추가해보고 Navigation도 추가해봤는데 아직은 추가할 때가 아니거나 ECS에서 동작하지 않아 쓰지 못해서 아쉽네요.
그래도 어디까지 이용 가능하고 새로 구현해야 하는지 알게 되어서 많은 도움이 되었다고 생각합니다.
'Study Log' 카테고리의 다른 글
Unity ECS Study Log - 6 (0) | 2023.01.15 |
---|---|
Unity ECS Study Log - 5 (0) | 2023.01.14 |
Unity ECS Study Log - 3 (1) | 2023.01.07 |
Unity ECS Study Log - 2 (0) | 2023.01.01 |
Unity ECS Study Log - 1 (0) | 2023.01.01 |