First, you'll need to make sure your development environment is set up properly. There's three things that need to be installed on your machine in order to successfully compile a Tetra project:
- The latest stable version of Rust
- The SDL2 development libraries
- The ALSA development libraries (only required on Linux)
There's instructions on how to set these up on the 'Installation' page, so make sure you've followed through those steps before continuing!
With that out of the way, we're now ready to get started on our first game! Open a terminal and run the following command to create a new Cargo project:
Next, add Tetra as a dependency in the newly-generated
If you're developing on Windows, make sure you've dropped the SDL libraries into your
pong folder, as described in the installation guide. Your game won't build or run without them!
You will also need to distribute
SDL2.dll with your game if you send it to someone else.
Finally, let's add the imports we're going to use in this chapter to
With that, we're ready to start developing our game! Let's take a closer look at one of the types you just imported.
Context is a struct that holds all of the 'global' state managed by the framework, such as window settings and connections to the graphics/audio/input hardware. Any function in Tetra's API that requires access to this state will take a reference to a
Context as the first parameter, so you won't get very far without one!
To build our game's
Context, we can use the descriptively-named
This creates a
Context that is configured to display a window with the title 'Pong', sized at 640 by 480 pixels, which will automatically close when the player presses the escape key.
To see what other options can be set on a
Context, and what the default settings are, take a look at the API documentation for
cargo run your project from the command line now, you may be confused, as nothing will appear to happen. This is because we're not actually starting a game loop yet -
main just returns straight away after the
Context is created!
To fix this, we'll need to implement
State is a trait exposed by Tetra, which is implemented for the type that stores your game's state. It exposes various methods that will be called during the game loop, and you can override these in order to define your game's behaviour.
This trait fulfils a similar purpose to the
Game base class in XNA, or the
ApplicationListener interface in LibGDX.
For now, we don't need to store data or override any of the default behaviour, so we can just use an empty struct and implementation:
Now that we have a
State, we're ready to start the game loop! To do this, call the
run method on
Context, passing in a closure that constructs your
There's a few things you should pay attention to here:
- The return type of
mainhas been changed to
?operator has been added to the end of
- There is no semi-colon after
run, so its output will be returned from
build will return an error if the context fails to be constructed, and
run will return any errors you throw during the game loop. By using the
? operator, we can propagate these errors up and out of
main. Rust will then automatically print out the error message to the terminal, which is handy when debugging.
main is nice for prototyping, but doesn't give you much control over how the error gets reported. If you want to customize this, you can always
match on the result of
You may also notice that the closure takes a parameter, which we're currently ignoring - we'll look at what that's for next chapter.
If you run
cargo run from your terminal now, you should finally see a window appear!
Our goal for this chapter was to set up our project, and we've done that! A black window isn't very interesting, though, so let's finish by changing the background color to something a bit more inspiring.
To do this, we'll implement one of the
State trait methods.
draw is called by Tetra whenever it is time for the engine to draw a new frame. We can call
tetra::graphics::clear inside this method to clear the window to a plain color:
draw (like all other methods on the
State trait) returns a
tetra::Result. If an error is returned from one of these methods, the game loop will stop, and the error will be sent back to
main (via the return value of
Context::run) for you to handle.
cargo run one more time, the window should open again, but this time with a nicer background color!
In this chapter, we set up a new Tetra project, and got a window to appear on the screen. Next, we'll start drawing some graphics and handling some input!
Here's the code from this chapter in full: