player and entity physics improvements
This commit is contained in:
@@ -7,7 +7,7 @@ namespace Voxel
|
||||
public static Vector3 Position = new Vector3(-8, 16, -8);
|
||||
|
||||
public static float Pitch = -22.5f;
|
||||
public static float Yaw = 45f;
|
||||
public static float Yaw = 0f;
|
||||
public static float FOV = 60f;
|
||||
public static float Speed = 5f;
|
||||
public static float ShiftSpeed = 20f;
|
||||
|
||||
416
Entity.cs
416
Entity.cs
@@ -17,89 +17,412 @@ namespace Voxel
|
||||
public float Width;
|
||||
public float Height;
|
||||
|
||||
private float _airDrag = 2f;
|
||||
private float _groundDrag = 8f;
|
||||
private float _gravity = 0.08f;
|
||||
private float _terminalVelocity = -3.92f;
|
||||
private float _airMultiplier = 0.98f;
|
||||
private float _groundMultiplier = 0.91f;
|
||||
|
||||
private World _world;
|
||||
private const float COLLISION_EPSILON = 0.01f;
|
||||
|
||||
protected World _world;
|
||||
|
||||
public Entity(Vector3 position, float width, float height, World world)
|
||||
{
|
||||
Position = position;
|
||||
Width = width;
|
||||
Height = height;
|
||||
|
||||
_world = world;
|
||||
}
|
||||
|
||||
public void Tick(float deltaTime)
|
||||
public void Tick()
|
||||
{
|
||||
Console.WriteLine(OnGround);
|
||||
Vector3 desiredMovement = Velocity;
|
||||
Vector3 newPosition = Position;
|
||||
|
||||
CheckAndResolveCollisions(ref newPosition, desiredMovement);
|
||||
|
||||
Position = newPosition;
|
||||
|
||||
if (!OnGround)
|
||||
{
|
||||
Console.WriteLine("Velocity: " + Velocity.Y.ToString());
|
||||
|
||||
Velocity -= new Vector3(
|
||||
Velocity.X * _airDrag * deltaTime,
|
||||
1.6f * deltaTime,
|
||||
Velocity.Z * _airDrag * deltaTime);
|
||||
Vector3 acceleration = new Vector3(0, -_gravity, 0);
|
||||
Velocity = (Velocity + acceleration) * _airMultiplier;
|
||||
|
||||
if (Velocity.Y < _terminalVelocity)
|
||||
{
|
||||
Velocity.Y = _terminalVelocity;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Velocity = new Vector3(Velocity.X, 0, Velocity.Z);
|
||||
Velocity -= new Vector3(
|
||||
Velocity.X * _groundDrag * deltaTime,
|
||||
0,
|
||||
Velocity.Z * _groundDrag * deltaTime);
|
||||
Velocity = new Vector3(
|
||||
Velocity.X * _groundMultiplier,
|
||||
0f,
|
||||
Velocity.Z * _groundMultiplier
|
||||
);
|
||||
}
|
||||
|
||||
UpdateOnGround();
|
||||
}
|
||||
|
||||
Position += Velocity;
|
||||
Console.WriteLine("Position: " + Position.Y.ToString());
|
||||
public void CheckAndResolveCollisions(ref Vector3 position, Vector3 movement)
|
||||
{
|
||||
Vector3 originalPosition = position;
|
||||
|
||||
// Try full movement first
|
||||
AABB futureBox = GetBoundingBoxAt(originalPosition + movement);
|
||||
|
||||
if (!HasCollision(futureBox))
|
||||
{
|
||||
// No collision, apply full movement
|
||||
position = originalPosition + movement;
|
||||
return;
|
||||
}
|
||||
|
||||
// Collision detected, resolve each axis separately but independently
|
||||
position = originalPosition;
|
||||
|
||||
// Resolve Y collision (always first for ground detection)
|
||||
ResolveYCollisionIndependent(ref position, movement.Y);
|
||||
|
||||
// Resolve X and Z collisions independently of each other
|
||||
Vector3 tempPosX = new Vector3(position.X + movement.X, position.Y, position.Z);
|
||||
if (!HasCollision(GetBoundingBoxAt(tempPosX)))
|
||||
{
|
||||
position.X = tempPosX.X;
|
||||
}
|
||||
else
|
||||
{
|
||||
ResolveXCollisionIndependent(ref position, movement.X);
|
||||
}
|
||||
|
||||
Vector3 tempPosZ = new Vector3(position.X, position.Y, position.Z + movement.Z);
|
||||
if (!HasCollision(GetBoundingBoxAt(tempPosZ)))
|
||||
{
|
||||
position.Z = tempPosZ.Z;
|
||||
}
|
||||
else
|
||||
{
|
||||
ResolveZCollisionIndependent(ref position, movement.Z);
|
||||
}
|
||||
}
|
||||
|
||||
private void ResolveYCollisionIndependent(ref Vector3 position, float velocityY)
|
||||
{
|
||||
if (velocityY == 0) return;
|
||||
|
||||
Vector3 testPos = new Vector3(position.X, position.Y + velocityY, position.Z);
|
||||
AABB testBox = GetBoundingBoxAt(testPos);
|
||||
|
||||
if (HasCollision(testBox))
|
||||
{
|
||||
if (velocityY > 0) // Hitting ceiling
|
||||
{
|
||||
float ceilingY = GetCeilingHeight(testBox);
|
||||
position.Y = ceilingY - (Height / 2) - COLLISION_EPSILON;
|
||||
Velocity.Y = 0;
|
||||
}
|
||||
else // Hitting floor
|
||||
{
|
||||
float floorY = GetFloorHeight(testBox);
|
||||
position.Y = floorY + (Height / 2) + COLLISION_EPSILON;
|
||||
Velocity.Y = 0;
|
||||
OnGround = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
position.Y += velocityY;
|
||||
}
|
||||
}
|
||||
|
||||
private void ResolveXCollisionIndependent(ref Vector3 position, float velocityX)
|
||||
{
|
||||
if (velocityX == 0) return;
|
||||
|
||||
// Check if we're already inside a block at current position
|
||||
AABB currentBox = GetBoundingBoxAt(new Vector3(position.X, position.Y, position.Z));
|
||||
if (HasCollision(currentBox))
|
||||
{
|
||||
// Already inside a block, allow movement to escape
|
||||
position.X += velocityX;
|
||||
return;
|
||||
}
|
||||
|
||||
float direction = Math.Sign(velocityX);
|
||||
float checkDistance = Math.Abs(velocityX) + COLLISION_EPSILON;
|
||||
|
||||
for (float offset = 0; offset <= checkDistance; offset += 0.01f)
|
||||
{
|
||||
float testX = position.X + (offset * direction);
|
||||
AABB testBox = GetBoundingBoxAt(new Vector3(testX, position.Y, position.Z));
|
||||
|
||||
if (HasCollision(testBox))
|
||||
{
|
||||
if (direction > 0) // Moving right
|
||||
{
|
||||
position.X = GetRightWallPosition(testBox) - (Width / 2) - COLLISION_EPSILON;
|
||||
}
|
||||
else // Moving left
|
||||
{
|
||||
position.X = GetLeftWallPosition(testBox) + (Width / 2) + COLLISION_EPSILON;
|
||||
}
|
||||
Velocity.X = 0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// No collision found, apply full movement
|
||||
position.X += velocityX;
|
||||
}
|
||||
|
||||
private void ResolveZCollisionIndependent(ref Vector3 position, float velocityZ)
|
||||
{
|
||||
if (velocityZ == 0) return;
|
||||
|
||||
// Check if we're already inside a block at current position
|
||||
AABB currentBox = GetBoundingBoxAt(new Vector3(position.X, position.Y, position.Z));
|
||||
if (HasCollision(currentBox))
|
||||
{
|
||||
// Already inside a block, allow movement to escape
|
||||
position.Z += velocityZ;
|
||||
return;
|
||||
}
|
||||
|
||||
float direction = Math.Sign(velocityZ);
|
||||
float checkDistance = Math.Abs(velocityZ) + COLLISION_EPSILON;
|
||||
|
||||
for (float offset = 0; offset <= checkDistance; offset += 0.01f)
|
||||
{
|
||||
float testZ = position.Z + (offset * direction);
|
||||
AABB testBox = GetBoundingBoxAt(new Vector3(position.X, position.Y, testZ));
|
||||
|
||||
if (HasCollision(testBox))
|
||||
{
|
||||
if (direction > 0) // Moving forward
|
||||
{
|
||||
position.Z = GetFrontWallPosition(testBox) - (Width / 2) - COLLISION_EPSILON;
|
||||
}
|
||||
else // Moving backward
|
||||
{
|
||||
position.Z = GetBackWallPosition(testBox) + (Width / 2) + COLLISION_EPSILON;
|
||||
}
|
||||
Velocity.Z = 0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// No collision found, apply full movement
|
||||
position.Z += velocityZ;
|
||||
}
|
||||
|
||||
private float GetFloorHeight(AABB box)
|
||||
{
|
||||
int minX = (int)MathF.Floor(box.Min.X);
|
||||
int maxX = (int)MathF.Floor(box.Max.X);
|
||||
int minZ = (int)MathF.Floor(box.Min.Z);
|
||||
int maxZ = (int)MathF.Floor(box.Max.Z);
|
||||
int checkY = (int)MathF.Floor(box.Min.Y);
|
||||
|
||||
float highestFloor = float.MinValue;
|
||||
|
||||
for (int x = minX; x <= maxX; x++)
|
||||
{
|
||||
for (int z = minZ; z <= maxZ; z++)
|
||||
{
|
||||
Blocks block = _world.GetBlock(x, checkY, z);
|
||||
if (block != Blocks.Air)
|
||||
{
|
||||
highestFloor = Math.Max(highestFloor, checkY + 1); // Top of the block
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return highestFloor != float.MinValue ? highestFloor : box.Min.Y;
|
||||
}
|
||||
|
||||
private float GetCeilingHeight(AABB box)
|
||||
{
|
||||
int minX = (int)MathF.Floor(box.Min.X);
|
||||
int maxX = (int)MathF.Floor(box.Max.X);
|
||||
int minZ = (int)MathF.Floor(box.Min.Z);
|
||||
int maxZ = (int)MathF.Floor(box.Max.Z);
|
||||
int checkY = (int)MathF.Floor(box.Max.Y);
|
||||
|
||||
float lowestCeiling = float.MaxValue;
|
||||
|
||||
for (int x = minX; x <= maxX; x++)
|
||||
{
|
||||
for (int z = minZ; z <= maxZ; z++)
|
||||
{
|
||||
Blocks block = _world.GetBlock(x, checkY, z);
|
||||
if (block != Blocks.Air)
|
||||
{
|
||||
lowestCeiling = Math.Min(lowestCeiling, checkY); // Bottom of the block
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return lowestCeiling != float.MaxValue ? lowestCeiling : box.Max.Y;
|
||||
}
|
||||
|
||||
private float GetLeftWallPosition(AABB box)
|
||||
{
|
||||
int minY = (int)MathF.Floor(box.Min.Y);
|
||||
int maxY = (int)MathF.Floor(box.Max.Y);
|
||||
int minZ = (int)MathF.Floor(box.Min.Z);
|
||||
int maxZ = (int)MathF.Floor(box.Max.Z);
|
||||
int checkX = (int)MathF.Floor(box.Min.X);
|
||||
|
||||
float rightmostWall = float.MinValue;
|
||||
|
||||
for (int y = minY; y <= maxY; y++)
|
||||
{
|
||||
for (int z = minZ; z <= maxZ; z++)
|
||||
{
|
||||
Blocks block = _world.GetBlock(checkX, y, z);
|
||||
if (block != Blocks.Air)
|
||||
{
|
||||
rightmostWall = Math.Max(rightmostWall, checkX + 1); // Right side of the block
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return rightmostWall != float.MinValue ? rightmostWall : box.Min.X;
|
||||
}
|
||||
|
||||
private float GetRightWallPosition(AABB box)
|
||||
{
|
||||
int minY = (int)MathF.Floor(box.Min.Y);
|
||||
int maxY = (int)MathF.Floor(box.Max.Y);
|
||||
int minZ = (int)MathF.Floor(box.Min.Z);
|
||||
int maxZ = (int)MathF.Floor(box.Max.Z);
|
||||
int checkX = (int)MathF.Floor(box.Max.X);
|
||||
|
||||
float leftmostWall = float.MaxValue;
|
||||
|
||||
for (int y = minY; y <= maxY; y++)
|
||||
{
|
||||
for (int z = minZ; z <= maxZ; z++)
|
||||
{
|
||||
Blocks block = _world.GetBlock(checkX, y, z);
|
||||
if (block != Blocks.Air)
|
||||
{
|
||||
leftmostWall = Math.Min(leftmostWall, checkX); // Left side of the block
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return leftmostWall != float.MaxValue ? leftmostWall : box.Max.X;
|
||||
}
|
||||
|
||||
private float GetBackWallPosition(AABB box)
|
||||
{
|
||||
int minX = (int)MathF.Floor(box.Min.X);
|
||||
int maxX = (int)MathF.Floor(box.Max.X);
|
||||
int minY = (int)MathF.Floor(box.Min.Y);
|
||||
int maxY = (int)MathF.Floor(box.Max.Y);
|
||||
int checkZ = (int)MathF.Floor(box.Min.Z);
|
||||
|
||||
float frontmostWall = float.MinValue;
|
||||
|
||||
for (int x = minX; x <= maxX; x++)
|
||||
{
|
||||
for (int y = minY; y <= maxY; y++)
|
||||
{
|
||||
Blocks block = _world.GetBlock(x, y, checkZ);
|
||||
if (block != Blocks.Air)
|
||||
{
|
||||
frontmostWall = Math.Max(frontmostWall, checkZ + 1); // Front side of the block
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return frontmostWall != float.MinValue ? frontmostWall : box.Min.Z;
|
||||
}
|
||||
|
||||
private float GetFrontWallPosition(AABB box)
|
||||
{
|
||||
int minX = (int)MathF.Floor(box.Min.X);
|
||||
int maxX = (int)MathF.Floor(box.Max.X);
|
||||
int minY = (int)MathF.Floor(box.Min.Y);
|
||||
int maxY = (int)MathF.Floor(box.Max.Y);
|
||||
int checkZ = (int)MathF.Floor(box.Max.Z);
|
||||
|
||||
float backmostWall = float.MaxValue;
|
||||
|
||||
for (int x = minX; x <= maxX; x++)
|
||||
{
|
||||
for (int y = minY; y <= maxY; y++)
|
||||
{
|
||||
Blocks block = _world.GetBlock(x, y, checkZ);
|
||||
if (block != Blocks.Air)
|
||||
{
|
||||
backmostWall = Math.Min(backmostWall, checkZ); // Back side of the block
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return backmostWall != float.MaxValue ? backmostWall : box.Max.Z;
|
||||
}
|
||||
|
||||
public bool HasCollision(AABB box)
|
||||
{
|
||||
int minX = (int)MathF.Floor(box.Min.X);
|
||||
int maxX = (int)MathF.Floor(box.Max.X);
|
||||
int minY = (int)MathF.Floor(box.Min.Y);
|
||||
int maxY = (int)MathF.Floor(box.Max.Y);
|
||||
int minZ = (int)MathF.Floor(box.Min.Z);
|
||||
int maxZ = (int)MathF.Floor(box.Max.Z);
|
||||
|
||||
for (int x = minX; x <= maxX; x++)
|
||||
{
|
||||
for (int y = minY; y <= maxY; y++)
|
||||
{
|
||||
for (int z = minZ; z <= maxZ; z++)
|
||||
{
|
||||
Blocks block = _world.GetBlock(x, y, z);
|
||||
if (block != Blocks.Air)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public void ApplyImpulse(Vector3 force)
|
||||
{
|
||||
Velocity += force;
|
||||
}
|
||||
|
||||
public AABB GetBoundingBox()
|
||||
{
|
||||
return GetBoundingBoxAt(Position);
|
||||
}
|
||||
|
||||
public AABB GetBoundingBoxAt(Vector3 position)
|
||||
{
|
||||
float halfWidth = Width / 2;
|
||||
float halfHeight = Height / 2;
|
||||
|
||||
Vector3 min = new Vector3(
|
||||
Position.X - halfWidth,
|
||||
Position.Y - Height,
|
||||
Position.Z - halfWidth
|
||||
position.X - halfWidth,
|
||||
position.Y - halfHeight, // Center Y minus half height
|
||||
position.Z - halfWidth
|
||||
);
|
||||
|
||||
Vector3 max = new Vector3(
|
||||
Position.X + halfWidth,
|
||||
Position.Y + Height,
|
||||
Position.Z + halfWidth
|
||||
position.X + halfWidth,
|
||||
position.Y + halfHeight, // Center Y plus half height
|
||||
position.Z + halfWidth
|
||||
);
|
||||
|
||||
return new AABB(min, max);
|
||||
}
|
||||
|
||||
private bool IsCollidingSide(Vector3 direction)
|
||||
{
|
||||
AABB box = GetBoundingBox();
|
||||
|
||||
// Determine which axis we’re checking
|
||||
int checkX = direction.X > 0 ? (int)MathF.Floor(box.Max.X) : (int)MathF.Floor(box.Min.X);
|
||||
int checkZ = direction.Z > 0 ? (int)MathF.Floor(box.Max.Z) : (int)MathF.Floor(box.Min.Z);
|
||||
|
||||
int minY = (int)MathF.Floor(box.Min.Y);
|
||||
int maxY = (int)MathF.Floor(box.Max.Y);
|
||||
|
||||
// Sweep along vertical range
|
||||
for (int y = minY; y <= maxY; y++)
|
||||
{
|
||||
if (_world.GetBlock(checkX, y, checkZ) != Blocks.Air)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public void UpdateOnGround()
|
||||
{
|
||||
AABB box = GetBoundingBox();
|
||||
@@ -124,6 +447,5 @@ namespace Voxel
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
13
Game.cs
13
Game.cs
@@ -1,13 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Voxel
|
||||
{
|
||||
public static class Game
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
81
Player.cs
81
Player.cs
@@ -11,11 +11,15 @@ namespace Voxel
|
||||
{
|
||||
public class Player : Entity
|
||||
{
|
||||
private World _world;
|
||||
public double lastClick = 0;
|
||||
public readonly float mouseCooldown = 0.2f;
|
||||
|
||||
private int _blockIndex = 0;
|
||||
private Blocks _selectedBlock = Blocks.Dirt;
|
||||
private double _tickTime = 0;
|
||||
private bool _isJumping = false;
|
||||
|
||||
private Blocks _selectedBlock = Blocks.OakPlanks;
|
||||
private Vector3 previousPosition;
|
||||
|
||||
public Player(Vector3 startPos, World world) : base(startPos, 0.5f, 1.8f, world)
|
||||
{
|
||||
@@ -42,20 +46,26 @@ namespace Voxel
|
||||
_world.SetBlock(x, y, z, Blocks.Air);
|
||||
}
|
||||
|
||||
public void Update(float deltaTime)
|
||||
public void Tick()
|
||||
{
|
||||
Camera.Position = Position + Vector3.UnitY * 0.5f;
|
||||
Rotation = Camera.Yaw;
|
||||
previousPosition = Position;
|
||||
|
||||
if (lastClick > 0)
|
||||
{
|
||||
lastClick -= deltaTime;
|
||||
if (lastClick < 0) lastClick = 0;
|
||||
}
|
||||
bool sprinting = Input.GetKey(Keys.LeftControl);
|
||||
|
||||
if (!Input.GetMouseButton(MouseButton.Right) && !Input.GetMouseButton(MouseButton.Left))
|
||||
if (Input.GetKey(Keys.W))
|
||||
ApplyWalkSpeed(0, -1, sprinting);
|
||||
if (Input.GetKey(Keys.S))
|
||||
ApplyWalkSpeed(0, 1, sprinting);
|
||||
if (Input.GetKey(Keys.A))
|
||||
ApplyWalkSpeed(-1, 0, false);
|
||||
if (Input.GetKey(Keys.D))
|
||||
ApplyWalkSpeed(1, 0, false);
|
||||
|
||||
if (Input.GetKey(Keys.Space) && OnGround)
|
||||
{
|
||||
lastClick = 0;
|
||||
Console.WriteLine("Jump");
|
||||
Velocity = new Vector3(Velocity.X, 0.42f, Velocity.Z);
|
||||
OnGround = false;
|
||||
}
|
||||
|
||||
if (Input.GetMouseButton(MouseButton.Right) && lastClick == 0)
|
||||
@@ -72,32 +82,47 @@ namespace Voxel
|
||||
BreakBlock();
|
||||
}
|
||||
|
||||
if (Input.GetKey(Keys.W))
|
||||
ApplyLocalVelocity(0, -5 * deltaTime);
|
||||
base.Tick();
|
||||
|
||||
if (Input.GetKey(Keys.Space) && OnGround)
|
||||
Console.WriteLine(Velocity.X.ToString() + ", " + Velocity.Y.ToString() + ", " + Velocity.Z.ToString());
|
||||
}
|
||||
|
||||
public void Update(float deltaTime, float alpha)
|
||||
{
|
||||
Camera.Position = Vector3.Lerp(previousPosition, Position, alpha) + Vector3.UnitY * 0.62f;
|
||||
Rotation = Camera.Yaw;
|
||||
|
||||
if (lastClick > 0)
|
||||
{
|
||||
Velocity = new Vector3(Velocity.X, 0.5f, Velocity.Z);
|
||||
OnGround = false;
|
||||
Console.WriteLine("Jump");
|
||||
lastClick -= deltaTime;
|
||||
if (lastClick < 0) lastClick = 0;
|
||||
}
|
||||
|
||||
if (!Input.GetMouseButton(MouseButton.Right) && !Input.GetMouseButton(MouseButton.Left))
|
||||
{
|
||||
lastClick = 0;
|
||||
}
|
||||
}
|
||||
|
||||
public void ApplyLocalVelocity(float x, float z)
|
||||
public void ApplyWalkSpeed(float x, float z, bool sprinting)
|
||||
{
|
||||
Vector3 localVelocity = new Vector3(x, 0, z);
|
||||
Vector3 inputDir = new Vector3(x, 0, z);
|
||||
if (inputDir.LengthSquared > 0)
|
||||
inputDir = Vector3.Normalize(inputDir);
|
||||
|
||||
float yaw = MathHelper.DegreesToRadians(Rotation);
|
||||
float cos = MathF.Cos(yaw); // yaw in radians
|
||||
float sin = MathF.Sin(yaw);
|
||||
float yawRad = MathHelper.DegreesToRadians(Rotation);
|
||||
float cos = MathF.Cos(yawRad);
|
||||
float sin = MathF.Sin(yawRad);
|
||||
|
||||
Vector3 worldVelocity = new Vector3(
|
||||
localVelocity.X * cos - localVelocity.Z * sin,
|
||||
Velocity.Y,
|
||||
localVelocity.X * sin + localVelocity.Z * cos
|
||||
Vector3 worldDir = new Vector3(
|
||||
inputDir.X * cos - inputDir.Z * sin,
|
||||
0,
|
||||
inputDir.X * sin + inputDir.Z * cos
|
||||
);
|
||||
|
||||
Velocity = worldVelocity;
|
||||
float speed = sprinting ? 0.13f : 0.10f;
|
||||
|
||||
Velocity += worldDir * speed;
|
||||
}
|
||||
|
||||
public void SwitchBlock(bool inverted)
|
||||
|
||||
@@ -45,7 +45,7 @@ internal class Program
|
||||
Vector3 startPos = new Vector3(15, 64, 15);
|
||||
Player player = new Player(startPos, world);
|
||||
|
||||
window.Update += player.Tick;
|
||||
window.Tick += player.Tick;
|
||||
window.Update += player.Update;
|
||||
|
||||
window.Run();
|
||||
|
||||
21
Window.cs
21
Window.cs
@@ -12,13 +12,24 @@ namespace Voxel
|
||||
public readonly int Height = height;
|
||||
public uint frames = 0;
|
||||
public double timeElapsed = 0;
|
||||
public event Action<float> Update;
|
||||
|
||||
public event Action<float, float> Update;
|
||||
public event Action Tick;
|
||||
|
||||
private double _tickTime;
|
||||
public const double TICK_LENGTH = 1.0 / 20.0; // 20 TPS
|
||||
|
||||
protected override void OnUpdateFrame(FrameEventArgs e)
|
||||
{
|
||||
base.OnUpdateFrame(e);
|
||||
|
||||
float deltaTime = (float)e.Time;
|
||||
_tickTime += e.Time;
|
||||
|
||||
while (_tickTime >= TICK_LENGTH)
|
||||
{
|
||||
_tickTime -= TICK_LENGTH;
|
||||
Tick(); // run exactly once per tick
|
||||
}
|
||||
|
||||
if (Input.GetKey(Keys.Escape))
|
||||
{
|
||||
@@ -32,8 +43,6 @@ namespace Voxel
|
||||
else
|
||||
WindowState = WindowState.Normal;
|
||||
}
|
||||
|
||||
Update.Invoke(deltaTime);
|
||||
}
|
||||
|
||||
protected override void OnRenderFrame(FrameEventArgs e)
|
||||
@@ -44,6 +53,8 @@ namespace Voxel
|
||||
|
||||
frames++;
|
||||
timeElapsed += e.Time;
|
||||
float alpha = (float)(_tickTime / Window.TICK_LENGTH);
|
||||
float deltaTime = (float)e.Time;
|
||||
if (timeElapsed >= 1)
|
||||
{
|
||||
Console.WriteLine("FPS: " + frames.ToString());
|
||||
@@ -51,6 +62,8 @@ namespace Voxel
|
||||
frames = 0;
|
||||
}
|
||||
|
||||
Update.Invoke(deltaTime, alpha);
|
||||
|
||||
Renderer.Render();
|
||||
|
||||
SwapBuffers();
|
||||
|
||||
12
Worldgen.cs
12
Worldgen.cs
@@ -15,14 +15,11 @@ namespace Voxel
|
||||
private static float amplitude1 = 4;
|
||||
private static float amplitude2 = 2;
|
||||
|
||||
private static float mountainMapRes = (float)1/2;
|
||||
private static float mountainMapAmplitude = 8;
|
||||
|
||||
private static float elevationMapRes = (float)1/8;
|
||||
private static float elevationMapAmplitude = 32;
|
||||
|
||||
private static FastNoiseLite noise = new FastNoiseLite();
|
||||
private static Random random = new Random();
|
||||
private static FastNoiseLite noise = new FastNoiseLite(random.Next());
|
||||
|
||||
public static int GetHeight(int x, int z)
|
||||
{
|
||||
@@ -35,16 +32,11 @@ namespace Voxel
|
||||
z * res2
|
||||
) * amplitude2;
|
||||
|
||||
float mountainMap = noise.GetNoise(
|
||||
x * mountainMapRes,
|
||||
z * mountainMapRes
|
||||
) * mountainMapAmplitude;
|
||||
|
||||
float elevationMap = (noise.GetNoise(
|
||||
x * elevationMapRes,
|
||||
z * elevationMapRes
|
||||
) + 0.25f) * elevationMapAmplitude;
|
||||
return baseHeight + (int)(elevationMap + ((map1 + map2) * 1 + mountainMap));
|
||||
return baseHeight + (int)(elevationMap + map1 + map2);
|
||||
}
|
||||
|
||||
public static Blocks GetBlock(int y, int maxY)
|
||||
|
||||
Reference in New Issue
Block a user