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; }
float AccelerationDueToGravity { get; }
float Drag { get; }
float TerminalVelocity { get; }
bool BeginUpdate();
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));
}
/// <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>
/// Calculates the distance between two Vector3 objects.
/// </summary>

View File

@ -99,6 +99,9 @@ namespace TrueCraft.Core.Entities
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; }

View File

@ -123,16 +123,22 @@ namespace TrueCraft.Core.Entities
OnPropertyChanged("Metadata");
}*/
}
base.Update(entityManager);
}
public float AccelerationDueToGravity
{
get { return 0.08f; }
get { return 0.4f; }
}
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 items = GetDrop(descriptor);
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)

View File

@ -177,6 +177,17 @@ namespace TrueCraft
spawnedClient = (RemoteClient)GetClientForEntity(entity as PlayerEntity);
client.KnownEntities.Add(entity);
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)
client.QueuePacket(new EntityMetadataPacket(entity.EntityID, entity.Metadata));
if (spawnedClient != null)
@ -265,6 +276,8 @@ namespace TrueCraft
while (PendingDespawns.Count != 0)
{
while (!PendingDespawns.TryTake(out entity));
if (entity is IPhysicsEntity)
PhysicsEngine.RemoveEntity((IPhysicsEntity)entity);
for (int i = 0, ServerClientsCount = Server.Clients.Count; i < ServerClientsCount; i++)
{
var client = (RemoteClient)Server.Clients[i];

View File

@ -40,7 +40,8 @@ namespace TrueCraft
{
if (!Entities.Contains(entity))
return;
Entities.Remove(entity);
lock (EntityLock)
Entities.Remove(entity);
}
private BoundingBox TempBoundingBox;
@ -57,6 +58,7 @@ namespace TrueCraft
{
entity.Velocity *= entity.Drag * multipler;
entity.Velocity -= new Vector3(0, entity.AccelerationDueToGravity * multipler, 0);
entity.Velocity.Clamp(entity.TerminalVelocity);
if (entity is IAABBEntity)
CheckWithTerrain((IAABBEntity)entity, World);
entity.EndUpdate(entity.Position + entity.Velocity);
@ -69,7 +71,7 @@ namespace TrueCraft
private void CheckWithTerrain(IAABBEntity entity, IWorld world)
{
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;
// Do terrain collisions
@ -80,7 +82,7 @@ namespace TrueCraft
}
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)
entity.TerrainCollision(collisionPoint, collisionDirection);
}
@ -114,22 +116,19 @@ namespace TrueCraft
if (entity.Velocity.X < 0)
{
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.Max.X, entity.BoundingBox.Max.Y, entity.BoundingBox.Max.Z) - (entity.Size / 2)
);
new Vector3(entity.BoundingBox.Min.X + entity.Velocity.X, entity.BoundingBox.Min.Y, entity.BoundingBox.Min.Z),
entity.BoundingBox.Max);
maxX = (int)(TempBoundingBox.Max.X);
minX = (int)(TempBoundingBox.Min.X + entity.Velocity.X);
minX = (int)(TempBoundingBox.Min.X + entity.Velocity.X) - 1;
}
else
{
TempBoundingBox = new BoundingBox(
entity.BoundingBox.Min - (entity.Size / 2),
new Vector3(
entity.BoundingBox.Max.X + entity.Velocity.X, entity.BoundingBox.Max.Y, entity.BoundingBox.Max.Z) - (entity.Size / 2)
);
entity.BoundingBox.Min,
new Vector3(entity.BoundingBox.Max.X + entity.Velocity.X, entity.BoundingBox.Max.Y, entity.BoundingBox.Max.Z));
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
@ -141,8 +140,8 @@ namespace TrueCraft
{
for (int z = minZ; z <= maxZ; z++)
{
var position = new Vector3(x, y, z);
var boundingBox = BlockPhysicsProvider.GetBoundingBox(world, (Coordinates3D)position);
var position = new Coordinates3D(x, y, z);
var boundingBox = BlockPhysicsProvider.GetBoundingBox(world, position);
if (boundingBox == null)
continue;
blockBox = boundingBox.Value.OffsetBy(position);
@ -213,22 +212,19 @@ namespace TrueCraft
if (entity.Velocity.Y < 0)
{
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.Max.X, entity.BoundingBox.Max.Y, entity.BoundingBox.Max.Z) - (entity.Size / 2)
);
new Vector3(entity.BoundingBox.Min.X, entity.BoundingBox.Min.Y + entity.Velocity.Y, entity.BoundingBox.Min.Z),
entity.BoundingBox.Max);
maxY = (int)(TempBoundingBox.Max.Y);
minY = (int)(TempBoundingBox.Min.Y + entity.Velocity.Y);
minY = (int)(TempBoundingBox.Min.Y + entity.Velocity.Y) - 1;
}
else
{
TempBoundingBox = new BoundingBox(
entity.BoundingBox.Min - (entity.Size / 2),
new Vector3(
entity.BoundingBox.Max.X, entity.BoundingBox.Max.Y + entity.Velocity.Y, entity.BoundingBox.Max.Z) - (entity.Size / 2)
);
entity.BoundingBox.Min,
new Vector3(entity.BoundingBox.Max.X, entity.BoundingBox.Max.Y + entity.Velocity.Y, entity.BoundingBox.Max.Z));
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
@ -250,8 +246,10 @@ namespace TrueCraft
{
for (int z = minZ; z <= maxZ; z++)
{
var position = new Vector3(x, y, z);
var boundingBox = BlockPhysicsProvider.GetBoundingBox(world, (Coordinates3D)position);
var position = new Coordinates3D(x, y, z);
if (!World.IsValidPosition(position))
continue;
var boundingBox = BlockPhysicsProvider.GetBoundingBox(world, position);
if (boundingBox == null)
continue;
blockBox = boundingBox.Value.OffsetBy(position);
@ -323,22 +321,20 @@ namespace TrueCraft
if (entity.Velocity.Z < 0)
{
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.Max.X, entity.BoundingBox.Max.Y, entity.BoundingBox.Max.Z) - (entity.Size / 2)
);
new Vector3(entity.BoundingBox.Min.X, entity.BoundingBox.Min.Y, entity.BoundingBox.Min.Z + entity.Velocity.Z),
entity.BoundingBox.Max);
maxZ = (int)(TempBoundingBox.Max.Z);
minZ = (int)(TempBoundingBox.Min.Z + entity.Velocity.Z);
minZ = (int)(TempBoundingBox.Min.Z + entity.Velocity.Z) - 1;
}
else
{
TempBoundingBox = new BoundingBox(
entity.BoundingBox.Min - (entity.Size / 2),
new Vector3(
entity.BoundingBox.Max.X, entity.BoundingBox.Max.Y, entity.BoundingBox.Max.Z + entity.Velocity.Z) - (entity.Size / 2)
entity.BoundingBox.Min,
new Vector3(entity.BoundingBox.Max.X, entity.BoundingBox.Max.Y, entity.BoundingBox.Max.Z + entity.Velocity.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
@ -350,8 +346,8 @@ namespace TrueCraft
{
for (int z = minZ; z <= maxZ; z++)
{
var position = new Vector3(x, y, z);
var boundingBox = BlockPhysicsProvider.GetBoundingBox(world, (Coordinates3D)position);
var position = new Coordinates3D(x, y, z);
var boundingBox = BlockPhysicsProvider.GetBoundingBox(world, position);
if (boundingBox == null)
continue;
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));
#if DEBUG
server.AddLogProvider(new FileLogProvider(new StreamWriter("packets.log", false), LogCategory.Packets));
server.EnableClientLogging = true;
#endif
CommandManager = new CommandManager();
server.ChatMessageReceived += HandleChatMessageReceived;