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; }
|
||||
float AccelerationDueToGravity { get; }
|
||||
float Drag { get; }
|
||||
float TerminalVelocity { get; }
|
||||
|
||||
bool BeginUpdate();
|
||||
void EndUpdate(Vector3 newPosition);
|
||||
|
@ -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>
|
||||
|
@ -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; }
|
||||
|
@ -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; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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];
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
Reference in New Issue
Block a user