From 11f76ca42915ffbdc4c7768b291eeb3d630b852d Mon Sep 17 00:00:00 2001 From: maxwes08 Date: Tue, 30 Sep 2025 10:58:12 +0200 Subject: [PATCH] player added --- AABB.cs | 41 ++++++++++++++ Camera.cs | 30 ++--------- Entity.cs | 129 ++++++++++++++++++++++++++++++++++++++++++++ Game.cs | 13 +++++ Player.cs | 39 +++++++++++--- Program.cs | 13 +++-- Renderer.cs | 1 + Shader.cs | 11 ++++ Shaders/shader.frag | 16 +++++- Shaders/shader.vert | 2 + Window.cs | 12 ++--- 11 files changed, 259 insertions(+), 48 deletions(-) create mode 100644 AABB.cs create mode 100644 Entity.cs create mode 100644 Game.cs diff --git a/AABB.cs b/AABB.cs new file mode 100644 index 0000000..1d26385 --- /dev/null +++ b/AABB.cs @@ -0,0 +1,41 @@ +using OpenTK.Mathematics; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Voxel +{ + public struct AABB + { + public Vector3 Min; + public Vector3 Max; + + public AABB(Vector3 min, Vector3 max) + { + Min = min; + Max = max; + } + + public static AABB FromCenter(Vector3 center, float width, float height, float depth) + { + Vector3 half = new Vector3(width / 2f, 0, depth / 2f); + return new AABB(center - half, center + new Vector3(half.X, height, half.Z)); + } + + public bool Intersects(AABB other) + { + return (Min.X <= other.Max.X && Max.X >= other.Min.X) && + (Min.Y <= other.Max.Y && Max.Y >= other.Min.Y) && + (Min.Z <= other.Max.Z && Max.Z >= other.Min.Z); + } + + public bool Contains(Vector3 point) + { + return (point.X >= Min.X && point.X <= Max.X) && + (point.Y >= Min.Y && point.Y <= Max.Y) && + (point.Z >= Min.Z && point.Z <= Max.Z); + } + } +} diff --git a/Camera.cs b/Camera.cs index e3d7f72..c910dd0 100644 --- a/Camera.cs +++ b/Camera.cs @@ -21,39 +21,15 @@ namespace Voxel { get { + float yawOffset = Yaw - 90f; Vector3 front; - front.X = MathF.Cos(MathHelper.DegreesToRadians(Yaw)) * MathF.Cos(MathHelper.DegreesToRadians(Pitch)); + front.X = MathF.Cos(MathHelper.DegreesToRadians(yawOffset)) * MathF.Cos(MathHelper.DegreesToRadians(Pitch)); front.Y = MathF.Sin(MathHelper.DegreesToRadians(Pitch)); - front.Z = MathF.Sin(MathHelper.DegreesToRadians(Yaw)) * MathF.Cos(MathHelper.DegreesToRadians(Pitch)); + front.Z = MathF.Sin(MathHelper.DegreesToRadians(yawOffset)) * MathF.Cos(MathHelper.DegreesToRadians(Pitch)); return front.Normalized(); } } - public static void Update(float time) - { - float moveSpeed = Speed * time; - if (Input.GetKey(OpenTK.Windowing.GraphicsLibraryFramework.Keys.LeftShift)) - { - moveSpeed = ShiftSpeed * time; - } - if (Input.GetKey(OpenTK.Windowing.GraphicsLibraryFramework.Keys.W)) - { - Position += Front * moveSpeed; - } - if (Input.GetKey(OpenTK.Windowing.GraphicsLibraryFramework.Keys.S)) - { - Position += Front * -moveSpeed; - } - if (Input.GetKey(OpenTK.Windowing.GraphicsLibraryFramework.Keys.A)) - { - Position += Vector3.Cross(Front, Vector3.UnitY).Normalized() * -moveSpeed; - } - if (Input.GetKey(OpenTK.Windowing.GraphicsLibraryFramework.Keys.D)) - { - Position += Vector3.Cross(Front, Vector3.UnitY).Normalized() * moveSpeed; - } - } - public static void UpdateMouse(Vector2 delta) { float sensitivity = 0.1f; diff --git a/Entity.cs b/Entity.cs new file mode 100644 index 0000000..3f198a3 --- /dev/null +++ b/Entity.cs @@ -0,0 +1,129 @@ +using OpenTK.Mathematics; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Voxel +{ + public class Entity + { + public Vector3 Position; + public Vector3 Velocity; + public bool OnGround; + public float Rotation; + + public float Width; + public float Height; + + private float _airDrag = 2f; + private float _groundDrag = 8f; + + private 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) + { + Console.WriteLine(OnGround); + + if (!OnGround) + { + Console.WriteLine("Velocity: " + Velocity.Y.ToString()); + + Velocity -= new Vector3( + Velocity.X * _airDrag * deltaTime, + 1.6f * deltaTime, + Velocity.Z * _airDrag * deltaTime); + + } + else + { + Velocity = new Vector3(Velocity.X, 0, Velocity.Z); + Velocity -= new Vector3( + Velocity.X * _groundDrag * deltaTime, + 0, + Velocity.Z * _groundDrag * deltaTime); + } + + UpdateOnGround(); + + Position += Velocity; + Console.WriteLine("Position: " + Position.Y.ToString()); + } + + public AABB GetBoundingBox() + { + float halfWidth = Width / 2; + + Vector3 min = new Vector3( + Position.X - halfWidth, + Position.Y - Height, + Position.Z - halfWidth + ); + + Vector3 max = new Vector3( + Position.X + halfWidth, + Position.Y + 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(); + float yCheck = box.Min.Y - 0.05f; + + 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); + + OnGround = false; + for (int x = minX; x <= maxX; x++) + { + for (int z = minZ; z <= maxZ; z++) + { + Blocks block = _world.GetBlock(x, (int)MathF.Floor(yCheck), z); + if (block != Blocks.Air) + { + OnGround = true; + return; + } + } + } + } + + } +} diff --git a/Game.cs b/Game.cs new file mode 100644 index 0000000..0ba4fc4 --- /dev/null +++ b/Game.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Voxel +{ + public static class Game + { + + } +} diff --git a/Player.cs b/Player.cs index ce9851d..59bf1a4 100644 --- a/Player.cs +++ b/Player.cs @@ -3,24 +3,23 @@ using OpenTK.Windowing.GraphicsLibraryFramework; using System; using System.Collections.Generic; using System.Linq; +using System.Runtime.CompilerServices; using System.Text; using System.Threading.Tasks; namespace Voxel { - public class Player + public class Player : Entity { - public Vector3 Position; - private World _world; public double lastClick = 0; public readonly float mouseCooldown = 0.2f; private int _blockIndex = 0; private Blocks _selectedBlock = Blocks.Dirt; - public Player(World world, Vector3 startPos) + public Player(Vector3 startPos, World world) : base(startPos, 0.5f, 1.8f, world) { - _world = world; + } public void PlaceBlock() @@ -45,7 +44,8 @@ namespace Voxel public void Update(float deltaTime) { - Camera.Update(deltaTime); + Camera.Position = Position + Vector3.UnitY * 0.5f; + Rotation = Camera.Yaw; if (lastClick > 0) { @@ -71,6 +71,33 @@ namespace Voxel BreakBlock(); } + + if (Input.GetKey(Keys.W)) + ApplyLocalVelocity(0, -5 * deltaTime); + + if (Input.GetKey(Keys.Space) && OnGround) + { + Velocity = new Vector3(Velocity.X, 0.5f, Velocity.Z); + OnGround = false; + Console.WriteLine("Jump"); + } + } + + public void ApplyLocalVelocity(float x, float z) + { + Vector3 localVelocity = new Vector3(x, 0, z); + + float yaw = MathHelper.DegreesToRadians(Rotation); + float cos = MathF.Cos(yaw); // yaw in radians + float sin = MathF.Sin(yaw); + + Vector3 worldVelocity = new Vector3( + localVelocity.X * cos - localVelocity.Z * sin, + Velocity.Y, + localVelocity.X * sin + localVelocity.Z * cos + ); + + Velocity = worldVelocity; } public void SwitchBlock(bool inverted) diff --git a/Program.cs b/Program.cs index 2bcc69f..c28eced 100644 --- a/Program.cs +++ b/Program.cs @@ -11,14 +11,11 @@ internal class Program World world = new World(); Window window = new Window(sizeX, sizeY, title); - Player player = new Player(world, Vector3.Zero); - - window.Player = player; Console.WriteLine("Generating map..."); - int worldSizeX = 32; - int worldSizeY = 32; + int worldSizeX = 8; + int worldSizeY = 8; float maxI = worldSizeX * worldSizeY; int i = 0; @@ -45,6 +42,12 @@ internal class Program Renderer.SetWorld(world); + Vector3 startPos = new Vector3(15, 64, 15); + Player player = new Player(startPos, world); + + window.Update += player.Tick; + window.Update += player.Update; + window.Run(); } } \ No newline at end of file diff --git a/Renderer.cs b/Renderer.cs index 1db9ed4..304c679 100644 --- a/Renderer.cs +++ b/Renderer.cs @@ -43,6 +43,7 @@ namespace Voxel _shader.Use(); _shader.SetMatrix4("view", Camera.view); + _shader.SetVector3("cameraPosition", Camera.Position); _shader.SetMatrix4("projection", Camera.projection); if (_buffersDirty) diff --git a/Shader.cs b/Shader.cs index 4dcc110..1a88320 100644 --- a/Shader.cs +++ b/Shader.cs @@ -67,6 +67,17 @@ namespace Voxel GL.UniformMatrix4(location, false, ref matrix); } + public void SetVector3(string name, Vector3 vector3) + { + int location = GL.GetUniformLocation(_handle, name); + if (location == -1) + { + Console.WriteLine($"Uniform '{name}' not found in shader."); + return; + } + GL.Uniform3(location, ref vector3); + } + public void SetInt(string name, int value) { int location = GL.GetUniformLocation(_handle, name); diff --git a/Shaders/shader.frag b/Shaders/shader.frag index 2b9b48d..7a31ca3 100644 --- a/Shaders/shader.frag +++ b/Shaders/shader.frag @@ -2,12 +2,24 @@ out vec4 FragColor; in vec2 fragUV; +in vec3 fragPos; in float lighting; uniform sampler2D uTexture; +uniform vec3 cameraPosition; void main() { - vec4 texColor = texture(uTexture, fragUV); - FragColor = vec4(texColor.rgb * lighting, texColor.a); + float fogEnd = 512; + float fogStart = 32; + + float dist = length(cameraPosition - fragPos); + float fogFactor = (fogEnd - dist) / (fogEnd - fogStart); + fogFactor = clamp(fogFactor, 0, 1); + + vec4 fogColor = vec4(0.8,0.8,0.8,1); + vec4 texColor = texture(uTexture, fragUV) * lighting; + vec4 color = mix(fogColor, texColor, fogFactor); + + FragColor = vec4(color.rgb, texColor.a); } \ No newline at end of file diff --git a/Shaders/shader.vert b/Shaders/shader.vert index c7cd954..2b35d53 100644 --- a/Shaders/shader.vert +++ b/Shaders/shader.vert @@ -20,6 +20,7 @@ uniform int chunkY; out vec2 fragUV; out float lighting; +out vec3 fragPos; const float lightMult[6] = float[6](0.6, 0.6, 1.0, 0.5, 0.8, 0.8); @@ -111,5 +112,6 @@ void main() fragUV = uv; lighting = lightMult[facing]; + fragPos = vec3(worldPos.x, worldPos.y, worldPos.z); gl_Position = projection * view * worldPos; } \ No newline at end of file diff --git a/Window.cs b/Window.cs index 6a97ddf..c452f04 100644 --- a/Window.cs +++ b/Window.cs @@ -10,14 +10,16 @@ namespace Voxel { public readonly int Width = width; public readonly int Height = height; - public Player Player; public uint frames = 0; public double timeElapsed = 0; + public event Action Update; protected override void OnUpdateFrame(FrameEventArgs e) { base.OnUpdateFrame(e); + float deltaTime = (float)e.Time; + if (Input.GetKey(Keys.Escape)) { Close(); @@ -31,10 +33,7 @@ namespace Voxel WindowState = WindowState.Normal; } - if (Player != null) - { - Player.Update((float)e.Time); - } + Update.Invoke(deltaTime); } protected override void OnRenderFrame(FrameEventArgs e) @@ -52,7 +51,6 @@ namespace Voxel frames = 0; } - Camera.Update((float)e.Time); Renderer.Render(); SwapBuffers(); @@ -123,8 +121,6 @@ namespace Voxel if (e.OffsetY < 0) inverted = true; - - Player.SwitchBlock(inverted); } } }