Hi I have been working on this for two days for my project and I think it be helpful for other people so here is the code. Its using Hybrid ECS but the Player Component is a IComponentData(Iv seen other examples of hybrid where all components are Monobehaviours, don’t like it).
using Unity.Entities;
using Unity.Mathematics;
using Unity.Transforms2D;
using UnityEngine;
public struct Player : IComponentData
{
}
public class PlayerComponent : ComponentDataWrapper<Player> { }
using System.Collections.Generic;
using Unity.Burst;
using Unity.Collections;
using Unity.Entities;
using Unity.Jobs;
using Unity.Transforms;
using Unity.Mathematics;
using Unity.Transforms2D;
using UnityEngine;
using UnityEngine.Experimental.PlayerLoop;
[UpdateAfter(typeof(PreLateUpdate))]
public class CameraSystem : ComponentSystem
{
public struct Data
{
public readonly int Length;
public GameObjectArray GameObject;
public ComponentDataArray<Player> Player;
}
public class ClipPlanePoints
{
public Vector3[] points;
public float hitDistance;
public bool didCollide;
}
[Inject]private Data data;
public LayerMask collisionLayers;
private float sensitivity = 200;
private float inputX;
private float inputY;
public float minRotatonY = -30;
public float maxRotationY = 50;
private float defaultDistance = 5;
protected override void OnUpdate()
{
if (data.Length == 0)
return;
var dt = Time.deltaTime;
var transform = Camera.main.transform;
var target = data.GameObject[0].transform.GetChild(0).transform;
collisionLayers = ~0;
//Rotate
inputX += Input.GetAxisRaw("RightHorizontal") * dt * sensitivity;
inputY += Input.GetAxisRaw("RightVertical") * dt * sensitivity;
inputY = Mathf.Clamp(inputY,minRotatonY,maxRotationY);
transform.eulerAngles = new Vector3(inputY,inputX);
//Move To Default Position
transform.position = (target.position) - transform.forward * defaultDistance;
//Collision
ClipPlanePoints nearClipPlanePoints = GetCameraClipPlanePoints (target);
DetectCollision(nearClipPlanePoints,target);
//Move To Position based on collision
transform.position = (target.position) - transform.forward * ((nearClipPlanePoints.didCollide) ? nearClipPlanePoints.hitDistance : defaultDistance);
}
private ClipPlanePoints GetCameraClipPlanePoints(Transform target)
{
//Variables
ClipPlanePoints clipPlanePoints = new ClipPlanePoints();
Transform transform = Camera.main.transform;
float length = Camera.main.nearClipPlane;
float height = Mathf.Tan((Camera.main.fieldOfView) * Mathf.Deg2Rad) * length;
float width = height * Camera.main.aspect;
clipPlanePoints.points = new Vector3[5];
//Get Points
clipPlanePoints.points[0] = (transform.position + transform.forward * length) + (transform.right * width) - (transform.up * height);
clipPlanePoints.points[1] = (transform.position + transform.forward * length) - (transform.right * width) - (transform.up * height);
clipPlanePoints.points[2] = (transform.position + transform.forward * length) + (transform.right * width) + (transform.up * height);
clipPlanePoints.points[3] = (transform.position + transform.forward * length) - (transform.right * width) + (transform.up * height);
clipPlanePoints.points[4] = (transform.position + transform.forward * length);
return clipPlanePoints;
}
public void DetectCollision(ClipPlanePoints clipPlanePoints, Transform target)
{
RaycastHit hit;
clipPlanePoints.hitDistance = -1f;
for(int i = 0; i < clipPlanePoints.points.Length; i++)
{
if (Physics.Raycast (target.position, (clipPlanePoints.points[i] - target.position), out hit, Vector3.Distance(target.position,clipPlanePoints.points[i]),collisionLayers))
{
Debug.DrawLine (target.position, hit.point, Color.red);
clipPlanePoints.didCollide = true;
if (clipPlanePoints.hitDistance < 0 || hit.distance < clipPlanePoints.hitDistance)
clipPlanePoints.hitDistance = hit.distance;
}
else
Debug.DrawLine (target.position, clipPlanePoints.points[i]);
}
}
}
Edit : Cleaner using statements
using Unity.Entities;
using UnityEngine;
using UnityEngine.Experimental.PlayerLoop;
I used a class because I’m just used to it. My bad. Here is the updated code with it being a struct and only 3 dependencies. I assure you that the rest of my project only uses structs except for one scriptable object class that holds prefabs in my Bootstrap code, and when I need to use Unity’s legacy components such as Transforms, Rigidbodys, and Animator.
Thanks for the feedback.
using Unity.Entities;
using UnityEngine;
using UnityEngine.Experimental.PlayerLoop;
[UpdateAfter(typeof(PreLateUpdate))]
public class CameraSystem : ComponentSystem
{
public struct Data
{
public readonly int Length;
public ComponentArray<Transform> Transform;
public ComponentDataArray<Player> Player;
}
public struct ClipPlanePoints
{
public Vector3[] points;
public float hitDistance;
public bool didCollide;
}
[Inject]private Data data;
public LayerMask collisionLayers;
private float sensitivity = 200;
private float inputX;
private float inputY;
public float minRotatonY = -50;
public float maxRotationY = 80;
private float defaultDistance = 5;
protected override void OnUpdate()
{
if (data.Length == 0)
return;
var dt = Time.deltaTime;
var transform = Camera.main.transform;
var target = data.Transform[0].GetChild(0).transform;
collisionLayers = ~0;
//Rotate
inputX += Input.GetAxisRaw("RightHorizontal") * dt * sensitivity;
inputY += Input.GetAxisRaw("RightVertical") * dt * sensitivity;
inputY = Mathf.Clamp(inputY,minRotatonY,maxRotationY);
transform.eulerAngles = new Vector3(inputY,inputX);
//Move To Default Position
transform.position = (target.position) - transform.forward * defaultDistance;
//Collision
ClipPlanePoints nearClipPlanePoints = GetCameraClipPlanePoints (target);
DetectCollision(ref nearClipPlanePoints,target);
//Move To Position based on collision
transform.position = (target.position) - transform.forward * ((nearClipPlanePoints.didCollide) ? nearClipPlanePoints.hitDistance : defaultDistance);
}
private ClipPlanePoints GetCameraClipPlanePoints(Transform target)
{
//Variables
ClipPlanePoints clipPlanePoints = new ClipPlanePoints();
Transform transform = Camera.main.transform;
float length = Camera.main.nearClipPlane;
float height = Mathf.Tan((Camera.main.fieldOfView) * Mathf.Deg2Rad) * length;
float width = height * Camera.main.aspect;
clipPlanePoints.points = new Vector3[5];
//Get Points
clipPlanePoints.points[0] = (transform.position + transform.forward * length) + (transform.right * width) - (transform.up * height);
clipPlanePoints.points[1] = (transform.position + transform.forward * length) - (transform.right * width) - (transform.up * height);
clipPlanePoints.points[2] = (transform.position + transform.forward * length) + (transform.right * width) + (transform.up * height);
clipPlanePoints.points[3] = (transform.position + transform.forward * length) - (transform.right * width) + (transform.up * height);
clipPlanePoints.points[4] = (transform.position + transform.forward * length);
return clipPlanePoints;
}
public void DetectCollision(ref ClipPlanePoints clipPlanePoints, Transform target)
{
RaycastHit hit;
clipPlanePoints.hitDistance = -1f;
for(int i = 0; i < clipPlanePoints.points.Length; i++)
{
if (Physics.Raycast (target.position, (clipPlanePoints.points[i] - target.position), out hit, Vector3.Distance(target.position,clipPlanePoints.points[i]),collisionLayers))
{
Debug.DrawLine (target.position, hit.point, Color.red);
clipPlanePoints.didCollide = true;
if (clipPlanePoints.hitDistance < 0 || hit.distance < clipPlanePoints.hitDistance)
clipPlanePoints.hitDistance = hit.distance;
}
else
Debug.DrawLine (target.position, clipPlanePoints.points[i]);
}
}
}
I have to disagree with what Antypodish said. I feel he has mixed up ECS with the job system. While generally used together, they are not the same thing.
There’s nothing wrong with ClipPlanePoints being a class, if you’re not using it in a burst job it doesn’t matter, especially as you have managed types within it anyway. It’s not like classes are obsolete, the sames reasons you used classes before still exist and there are still many uses for managed types within ECS.
What you’ve done is pretty much exactly what the Unity team suggested as the first step for converting old projects onto ECS, and that’s just replacing MonoBehaviour.Update() with ComponentSystem. It is correct to say that you won’t really get many performance benefits for what you’ve done, but it will provide you better laid out code.
You should totally look into taking it further though and seeing if you can jobify everything!