Your First Game
This tutorial will guide you through creating your first game with the Popcorning Guinea Pig engine. We'll build a simple "Hello World" game that demonstrates the core concepts and gets you familiar with the engine's structure.
What We're Building
We'll create a simple game that:
- Shows a splash screen with the engine logo
- Transitions to a main menu
- Displays a "Hello World" message when you click a button
- Demonstrates basic UI components and scene management
Step 1: Create a New Project
Using Visual Studio
Create a new Console Application
- File → New → Project
- Select "Console App (.NET)"
- Name:
MyFirstGame - Framework: .NET 10.0
Add Engine Reference
<!-- Add to your .csproj file --> <ProjectReference Include="..\..\src\PopcorningGuineaPig.Engine\PopcorningGuineaPig.Engine.csproj" />
Using Command Line
# Create new project
dotnet new console -n MyFirstGame
cd MyFirstGame
# Add reference to the engine
dotnet add reference ../path/to/PopcorningGuineaPig.Engine/PopcorningGuineaPig.Engine.csproj
Step 2: Basic Game Structure
Replace the contents of Program.cs:
using PopcorningGuineaPig.Engine;
using PopcorningGuineaPig.Engine.Scenes;
namespace MyFirstGame
{
class Program
{
static void Main(string[] args)
{
var game = new MyGame();
game.Init(800, 600, 60, "My First Game");
game.RunGame();
}
}
}
Step 3: Create Your Game Class
Create a new file MyGame.cs:
using PopcorningGuineaPig.Engine;
using PopcorningGuineaPig.Engine.Scenes;
using PopcorningGuineaPig.Engine.Services;
namespace MyFirstGame
{
public class MyGame : Game
{
private SceneManager sceneManager;
private ISoundPlayer soundPlayer;
private ISettingsService settingsService;
public override void Load()
{
// Initialize services
soundPlayer = new SoundPlayer();
settingsService = new SettingsService();
// Initialize scene manager
sceneManager = new SceneManager();
// Start with splash screen
var splashScene = new SplashScene(sceneManager);
sceneManager.ChangeScene(splashScene);
}
public override void Update(double deltaTime)
{
sceneManager.Update(deltaTime);
}
public override void Render()
{
sceneManager.Render();
}
protected override void CleanupResources()
{
soundPlayer?.Dispose();
sceneManager?.UnloadAllScenes();
}
}
}
Step 4: Create a Splash Screen Scene
Create SplashScene.cs:
using System;
using PopcorningGuineaPig.Engine.Scenes;
using PopcorningGuineaPig.Engine.UI;
using Raylib_cs;
namespace MyFirstGame
{
public class SplashScene : Scene
{
private SceneManager sceneManager;
private Label titleLabel;
private Label subtitleLabel;
private double displayTimer;
private const double DISPLAY_TIME = 3.0; // 3 seconds
public SplashScene(SceneManager sceneManager)
{
this.sceneManager = sceneManager;
}
public override void Load()
{
// Create title label
titleLabel = new Label(
text: "My First Game",
position: new System.Numerics.Vector2(400, 250),
fontSize: 48,
color: Color.WHITE
);
// Create subtitle label
subtitleLabel = new Label(
text: "Built with Popcorning Guinea Pig Engine",
position: new System.Numerics.Vector2(400, 320),
fontSize: 24,
color: Color.LIGHTGRAY
);
displayTimer = 0.0;
}
public override void Update(double deltaTime)
{
displayTimer += deltaTime;
// Transition to main menu after display time
if (displayTimer >= DISPLAY_TIME)
{
var mainMenuScene = new MainMenuScene(sceneManager);
sceneManager.ChangeScene(mainMenuScene);
}
}
public override void Render(int width, int height)
{
// Clear background
Raylib.ClearBackground(Color.DARKBLUE);
// Draw labels
titleLabel.Draw();
subtitleLabel.Draw();
}
public override void Unload()
{
titleLabel?.Dispose();
subtitleLabel?.Dispose();
}
}
}
Step 5: Create a Main Menu Scene
Create MainMenuScene.cs:
using System;
using PopcorningGuineaPig.Engine.Scenes;
using PopcorningGuineaPig.Engine.UI;
using Raylib_cs;
using System.Numerics;
namespace MyFirstGame
{
public class MainMenuScene : Scene
{
private SceneManager sceneManager;
private Label titleLabel;
private Button playButton;
private Button exitButton;
private Label messageLabel;
private bool showMessage = false;
public MainMenuScene(SceneManager sceneManager)
{
this.sceneManager = sceneManager;
}
public override void Load()
{
// Create title
titleLabel = new Label(
text: "Main Menu",
position: new Vector2(400, 150),
fontSize: 36,
color: Color.WHITE
);
// Create play button
playButton = new Button(
position: new Vector2(350, 250),
size: new Vector2(100, 40),
text: "Say Hello"
);
playButton.SetOnClick(() => {
showMessage = true;
});
// Create exit button
exitButton = new Button(
position: new Vector2(350, 320),
size: new Vector2(100, 40),
text: "Exit"
);
exitButton.SetOnClick(() => {
Environment.Exit(0);
});
// Create message label (initially hidden)
messageLabel = new Label(
text: "Hello, World! Welcome to game development with Popcorning Guinea Pig!",
position: new Vector2(400, 400),
fontSize: 20,
color: Color.YELLOW
);
}
public override void Update(double deltaTime)
{
playButton.Update();
exitButton.Update();
}
public override void Render(int width, int height)
{
// Clear background
Raylib.ClearBackground(Color.DARKGREEN);
// Draw UI elements
titleLabel.Draw();
playButton.Draw();
exitButton.Draw();
// Show message if button was clicked
if (showMessage)
{
messageLabel.Draw();
}
// Draw instructions
Raylib.DrawText("Click 'Say Hello' to see a message!", 10, height - 30, 16, Color.WHITE);
}
public override void Unload()
{
titleLabel?.Dispose();
messageLabel?.Dispose();
}
}
}
Step 6: Build and Run
From Command Line
dotnet build
dotnet run
From Visual Studio
- Press F5 or click "Start Debugging"
- The game window should open
What You Should See
- Splash Screen: A blue screen showing "My First Game" for 3 seconds
- Main Menu: A green screen with two buttons
- Interaction: Clicking "Say Hello" displays a welcome message
- Exit: Clicking "Exit" closes the game
Understanding the Code
Game Class Structure
public class MyGame : Game
{
// Services and managers
private SceneManager sceneManager;
private ISoundPlayer soundPlayer;
// Lifecycle methods
public override void Load() // Initialize resources
public override void Update() // Update game state
public override void Render() // Draw everything
}
Scene Lifecycle
Each scene follows this pattern:
public override void Load() // Setup UI, load assets
public override void Update() // Handle input, update state
public override void Render() // Draw scene content
public override void Unload() // Clean up resources
UI Components
The engine provides several UI components:
- Label: Text display
- Button: Clickable buttons with hover states
- Panel: Background containers
- Slider: Value selection
- Dropdown: Option selection
Next Steps
Now that you have a working game, try these enhancements:
Add Sound Effects
// In your scene Load() method
await soundPlayer.PlayMenuClick(); // When button is clicked
Add More UI Components
// Add a slider for volume control
var volumeSlider = new Slider(
position: new Vector2(300, 200),
size: new Vector2(200, 20),
minValue: 0,
maxValue: 100,
initialValue: 50
);
volumeSlider.SetOnValueChanged(value => {
// Handle volume change
});
Create More Scenes
- Settings scene with options
- Game scene with actual gameplay
- Pause menu overlay
Add Settings Management
// Load and apply settings
var settings = settingsService.LoadSettings("settings.json");
settingsService.ApplySettings(settings, this);
Common Patterns
Scene Transitions
// Immediate transition
sceneManager.ChangeSceneImmediate(newScene);
// Delayed transition (with fade effect)
sceneManager.ChangeScene(newScene, transitionTime: 1.0f);
Resource Management
public override void Unload()
{
// Always dispose of resources
label?.Dispose();
texture?.Dispose();
}
Event Handling
button.SetOnClick(() => {
// Handle button click
});
slider.SetOnValueChanged(value => {
// Handle value change
});
Troubleshooting
Common Issues
"Could not load file or assembly"
- Check that the engine project reference is correct
- Ensure both projects target the same .NET version
Black screen on startup
- Verify that
Load()method is being called - Check that scenes are being properly initialized
UI not responding
- Ensure
Update()is being called on UI components - Verify event handlers are properly set
Graphics not appearing
- Check that
Render()draws in the correct order - Verify screen coordinates are within viewport
Best Practices
- Resource Management: Always dispose of resources in
Unload() - Scene Organization: Keep scenes focused on specific functionality
- Service Usage: Use dependency injection for services
- Error Handling: Wrap file operations in try-catch blocks
- Performance: Update only what's necessary in
Update()method
Further Reading
- Core Concepts - Deep dive into engine architecture
- UI System - Complete UI component reference
- Services - Audio, settings, and platform services
- Examples - More complex example projects
Congratulations! You've successfully created your first game with the Popcorning Guinea Pig engine. This foundation will serve as the starting point for more complex games and applications.