feat: camera following player
This commit is contained in:
@@ -1,3 +1,4 @@
|
|||||||
|
using BakeryGame.Models;
|
||||||
using Raylib_cs;
|
using Raylib_cs;
|
||||||
using Scellecs.Morpeh;
|
using Scellecs.Morpeh;
|
||||||
|
|
||||||
@@ -5,5 +6,5 @@ namespace BakeryGame.Components.Player;
|
|||||||
|
|
||||||
public struct CameraComponent : IComponent
|
public struct CameraComponent : IComponent
|
||||||
{
|
{
|
||||||
public Camera3D Camera;
|
public CameraRef Camera;
|
||||||
}
|
}
|
||||||
@@ -28,19 +28,7 @@ public class BlockFactory
|
|||||||
return block;
|
return block;
|
||||||
}
|
}
|
||||||
|
|
||||||
public IEnumerable<Entity> GenerateMapOfBlocks()
|
|
||||||
{
|
|
||||||
for (int x = -16 / 2; x <= 16 / 2; x++) {
|
|
||||||
for (int z = -16 / 2; z <= 16 / 2; z++) {
|
|
||||||
if (x == -16 / 2 || x == 16 / 2 || z == -16 / 2 || z == 16 / 2)
|
|
||||||
{
|
|
||||||
yield return CreateBlock(x, z);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public const float BlockSize = 1;
|
public const float BlockSize = 1;
|
||||||
}
|
}
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
using System.Numerics;
|
using System.Numerics;
|
||||||
using BakeryGame.Components.Common;
|
using BakeryGame.Components.Common;
|
||||||
using BakeryGame.Components.Player;
|
using BakeryGame.Components.Player;
|
||||||
|
using BakeryGame.Models;
|
||||||
using Raylib_cs;
|
using Raylib_cs;
|
||||||
using Scellecs.Morpeh;
|
using Scellecs.Morpeh;
|
||||||
|
|
||||||
@@ -23,7 +24,7 @@ public class PlayerFactory
|
|||||||
player.SetComponent(new MovementComponent() { Speed = 0.1f });
|
player.SetComponent(new MovementComponent() { Speed = 0.1f });
|
||||||
camera = new CameraComponent()
|
camera = new CameraComponent()
|
||||||
{
|
{
|
||||||
Camera = new Camera3D(new(0.0f, 10.0f, 10.0f), new(0.0f, 0.0f, 0.0f), new(0.0f, 1.0f, 0.0f), 45.0f, 0)
|
Camera = new CameraRef(new(0.0f, 20.0f, 10.0f), new(0.0f, 0.0f, 0.0f), new(0.0f, 1.0f, 0.0f), 60.0f)
|
||||||
};
|
};
|
||||||
player.SetComponent(camera);
|
player.SetComponent(camera);
|
||||||
|
|
||||||
|
|||||||
20
Entities/RoomBuilder.cs
Normal file
20
Entities/RoomBuilder.cs
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
using Scellecs.Morpeh;
|
||||||
|
|
||||||
|
namespace BakeryGame.Entities;
|
||||||
|
|
||||||
|
public class RoomBuilder
|
||||||
|
{
|
||||||
|
public static int RoomSize = 16;
|
||||||
|
|
||||||
|
public static IEnumerable<Entity> GenerateMapOfBlocks(BlockFactory blockFactory)
|
||||||
|
{
|
||||||
|
for (int x = -RoomSize / 2; x <= RoomSize / 2; x++) {
|
||||||
|
for (int z = -RoomSize / 2; z <= RoomSize / 2; z++) {
|
||||||
|
if (x == -RoomSize / 2 || x == RoomSize / 2 || z == -RoomSize / 2 || z == RoomSize / 2)
|
||||||
|
{
|
||||||
|
yield return blockFactory.CreateBlock(x, z);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
56
Models/CameraRef.cs
Normal file
56
Models/CameraRef.cs
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
using System.Numerics;
|
||||||
|
using Raylib_cs;
|
||||||
|
|
||||||
|
namespace BakeryGame.Models;
|
||||||
|
|
||||||
|
public class CameraRef
|
||||||
|
{
|
||||||
|
private Camera3D _cam;
|
||||||
|
|
||||||
|
public CameraRef(Vector3 position, Vector3 target, Vector3 up, float fovy)
|
||||||
|
{
|
||||||
|
_cam = new Camera3D(position, target, up, fovy, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Camera position
|
||||||
|
/// </summary>
|
||||||
|
public void SetPosition(Vector3 position)
|
||||||
|
{
|
||||||
|
_cam.Position = position;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Camera target it looks-at
|
||||||
|
/// </summary>
|
||||||
|
public void SetTarget(Vector3 target)
|
||||||
|
{
|
||||||
|
_cam.Target = target;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Camera up vector (rotation over its axis)
|
||||||
|
/// </summary>
|
||||||
|
public void SetUp(Vector3 up)
|
||||||
|
{
|
||||||
|
_cam.Up = up;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Camera field-of-view apperture in Y (degrees) in perspective, used as near plane width in orthographic
|
||||||
|
/// </summary>
|
||||||
|
public void FovY(float fovy)
|
||||||
|
{
|
||||||
|
_cam.FovY = fovy;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Camera type, defines projection type: CAMERA_PERSPECTIVE or CAMERA_ORTHOGRAPHIC
|
||||||
|
/// </summary>
|
||||||
|
public void SetProjection(CameraProjection projection)
|
||||||
|
{
|
||||||
|
_cam.Projection = projection;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Camera3D GetCamera3D() => _cam;
|
||||||
|
}
|
||||||
28
Program.cs
28
Program.cs
@@ -18,17 +18,8 @@ namespace BakeryGame;
|
|||||||
internal class Program
|
internal class Program
|
||||||
{
|
{
|
||||||
private static World _world;
|
private static World _world;
|
||||||
|
private static int WindowWidth = 800;
|
||||||
private static readonly EnvItem[] _envItems =
|
private static int WindowHeight = 480;
|
||||||
{
|
|
||||||
new EnvItem(new Rectangle(0, 0, 1000, 400), Color.LightGray, false),
|
|
||||||
new EnvItem(new Rectangle(0, 400, 1000, 200), Color.Gray, true),
|
|
||||||
new EnvItem(new Rectangle(300, 200, 400, 100), Color.Gray, true),
|
|
||||||
new EnvItem(new Rectangle(250, 300, 100, 10), Color.Gray, true),
|
|
||||||
new EnvItem(new Rectangle(650, 300, 100, 10), Color.Gray, true)
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private static void Main(string[] args)
|
private static void Main(string[] args)
|
||||||
{
|
{
|
||||||
@@ -36,10 +27,11 @@ internal class Program
|
|||||||
var playerFactory = new PlayerFactory(_world);
|
var playerFactory = new PlayerFactory(_world);
|
||||||
var blockFactory = new BlockFactory(_world);
|
var blockFactory = new BlockFactory(_world);
|
||||||
|
|
||||||
Raylib.InitWindow(800, 480, "Hello World");
|
Raylib.InitWindow(WindowWidth, WindowHeight, "Hello World");
|
||||||
|
|
||||||
var player = playerFactory.CreatePlayer(out var camera);
|
CameraComponent camera;
|
||||||
var block = blockFactory.GenerateMapOfBlocks().ToList();
|
var player = playerFactory.CreatePlayer(out camera);
|
||||||
|
var block = RoomBuilder.GenerateMapOfBlocks(blockFactory).ToList();
|
||||||
|
|
||||||
SystemRegistrations.RegisterLogicGroup(_world);
|
SystemRegistrations.RegisterLogicGroup(_world);
|
||||||
SystemRegistrations.RegisterGraphicsGroup(_world);
|
SystemRegistrations.RegisterGraphicsGroup(_world);
|
||||||
@@ -48,15 +40,15 @@ internal class Program
|
|||||||
while (!Raylib.WindowShouldClose())
|
while (!Raylib.WindowShouldClose())
|
||||||
{
|
{
|
||||||
var deltaTime = Raylib.GetFrameTime();
|
var deltaTime = Raylib.GetFrameTime();
|
||||||
//Raylib.UpdateCamera(ref camera.Camera, CameraMode.Free);
|
//Raylib.UpdateCamera(ref camera.Camera, CameraMode.Custom);
|
||||||
Raylib.BeginDrawing();
|
Raylib.BeginDrawing();
|
||||||
Raylib.ClearBackground(Color.White);
|
Raylib.ClearBackground(Color.White);
|
||||||
Raylib.BeginMode3D(camera.Camera);
|
Raylib.BeginMode3D(camera.Camera.GetCamera3D());
|
||||||
_world.Update(deltaTime);
|
_world.Update(deltaTime);
|
||||||
Raylib.DrawGrid(10, 1.0f);
|
Raylib.DrawGrid(RoomBuilder.RoomSize, 1.0f);
|
||||||
_world.CleanupUpdate(deltaTime);
|
_world.CleanupUpdate(deltaTime);
|
||||||
Raylib.EndMode3D();
|
Raylib.EndMode3D();
|
||||||
Raylib.DrawFPS(100, 10);
|
Raylib.DrawFPS(WindowWidth - 100, 12);
|
||||||
_world.LateUpdate(deltaTime);
|
_world.LateUpdate(deltaTime);
|
||||||
_world.Commit();
|
_world.Commit();
|
||||||
Raylib.EndDrawing();
|
Raylib.EndDrawing();
|
||||||
|
|||||||
@@ -12,11 +12,13 @@ public static class SystemRegistrations
|
|||||||
var healthSystem = new HealthSystem { World = world };
|
var healthSystem = new HealthSystem { World = world };
|
||||||
var movementSystem = new MovementSystem { World = world };
|
var movementSystem = new MovementSystem { World = world };
|
||||||
var collisionSystem = new CollisionSystem(world);
|
var collisionSystem = new CollisionSystem(world);
|
||||||
|
|
||||||
var systemsGroup = world.CreateSystemsGroup();
|
var systemsGroup = world.CreateSystemsGroup();
|
||||||
systemsGroup.AddSystem(healthSystem);
|
systemsGroup.AddSystem(healthSystem);
|
||||||
systemsGroup.AddSystem(movementSystem);
|
systemsGroup.AddSystem(movementSystem);
|
||||||
systemsGroup.AddSystem(collisionSystem);
|
systemsGroup.AddSystem(collisionSystem);
|
||||||
|
|
||||||
|
|
||||||
systemsGroup.EnableSystem(movementSystem);
|
systemsGroup.EnableSystem(movementSystem);
|
||||||
systemsGroup.EnableSystem(healthSystem);
|
systemsGroup.EnableSystem(healthSystem);
|
||||||
systemsGroup.EnableSystem(collisionSystem);
|
systemsGroup.EnableSystem(collisionSystem);
|
||||||
@@ -28,7 +30,7 @@ public static class SystemRegistrations
|
|||||||
var renderSystemsGroup = world.CreateSystemsGroup();
|
var renderSystemsGroup = world.CreateSystemsGroup();
|
||||||
var hpRenreSystem = new HPRenderSystem { World = world };
|
var hpRenreSystem = new HPRenderSystem { World = world };
|
||||||
var ballRenderSystem = new PlayerRenderSystem { World = world };
|
var ballRenderSystem = new PlayerRenderSystem { World = world };
|
||||||
var cameraSystem = new CameraSystem(world);
|
var cameraSystem = new CameraSystem() {World = world };
|
||||||
var blockRenderSystem = new BlockRenderSystem(world);
|
var blockRenderSystem = new BlockRenderSystem(world);
|
||||||
|
|
||||||
renderSystemsGroup.AddSystem(blockRenderSystem);
|
renderSystemsGroup.AddSystem(blockRenderSystem);
|
||||||
|
|||||||
@@ -1,62 +0,0 @@
|
|||||||
using BakeryGame.Components.Common;
|
|
||||||
using BakeryGame.Components.Player;
|
|
||||||
using Scellecs.Morpeh;
|
|
||||||
|
|
||||||
namespace BakeryGame.Systems.Player;
|
|
||||||
|
|
||||||
public class CameraSystem : ISystem
|
|
||||||
{
|
|
||||||
private Filter _filter;
|
|
||||||
|
|
||||||
public CameraSystem(World world)
|
|
||||||
{
|
|
||||||
World = world;
|
|
||||||
}
|
|
||||||
|
|
||||||
public World World { get; set; }
|
|
||||||
|
|
||||||
|
|
||||||
public void OnAwake()
|
|
||||||
{
|
|
||||||
_filter = World.Filter.With<CameraComponent>().Build();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void OnUpdate(float deltaTime)
|
|
||||||
{
|
|
||||||
foreach (var entity in _filter)
|
|
||||||
{
|
|
||||||
var position = entity.GetComponent<PositionComponent>().Position;
|
|
||||||
ref var cameraComponent = ref entity.GetComponent<CameraComponent>();
|
|
||||||
|
|
||||||
ref var camera = ref cameraComponent.Camera;
|
|
||||||
// Camera target follows player
|
|
||||||
//camera.Target.X = position.X;
|
|
||||||
//camera.Target.Z = position.Z;
|
|
||||||
|
|
||||||
// // Camera rotation controls
|
|
||||||
// if (IsKeyDown(KEY_A)) camera.rotation--;
|
|
||||||
// else if (IsKeyDown(KEY_S)) camera.rotation++;
|
|
||||||
|
|
||||||
// Limit camera rotation to 80 degrees (-40 to 40)
|
|
||||||
// if (camera.Rotation > 40) camera.Rotation = 40;
|
|
||||||
// else if (camera.Rotation < -40) camera.Rotation = -40;
|
|
||||||
|
|
||||||
// Camera zoom controls
|
|
||||||
// camera.Zoom += Raylib.GetMouseWheelMove() * 0.05f;
|
|
||||||
//
|
|
||||||
// if (camera.Zoom > 3.0f) camera.Zoom = 3.0f;
|
|
||||||
// else if (camera.Zoom < 0.1f) camera.Zoom = 0.1f;
|
|
||||||
|
|
||||||
// // Camera reset (zoom and rotation)
|
|
||||||
// if (IsKeyPressed(KEY_R))
|
|
||||||
// {
|
|
||||||
// camera.zoom = 1.0f;
|
|
||||||
// camera.rotation = 0.0f;
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
46
Systems/Rendering/CameraSystem.cs
Normal file
46
Systems/Rendering/CameraSystem.cs
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
using BakeryGame.Components.Common;
|
||||||
|
using BakeryGame.Components.Player;
|
||||||
|
using Raylib_cs;
|
||||||
|
using Scellecs.Morpeh;
|
||||||
|
|
||||||
|
namespace BakeryGame.Systems.Rendering;
|
||||||
|
|
||||||
|
public class CameraSystem: ILateSystem
|
||||||
|
{
|
||||||
|
private Filter _player;
|
||||||
|
float sliderValue = 50.0f; // Initial value of the slider
|
||||||
|
float minValue = -20.0f; // Minimum value of the slider
|
||||||
|
float maxValue = 20.0f; // Maximum value of the slider
|
||||||
|
Rectangle sliderRect = new Rectangle( 100, 50, 200, 20 ); // Rectangle defining the slider's position and size
|
||||||
|
bool isSliderActive = false;
|
||||||
|
private const float CameraSpeed = 0.1f;
|
||||||
|
private const float DistanceToPlayer = 10.0f;
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnAwake()
|
||||||
|
{
|
||||||
|
_player = World.Filter.With<PlayerComponent>().Build();
|
||||||
|
}
|
||||||
|
|
||||||
|
public World World { get; set; }
|
||||||
|
|
||||||
|
private float Lerp(float a, float b, float t)
|
||||||
|
{
|
||||||
|
return a + (b - a) * t;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnUpdate(float deltaTime)
|
||||||
|
{
|
||||||
|
var player = _player.First();
|
||||||
|
ref var cameraComponent = ref player.GetComponent<CameraComponent>();
|
||||||
|
var camera = cameraComponent.Camera.GetCamera3D();
|
||||||
|
var playerPosition = player.GetComponent<PositionComponent>().Position;
|
||||||
|
// Update camera position to follow the player
|
||||||
|
cameraComponent.Camera.SetPosition(camera.Position with {X = Lerp(camera.Position.X, playerPosition.X, CameraSpeed), Z = Lerp(camera.Position.Z, playerPosition.Z + DistanceToPlayer, CameraSpeed)});
|
||||||
|
// Update camera target to look at the player
|
||||||
|
cameraComponent.Camera.SetTarget(playerPosition);
|
||||||
|
}
|
||||||
|
}
|
||||||
75
Systems/Rendering/SliderSystem.cs
Normal file
75
Systems/Rendering/SliderSystem.cs
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
using BakeryGame.Components.Common;
|
||||||
|
using BakeryGame.Components.Player;
|
||||||
|
using Raylib_cs;
|
||||||
|
using Scellecs.Morpeh;
|
||||||
|
|
||||||
|
namespace BakeryGame.Systems.Rendering;
|
||||||
|
|
||||||
|
public class SliderSystem:ILateSystem
|
||||||
|
{
|
||||||
|
private Filter _player;
|
||||||
|
float sliderValue = 50.0f; // Initial value of the slider
|
||||||
|
float minValue = -20.0f; // Minimum value of the slider
|
||||||
|
float maxValue = 20.0f; // Maximum value of the slider
|
||||||
|
Rectangle sliderRect = new Rectangle( 100, 50, 200, 20 ); // Rectangle defining the slider's position and size
|
||||||
|
bool isSliderActive = false;
|
||||||
|
private const float CameraSpeed = 0.1f;
|
||||||
|
private const float DistanceToPlayer = 10.0f;
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnAwake()
|
||||||
|
{
|
||||||
|
_player = World.Filter.With<PlayerComponent>().Build();
|
||||||
|
}
|
||||||
|
|
||||||
|
public World World { get; set; }
|
||||||
|
|
||||||
|
|
||||||
|
private float Lerp(float a, float b, float t)
|
||||||
|
{
|
||||||
|
return a + (b - a) * t;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnUpdate(float deltaTime)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (Raylib.IsMouseButtonPressed(MouseButton.Left)) {
|
||||||
|
// Check if mouse is clicked within the slider rectangle
|
||||||
|
if (Raylib.CheckCollisionPointRec(Raylib.GetMousePosition(), sliderRect)) {
|
||||||
|
isSliderActive = true; // Slider is being interacted with
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Raylib.IsMouseButtonReleased(MouseButton.Left)) {
|
||||||
|
isSliderActive = false; // Stop slider interaction
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update slider value when slider is active
|
||||||
|
if (isSliderActive) {
|
||||||
|
// // Calculate new slider value based on mouse position
|
||||||
|
float mousePosX = Raylib.GetMouseX();
|
||||||
|
sliderValue = minValue + (mousePosX - sliderRect.X) / sliderRect.Width * (maxValue - minValue);
|
||||||
|
|
||||||
|
// Clamp slider value within the valid range
|
||||||
|
if (sliderValue < minValue) sliderValue = minValue;
|
||||||
|
if (sliderValue > maxValue) sliderValue = maxValue;
|
||||||
|
|
||||||
|
// ref var cameraComponent = ref player.GetComponent<CameraComponent>();
|
||||||
|
// var camera = cameraComponent.Camera.GetCamera3D();
|
||||||
|
// cameraComponent.Camera.SetTarget(camera.Target with {X = sliderValue});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Draw slider background
|
||||||
|
Raylib.DrawRectangleRec(sliderRect, Color.LightGray);
|
||||||
|
|
||||||
|
// Draw slider handle
|
||||||
|
float sliderHandlePosX = sliderRect.X + (sliderValue - minValue) / (maxValue - minValue) * sliderRect.Width;
|
||||||
|
var sliderHandleRect = new Rectangle( sliderHandlePosX - 5, sliderRect.Y - 5, 10, sliderRect.Height + 10 );
|
||||||
|
Raylib.DrawRectangleRec(sliderHandleRect, Color.Blue);
|
||||||
|
isSliderActive = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user