Last active
February 5, 2022 12:43
-
-
Save thygrrr/4138fdbed9bdaff5bf9d41ee08d3dd04 to your computer and use it in GitHub Desktop.
A ECS system where a physical object can "cut" through a turn and glide like a ship or a bird.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using Jovian.ECS.Components; | |
using Jovian.ECS.Components.Space; | |
using Jovian.ECS.Components.Vessels; | |
using Jovian.ECS.Systems.Physics; | |
using Unity.Burst; | |
using Unity.Entities; | |
using Unity.Jobs; | |
using Unity.Mathematics; | |
using Unity.Physics; | |
using Unity.Physics.Systems; | |
using Unity.Transforms; | |
using UnityEngine; | |
namespace Jovian.ECS.Systems.Control | |
{ | |
[UpdateInGroup(typeof(FixedStepSimulationSystemGroup))] | |
[UpdateBefore(typeof(BuildPhysicsWorld))] | |
public class VesselOpenSpaceControl : PhysicsSystemBase | |
{ | |
protected override void OnUpdate() | |
{ | |
var dt = timeStep; | |
//Ok why is this not needed | |
Dependency = JobHandle.CombineDependencies(exportPhysicsWorldSystem.GetOutputDependency(), Dependency); | |
//Hey, this indents kinda nicely for once. :) | |
Entities | |
.WithNone<BubbleGroup>() | |
.ForEach( | |
( | |
ref OpenSpaceVelocity velocity, | |
in ShipControls controls, | |
in Propulsion propulsion, //TODO: Create custom OS propulsion? | |
in PhysicsMass mass, | |
in Rotation rotation | |
) => | |
{ | |
//We don't have transform.rotation in ECS | |
var rot = rotation.Value; | |
//We don't have transform.forward etc. in ECS, much simpler for GameObjects | |
var forward = math.rotate(rot, new float3(0, 0, 1)); | |
var right = math.rotate(rot, new float3(1, 0, 0)); | |
var up = math.rotate(rot, new float3(0, 1, 0)); | |
var linear_thrust = | |
forward * | |
controls.translate.z * | |
propulsion.Thrust.z * | |
mass.InverseMass * dt; | |
var linear_magnitude = math.length(velocity.Linear); | |
if (linear_magnitude > 0) | |
{ | |
var linear_direction = math.normalize(velocity.Linear); | |
//Apply trim tensor logic allowing to preserve forward velocity through turns. | |
var lateral_flow = propulsion.TrimX * math.abs(math.dot(right, linear_direction)); | |
var vertical_flow = propulsion.TrimY * math.abs(math.dot(up, linear_direction)); | |
var flow = (lateral_flow + vertical_flow) * linear_magnitude * dt; | |
var inert = linear_magnitude - flow; //this is a remainder, so no dt | |
// "Gliding" | |
var linear_flow = flow * forward; | |
// "Sliding" | |
var linear_inert = inert * linear_direction; | |
velocity.Linear = linear_flow + linear_inert; | |
} | |
//Standard thrust addition. | |
velocity.Linear += linear_thrust; | |
//Lerp between different turning speeds based on current speed | |
var v_effective = math.saturate(math.length(velocity.Linear / propulsion.MaxRequiredVelocity)); | |
var turning = controls.pitch * math.lerp(propulsion.TurnMin, propulsion.TurnMax, v_effective); | |
velocity.Angular += turning * dt * mass.InverseMass; | |
} | |
).ScheduleParallel(); | |
//Ok why is this not needed, and why wasn't it BuildPhysicsWorld | |
//endFramePhysicsSystem.AddInputDependency(Dependency); | |
} | |
} | |
[UpdateInGroup(typeof(FixedStepSimulationSystemGroup))] | |
[UpdateBefore(typeof(BuildPhysicsWorld))] | |
[UpdateAfter((typeof(VesselOpenSpaceControl)))] | |
public class VesselSpaceIntegrator : PhysicsSystemBase | |
{ | |
[BurstCompile] | |
protected override void OnUpdate() | |
{ | |
var dt = timeStep; | |
Entities | |
.WithNone<BubbleGroup>() | |
.ForEach( | |
( | |
ref FloatingPosition floating, | |
ref OpenSpaceVelocity velocity, | |
ref Rotation rotation, | |
in PhysicsDamping damping | |
) => | |
{ | |
velocity.Angular *= math.clamp(1.0f - damping.Angular * dt, 0, 1); | |
velocity.Linear *= math.clamp(1.0f - damping.Linear * dt, 0, 1); | |
IntegrateOrientation(ref rotation.Value, velocity.Angular, dt); | |
floating.position += velocity.Linear * Constants.Space2ViewF * dt; | |
} | |
).ScheduleParallel(); | |
} | |
private static void IntegrateOrientation(ref quaternion orientation, float3 angular_velocity, float dt) | |
{ | |
quaternion dq = IntegrateAngularVelocity(angular_velocity, dt); | |
quaternion r = math.mul(orientation, dq); | |
orientation = math.normalize(r); | |
} | |
// Returns a non-normalized quaternion that approximates the change in angle angularVelocity * timestep. | |
private static quaternion IntegrateAngularVelocity(float3 angular_velocity, float dt) | |
{ | |
var half_delta_time = new float3(dt * 0.5f); | |
var half_delta_angle = angular_velocity * half_delta_time; | |
return new quaternion(new float4(half_delta_angle, 1.0f)); | |
} | |
} | |
[UpdateInGroup(typeof(FixedStepSimulationSystemGroup))] | |
[UpdateBefore(typeof(BuildPhysicsWorld))] | |
public class VesselSpaceTrajectoryMover : PhysicsSystemBase | |
{ | |
protected override void OnUpdate() | |
{ | |
var dt = timeStep; | |
Dependency = JobHandle.CombineDependencies(exportPhysicsWorldSystem.GetOutputDependency(), Dependency); | |
var up = new float3(0, 1, 0); | |
//Trajectory Movement | |
Entities | |
.WithNone<BubbleGroup>() | |
.ForEach( | |
( | |
ref FlipAndBurnTrajectory trajectory, | |
ref FloatingPosition floating, | |
ref Rotation rotation | |
) => | |
{ | |
if (trajectory.time == 0) | |
{ | |
trajectory.Initialize(); | |
} | |
trajectory.time += dt / trajectory.duration; | |
trajectory.Evaluate(out var pos, out var dir, out var accel); | |
floating.position = pos; | |
rotation = new Rotation() {Value = quaternion.LookRotation(dir, up)}; | |
} | |
).ScheduleParallel(); | |
endFramePhysicsSystem.AddInputDependency(Dependency); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment