CodeWalker/CodeWalker.Core/World/Entity.cs

199 lines
6.6 KiB
C#

using CodeWalker.GameFiles;
using SharpDX;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CodeWalker.World
{
public class Entity
{
public Space Space;
public YmapEntityDef EntityDef;
public float Radius;
public Vector3 Center;
public Vector3 Position;
public Quaternion Orientation = Quaternion.Identity;
public Quaternion OrientationInv = Quaternion.Identity;
public float Mass;
public Matrix MomentOfInertia;
public Vector3 Momentum;
public Vector3 Velocity;
public Vector3 AngularMomentum;
public Vector3 AngularVelocity;
public bool WasColliding;
public bool EnableCollisions;
public bool Enabled;
public float Lifetime;
public float Age;
//public CollisionShape ..
public virtual void PreUpdate(float elapsed)
{ }
}
public class PedEntity : Entity
{
public Vector2 ControlMovement;
public bool ControlJump;
public bool ControlBoost;
public Vector3 ForwardVec;
public Quaternion CameraOrientation = Quaternion.LookAtLH(Vector3.Zero, Vector3.Up, Vector3.ForwardLH);
public Entity CameraEntity = new Entity();
public bool OnGround = false;
public PedEntity()
{
Radius = 0.5f;
Center = new Vector3(0.0f, 0.0f, -1.2f); //base collision point is 1.7m below center... for camera offset
Mass = 80.0f;
ForwardVec = Vector3.UnitY;
CameraEntity.Orientation = CameraOrientation;
CameraEntity.OrientationInv = Quaternion.Invert(Orientation);
}
public override void PreUpdate(float elapsed)
{
//float rotspd = 0.5f;
float movspd = 10.0f;
float velspd = 10.0f;
float jmpvel = 3.0f;
float boostmult = 10.0f;
if (ControlBoost) movspd *= boostmult;
Quaternion rot = Quaternion.Identity;// .RotationAxis(Vector3.UnitZ, -ControlMovement.X * rotspd * elapsed);
Quaternion ori = Quaternion.Multiply(Orientation, rot);
SetOrientation(ori);
float jmpamt = (ControlJump ? jmpvel : 0);
Vector3 curvel = Velocity;
Vector3 controlvel = new Vector3(ControlMovement * movspd, jmpamt);
Vector3 targetvel = controlvel + new Vector3(0, 0, curvel.Z);
Vector3 newvel = curvel + (targetvel - curvel) * velspd * elapsed;
Velocity = newvel;
var coll = Space.FindFirstCollision(this, elapsed);
if (coll.Hit)
{
Vector3 collpos = coll.PrePos; //last known ok position
Vector3 disp = Velocity * elapsed;
Vector3 oldpos = Position;
Vector3 targetpos = Position + disp;
float displ = disp.Length();
//////BoundingSphere sph = new BoundingSphere(targetpos + Center, Radius);
//////r.SphereHit = SphereIntersect(sph);
if ((disp.Z > -0.25f))/* && (displ < Radius * 2.0f)*/
{
Vector3 raydir = new Vector3(0.0f, 0.0f, -1.0f);
Vector3 rayoff = new Vector3(0.0f, 0.0f, 0.0f);
Ray ray = new Ray(targetpos + Center + rayoff, raydir);
var rayhit = Space.RayIntersect(ray, 1.0f);
if (rayhit.Hit)
{
if (rayhit.HitDist > 0)
{
Position = rayhit.Position - Center + new Vector3(0, 0, Radius);
//collpos = Position;//targetpos;//
}
else
{
//the start of the ray was a collision... can't move here
Position = collpos;
}
}
else //might happen when about to go off a big drop?
{
Position = targetpos;// collpos;
//collpos = targetpos;
}
}
else //moving fast...
{
Position = collpos; //last known ok position
}
//Position = collpos; //last known ok position
bool wasOnGround = OnGround;
OnGround = (Vector3.Dot(coll.SphereHit.Normal, Vector3.UnitZ) > 0.8f);
if (OnGround)
{
}
Vector3 findisp = Position - oldpos;
float findispl = findisp.Length();
float fdisp = Math.Min(displ, findispl);
Vector3 dispdir = findisp / Math.Max(findispl, 0.0001f);
float absvel = fdisp / Math.Max(elapsed, 0.0001f);
Velocity = dispdir * absvel;
//Vector3 veldir = Vector3.Normalize(Position - oldpos);
//float vellen = (collpos - oldpos).Length() / Math.Max(elapsed, 0.0001f);
//Velocity = veldir * vellen;
//Velocity = (Position - oldpos) / Math.Max(elapsed, 0.0001f);
}
else
{
Position = coll.HitPos; //hitpos is the end pos if not hit
OnGround = false;
var raydir = new Vector3(0.0f, 0.0f, -1.0f);
var ray = new Ray(Position, raydir);
var rayhit = Space.RayIntersect(ray, float.MaxValue);
if (!rayhit.Hit && rayhit.TestComplete)
{
//must be under the map? try to find the ground...
ray.Position = Position + new Vector3(0.0f, 0.0f, 1000.0f);
rayhit = Space.RayIntersect(ray, float.MaxValue);
if (rayhit.Hit)
{
Position = rayhit.Position + new Vector3(0.0f, 0.0f, Radius) - Center;
OnGround = true;
}
else
{ }//didn't find the ground, what to do now?
}
}
CameraEntity.Position = Position;
}
private void SetOrientation(Quaternion ori)
{
Orientation = ori;
OrientationInv = Quaternion.Invert(Orientation);
CameraEntity.Orientation = Quaternion.Multiply(Orientation, CameraOrientation);
CameraEntity.OrientationInv = Quaternion.Invert(Orientation);
}
}
}