Significant improvements to entity physics
No more jitter! Collisions actually work all the time!
This commit is contained in:
parent
70ee5df9d8
commit
775adf685a
@ -11,6 +11,7 @@ namespace TrueCraft.API.Entities
|
|||||||
Vector3 Velocity { get; set; }
|
Vector3 Velocity { get; set; }
|
||||||
float AccelerationDueToGravity { get; }
|
float AccelerationDueToGravity { get; }
|
||||||
float Drag { get; }
|
float Drag { get; }
|
||||||
|
float TerminalVelocity { get; }
|
||||||
|
|
||||||
bool BeginUpdate();
|
bool BeginUpdate();
|
||||||
void EndUpdate(Vector3 newPosition);
|
void EndUpdate(Vector3 newPosition);
|
||||||
|
@ -54,6 +54,20 @@ namespace TrueCraft.API
|
|||||||
return new Vector3(Math.Floor(X), Math.Floor(Y), Math.Floor(Z));
|
return new Vector3(Math.Floor(X), Math.Floor(Y), Math.Floor(Z));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Clamps the vector to within the specified value.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">Value.</param>
|
||||||
|
public void Clamp(double value)
|
||||||
|
{
|
||||||
|
if (Math.Abs(X) > value)
|
||||||
|
X = value * (X < 0 ? -1 : 1);
|
||||||
|
if (Math.Abs(Y) > value)
|
||||||
|
Y = value * (Y < 0 ? -1 : 1);
|
||||||
|
if (Math.Abs(Z) > value)
|
||||||
|
Z = value * (Z < 0 ? -1 : 1);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Calculates the distance between two Vector3 objects.
|
/// Calculates the distance between two Vector3 objects.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -99,6 +99,9 @@ namespace TrueCraft.Core.Entities
|
|||||||
|
|
||||||
public virtual void Update(IEntityManager entityManager)
|
public virtual void Update(IEntityManager entityManager)
|
||||||
{
|
{
|
||||||
|
// TODO: Losing health and all that jazz
|
||||||
|
if (Position.Y < -50)
|
||||||
|
entityManager.DespawnEntity(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected bool EnablePropertyChange { get; set; }
|
protected bool EnablePropertyChange { get; set; }
|
||||||
|
@ -123,16 +123,22 @@ namespace TrueCraft.Core.Entities
|
|||||||
OnPropertyChanged("Metadata");
|
OnPropertyChanged("Metadata");
|
||||||
}*/
|
}*/
|
||||||
}
|
}
|
||||||
|
base.Update(entityManager);
|
||||||
}
|
}
|
||||||
|
|
||||||
public float AccelerationDueToGravity
|
public float AccelerationDueToGravity
|
||||||
{
|
{
|
||||||
get { return 0.08f; }
|
get { return 0.4f; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public float Drag
|
public float Drag
|
||||||
{
|
{
|
||||||
get { return 0.98f; }
|
get { return 0.2f; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public float TerminalVelocity
|
||||||
|
{
|
||||||
|
get { return 1.96f; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -35,7 +35,11 @@ namespace TrueCraft.Core.Logic
|
|||||||
var entityManager = server.GetEntityManagerForWorld(world);
|
var entityManager = server.GetEntityManagerForWorld(world);
|
||||||
var items = GetDrop(descriptor);
|
var items = GetDrop(descriptor);
|
||||||
foreach (var item in items)
|
foreach (var item in items)
|
||||||
entityManager.SpawnEntity(new ItemEntity(new Vector3(descriptor.Coordinates) + new Vector3(0.5), item));
|
{
|
||||||
|
var entity = new ItemEntity(new Vector3(descriptor.Coordinates) + new Vector3(0.5), item);
|
||||||
|
entity.Velocity += new Vector3(MathHelper.Random.NextDouble());
|
||||||
|
entityManager.SpawnEntity(entity);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual bool IsSupported(BlockDescriptor descriptor, IMultiplayerServer server, IWorld world)
|
public virtual bool IsSupported(BlockDescriptor descriptor, IMultiplayerServer server, IWorld world)
|
||||||
|
@ -177,6 +177,17 @@ namespace TrueCraft
|
|||||||
spawnedClient = (RemoteClient)GetClientForEntity(entity as PlayerEntity);
|
spawnedClient = (RemoteClient)GetClientForEntity(entity as PlayerEntity);
|
||||||
client.KnownEntities.Add(entity);
|
client.KnownEntities.Add(entity);
|
||||||
client.QueuePacket(entity.SpawnPacket);
|
client.QueuePacket(entity.SpawnPacket);
|
||||||
|
if (entity is IPhysicsEntity)
|
||||||
|
{
|
||||||
|
var pentity = entity as IPhysicsEntity;
|
||||||
|
client.QueuePacket(new EntityVelocityPacket
|
||||||
|
{
|
||||||
|
EntityID = entity.EntityID,
|
||||||
|
XVelocity = (short)(pentity.Velocity.X * 320),
|
||||||
|
YVelocity = (short)(pentity.Velocity.Y * 320),
|
||||||
|
ZVelocity = (short)(pentity.Velocity.Z * 320),
|
||||||
|
});
|
||||||
|
}
|
||||||
if (entity.SendMetadataToClients)
|
if (entity.SendMetadataToClients)
|
||||||
client.QueuePacket(new EntityMetadataPacket(entity.EntityID, entity.Metadata));
|
client.QueuePacket(new EntityMetadataPacket(entity.EntityID, entity.Metadata));
|
||||||
if (spawnedClient != null)
|
if (spawnedClient != null)
|
||||||
@ -265,6 +276,8 @@ namespace TrueCraft
|
|||||||
while (PendingDespawns.Count != 0)
|
while (PendingDespawns.Count != 0)
|
||||||
{
|
{
|
||||||
while (!PendingDespawns.TryTake(out entity));
|
while (!PendingDespawns.TryTake(out entity));
|
||||||
|
if (entity is IPhysicsEntity)
|
||||||
|
PhysicsEngine.RemoveEntity((IPhysicsEntity)entity);
|
||||||
for (int i = 0, ServerClientsCount = Server.Clients.Count; i < ServerClientsCount; i++)
|
for (int i = 0, ServerClientsCount = Server.Clients.Count; i < ServerClientsCount; i++)
|
||||||
{
|
{
|
||||||
var client = (RemoteClient)Server.Clients[i];
|
var client = (RemoteClient)Server.Clients[i];
|
||||||
|
@ -40,7 +40,8 @@ namespace TrueCraft
|
|||||||
{
|
{
|
||||||
if (!Entities.Contains(entity))
|
if (!Entities.Contains(entity))
|
||||||
return;
|
return;
|
||||||
Entities.Remove(entity);
|
lock (EntityLock)
|
||||||
|
Entities.Remove(entity);
|
||||||
}
|
}
|
||||||
|
|
||||||
private BoundingBox TempBoundingBox;
|
private BoundingBox TempBoundingBox;
|
||||||
@ -57,6 +58,7 @@ namespace TrueCraft
|
|||||||
{
|
{
|
||||||
entity.Velocity *= entity.Drag * multipler;
|
entity.Velocity *= entity.Drag * multipler;
|
||||||
entity.Velocity -= new Vector3(0, entity.AccelerationDueToGravity * multipler, 0);
|
entity.Velocity -= new Vector3(0, entity.AccelerationDueToGravity * multipler, 0);
|
||||||
|
entity.Velocity.Clamp(entity.TerminalVelocity);
|
||||||
if (entity is IAABBEntity)
|
if (entity is IAABBEntity)
|
||||||
CheckWithTerrain((IAABBEntity)entity, World);
|
CheckWithTerrain((IAABBEntity)entity, World);
|
||||||
entity.EndUpdate(entity.Position + entity.Velocity);
|
entity.EndUpdate(entity.Position + entity.Velocity);
|
||||||
@ -69,7 +71,7 @@ namespace TrueCraft
|
|||||||
private void CheckWithTerrain(IAABBEntity entity, IWorld world)
|
private void CheckWithTerrain(IAABBEntity entity, IWorld world)
|
||||||
{
|
{
|
||||||
Vector3 collisionPoint, collisionDirection;
|
Vector3 collisionPoint, collisionDirection;
|
||||||
if (entity.Position.Y + entity.Velocity.Y >= 0 && entity.Position.Y + entity.Velocity.Y <= 255) // Don't do checks outside the map
|
if (entity.Position.Y > 0 && entity.Position.Y <= 127) // Don't do checks outside the map
|
||||||
{
|
{
|
||||||
bool fireEvent = entity.Velocity != Vector3.Zero;
|
bool fireEvent = entity.Velocity != Vector3.Zero;
|
||||||
// Do terrain collisions
|
// Do terrain collisions
|
||||||
@ -80,7 +82,7 @@ namespace TrueCraft
|
|||||||
}
|
}
|
||||||
if (AdjustVelocityY(entity, world, out collisionPoint, out collisionDirection))
|
if (AdjustVelocityY(entity, world, out collisionPoint, out collisionDirection))
|
||||||
{
|
{
|
||||||
entity.Velocity *= new Vector3(0.2, 1, 0.2); // TODO: More sophisticated friction
|
entity.Velocity *= new Vector3(0.1, 1, 0.1); // TODO: More sophisticated friction
|
||||||
if (fireEvent)
|
if (fireEvent)
|
||||||
entity.TerrainCollision(collisionPoint, collisionDirection);
|
entity.TerrainCollision(collisionPoint, collisionDirection);
|
||||||
}
|
}
|
||||||
@ -114,22 +116,19 @@ namespace TrueCraft
|
|||||||
if (entity.Velocity.X < 0)
|
if (entity.Velocity.X < 0)
|
||||||
{
|
{
|
||||||
TempBoundingBox = new BoundingBox(
|
TempBoundingBox = new BoundingBox(
|
||||||
new Vector3(entity.BoundingBox.Min.X + entity.Velocity.X, entity.BoundingBox.Min.Y, entity.BoundingBox.Min.Z) - (entity.Size / 2),
|
new Vector3(entity.BoundingBox.Min.X + entity.Velocity.X, entity.BoundingBox.Min.Y, entity.BoundingBox.Min.Z),
|
||||||
new Vector3(entity.BoundingBox.Max.X, entity.BoundingBox.Max.Y, entity.BoundingBox.Max.Z) - (entity.Size / 2)
|
entity.BoundingBox.Max);
|
||||||
);
|
|
||||||
|
|
||||||
maxX = (int)(TempBoundingBox.Max.X);
|
maxX = (int)(TempBoundingBox.Max.X);
|
||||||
minX = (int)(TempBoundingBox.Min.X + entity.Velocity.X);
|
minX = (int)(TempBoundingBox.Min.X + entity.Velocity.X) - 1;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
TempBoundingBox = new BoundingBox(
|
TempBoundingBox = new BoundingBox(
|
||||||
entity.BoundingBox.Min - (entity.Size / 2),
|
entity.BoundingBox.Min,
|
||||||
new Vector3(
|
new Vector3(entity.BoundingBox.Max.X + entity.Velocity.X, entity.BoundingBox.Max.Y, entity.BoundingBox.Max.Z));
|
||||||
entity.BoundingBox.Max.X + entity.Velocity.X, entity.BoundingBox.Max.Y, entity.BoundingBox.Max.Z) - (entity.Size / 2)
|
|
||||||
);
|
|
||||||
minX = (int)(entity.BoundingBox.Min.X);
|
minX = (int)(entity.BoundingBox.Min.X);
|
||||||
maxX = (int)(entity.BoundingBox.Max.X + entity.Velocity.X);
|
maxX = (int)(entity.BoundingBox.Max.X + entity.Velocity.X) + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Do terrain checks
|
// Do terrain checks
|
||||||
@ -141,8 +140,8 @@ namespace TrueCraft
|
|||||||
{
|
{
|
||||||
for (int z = minZ; z <= maxZ; z++)
|
for (int z = minZ; z <= maxZ; z++)
|
||||||
{
|
{
|
||||||
var position = new Vector3(x, y, z);
|
var position = new Coordinates3D(x, y, z);
|
||||||
var boundingBox = BlockPhysicsProvider.GetBoundingBox(world, (Coordinates3D)position);
|
var boundingBox = BlockPhysicsProvider.GetBoundingBox(world, position);
|
||||||
if (boundingBox == null)
|
if (boundingBox == null)
|
||||||
continue;
|
continue;
|
||||||
blockBox = boundingBox.Value.OffsetBy(position);
|
blockBox = boundingBox.Value.OffsetBy(position);
|
||||||
@ -213,22 +212,19 @@ namespace TrueCraft
|
|||||||
if (entity.Velocity.Y < 0)
|
if (entity.Velocity.Y < 0)
|
||||||
{
|
{
|
||||||
TempBoundingBox = new BoundingBox(
|
TempBoundingBox = new BoundingBox(
|
||||||
new Vector3(entity.BoundingBox.Min.X, entity.BoundingBox.Min.Y + entity.Velocity.Y, entity.BoundingBox.Min.Z) - (entity.Size / 2),
|
new Vector3(entity.BoundingBox.Min.X, entity.BoundingBox.Min.Y + entity.Velocity.Y, entity.BoundingBox.Min.Z),
|
||||||
new Vector3(entity.BoundingBox.Max.X, entity.BoundingBox.Max.Y, entity.BoundingBox.Max.Z) - (entity.Size / 2)
|
entity.BoundingBox.Max);
|
||||||
);
|
|
||||||
|
|
||||||
maxY = (int)(TempBoundingBox.Max.Y);
|
maxY = (int)(TempBoundingBox.Max.Y);
|
||||||
minY = (int)(TempBoundingBox.Min.Y + entity.Velocity.Y);
|
minY = (int)(TempBoundingBox.Min.Y + entity.Velocity.Y) - 1;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
TempBoundingBox = new BoundingBox(
|
TempBoundingBox = new BoundingBox(
|
||||||
entity.BoundingBox.Min - (entity.Size / 2),
|
entity.BoundingBox.Min,
|
||||||
new Vector3(
|
new Vector3(entity.BoundingBox.Max.X, entity.BoundingBox.Max.Y + entity.Velocity.Y, entity.BoundingBox.Max.Z));
|
||||||
entity.BoundingBox.Max.X, entity.BoundingBox.Max.Y + entity.Velocity.Y, entity.BoundingBox.Max.Z) - (entity.Size / 2)
|
|
||||||
);
|
|
||||||
minY = (int)(entity.BoundingBox.Min.Y);
|
minY = (int)(entity.BoundingBox.Min.Y);
|
||||||
maxY = (int)(entity.BoundingBox.Max.Y + entity.Velocity.Y);
|
maxY = (int)(entity.BoundingBox.Max.Y + entity.Velocity.Y) + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clamp Y into map boundaries
|
// Clamp Y into map boundaries
|
||||||
@ -250,8 +246,10 @@ namespace TrueCraft
|
|||||||
{
|
{
|
||||||
for (int z = minZ; z <= maxZ; z++)
|
for (int z = minZ; z <= maxZ; z++)
|
||||||
{
|
{
|
||||||
var position = new Vector3(x, y, z);
|
var position = new Coordinates3D(x, y, z);
|
||||||
var boundingBox = BlockPhysicsProvider.GetBoundingBox(world, (Coordinates3D)position);
|
if (!World.IsValidPosition(position))
|
||||||
|
continue;
|
||||||
|
var boundingBox = BlockPhysicsProvider.GetBoundingBox(world, position);
|
||||||
if (boundingBox == null)
|
if (boundingBox == null)
|
||||||
continue;
|
continue;
|
||||||
blockBox = boundingBox.Value.OffsetBy(position);
|
blockBox = boundingBox.Value.OffsetBy(position);
|
||||||
@ -323,22 +321,20 @@ namespace TrueCraft
|
|||||||
if (entity.Velocity.Z < 0)
|
if (entity.Velocity.Z < 0)
|
||||||
{
|
{
|
||||||
TempBoundingBox = new BoundingBox(
|
TempBoundingBox = new BoundingBox(
|
||||||
new Vector3(entity.BoundingBox.Min.X, entity.BoundingBox.Min.Y, entity.BoundingBox.Min.Z + entity.Velocity.Z) - (entity.Size / 2),
|
new Vector3(entity.BoundingBox.Min.X, entity.BoundingBox.Min.Y, entity.BoundingBox.Min.Z + entity.Velocity.Z),
|
||||||
new Vector3(entity.BoundingBox.Max.X, entity.BoundingBox.Max.Y, entity.BoundingBox.Max.Z) - (entity.Size / 2)
|
entity.BoundingBox.Max);
|
||||||
);
|
|
||||||
|
|
||||||
maxZ = (int)(TempBoundingBox.Max.Z);
|
maxZ = (int)(TempBoundingBox.Max.Z);
|
||||||
minZ = (int)(TempBoundingBox.Min.Z + entity.Velocity.Z);
|
minZ = (int)(TempBoundingBox.Min.Z + entity.Velocity.Z) - 1;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
TempBoundingBox = new BoundingBox(
|
TempBoundingBox = new BoundingBox(
|
||||||
entity.BoundingBox.Min - (entity.Size / 2),
|
entity.BoundingBox.Min,
|
||||||
new Vector3(
|
new Vector3(entity.BoundingBox.Max.X, entity.BoundingBox.Max.Y, entity.BoundingBox.Max.Z + entity.Velocity.Z)
|
||||||
entity.BoundingBox.Max.X, entity.BoundingBox.Max.Y, entity.BoundingBox.Max.Z + entity.Velocity.Z) - (entity.Size / 2)
|
|
||||||
);
|
);
|
||||||
minZ = (int)(entity.BoundingBox.Min.Z);
|
minZ = (int)(entity.BoundingBox.Min.Z);
|
||||||
maxZ = (int)(entity.BoundingBox.Max.Z + entity.Velocity.Z);
|
maxZ = (int)(entity.BoundingBox.Max.Z + entity.Velocity.Z) + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Do terrain checks
|
// Do terrain checks
|
||||||
@ -350,8 +346,8 @@ namespace TrueCraft
|
|||||||
{
|
{
|
||||||
for (int z = minZ; z <= maxZ; z++)
|
for (int z = minZ; z <= maxZ; z++)
|
||||||
{
|
{
|
||||||
var position = new Vector3(x, y, z);
|
var position = new Coordinates3D(x, y, z);
|
||||||
var boundingBox = BlockPhysicsProvider.GetBoundingBox(world, (Coordinates3D)position);
|
var boundingBox = BlockPhysicsProvider.GetBoundingBox(world, position);
|
||||||
if (boundingBox == null)
|
if (boundingBox == null)
|
||||||
continue;
|
continue;
|
||||||
blockBox = boundingBox.Value.OffsetBy(position);
|
blockBox = boundingBox.Value.OffsetBy(position);
|
||||||
|
@ -24,7 +24,6 @@ namespace TrueCraft
|
|||||||
server.AddLogProvider(new ConsoleLogProvider(LogCategory.Notice | LogCategory.Warning | LogCategory.Error | LogCategory.Debug));
|
server.AddLogProvider(new ConsoleLogProvider(LogCategory.Notice | LogCategory.Warning | LogCategory.Error | LogCategory.Debug));
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
server.AddLogProvider(new FileLogProvider(new StreamWriter("packets.log", false), LogCategory.Packets));
|
server.AddLogProvider(new FileLogProvider(new StreamWriter("packets.log", false), LogCategory.Packets));
|
||||||
server.EnableClientLogging = true;
|
|
||||||
#endif
|
#endif
|
||||||
CommandManager = new CommandManager();
|
CommandManager = new CommandManager();
|
||||||
server.ChatMessageReceived += HandleChatMessageReceived;
|
server.ChatMessageReceived += HandleChatMessageReceived;
|
||||||
|
Reference in New Issue
Block a user