Significant improvements to entity physics

No more jitter! Collisions actually work all the time!
This commit is contained in:
Drew DeVault 2015-02-02 01:24:43 -07:00
parent 70ee5df9d8
commit 775adf685a
8 changed files with 75 additions and 39 deletions

View File

@ -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);

View File

@ -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>

View File

@ -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; }

View File

@ -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; }
} }
} }
} }

View File

@ -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)

View File

@ -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];

View File

@ -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);

View File

@ -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;