Compare commits

..

2 Commits

Author SHA1 Message Date
d71a0aab5e added rough movement and level loader 2025-11-28 21:29:24 +00:00
c175d01ead fixed some bugs 2025-11-28 20:18:18 +00:00
8 changed files with 187 additions and 38 deletions

View File

@ -0,0 +1,27 @@
using OpenTK.Mathematics;
namespace TheLabs;
public class BoxCollider
{
public Vector3 Center;
public Vector3 HalfSize;
public BoxCollider(Vector3 center, Vector3 halfSize)
{
Center = center;
HalfSize = halfSize * 0.5f;
}
public Vector3 Min => Center - HalfSize;
public Vector3 Max => Center + HalfSize;
public bool CheckCollision(BoxCollider other)
{
bool collisionX = Max.X >= other.Min.X && Min.X <= other.Max.X;
bool collisionY = Max.Y >= other.Min.Y && Min.Y <= other.Max.Y;
bool collisionZ = Max.Z >= other.Min.Z && Min.Z <= other.Max.Z;
return collisionX && collisionY && collisionZ;
}
}

View File

@ -0,0 +1,64 @@
using Assimp;
using LearnOpenTK.Common;
using OpenTK.Mathematics;
namespace TheLabs;
public class LevelLoader
{
private Shader _shader;
private Texture _texture;
private Texture _normalTexture;
private Material _material;
private Lighting _lighting;
public LevelLoader(Shader shader, Texture texture, Texture normalTexture, Material material, Lighting lighting)
{
_shader = shader;
_texture = texture;
_normalTexture = normalTexture;
_material = material;
_lighting = lighting;
}
public void LoadLevel(string filepath, SceneNode rootenode, List<BoxCollider> colliders)
{
Mesh _mesh = ShapeFactory.CreateTexturedCube();
RenderObject renderObject = new RenderObject(_mesh, _shader, _texture, _material, _lighting);
renderObject.NormalMap = _normalTexture;
renderObject.UseTexture = true;
if (!File.Exists(filepath))
{
throw new FileNotFoundException("The specified level file was not found.", filepath);
}
string[] lines = File.ReadAllLines(filepath);
float spacing = 1.0f;
for (int z = 0; z < lines.Length; z++)
{
string line = lines[z];
for (int x = 0; x < line.Length; x++)
{
char tile = line[x];
SceneNode floorNode = new SceneNode(renderObject);
floorNode.Position = new Vector3(x * spacing, -0.5f, z * spacing);
floorNode.Scale = new Vector3(1.0f, 0.1f, 1.0f);
rootenode.AddChild(floorNode);
if (tile == '1')
{
BoxCollider wallCollider = new BoxCollider(new Vector3(x, 0, z), new Vector3(1, 1, 1));
colliders.Add(wallCollider);
SceneNode wallNode = new SceneNode(renderObject);
wallNode.Position = new Vector3(x * spacing, 0.0f, z * spacing);
rootenode.AddChild(wallNode);
}
}
}
}
}

View File

@ -0,0 +1,7 @@
1111111111
1000000001
1011101101
1010000101
1010110101
1000000001
1111111111

View File

@ -38,11 +38,14 @@ namespace TheLabs
private float _mouseSensitivity = 0.1f;
private float _pitch = 0.0f;
private float _rotation = 0.0f;
Vector3 playerSize = new Vector3(0.5f, 1.0f, 0.5f);
// Materials and Lighting
private Lighting _mainLight;
private Material _defaultMaterial;
private List<BoxCollider> _wallColliders = new List<BoxCollider>();
// This prevents a large camera jump when the window first gets focus
private bool _firstMove = true;
@ -60,9 +63,9 @@ namespace TheLabs
// --- Set up Lighting and Material ---
_mainLight = new Lighting(new Vector3(
1.2f, 1.0f, 2.0f),
new Vector3(0.5f),
new Vector3(5.0f),
new Vector3(1.5f),
new Vector3(1.0f));
new Vector3(4.0f));
_defaultMaterial = new Material(
new Vector3(0.5f, 0.5f, 0.5f) * 0.1f,
@ -75,27 +78,25 @@ namespace TheLabs
GL.Enable(EnableCap.DepthTest);
// --- Set up Camera ---
_camera = new Camera(_cameraPosition, _cameraFront, _cameraUp);
// -- Load Shaders, Textures, and Create Scene Objects ---
_shader = new Shader("Shaders/shader.vert", "Shaders/shader.frag");
_texture = new Texture("Textures/cobble.jpg");
Texture _normalMap = new Texture("Textures/cobbleNormal.jpg");
LevelLoader levelLoader = new LevelLoader(_shader, _texture, _normalMap, _defaultMaterial, _mainLight);
// --- Create Scene Graph ---
_rootNode = new SceneNode();
// Create Example Object
_buildingObject = ShapeFactory.CreateTexturedCube();
_buildingRender = new RenderObject(_buildingObject, _shader, _texture, _defaultMaterial, _mainLight);
_buildingRender.NormalMap = _normalMap;
_buildingNode = new SceneNode(_buildingRender);
_buildingNode.Position = new Vector3(2.0f, -1.0f, 0.0f);
_buildingNode.Scale = new Vector3(0.1f, 0.1f, 0.1f);
_rootNode.AddChild(_buildingNode);
string levelFilePath = "Levels/level1.txt";
levelLoader.LoadLevel(levelFilePath, _rootNode, _wallColliders);
// --- Create Scene Graph ---
// Create Character Object
_cameraPosition = new Vector3(-2.5f, 0.0f, 1.5f);
_camera = new Camera(_cameraPosition, _cameraFront, _cameraUp);
CursorState = CursorState.Grabbed;
@ -138,6 +139,15 @@ namespace TheLabs
base.OnUpdateFrame(e);
_rotation += (float)e.Time;
var input = KeyboardState;
float gravity = -9.81f;
_camera._position.Y += gravity * (float)e.Time;
float floorHeight = 0.0f;
if (_camera._position.Y < floorHeight)
{
_camera._position.Y = floorHeight;
}
if (input.IsKeyDown(Keys.Escape))
{
@ -186,6 +196,17 @@ namespace TheLabs
{
_pitch -= _rotationSpeed * (float)e.Time;
}
if (input.IsKeyDown(Keys.Space))
{
if (_camera._position.Y <= floorHeight + 0.01f)
{
_camera._position.Y += 10.0f * (float)e.Time;
}
}
_pitch = MathHelper.Clamp(_pitch, -89.0f, 89.0f);
Vector3 front;
_camera._target.X = MathF.Cos(MathHelper.DegreesToRadians(_yaw)) * MathF.Cos(MathHelper.DegreesToRadians(_pitch));
@ -194,7 +215,29 @@ namespace TheLabs
_cameraFront = Vector3.Normalize(_camera._target);
var _cameraRight = Vector3.Normalize(Vector3.Cross(_cameraFront, _camera._up));
if (input.IsKeyDown(Keys.W)) _camera._position += _cameraFront * _cameraSpeed * (float)e.Time;
if (input.IsKeyDown(Keys.W))
{
Vector3 proposedPosition = _camera._position + _cameraFront * _cameraSpeed * (float)e.Time;
BoxCollider playerCollider = new BoxCollider(proposedPosition, playerSize);
bool safe = true;
foreach (var wall in _wallColliders)
{
if (playerCollider.CheckCollision(wall))
{
safe = false;
break;
}
}
if (safe)
{
_camera._position = proposedPosition;
}
}
if (input.IsKeyDown(Keys.S)) _camera._position -= _cameraFront * _cameraSpeed * (float)e.Time;
if (input.IsKeyDown(Keys.A)) _camera._position -= _cameraRight * _cameraSpeed * (float)e.Time;
if (input.IsKeyDown(Keys.D)) _camera._position += _cameraRight * _cameraSpeed * (float)e.Time;

View File

@ -36,8 +36,6 @@ public class RenderObject
public void Draw(Matrix4 view, Matrix4 projection, Lighting light)
{
Vector3 pink = new Vector3(0.5f, 0.5f, 0.5f);
Material mat = new Material(pink * 0.1f, pink * 0.6f, Vector3.One, 32.0f);
Shader.Use();
if (Texture != null && UseTexture)

View File

@ -30,9 +30,9 @@ public class SceneNode
if (RenderObject != null)
{
RenderObject.Position = Vector3.Zero;
RenderObject.Rotation = Quaternion.Identity;
RenderObject.Scale = Vector3.One;
RenderObject.Position = Position;
RenderObject.Rotation = Rotation;
RenderObject.Scale = Scale;
RenderObject.Draw(view, projection, light);
}

View File

@ -332,26 +332,31 @@ public static class ShapeFactory
return new Mesh(vertices.ToArray(), indices.ToArray(), Mesh.VertexLayout.PosTexNormal);
}
public static Mesh createTexturedSquare()
public static Mesh CreateTexturedQuad()
{
float[] vertices = {
// Format: X, Y, Z, U, V
List<Vertex> vertices = new List<Vertex>();
List<uint> indices = new List<uint>();
// --- Front Face ---
-0.5f, -0.5f, 0.0f, 0f, 0f, // Bottom-left
0.5f, -0.5f, 0.0f, 1f, 0f, // Bottom-right
0.5f, 0.5f, 0.0f, 1f, 1f, // Top-right
-0.5f, 0.5f, 0.0f, 0f, 1f, // Top-left
};
// Create a flat quad facing UP (Normal 0, 1, 0)
Helpers.AddFace(vertices, indices,
new Vertex(new Vector3(-0.5f, 0.0f, 0.5f), new Vector3(0, 1, 0), new Vector2(0, 0), Vector3.Zero, Vector3.Zero), // BL
new Vertex(new Vector3( 0.5f, 0.0f, 0.5f), new Vector3(0, 1, 0), new Vector2(1, 0), Vector3.Zero, Vector3.Zero), // BR
new Vertex(new Vector3( 0.5f, 0.0f, -0.5f), new Vector3(0, 1, 0), new Vector2(1, 1), Vector3.Zero, Vector3.Zero), // TR
new Vertex(new Vector3(-0.5f, 0.0f, -0.5f), new Vector3(0, 1, 0), new Vector2(0, 1), Vector3.Zero, Vector3.Zero) // TL
);
uint[] indices = {
// Front face
0, 2, 1,
0, 2, 3,
};
return new Mesh(vertices, indices, Mesh.VertexLayout.PosTex);
// Convert to arrays and return
List<float> finalFloats = new List<float>();
foreach (var v in vertices)
{
finalFloats.Add(v.Position.X); finalFloats.Add(v.Position.Y); finalFloats.Add(v.Position.Z);
finalFloats.Add(v.Normal.X); finalFloats.Add(v.Normal.Y); finalFloats.Add(v.Normal.Z);
finalFloats.Add(v.TexCoords.X); finalFloats.Add(v.TexCoords.Y);
finalFloats.Add(v.Tangent.X); finalFloats.Add(v.Tangent.Y); finalFloats.Add(v.Tangent.Z);
finalFloats.Add(v.Bitangent.X); finalFloats.Add(v.Bitangent.Y); finalFloats.Add(v.Bitangent.Z);
}
return new Mesh(finalFloats.ToArray(), indices.ToArray(), Mesh.VertexLayout.PosTexNormalTangent);
}
}

View File

@ -33,5 +33,10 @@
<ItemGroup>
<Compile Remove="Shapes\Bus.cs" />
</ItemGroup>
<ItemGroup>
<None Update="Levels\**">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project>