This article serves as a quick-start guide for C#/.NET developers looking to explore game development with the Stride Community Toolkit. Using a code-only approach, the article walks you through creating a simple project in a .NET 8 Console App by adding basic entities, implementing keyboard interaction, and applying physics, all without needing the Stride Game Studio. By the end, you'll understand how to build a basic game project with Stride's powerful engine and tools, all while working within a familiar C#/.NET environment.
Introduction🌱
Welcome to the preview of the Stride Community Toolkit a collection of extensions and helpers for the Stride C# game engine, developed as a community-driven, open-source project. This toolkit enables developers to create 2D/3D games and visualizations using Stride's code-only approach, bypassing the need for the Game Studio.
In this short post, we’ll explore the code-only feature, which I found particularly useful as a C#/.NET developer. We'll use a .NET 8 Console App to create a simple project by adding a few NuGet packages. If you enjoy this post, be sure to check out the more comprehensive article linked at the end for a deeper dive.
Table of contents:
- Introduction
- Background
- Prerequisites
- Using the code
- Step 1: Create a New C# .NET 8 Console App
- Step 2: Add Code
- Step 3: Build the Game
- Step 4: Run the Game
- Step 5: Understanding the Code
- Step 6: Your Turn
- References
- Conclusion
Background 🌄
I came across Stride a few years ago, and it caught my attention because Stride was using .NET 6 and C# 10, while other C#/.NET game engines weren't. I began exploring it but didn't want to follow the usual route through the Game Studio to learn Stride. Instead, I wanted to run a console application and gradually add features and logic, learning step by step, the ".NET way."
At that time, the code-only approach wasn't as available as it is now, so I started digging into the engine, connecting with the community, and contributing some ideas and PRs. Fast forward to today, with the Stride Community Toolkit, I can run the Stride Game Engine from a simple console by adding regular NuGet packages.
Prerequisites 🏠
Basic knowledge of C# and .NET is required to follow along with this tutorial.
These prerequisites were tested on a clean Windows 11 installation.
- Install the Microsoft Visual C++ 2015-2022 Redistributable (25MB) and restart your system if prompted.
- Install the .NET 8 SDK x64 (200MB).
- Install the IDE of your choice. I will be using Visual Studio 2022, but you can also use Visual Studio Code, Rider, or any other IDE that supports .NET development.
Using the code
You can copy and paste the code into your Program.cs
file and run the application to see the results.
Step 1: Create a New C# .NET 8 Console App
- Create a new C# .NET 8 Console App in your IDE.
- Add the following NuGet package 📦
dotnet add package Stride.CommunityToolkit.Windows --prerelease
Step 2: Add Code
Paste the following code into your Program.cs
file: 💻
using Stride.CommunityToolkit.Engine;
using Stride.CommunityToolkit.Rendering.ProceduralModels;
using Stride.Core.Mathematics;
using Stride.Engine;
using Stride.Games;
using Stride.Input;
using Stride.Physics;
float movementSpeed = 1f;
float force = 3f;
Entity? sphere1 = null;
Entity? sphere2 = null;
using var game = new Game();
game.Run(start: Start, update: Update);
void Start(Scene rootScene)
{
game.AddGraphicsCompositor();
game.Add3DCamera().Add3DCameraController();
game.AddDirectionalLight();
game.Add3DGround();
game.AddGroundGizmo(position: new Vector3(-5, 0.1f, -5), showAxisName: true);
var entity = game.Create3DPrimitive(PrimitiveModelType.Cone);
entity.Transform.Position = new Vector3(0, 8, 0);
entity.Scene = rootScene;
sphere1 = game.Create3DPrimitive(PrimitiveModelType.Sphere, new()
{
Material = game.CreateMaterial(Color.Gold),
IncludeCollider = false
});
sphere1.Scene = rootScene;
sphere2 = game.Create3DPrimitive(PrimitiveModelType.Sphere, new()
{
Material = game.CreateMaterial(Color.Orange)
});
sphere2.Transform.Position = new Vector3(-3, 5, 0);
sphere2.Scene = rootScene;
}
void Update(Scene scene, GameTime time)
{
var deltaTime = (float)time.Elapsed.TotalSeconds;
if (sphere1 != null)
{
if (game.Input.IsKeyDown(Keys.Z))
{
sphere1.Transform.Position -= new Vector3(movementSpeed * deltaTime, 0, 0);
}
else if (game.Input.IsKeyDown(Keys.X))
{
sphere1.Transform.Position += new Vector3(movementSpeed * deltaTime, 0, 0);
}
}
if (sphere2 != null)
{
var rigidBody = sphere2.Get<RigidbodyComponent>();
if (game.Input.IsKeyPressed(Keys.C))
{
rigidBody.ApplyImpulse(new Vector3(-force, 0, 0));
}
else if (game.Input.IsKeyPressed(Keys.V))
{
rigidBody.ApplyImpulse(new Vector3(force, 0, 0));
}
}
}
Step 3: Build the Game
Build the project from the command line or use your IDE to build it:
dotnet build
Step 4: Run the Game
Run the application from your IDE. You should see this below.
Step 5: Understanding the Code
Let’s take a closer look at the code.
With just this code, we can run the game, but while the loop is running, there’s nothing to see yet.
using Stride.Engine;
using var game = new Game();
game.Run();
We need to add basic components to the game loop so that something appears in the 3D space. These are all extensions that wrap basic functionality, but you can further customize them by implementing your own versions if the extensions are too limiting.
We’ll add a Start()
callback method to game.Run()
and use it to set up the scene with the necessary components.
using Stride.CommunityToolkit.Engine;
using Stride.Core.Mathematics;
using Stride.Engine;
using var game = new Game();
game.Run(start: Start);
void Start(Scene rootScene)
{
game.AddGraphicsCompositor();
game.Add3DCamera().Add3DCameraController();
game.AddDirectionalLight();
game.Add3DGround();
game.AddGroundGizmo(position: new Vector3(-5, 0.1f, -5), showAxisName: true);
}
Great! Now we have an empty space with a ground plane. 🤷♂️
Next, let's add some 3D primitives, which will be wrapped in entities. Remember to assign the rootScene
to each entity, or they won’t appear in the scene.
This part of the code initializes and adds 3D primitives in the Start()
method.
var entity = game.Create3DPrimitive(PrimitiveModelType.Cone);
entity.Transform.Position = new Vector3(0, 8, 0);
entity.Scene = rootScene;
var sphere1 = game.Create3DPrimitive(PrimitiveModelType.Sphere, new()
{
Material = game.CreateMaterial(Color.Gold),
IncludeCollider = false
});
sphere1.Scene = rootScene;
var sphere2 = game.Create3DPrimitive(PrimitiveModelType.Sphere, new()
{
Material = game.CreateMaterial(Color.Orange)
});
sphere2.Transform.Position = new Vector3(-3, 5, 0);
sphere2.Scene = rootScene;
We’ve added three 3D primitives, some with colliders and some without.
Now, let's dive into keyboard interaction and motion.
The keyboard interaction is straightforward. The Update()
method is called within the game loop, and we detect player input using the Input.IsKeyDown()
and Input.IsKeyPressed()
methods to trigger actions based on the keys being pressed.
void Update(Scene scene, GameTime time)
{
var deltaTime = (float)time.Elapsed.TotalSeconds;
if (sphere1 != null)
{
if (game.Input.IsKeyDown(Keys.Z))
{
sphere1.Transform.Position -= new Vector3(movementSpeed * deltaTime, 0, 0);
}
else if (game.Input.IsKeyDown(Keys.X))
{
sphere1.Transform.Position += new Vector3(movementSpeed * deltaTime, 0, 0);
}
}
if (sphere2 != null)
{
var rigidBody = sphere2.Get<RigidbodyComponent>();
if (game.Input.IsKeyPressed(Keys.C))
{
rigidBody.ApplyImpulse(new Vector3(-force, 0, 0));
}
else if (game.Input.IsKeyPressed(Keys.V))
{
rigidBody.ApplyImpulse(new Vector3(force, 0, 0));
}
}
}
Motion Explanation
We have two types of movement: one for primitives without a collider and one for primitives with a collider.
-
Primitives Without a Collider: We move these by directly modifying their Transform.Position
. For example, sphere1
can move freely in the scene, but since it lacks a collider, it won’t interact with other entities—it will just float in the void.
-
Primitives With a Collider: Primitives with colliders must be moved using the RigidbodyComponent
. That’s why we reference the RigidbodyComponent
and apply an impulse to make the object move, simulating real-world physics.
The code is fairly self-explanatory, and I've added comments to guide you through it. I hope you've had fun exploring these features!
Step 6: Your Turn
I hope you can see that learning game development with pure C# and .NET is achievable with just a few lines of code.
Coding not only enhances creativity and problem-solving but also takes that creativity to the next level through visualization, whether it's in games, simulations, or simply experimenting with 3D models in a virtual space.
Let's see where you take it 🙂.
References
Did I catch your attention? The full, comprehensive version of this tutorial is available here: Stride Community Toolkit Preview - Code-Only Feature Basics in C#.
Alternatively, if you're interested in F#, the condensed version of this article can be found here: Stride Community Toolkit Preview - Code-Only Feature Basics in F#. Yes, you can run this in F# 👀 too!
Visual Basic, you ask? 👀 Well, technically, you can, but that's not really my cup of tea. However, if you're curious, here's a super simple example: Capsule with rigid body in Visual Basic.
Conclusion
In this article, you've learned how to get started with the Stride Community Toolkit, focusing on its code-only feature for developing game projects purely through C# and .NET. We walked through setting up a simple .NET 8 Console App, adding entities and motion to the scene, and implementing user interaction with the keyboard. By embracing this code-first approach, you've seen how powerful and flexible game development can be without relying on a graphical Game Studio.
Whether you're building games, simulations, or experimenting with 3D models, the Stride engine and its toolkit open up new possibilities for developers. Now it’s your turn to take these foundational skills and apply them to your own creative projects. Keep experimenting, keep learning, and continue pushing the boundaries of what you can create! 🚀
History
- 23/09/2024 Initial release