In this tutorial, we will create a simple version of the "Doodle Jump" game using the SplashKit SDK in C#. This game features a player character that jumps between platforms, avoids enemies, and collects power-ups while aiming for a high score.
Created by Thai Ha NGUYEN, Deakin University.
Game Objective: The player controls a character that jumps between platforms, collects power-ups, and avoids falling off the screen. The goal is to achieve the highest score possible.
- Game Structure: Understanding how game components interact.
- Classes and Inheritance: Using object-oriented programming to create reusable game object classes.
- Collision Detection: Implementing methods to check for interactions between objects.
- Game Loop: Managing the continuous flow of the game.
- User Input: Handling keyboard input to control the player character.
- C# Knowledge: Basic understanding of C# programming.
- Game Development Concepts: Familiarity with game loops, classes, and object-oriented programming.
- SplashKit SDK: Ensure you have the SplashKit SDK installed and set up in your C# development environment. Visit the SplashKit website for installation instructions.
-
Install Visual Studio:
- Download and install Visual Studio. Choose the Community edition, which is free.
-
Install SplashKit SDK:
- Download the SplashKit SDK from SplashKit's website.
- Follow the installation instructions specific to your operating system.
-
Create a New Project:
- Open Visual Studio and create a new Console Application project.
- Name your project (e.g.,
DoodleJump).
-
Add SplashKit Reference:
- Right-click on the project in Solution Explorer and select "Manage NuGet Packages."
- Search for
SplashKitand install it.
We will create multiple classes to represent the various objects in the game.
This is the base class for all game objects. It handles the common properties and behaviors of game entities.
using SplashKitSDK;
public abstract class GameObject
{
protected Sprite _sprite; // The sprite representing this game object
// Constructor to load the bitmap and initialize the sprite
public GameObject(string bitmapName, string bitmapFile)
{
SplashKit.LoadBitmap(bitmapName, bitmapFile);
_sprite = new Sprite(bitmapName, bitmapFile);
}
// Draw the sprite on the screen
public virtual void Draw()
{
_sprite.Draw();
}
// Update method to be overridden in derived classes
public virtual void Update() { }
// Check for collision with another game object
public virtual bool CollidesWith(GameObject other)
{
return SplashKit.SpriteCollision(this._sprite, other._sprite);
}
// Properties for accessing the sprite's position and dimensions
public float X
{
get { return _sprite.X; }
set { _sprite.X = value; }
}
public float Y
{
get { return _sprite.Y; }
set { _sprite.Y = value; }
}
public int Width => _sprite.Width;
public int Height => _sprite.Height;
}- Sprite: Represents the visual element of the game object. We load a bitmap image that will be displayed on the screen.
- Collision Detection: The
CollidesWithmethod uses the SplashKit functionality to check if this game object collides with another.
This class inherits from GameObject and manages the player's actions, including movement and jumping.
public class Player : GameObject
{
private const float Gravity = 0.5f; // The force of gravity affecting the player
public const float JumpStrength = -15f; // The strength of the player's jump
private float _yVelocity; // The current vertical velocity of the player
// Constructor initializes the player position and sprite
public Player() : base("doodle", "kangaroo.png")
{
X = DoodleJumpGame.WindowWidth / 2; // Start in the middle of the screen
Y = DoodleJumpGame.WindowHeight / 2; // Start at the center vertically
_yVelocity = 0; // Initial vertical velocity
}
// Apply gravity to the player
public void ApplyGravity()
{
_yVelocity += Gravity; // Increase vertical velocity
Y += _yVelocity; // Update position based on velocity
}
// Jump method to give the player an upward velocity
public void Jump(float strength = JumpStrength)
{
_yVelocity = strength; // Set the upward velocity
}
// Move the player to the left
public void MoveLeft()
{
X -= 5; // Move 5 units left
}
// Move the player to the right
public void MoveRight()
{
X += 5; // Move 5 units right
}
// Check if the player is falling
public bool IsFalling => _yVelocity > 0;
// Update the player position and handle screen boundaries
public override void Update()
{
if (X < 0) X = 0; // Prevent moving off the left edge
if (X > DoodleJumpGame.WindowWidth - Width) X = DoodleJumpGame.WindowWidth - Width; // Prevent moving off the right edge
}
// Check if the player has fallen off the screen
public bool IsOffScreen()
{
return Y > DoodleJumpGame.WindowHeight; // Check if the Y position exceeds the window height
}
}- Gravity: The
ApplyGravitymethod simulates the downward force affecting the player, increasing their downward velocity over time. - Movement: The
MoveLeftandMoveRightmethods allow the player to move horizontally across the screen. - Jumping: The
Jumpmethod sets an upward velocity to simulate jumping.
This class represents the platforms the player can jump on.
public class Platform : GameObject
{
// Constructor initializes the platform's position
public Platform(float x, float y) : base("platform", "platform.png")
{
X = x;
Y = y;
}
// Check if the player can bounce off this platform
public bool CanBounce(Player player)
{
return player.Y < Y && player.CollidesWith(this) && player.IsFalling;
}
// Update the platform's position
public override void Update()
{
if (Y > DoodleJumpGame.WindowHeight) // If the platform goes off-screen
{
X = SplashKit.Rnd(DoodleJumpGame.WindowWidth - Width); // Randomize the X position
Y = -Height; // Reset to the top of the screen
}
}
}- Bounce Detection: The
CanBouncemethod checks if the player is falling onto the platform, allowing them to bounce off. - Platform Reset: The
Updatemethod randomizes the position of the platform when it moves off-screen, creating a continuous gameplay experience.
Represents the enemies in the game.
public class Enemy : GameObject
{
// Constructor initializes the enemy's position
public Enemy(float x, float y) : base("enemy", "enemy.png")
{
X = x;
Y = y;
}
// Update the enemy's position
public override void Update()
{
if (Y > DoodleJumpGame.WindowHeight) // If the enemy goes off-screen
{
X = SplashKit.Rnd(DoodleJumpGame.WindowWidth - Width); // Randomize the X position
Y = -Height; // Reset to the top of the screen
}
}
}- Similar to the
Platformclass, theEnemyclass resets its position when it moves off-screen, allowing for a continuous challenge for the player.
Represents power-ups that boost the player's jump strength.
public class PowerUp : GameObject
{
// Constructor initializes the power-up's position
public PowerUp(float x, float y) : base("spring", "spring.png")
{
X = x;
Y = y;
}
// Apply the power-up to the player
public void ApplyPowerUp(Player player)
{
player.Jump(Player.JumpStrength * 2); // Boost the player's jump strength
}
// Update the power-up's position
public override void Update()
{
if (Y > DoodleJumpGame.WindowHeight) // If the power-up goes off-screen
{
X = SplashKit.Rnd(DoodleJumpGame.WindowWidth - Width); // Randomize the X position
Y = -Height; // Reset to the top of the screen
}
}
}- The
ApplyPowerUpmethod doubles the jump strength of the player when they collect the power-up, providing an advantage during gameplay.
This class manages the game loop, updates, and rendering. It also initializes game objects and handles game state.
public class DoodleJumpGame
{
public const int WindowWidth = 400; // Width of the game window
public const int WindowHeight = 600; // Height of the game window
private Player _player; // Player instance
private List<Platform> _platforms; // List of platforms
private List<Enemy> _enemies; // List of enemies
private List<PowerUp> _powerUps; // List of power-ups
private float _viewOffset; // Offset for scrolling
private int _score; // Player's score
private bool _game
Over; // Game over flag
public DoodleJumpGame()
{
SplashKit.OpenWindow("Doodle Jump", WindowWidth, WindowHeight);
_player = new Player();
_platforms = new List<Platform>();
_enemies = new List<Enemy>();
_powerUps = new List<PowerUp>();
InitializePlatforms(); // Create initial platforms
InitializeEnemies(); // Create initial enemies
InitializePowerUps(); // Create initial power-ups
}
private void InitializePlatforms()
{
for (int i = 0; i < 10; i++) // Create 10 platforms
{
float x = SplashKit.Rnd(WindowWidth - 100); // Random X position
float y = SplashKit.Rnd(WindowHeight - 100); // Random Y position
_platforms.Add(new Platform(x, y)); // Add platform to the list
}
}
private void InitializeEnemies()
{
for (int i = 0; i < 5; i++) // Create 5 enemies
{
float x = SplashKit.Rnd(WindowWidth - 50); // Random X position
float y = SplashKit.Rnd(WindowHeight - 200); // Random Y position
_enemies.Add(new Enemy(x, y)); // Add enemy to the list
}
}
private void InitializePowerUps()
{
for (int i = 0; i < 3; i++) // Create 3 power-ups
{
float x = SplashKit.Rnd(WindowWidth - 50); // Random X position
float y = SplashKit.Rnd(WindowHeight - 200); // Random Y position
_powerUps.Add(new PowerUp(x, y)); // Add power-up to the list
}
}
public void Run()
{
while (!SplashKit.WindowCloseRequested("Doodle Jump")) // Game loop
{
SplashKit.ProcessEvents(); // Handle user input
Update(); // Update game state
Draw(); // Render game objects
SplashKit.RefreshScreen(60); // Refresh the screen at 60 FPS
}
}
private void Update()
{
if (_gameOver) return; // If the game is over, skip updates
_player.ApplyGravity(); // Apply gravity to the player
// Handle user input for movement and jumping
if (SplashKit.KeyDown(KeyCode.LeftKey)) _player.MoveLeft();
if (SplashKit.KeyDown(KeyCode.RightKey)) _player.MoveRight();
if (SplashKit.KeyDown(KeyCode.Space)) _player.Jump();
foreach (var platform in _platforms)
{
if (platform.CanBounce(_player)) // Check if the player can bounce
{
_player.Jump();
}
}
// Check for collisions with enemies
foreach (var enemy in _enemies)
{
if (enemy.CollidesWith(_player))
{
GameOver(); // End the game if the player collides with an enemy
}
}
// Check for collisions with power-ups
foreach (var powerUp in _powerUps)
{
if (powerUp.CollidesWith(_player))
{
powerUp.ApplyPowerUp(_player); // Apply the power-up effect
// Remove power-up after collection
_powerUps.Remove(powerUp);
break; // Exit loop to avoid modifying the list while iterating
}
}
// Update all game objects
foreach (var platform in _platforms) platform.Update();
foreach (var enemy in _enemies) enemy.Update();
foreach (var powerUp in _powerUps) powerUp.Update();
// Check if the player has fallen off the screen
if (_player.IsOffScreen())
{
GameOver(); // End the game if the player falls
}
}
private void Draw()
{
SplashKit.ClearScreen(); // Clear the screen
// Draw all game objects
_player.Draw();
foreach (var platform in _platforms) platform.Draw();
foreach (var enemy in _enemies) enemy.Draw();
foreach (var powerUp in _powerUps) powerUp.Draw();
// Draw the score
SplashKit.DrawText("Score: " + _score, Color.White, 10, 10); // Display the score
}
private void GameOver()
{
_gameOver = true; // Set game over flag
SplashKit.DrawText("Game Over!", Color.Red, WindowWidth / 2 - 50, WindowHeight / 2); // Display game over message
SplashKit.DrawText("Press R to Restart", Color.White, WindowWidth / 2 - 75, WindowHeight / 2 + 30); // Display restart message
}
private void Restart()
{
// Reset game state
_player = new Player();
_platforms.Clear();
_enemies.Clear();
_powerUps.Clear();
InitializePlatforms();
InitializeEnemies();
InitializePowerUps();
_score = 0;
_gameOver = false;
}
}- Game Initialization: The constructor initializes the game window and creates instances of the player, platforms, enemies, and power-ups.
- Game Loop: The
Runmethod contains the main game loop that processes events, updates game states, and draws objects. - Updating Game State: The
Updatemethod manages player movement, gravity, collision detection, and handles game logic such as scoring and game-over conditions. - Drawing Game Objects: The
Drawmethod clears the screen and renders all game objects along with the score. - Game Over Logic: The
GameOvermethod displays the game over message and handles the restart logic.
The Main method starts the game.
public static class Program
{
public static void Main()
{
DoodleJumpGame game = new DoodleJumpGame(); // Create an instance of the game
game.Run();
}
}-
Build the Project:
- Click on "Build" in the menu and select "Build Solution."
-
Run the Game:
- Press
Ctrl + F5or select "Start Without Debugging" to run the game.
- Press
- Scoring System: Implement a scoring system that increases as the player jumps on platforms or collects power-ups.
- Levels and Progression: Create different levels with varying difficulty, platforms, enemies, and power-ups.
- Sound Effects: Add sound effects for jumping, collecting power-ups, and game over.
You've created a simple version of Doodle Jump using C# and SplashKit. You can expand on this base by adding more features and polishing the gameplay. Enjoy coding and have fun!
