ggez Tutorial
Lesson 0 - Setting up ggez
Let's set up a project that uses ggez and does nothing more than displaying a blank window.
Declare the dependency
Create a new project with cargo new hello-ggez
.
Add ggez to Cargo.toml
:
[dependencies]
ggez = "0.6.0-rc1"
We need to use the release candidate because the latest stable version (0.5.1) doesn't work with the latest Rust .
Run cargo build
.
What to expect
The first build will take a few minutes because there are a few dependencies, and they all have dependencies of their own and so on. All these need to be built. Subsequent builds will be faster.
The target
directory of your project
will be about 3.0G in size if you build for both
debug and release. The binary will be about 127M for debug
and about 9.5M for release (5.2M if you strip
it,
and some further optimizations might be possible),
but it is self-contained and you don't need to distribute
any dependencies along with it.
Basic Game Structure
A typical game loop goes like this:
- handle input events (from keyboard, mouse, joystick...)
- update the internal game state (position of the hero, monster, ball, ...)
- render the new state of the game to the screen
For the game state, define a struct
.
It may be empty for now; we'll add fields as needed.
struct MyGame {}
From ggez's side, we'll need a Context
, which is
an object that provides access to the hardware: video for
displaying the game, audio for playing sounds, keyboard
for input and so on. A Context
can be obtained
from a ContextBuilder
.
To make a ContextBuilder
you'll need a game ID.
This will be used for the name of a directory in
~/.local/share
on the player's computer, where
game resources can be stored
(see the filesystem
module).
You also need to provide a name for the game's author,
but that's not used for GNU/Linux.
use ggez::ContextBuilder;
fn main() {
let (ctx, event_loop) = ContextBuilder::new("game_id", "author")
.build()
.expect("Could not create ggez context!");
}
To use your game state struct in the game loop,
implement the EventHandler
trait. Two methods are required: update()
and draw()
.
You'll notice they both take a Context
as an input parameter.
In the update()
method we don't do anything for now,
since all we want to do is to display a window and we don't
care about any events.
In the draw()
method, let's clear()
the window to the white color,
and then call present()
to send its contents to the screen.
use ggez::event::EventHandler;
use ggez::graphics;
use ggez::{Context, GameResult};
impl EventHandler for MyGame {
fn update(&mut self, _ctx: &mut Context) -> GameResult<()> {
Ok(())
}
fn draw(&mut self, ctx: &mut Context) -> GameResult<()> {
graphics::clear(ctx, graphics::Color::WHITE);
graphics::present(ctx)
}
}
Finally, to link your EventHandler
-enabled
game state with the ggez Context
,
let's call event::run()
.
use ggez::event;
fn main() {
// --snip--
event::run(ctx, event_loop, my_game)
}
Putting It All Together
This is how everything looks in the end:
use ggez::event::{self, EventHandler};
use ggez::graphics;
use ggez::{Context, ContextBuilder, GameResult};
fn main() {
let (ctx, event_loop) = ContextBuilder::new("game_id", "author")
.build()
.expect("Could not create ggez context!");
let my_game = MyGame {};
event::run(ctx, event_loop, my_game)
}
struct MyGame {}
impl EventHandler for MyGame {
fn update(&mut self, _ctx: &mut Context) -> GameResult<()> {
Ok(())
}
fn draw(&mut self, ctx: &mut Context) -> GameResult<()> {
graphics::clear(ctx, graphics::Color::WHITE);
graphics::present(ctx)
}
}
Run this with cargo run
and a white window
should appear on the screen.