* 대상의 이동과 회전을 조작할 수 있다.
* 가상 조이스틱과 키보드, 마우스를 이용할 수 있다.
1. Transform - MoveTowards & eulerAngles 이용
2. Rigidbody - MovePosition & MoveRotation 이용
3. NavAgent - Move 이용
4. DOT - Translation & Rotation 이용
transform.position 이동은 transform의 월드 좌표 기준으로 이동한다. - transform 방향에 영향을 받지 않음.
transform.Translate 이동은 transform의 로컬 기준으로 이동한다. - transform 방향에 영향을 받음.
transform.position = Vector3.Lerp(position , destination, Time.deltaTime * speed);
transform.position = Vector3.MoveTowards(position, destination, Time.deltaTime * speed);
eulerAngle을 사용할 경우 발생할 수 있는 짐벌락 현상을 해결하기 위해 Quaternion이 존재한다.
1.321 Quaternion 예시
transform.rotation = Quaternion.Euler(0,90,0);
1.322 eulerAngles 예시 (3D 기준)
transform.eulerAngles = new Vector(0, Mathf.Atan2(getAxisX,getAxisY) * Mathf.Rad2Deg, 0);
1.323 eulerAngels 예시 (2D 기준)
transform.eulerAngles = new Vector(0, 0, Mathf.Atan(getAxisX,getAxisY) * Mathf.Rad2Deg);
2.11 MovePosition 예시
RigidBody rigid;
Vector3 vel;
float inputMagnitude;
float inputDirection;
float moveSpeed = 5;
float smoothMoveTime = 0.1f;
float smoothMoveVel = 0;
void CalVelocity()
{
inputDirection = new Vector3(Input.GetAxisRaw("Horizontal"), 0, (Input.GetAxisRaw("Vertical"));
inputMagnitude = inputDirection.magnitude;
float smoothInputMagnitude = Mathf.SmoothDamp(smoothInputMagnitude, inputMagnitude, ref smoothMoveVel, smoothMoveTime);
vel = transform.forward * moveSpeed * smoothInputMagnitude;
}
void Update()
{
...
CalVelocity();
...
}
void FixedUpdate()
{
rigid.MovePosition(rigid.position + vel * Time.deltaTime);
}
...
float angle;
float turnSpeed = 5;
...
void CalAngle()
{
flaot target = Mathf.Atan2(inputDirection.x,inputDirection.z) * Mathf.Rad2Deg;
angle = Mathf.LerpAngle(angle, targetAngle, Time.deltaTime * turnSpeed * inputMagnitude);
}
void Update()
{
...
CalVelocity();
CalAngle();
...
}
void FixedUpdate()
{
rigid.MoveRotation(Quaternion.Euler(Vector3.up * angle));
rigid.MovePosition(rigid.position + vel * Time.deltaTime);
}
NavmeshAgent agent;
Transform target;
void Start()
{
agent = GetComponent<NavMeshAgent>();
}
void Update()
{
agent.Move(target.position);
}
public struct PlayerSpeed : IComponentData
{
float speed;
}
public struct InputVectorComponent : IComponentData
{
float3 input;
}
// moving speed authoring
public class PlayerSpeedAuthoring : MonoBehaviour
{
public float speed;
}
public class PlayerSpeedBaker : Baker<SpeedAuthoring>
{
public override void Bake(SpeedAuthoring authoring)
{
AddComponent(new Speed()
{
speed = authoring.speed;
});
}
}
// input Horizontal or Vertical authoring
public class InputVectorAuthoring : MonoBehaviour
{
public float3 input;
}
public class InputVectorBaker : Baker<InputVectorAuthoring>
{
public override void Bake(InputVectorAuthoring authoring)
{
AddComponent(new InputVectorComponent()
{
input = authoring.input;
});
}
}
public struct MovingPlayerTag : IComponentData
{
// stay empty..
}
public class MovingPlayerAuthoring : MonoBehaviour
{
// stay empty..
}
public class MovingPlayerBaker : Baker<MovingPlayerAuthoring>
{
public override void Bake(MovingPlayerAutohring authoring)
{
AddComponent(new MovingPlayerTag());
}
}
// must use 'readonly-partial' pair
public readonly partial struct PlayerMovementAspect : IAspect
{
private readonly Entity _entity;
private readonly TransformAspect _transformAspect;
public void Move(float deltaTime, RefRO<Speed> speed, RewfRW<InputVectorComponent> input)
{
_transformAspect.Position += input.ValueRW.input * deltaTime * speed.ValueRO.speed;
}
}
4.51 Not Rotate But Move
public partial class PlayerMovementSystem : SystemBase
{
protected override void OnUpdate()
{
// Do not use UnityEngine.Time.DeltaTime;
// Use SystemAPI
var deltaTime = SystemAPI.Time.DeltaTime;
// 2d 이동
var input = new float3(Input.GetAxis("Horizontal"), Input.GetAxis("Vertial"),0);
// 3d 이동
// var input = new float3(Input.GetAxis("Horizontal"), 0,Input.GetAxis("Vertial"));
// Init InputVectorComponent, RW - Read & Write | RO - ReadOnly
var inputVector = SystemAPI.GetSingletonRW<InputVectorComponent>();
inputVector.ValueRW.input = input;
// 3 way
// 1. foreach
/*
foreach((var agent in SystemAPI.Query<PlayerMovmentAspect, PlayerTag, PlayerSpeed, InputVectorComponent>())
{
// item1 => PlayerMovementAspect : For Behaviour
// item2 => PlayerTag : For Filtering
// item3 => PlayerSpeed : Variable
// item4 => InputVectorComponent : Controll
agent.Item1.Move(deltaTime, agent.item3, agent.item4);
}
*/
// Player Only one ..But It also Work.
// 2. Entities.With-..
/*
Entities
.WithAll<PlayerTag>()
.ForEach((PlayerMovementAspect player, RefRW<PlayerSpeed> speed) =>
{
player.Move(deltaTime,speed,inputVectorComponent);
}).Run();
*/
// 3. GetSingletonEntity ( recommand )
var player = GetSingletonEntity<PlayerTag>();
var speed = GetSingletonRW<PlayerSpeed>();
SystemAPI.GetAspectRW<PlayerMovementAspect>(player)
.Move(deltaTime,speed, inputVectorComponent);
}
}
protected override void OnUpdate()
{
_transformAspect.Rotation =
math.mul(math.normalize(_transformAspect.Rotation.value),
quaternion.AxisAngle(math.forward(),deltaTime * speed.ValueRW.value));
}
결과 ▼
public void Move(float deltaTime,RefRW<PlayerSpeed> speed, RefRW<PlayerMoveComponent> _playerMoveComponent)
{
// self speed
_transformAspect.Rotation = math.mul(math.normalize(_transformAspect.Rotation.value), quaternion.AxisAngle(math.forward(),deltaTime * speed.ValueRW.value));
// orbit speed
_playerMoveComponent.ValueRW.speed += deltaTime * speed.ValueRW.value;
// orbit Move
_transformAspect.Position = new float3(math.cos(_playerMoveComponent.ValueRW.speed), math.sin(_playerMoveComponent.ValueRW.speed ), 0);
// x와 y좌표에 angle을 float로 더해주고 여러개의 오브젝트를 배치하면, 원 위의 여러 점으로 나타난다.
// ex. 위의 코드 재활용
// new float3(math.cos(_playerMoveComponent.ValueRW.speed + 45) , math.sin(_playerMoveComponent.ValueRW.speed + 45) , 0)
// 당연히 45 대신 간단한 알고리즘을 사용하여 여러 개를 자동 배치 하자.
}
결과 ▼
public struct Destination : IComponentData
{
public float3 destination;
}
public class DestinationAuthoring : MonoBehaviour
{
public float3 destination;
}
public class DestinationBaker : Baker<DestinationAuthoring>
{
public override void Bake(DestinationAuthoring authoring)
{
AddComponent(new Destination()
{
destination = authoring.destination
});
}
}
public struct Random : IComponentData
{
public Random random;
}
public class RandomAuthoring : MonoBehaviour
{
// Empty
}
public class RandomBaker : Baker<RandomAuthoring>
{
public override void Bake(RandomAuthoring authoring)
{
AddComponent(new Random()
{
random = new Random(seed : 1)
});
}
}
private float3 SetRandomDestination(RefRW<RandomComponent> random, float2 range)
{
return new float3(random.ValueRW.random.NextFloat(range.x, range.y), random.ValueRW.random.NextFloat(range.x, range.y), 0);
}
public bool IsArrived(float3 lhs, float3 rhs, float tolerence)
{
return math.distance(lhs, rhs) < tolerence;
}
public readonly partial struct MoveAspect : IAspect
{
private readonly Entity _entity;
private readonly TransformAspect _transformAspect;
private readonly RefRW<DetectComponent> _detectComponent;
private readonly RefRW<Speed> _speed;
private readonly RefRW<Destination> _destination;
public void Move(float deltaTime, RefRW<RandomComponent> random, float2 range)
{
if (IsArrived(_destination.ValueRW.point, _transformAspect.Position, _detectComponent.ValueRO.detectingDistanceRangeSensitive))
_destination.ValueRW.point = SetRandomDestination(random, range);
var dir = math.normalize(_destination.ValueRW.point - _transformAspect.Position);
_transformAspect.Position += dir * deltaTime * _speed.ValueRW.value;
}
}
public partial struct MoveJob : IJobEntity
{
public float deltaTime;
// Must use this attributte.
[NativeDisableUnsafePtrRestriction]public RefRW<RandomComponent> random;
public float2 range;
public void Execute(MoveAspect agent)
{
agent.Move(deltaTime, random, range);
}
}
public partial struct MovingISystem : ISystem
{
public void OnCreate(ref SystemState state)
{
}
public void OnDestroy(ref SystemState state)
{
}
[BurstCompile]
public void OnUpdate(ref SystemState state)
{
var deltaTime = SystemAPI.Time.DeltaTime;
var random = SystemAPI.GetSingletonRW<RandomComponent>();
var range = new float2(10, -10);
var moveJobHandle = new MoveJob()
{
deltaTime = deltaTime,
random = random,
range = range
}.Schedule(state.Dependency);
moveJobHandle.Complete();
}
}
결과 ▼