Initial commit
This commit is contained in:
11
code/EntityComponents/Client/ClientComponent.cs
Normal file
11
code/EntityComponents/Client/ClientComponent.cs
Normal file
@@ -0,0 +1,11 @@
|
||||
using Sandbox;
|
||||
|
||||
namespace LuckerGame.Components.Client;
|
||||
|
||||
/// <summary>
|
||||
/// Intended to be a base class for components intended for IClient, as IClient cannot be used as an EntityComponent type param
|
||||
/// </summary>
|
||||
public abstract class ClientComponent : EntityComponent
|
||||
{
|
||||
public IClient Client => Entity as IClient;
|
||||
}
|
||||
36
code/EntityComponents/Lucker/Cameras/AbstractCamera.cs
Normal file
36
code/EntityComponents/Lucker/Cameras/AbstractCamera.cs
Normal file
@@ -0,0 +1,36 @@
|
||||
using LuckerGame.Entities;
|
||||
using Sandbox;
|
||||
|
||||
namespace LuckerGame.Components.Lucker.Cameras;
|
||||
|
||||
public abstract class AbstractCamera : EntityComponent<Entities.Lucker>
|
||||
{
|
||||
protected Vector3 CameraPosition { get; set; }
|
||||
protected Rotation CameraRotation { get; set; }
|
||||
protected float FieldOfView { get; set; }
|
||||
protected IEntity FirstPersonViewer { get; set; }
|
||||
protected Transform SoundSource { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Handles any input-independent camera updates (ie following a pawn)
|
||||
/// </summary>
|
||||
protected abstract void UpdateCameraParameters();
|
||||
|
||||
/// <summary>
|
||||
/// Handles any input dependent camera updates (ie moving around a top down cam)
|
||||
/// </summary>
|
||||
public abstract void BuildInput();
|
||||
|
||||
/// <summary>
|
||||
/// Applies Camera parameters to the static Camera
|
||||
/// </summary>
|
||||
public virtual void Update()
|
||||
{
|
||||
UpdateCameraParameters();
|
||||
Camera.Position = CameraPosition;
|
||||
Camera.Rotation = CameraRotation;
|
||||
Camera.FieldOfView = FieldOfView;
|
||||
Camera.FirstPersonViewer = FirstPersonViewer;
|
||||
Sound.Listener = SoundSource;
|
||||
}
|
||||
}
|
||||
47
code/EntityComponents/Lucker/Cameras/RTSCamera.cs
Normal file
47
code/EntityComponents/Lucker/Cameras/RTSCamera.cs
Normal file
@@ -0,0 +1,47 @@
|
||||
using Sandbox;
|
||||
using System;
|
||||
using System.Linq;
|
||||
|
||||
namespace LuckerGame.Components.Lucker.Cameras;
|
||||
|
||||
/// <summary>
|
||||
/// A top down camera that can be
|
||||
/// </summary>
|
||||
public partial class RTSCamera : AbstractCamera, ISingletonComponent
|
||||
{
|
||||
private const float MaxDistance = 400f;
|
||||
private const float MinDistance = 200f;
|
||||
private const float Speed = 4f;
|
||||
protected float WheelSpeed => 5f;
|
||||
protected Vector2 DistanceClamp => new( MinDistance, MaxDistance );
|
||||
protected float CameraDistance = MinDistance;
|
||||
protected float TargetDistance = MinDistance;
|
||||
|
||||
private Vector3 CameraPositionOffset = Vector3.Zero;
|
||||
|
||||
protected override void UpdateCameraParameters()
|
||||
{
|
||||
CameraPosition = Entity.Position + CameraPositionOffset;
|
||||
CameraRotation = Rotation.FromPitch( -270 );
|
||||
FieldOfView = 70f;
|
||||
FirstPersonViewer = null;
|
||||
CameraPosition = CameraPosition.WithZ( CameraDistance );
|
||||
SoundSource = new Transform { Position = CameraPosition };
|
||||
}
|
||||
|
||||
public override void BuildInput()
|
||||
{
|
||||
// Zooming in and out
|
||||
var wheel = Input.MouseWheel;
|
||||
if ( wheel != 0 )
|
||||
{
|
||||
TargetDistance -= wheel * WheelSpeed;
|
||||
TargetDistance = TargetDistance.Clamp( DistanceClamp.x, DistanceClamp.y );
|
||||
}
|
||||
|
||||
CameraDistance = CameraDistance.LerpTo( TargetDistance, Time.Delta * 10f );
|
||||
|
||||
// Moving
|
||||
CameraPositionOffset += Input.AnalogMove * Speed;
|
||||
}
|
||||
}
|
||||
97
code/EntityComponents/Lucker/Cameras/TopDownCamera.cs
Normal file
97
code/EntityComponents/Lucker/Cameras/TopDownCamera.cs
Normal file
@@ -0,0 +1,97 @@
|
||||
/*using Sandbox;
|
||||
using System;
|
||||
using System.Linq;
|
||||
|
||||
namespace LuckerGame.Components.Lucker.Cameras;
|
||||
|
||||
/// <summary>
|
||||
/// A top downish camera that follows an entity
|
||||
/// </summary>
|
||||
public partial class TopDownCamera : AbstractCamera, ISingletonComponent
|
||||
{
|
||||
protected float WheelSpeed => 30f;
|
||||
protected Vector2 CameraDistance => new( 125, 1000 );
|
||||
protected Vector2 PitchClamp => new( 30, 60 );
|
||||
|
||||
float OrbitDistance = 400f;
|
||||
float TargetOrbitDistance = 400f;
|
||||
Angles OrbitAngles = Angles.Zero;
|
||||
|
||||
protected static Vector3 IntersectPlane( Vector3 pos, Vector3 dir, float z )
|
||||
{
|
||||
float a = (z - pos.z) / dir.z;
|
||||
return new( dir.x * a + pos.x, dir.y * a + pos.y, z );
|
||||
}
|
||||
|
||||
protected static Rotation LookAt( Vector3 targetPosition, Vector3 position )
|
||||
{
|
||||
var targetDelta = (targetPosition - position);
|
||||
var direction = targetDelta.Normal;
|
||||
|
||||
return Rotation.From( new Angles(
|
||||
((float)Math.Asin( direction.z )).RadianToDegree() * -1.0f,
|
||||
((float)Math.Atan2( direction.y, direction.x )).RadianToDegree(),
|
||||
0.0f ) );
|
||||
}
|
||||
|
||||
public override void Update()
|
||||
{
|
||||
var pawn = Entity;
|
||||
if ( !pawn.IsValid() )
|
||||
return;
|
||||
|
||||
Camera.Position = pawn.Position;
|
||||
Vector3 targetPos;
|
||||
|
||||
Camera.Position += Vector3.Up * (pawn.CollisionBounds.Center.z * pawn.Scale);
|
||||
Camera.Rotation = Rotation.From( OrbitAngles );
|
||||
|
||||
targetPos = Camera.Position + Camera.Rotation.Backward * OrbitDistance;
|
||||
|
||||
Camera.Position = targetPos;
|
||||
Camera.FieldOfView = 70f;
|
||||
Camera.FirstPersonViewer = null;
|
||||
|
||||
Sound.Listener = new()
|
||||
{
|
||||
Position = pawn.AimRay.Position,
|
||||
Rotation = pawn.EyeRotation
|
||||
};
|
||||
}
|
||||
|
||||
public override void BuildInput()
|
||||
{
|
||||
var wheel = Input.MouseWheel;
|
||||
if ( wheel != 0 )
|
||||
{
|
||||
TargetOrbitDistance -= wheel * WheelSpeed;
|
||||
TargetOrbitDistance = TargetOrbitDistance.Clamp( CameraDistance.x, CameraDistance.y );
|
||||
}
|
||||
|
||||
OrbitDistance = OrbitDistance.LerpTo( TargetOrbitDistance, Time.Delta * 10f );
|
||||
|
||||
// Sets pawn to face where the camera faces
|
||||
if ( Input.UsingController || Input.Down( "attack2" ) )
|
||||
{
|
||||
OrbitAngles.yaw += Input.AnalogLook.yaw;
|
||||
OrbitAngles.pitch += Input.AnalogLook.pitch;
|
||||
OrbitAngles = OrbitAngles.Normal;
|
||||
|
||||
Entity.ViewAngles = OrbitAngles.WithPitch( 0f );
|
||||
}
|
||||
// Sets pawn to face to point that the mouse is over
|
||||
else
|
||||
{
|
||||
// Get ray from direction vector from mouse pointer through screen
|
||||
var direction = Screen.GetDirection( Mouse.Position, Camera.FieldOfView, Camera.Rotation, Screen.Size );
|
||||
|
||||
var hitPos = IntersectPlane( Camera.Position, direction, Entity.EyePosition.z );
|
||||
|
||||
Entity.ViewAngles = (hitPos - Entity.EyePosition).EulerAngles;
|
||||
}
|
||||
|
||||
OrbitAngles.pitch = OrbitAngles.pitch.Clamp( PitchClamp.x, PitchClamp.y );
|
||||
|
||||
Entity.InputDirection = Input.AnalogMove;
|
||||
}
|
||||
}*/
|
||||
15
code/EntityComponents/Lucker/LuckerClientInput.cs
Normal file
15
code/EntityComponents/Lucker/LuckerClientInput.cs
Normal file
@@ -0,0 +1,15 @@
|
||||
using Sandbox;
|
||||
|
||||
namespace LuckerGame.EntityComponents.Lucker;
|
||||
|
||||
/// <summary>
|
||||
/// A component for capturing and passing around a client's input for an attached Lucker
|
||||
/// </summary>
|
||||
public class LuckerClientInput : EntityComponent<Entities.Lucker>
|
||||
{
|
||||
[ClientInput]
|
||||
public Vector3 InputDirection { get; set; }
|
||||
|
||||
[ClientInput]
|
||||
public Angles ViewAngles { get; set; }
|
||||
}
|
||||
21
code/EntityComponents/Pawn/PawnAnimator.cs
Normal file
21
code/EntityComponents/Pawn/PawnAnimator.cs
Normal file
@@ -0,0 +1,21 @@
|
||||
using Sandbox;
|
||||
using System;
|
||||
|
||||
namespace LuckerGame.Components.Pawn;
|
||||
|
||||
public class PawnAnimator : EntityComponent<Entities.Pawn>, ISingletonComponent
|
||||
{
|
||||
public void Simulate()
|
||||
{
|
||||
var helper = new CitizenAnimationHelper( Entity );
|
||||
helper.WithVelocity( Entity.Velocity );
|
||||
helper.WithLookAt( Entity.EyePosition + Entity.EyeRotation.Forward * 100 );
|
||||
helper.HoldType = CitizenAnimationHelper.HoldTypes.None;
|
||||
helper.IsGrounded = Entity.GroundEntity.IsValid();
|
||||
|
||||
if ( Entity.Controller.HasEvent( "jump" ) )
|
||||
{
|
||||
helper.TriggerJump();
|
||||
}
|
||||
}
|
||||
}
|
||||
174
code/EntityComponents/Pawn/UserPawnController.cs
Normal file
174
code/EntityComponents/Pawn/UserPawnController.cs
Normal file
@@ -0,0 +1,174 @@
|
||||
using Sandbox;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace LuckerGame.Components.Pawn;
|
||||
|
||||
public class UserPawnController : EntityComponent<Entities.Pawn>
|
||||
{
|
||||
public int StepSize => 24;
|
||||
public int GroundAngle => 45;
|
||||
public int JumpSpeed => 410;
|
||||
public float Gravity => 800f;
|
||||
|
||||
HashSet<string> ControllerEvents = new( StringComparer.OrdinalIgnoreCase );
|
||||
|
||||
bool Grounded => Entity.GroundEntity.IsValid();
|
||||
|
||||
public void Simulate( IClient cl )
|
||||
{
|
||||
ControllerEvents.Clear();
|
||||
|
||||
var movement = Entity.InputDirection.Normal;
|
||||
var angles = Camera.Rotation.Angles().WithPitch( 0 );
|
||||
var moveVector = Rotation.From( angles ) * movement * 320f;
|
||||
var groundEntity = CheckForGround();
|
||||
|
||||
if ( groundEntity.IsValid() )
|
||||
{
|
||||
if ( !Grounded )
|
||||
{
|
||||
Entity.Velocity = Entity.Velocity.WithZ( 0 );
|
||||
AddEvent( "grounded" );
|
||||
}
|
||||
|
||||
Entity.Velocity = Accelerate( Entity.Velocity, moveVector.Normal, moveVector.Length, 200.0f * ( Input.Down( "run" ) ? 2.5f : 1f ), 7.5f );
|
||||
Entity.Velocity = ApplyFriction( Entity.Velocity, 4.0f );
|
||||
}
|
||||
else
|
||||
{
|
||||
Entity.Velocity = Accelerate( Entity.Velocity, moveVector.Normal, moveVector.Length, 15, 20f );
|
||||
Entity.Velocity += Vector3.Down * Gravity * Time.Delta;
|
||||
}
|
||||
|
||||
if ( Input.Pressed( "jump" ) )
|
||||
{
|
||||
DoJump();
|
||||
}
|
||||
|
||||
var mh = new MoveHelper( Entity.Position, Entity.Velocity );
|
||||
mh.Trace = mh.Trace.Size( Entity.Hull ).Ignore( Entity );
|
||||
|
||||
if ( mh.TryMoveWithStep( Time.Delta, StepSize ) > 0 )
|
||||
{
|
||||
if ( Grounded )
|
||||
{
|
||||
mh.Position = StayOnGround( mh.Position );
|
||||
}
|
||||
Entity.Position = mh.Position;
|
||||
Entity.Velocity = mh.Velocity;
|
||||
}
|
||||
|
||||
Entity.GroundEntity = groundEntity;
|
||||
}
|
||||
|
||||
void DoJump()
|
||||
{
|
||||
if ( Grounded )
|
||||
{
|
||||
Entity.Velocity = ApplyJump( Entity.Velocity, "jump" );
|
||||
}
|
||||
}
|
||||
|
||||
Entity CheckForGround()
|
||||
{
|
||||
if ( Entity.Velocity.z > 300f )
|
||||
return null;
|
||||
|
||||
var trace = Entity.TraceBBox( Entity.Position, Entity.Position + Vector3.Down, 2f );
|
||||
|
||||
if ( !trace.Hit )
|
||||
return null;
|
||||
|
||||
if ( trace.Normal.Angle( Vector3.Up ) > GroundAngle )
|
||||
return null;
|
||||
|
||||
return trace.Entity;
|
||||
}
|
||||
|
||||
Vector3 ApplyFriction( Vector3 input, float frictionAmount )
|
||||
{
|
||||
float StopSpeed = 100.0f;
|
||||
|
||||
var speed = input.Length;
|
||||
if ( speed < 0.1f ) return input;
|
||||
|
||||
// Bleed off some speed, but if we have less than the bleed
|
||||
// threshold, bleed the threshold amount.
|
||||
float control = (speed < StopSpeed) ? StopSpeed : speed;
|
||||
|
||||
// Add the amount to the drop amount.
|
||||
var drop = control * Time.Delta * frictionAmount;
|
||||
|
||||
// scale the velocity
|
||||
float newspeed = speed - drop;
|
||||
if ( newspeed < 0 ) newspeed = 0;
|
||||
if ( newspeed == speed ) return input;
|
||||
|
||||
newspeed /= speed;
|
||||
input *= newspeed;
|
||||
|
||||
return input;
|
||||
}
|
||||
|
||||
Vector3 Accelerate( Vector3 input, Vector3 wishdir, float wishspeed, float speedLimit, float acceleration )
|
||||
{
|
||||
if ( speedLimit > 0 && wishspeed > speedLimit )
|
||||
wishspeed = speedLimit;
|
||||
|
||||
var currentspeed = input.Dot( wishdir );
|
||||
var addspeed = wishspeed - currentspeed;
|
||||
|
||||
if ( addspeed <= 0 )
|
||||
return input;
|
||||
|
||||
var accelspeed = acceleration * Time.Delta * wishspeed;
|
||||
|
||||
if ( accelspeed > addspeed )
|
||||
accelspeed = addspeed;
|
||||
|
||||
input += wishdir * accelspeed;
|
||||
|
||||
return input;
|
||||
}
|
||||
|
||||
Vector3 ApplyJump( Vector3 input, string jumpType )
|
||||
{
|
||||
AddEvent( jumpType );
|
||||
|
||||
return input + Vector3.Up * JumpSpeed;
|
||||
}
|
||||
|
||||
Vector3 StayOnGround( Vector3 position )
|
||||
{
|
||||
var start = position + Vector3.Up * 2;
|
||||
var end = position + Vector3.Down * StepSize;
|
||||
|
||||
// See how far up we can go without getting stuck
|
||||
var trace = Entity.TraceBBox( position, start );
|
||||
start = trace.EndPosition;
|
||||
|
||||
// Now trace down from a known safe position
|
||||
trace = Entity.TraceBBox( start, end );
|
||||
|
||||
if ( trace.Fraction <= 0 ) return position;
|
||||
if ( trace.Fraction >= 1 ) return position;
|
||||
if ( trace.StartedSolid ) return position;
|
||||
if ( Vector3.GetAngle( Vector3.Up, trace.Normal ) > GroundAngle ) return position;
|
||||
|
||||
return trace.EndPosition;
|
||||
}
|
||||
|
||||
public bool HasEvent( string eventName )
|
||||
{
|
||||
return ControllerEvents.Contains( eventName );
|
||||
}
|
||||
|
||||
void AddEvent( string eventName )
|
||||
{
|
||||
if ( HasEvent( eventName ) )
|
||||
return;
|
||||
|
||||
ControllerEvents.Add( eventName );
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user