Skip to content

Commit 06a05c4

Browse files
AngelMunozCopilot
andauthored
feat: add Mibo.Raylib.Templates with 2D and 3D template projects (#3)
- feat: add Mibo.Raylib.Templates with 2D and 3D template projects - Add Mibo.Raylib.Templates NuGet template package (netstandard2.0) - Add mibo-raylib-2d template: 2D game with WASD input and bouncing rect - Add mibo-raylib-3d template: 3D game with WASD input and bouncing cube - Both templates use pure functional style: helper functions with params-in/result-out, no mutable state in game logic - Include .template.config, dotnet-tools.json, and proper fsproj setup - Update solution and changelog Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * chore(docs): update changelog and README for template installation instructions - Simplified changelog entry for Mibo.Raylib.Templates NuGet package. - Added installation instructions for templates in README. - Removed outdated notes about early development from documentation. --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 0e46e4a commit 06a05c4

13 files changed

Lines changed: 471 additions & 13 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
### Added
66

7+
- `Mibo.Raylib.Templates` NuGet package with `mibo-2d` and `mibo-3d` dotnet templates for scaffolding new Mibo Raylib game projects.
78
- PlatformerSample: 2D minimap with MVU pattern (`MinimapModel`, `Minimap.system`, `Minimap.view`). Bakes tiles into CPU image, uploads to GPU texture, draws as single sprite. Background matches sky color gradient.
89
- PlatformerSample: Variable jump height — releasing jump early cuts upward velocity for short hops.
910
- PlatformerSample: New tile types — `Spikes` (hazard), `Coin` (collectible, increments score), `Flag` (goal marker).

Mibo.Raylib.slnx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,6 @@
55
</Folder>
66
<Folder Name="/src/">
77
<Project Path="src/Mibo.Raylib/Mibo.Raylib.fsproj" />
8+
<Project Path="src/Templates/Mibo.Raylib.Templates.csproj" />
89
</Folder>
910
</Solution>

README.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,14 @@
11
# Mibo.Raylib
22

3+
> Install the templates:
4+
>
5+
> ```bash
6+
> dotnet new install Mibo.Raylib.Templates
7+
> dotnet new mibo-2d -o MyGame
8+
> cd MyGame
9+
> dotnet run
10+
> ```
11+
312
> **NOTE for ADVENTURERS:** raylib is a programming library to enjoy videogames programming; no fancy interface, no visual helpers, no debug button... just coding in the most pure spartan-programmers way.
413
514
Following that spirit, Mibo.Raylib keeps it lean, just F# and the Elmish loop with a handful of commodities to get out of your way and let you enjoy the craft.

docs/index.md

Lines changed: 4 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -16,20 +16,11 @@ Mibo.Raylib is a lightweight, Elmish-based game framework built on top of raylib
1616

1717
To get started with Mibo.Raylib, you need the [dotnet SDK](https://get.dot.net) installed.
1818

19-
> **NOTE:** Mibo.Raylib is currently in early development. NuGet packages are not yet available, but you can clone the repository and run the samples to see it in action.
20-
21-
Start by cloning the repository and running one of the samples:
22-
23-
```bash
24-
git clone https://github.com/your-org/Mibo.Raylib
25-
cd Mibo.Raylib
26-
dotnet run --project samples/PlatformerSample
27-
```
28-
29-
Or the 3D sample:
30-
3119
```bash
32-
dotnet run --project samples/ThreeDSample
20+
dotnet new install Mibo.Raylib.Templates
21+
dotnet new mibo-2d -o MyGame
22+
cd MyGame
23+
dotnet run
3324
```
3425

3526
The projects in `samples/PlatformerSample` and `samples/ThreeDSample` show complete, working setups.
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<PackageType>Template</PackageType>
5+
<PackageId>Mibo.Raylib.Templates</PackageId>
6+
<Title>Mibo Raylib Templates</Title>
7+
<Authors>Mibo Authors</Authors>
8+
<Description>Mibo templates for creating functional 2D and 3D games with F#, Elmish, and raylib-cs. Includes project templates for 2D and 3D game development.</Description>
9+
<PackageTags>dotnet-new;templates;mibo;raylib;game;fsharp</PackageTags>
10+
<TargetFramework>netstandard2.0</TargetFramework>
11+
<IncludeContentInPack>true</IncludeContentInPack>
12+
<IncludeBuildOutput>false</IncludeBuildOutput>
13+
<ContentTargetFolders>content</ContentTargetFolders>
14+
<NoWarn>$(NoWarn);NU5128</NoWarn>
15+
<NoDefaultExcludes>true</NoDefaultExcludes>
16+
</PropertyGroup>
17+
18+
<ItemGroup>
19+
<Content Include="Templates/**/*" Exclude="Templates/**/bin/**;Templates/**/obj/**;Templates/**/.DS_Store" />
20+
<Compile Remove="**/*" />
21+
</ItemGroup>
22+
23+
</Project>
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{
2+
"version": 1,
3+
"isRoot": true,
4+
"tools": {
5+
"fantomas": {
6+
"version": "7.0.5",
7+
"commands": ["fantomas"],
8+
"rollForward": false
9+
}
10+
}
11+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
{
2+
"$schema": "http://json.schemastore.org/template",
3+
"author": "Mibo Authors",
4+
"classifications": ["Game", "Mibo", "Raylib", "2D"],
5+
"name": "Mibo Raylib 2D Game",
6+
"identity": "Mibo.Raylib.Templates.2D",
7+
"shortName": "mibo-2d",
8+
"tags": {
9+
"language": "F#",
10+
"type": "project"
11+
},
12+
"sourceName": "MiboRaylib2D",
13+
"preferNameDirectory": true
14+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<OutputType>Exe</OutputType>
5+
<TargetFramework>net10.0</TargetFramework>
6+
</PropertyGroup>
7+
8+
<ItemGroup>
9+
<Compile Include="Program.fs" />
10+
</ItemGroup>
11+
12+
<ItemGroup>
13+
<PackageReference Include="Mibo.Raylib" Version="1.*" />
14+
</ItemGroup>
15+
16+
</Project>
Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
module MiboRaylib2D.Program
2+
3+
open System
4+
open System.Numerics
5+
open Raylib_cs
6+
open Mibo.Elmish
7+
open Mibo.Elmish.Graphics2D
8+
open Mibo.Input
9+
10+
// ─────────────────────────────────────────────────────────────
11+
// Input
12+
// ─────────────────────────────────────────────────────────────
13+
14+
[<Struct>]
15+
type GameAction =
16+
| MoveLeft
17+
| MoveRight
18+
| MoveUp
19+
| MoveDown
20+
21+
let inputMap =
22+
InputMap.empty
23+
|> InputMap.key MoveLeft KeyboardKey.Left
24+
|> InputMap.key MoveLeft KeyboardKey.A
25+
|> InputMap.key MoveRight KeyboardKey.Right
26+
|> InputMap.key MoveRight KeyboardKey.D
27+
|> InputMap.key MoveUp KeyboardKey.Up
28+
|> InputMap.key MoveUp KeyboardKey.W
29+
|> InputMap.key MoveDown KeyboardKey.Down
30+
|> InputMap.key MoveDown KeyboardKey.S
31+
32+
// ─────────────────────────────────────────────────────────────
33+
// Model
34+
// ─────────────────────────────────────────────────────────────
35+
36+
type Model = {
37+
Position: Vector2
38+
Velocity: Vector2
39+
Input: ActionState<GameAction>
40+
}
41+
42+
// ─────────────────────────────────────────────────────────────
43+
// Messages
44+
// ─────────────────────────────────────────────────────────────
45+
46+
[<Struct>]
47+
type Msg =
48+
| Tick of tick: GameTime
49+
| InputChanged of inputs: ActionState<GameAction>
50+
51+
// ─────────────────────────────────────────────────────────────
52+
// Init
53+
// ─────────────────────────────────────────────────────────────
54+
55+
let init(_ctx: GameContext) : struct (Model * Cmd<Msg>) =
56+
let model = {
57+
Position = Vector2(400.f, 300.f)
58+
Velocity = Vector2(200.f, 150.f)
59+
Input = ActionState.empty
60+
}
61+
62+
model, Cmd.none
63+
64+
// ─────────────────────────────────────────────────────────────
65+
// Update
66+
// ─────────────────────────────────────────────────────────────
67+
68+
let speed = 200.f
69+
70+
let computeManualVelocity(input: ActionState<GameAction>) =
71+
let x =
72+
if input.Held.Contains MoveLeft then -speed
73+
elif input.Held.Contains MoveRight then speed
74+
else 0.f
75+
76+
let y =
77+
if input.Held.Contains MoveUp then -speed
78+
elif input.Held.Contains MoveDown then speed
79+
else 0.f
80+
81+
Vector2(x, y)
82+
83+
let bounce
84+
(min: Vector2)
85+
(max: Vector2)
86+
(position: Vector2)
87+
(velocity: Vector2)
88+
=
89+
let x =
90+
if position.X < min.X || position.X > max.X then
91+
-velocity.X
92+
else
93+
velocity.X
94+
95+
let y =
96+
if position.Y < min.Y || position.Y > max.Y then
97+
-velocity.Y
98+
else
99+
velocity.Y
100+
101+
Vector2(x, y)
102+
103+
let update (msg: Msg) (model: Model) : struct (Model * Cmd<Msg>) =
104+
match msg with
105+
| InputChanged input -> { model with Input = input }, Cmd.none
106+
| Tick gt ->
107+
let dt = float32 gt.ElapsedGameTime.TotalSeconds
108+
let manual = computeManualVelocity model.Input
109+
let position = model.Position + (model.Velocity * dt) + (manual * dt)
110+
111+
let velocity =
112+
bounce Vector2.Zero (Vector2(768.f, 568.f)) position model.Velocity
113+
114+
{
115+
model with
116+
Position = position
117+
Velocity = velocity
118+
},
119+
Cmd.none
120+
121+
// ─────────────────────────────────────────────────────────────
122+
// View
123+
// ─────────────────────────────────────────────────────────────
124+
125+
let view (_ctx: GameContext) (model: Model) (buffer: RenderBuffer2D) =
126+
let rect =
127+
Rectangle(float32 model.Position.X, float32 model.Position.Y, 32.f, 32.f)
128+
129+
buffer |> Draw.fillRect (0<RenderLayer>, Color.Red) rect |> Draw.drop
130+
131+
// ─────────────────────────────────────────────────────────────
132+
// Program
133+
// ─────────────────────────────────────────────────────────────
134+
135+
[<EntryPoint>]
136+
let main _ =
137+
let program =
138+
Program.mkProgram init update
139+
|> Program.withConfig(fun cfg -> {
140+
cfg with
141+
Width = 800
142+
Height = 600
143+
Title = "Mibo Raylib 2D Game"
144+
TargetFPS = 60
145+
})
146+
|> Program.withInput
147+
|> Program.withSubscription(fun ctx _model ->
148+
InputMapper.subscribeStatic inputMap InputChanged ctx)
149+
|> Program.withTick Tick
150+
|> Program.withRenderer(fun () -> Renderer2D.create view)
151+
152+
let game = new RaylibGame<Model, Msg>(program)
153+
game.Run()
154+
0
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{
2+
"version": 1,
3+
"isRoot": true,
4+
"tools": {
5+
"fantomas": {
6+
"version": "7.0.5",
7+
"commands": ["fantomas"],
8+
"rollForward": false
9+
}
10+
}
11+
}

0 commit comments

Comments
 (0)