Initial Combat Implementation
This commit is contained in:
@@ -0,0 +1,98 @@
|
||||
using ProjectM.Simulation;
|
||||
using Unity.Entities;
|
||||
using Unity.Mathematics;
|
||||
using Unity.NetCode;
|
||||
using Unity.Transforms;
|
||||
using UnityEngine;
|
||||
|
||||
namespace ProjectM.Client
|
||||
{
|
||||
/// <summary>
|
||||
/// Prototype ARPG follow camera. Attach to the Main Camera (a plain MonoBehaviour): each LateUpdate
|
||||
/// it frames the local player at a fixed pitch/yaw and distance — the classic top-down/isometric ARPG
|
||||
/// framing (V Rising / Diablo / PoE2). Every lever is exposed so the feel can be dialled in live in
|
||||
/// Play Mode. The player's world position is published by <see cref="PrototypeCameraTargetSystem"/>
|
||||
/// (an ECS system that observes job dependencies safely); the MonoBehaviour never touches the
|
||||
/// EntityManager directly — doing so from LateUpdate raced the subscene async-load job and threw a
|
||||
/// job-safety exception at startup. Before a player spawns it frames <see cref="FallbackTarget"/>.
|
||||
/// <para>
|
||||
/// Presentation only — uses wall-clock <c>Time.deltaTime</c> for framerate-independent smoothing,
|
||||
/// which is correct here (not deterministic simulation). Default: mid 3/4 ~45°, perspective.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
[RequireComponent(typeof(Camera))]
|
||||
[DisallowMultipleComponent]
|
||||
public class PrototypeCameraRig : MonoBehaviour
|
||||
{
|
||||
/// <summary>Local player world position, published each client tick by <see cref="PrototypeCameraTargetSystem"/>.</summary>
|
||||
public static float3 TargetWorldPos;
|
||||
|
||||
/// <summary>True while a locally-owned player exists to follow.</summary>
|
||||
public static bool HasTarget;
|
||||
|
||||
[Header("Angle (degrees)")]
|
||||
[Range(10f, 89f)] public float Pitch = 45f;
|
||||
[Range(-180f, 180f)] public float Yaw = 0f;
|
||||
|
||||
[Header("Framing")]
|
||||
[Min(1f)] public float Distance = 16f;
|
||||
[Tooltip("Raise the look-at point off the ground toward the character's centre of mass.")]
|
||||
public float TargetHeight = 1f;
|
||||
|
||||
[Header("Lens")]
|
||||
public bool Orthographic = false;
|
||||
[Range(20f, 90f)] public float FieldOfView = 55f;
|
||||
[Min(1f)] public float OrthoSize = 10f;
|
||||
|
||||
[Header("Follow")]
|
||||
[Tooltip("Higher = snappier follow. 0 = instant. Framerate-independent.")]
|
||||
[Min(0f)] public float FollowSharpness = 8f;
|
||||
[Tooltip("What to frame before a local player exists (edit mode / pre-spawn).")]
|
||||
public Vector3 FallbackTarget = new Vector3(3f, 0f, 4f);
|
||||
|
||||
Camera _cam;
|
||||
|
||||
void Awake() => _cam = GetComponent<Camera>();
|
||||
|
||||
void LateUpdate()
|
||||
{
|
||||
if (_cam == null) _cam = GetComponent<Camera>();
|
||||
|
||||
_cam.orthographic = Orthographic;
|
||||
_cam.fieldOfView = FieldOfView;
|
||||
_cam.orthographicSize = OrthoSize;
|
||||
|
||||
Vector3 target = HasTarget ? (Vector3)TargetWorldPos : FallbackTarget;
|
||||
target.y += TargetHeight;
|
||||
|
||||
var rot = Quaternion.Euler(Pitch, Yaw, 0f);
|
||||
Vector3 desired = target - (rot * Vector3.forward) * Distance;
|
||||
|
||||
float k = FollowSharpness <= 0f ? 1f : 1f - Mathf.Exp(-FollowSharpness * Time.deltaTime);
|
||||
transform.SetPositionAndRotation(Vector3.Lerp(transform.position, desired, k), rot);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Publishes the locally-owned player's world position to <see cref="PrototypeCameraRig"/> statics
|
||||
/// each client tick. Lives in ECS (not the camera MonoBehaviour) so reading <see cref="LocalTransform"/>
|
||||
/// respects job dependencies — avoiding the subscene-load job-safety exception that direct
|
||||
/// EntityManager access from LateUpdate caused.
|
||||
/// </summary>
|
||||
[WorldSystemFilter(WorldSystemFilterFlags.ClientSimulation)]
|
||||
public partial class PrototypeCameraTargetSystem : SystemBase
|
||||
{
|
||||
protected override void OnUpdate()
|
||||
{
|
||||
bool found = false;
|
||||
foreach (var transform in SystemAPI.Query<RefRO<LocalTransform>>()
|
||||
.WithAll<GhostOwnerIsLocal, PlayerTag>())
|
||||
{
|
||||
PrototypeCameraRig.TargetWorldPos = transform.ValueRO.Position;
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
PrototypeCameraRig.HasTarget = found;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3e5890693b64a429789bf3edfae0a6ff
|
||||
Reference in New Issue
Block a user