Rust Web Assembly - Building a Canvas Snake Game using Stdweb - Part 2
Repository
https://github.com/rust-lang/rust
What Will I Learn?
- You will learn how to use RefCells
- You will learn about RCs or reference-counting pointer
- You will learn how to attach a Keyboard listener to a Rust WASM project
- You will learn about how you can access libraries that exist in JavaScript from Rust
- You will learn how to simulate animation using redraws and screen wipes
- You will learn how to simulate a snake game in Rust WASM with HTML Canvas
Requirements
System Requirements:
- Visual Studio Code or any other Text Editor with Rust language plugins
- The Rustup command line tool and the nightly Rust compiler
Required Knowledge
- Some understanding of JavaScript and Node.Js
- Some basic understanding of Rust
- A fair amount of knowledge on web technologies and how they work
Resources for Rust
- Rust Website: https://www.rust-lang.org/
- Web Assembly Website: https://webassembly.org/
- Awesome Rust: https://github.com/rust-unofficial/awesome-rust
- Wasm Bindgen Repo: https://github.com/rustwasm/wasm-bindgen
Sources
- WASM Logo: https://webassembly.org/
Difficulty
- Intermediate
Description
Outline and Overview
In this Web Assembly Rust Video Tutorial, we finish the snake game HTML canvas project by creating the game logic for our game and then wiring up the various modules. We make use of multiple different concepts inside of this project, including the js!
macro, the RefCell
type, and the RC
type. We also make use of JavaScript native Math functions to generate the random coordinates for the Apple and the Snake head. Finally, we combine all of our modules to make a functioning snake game.
Accessing JavaScript functions from Rust
We've seen in past, that Rust's WASM interface gives us the ability to directly call and access various JavaScript functions in our Rust code. In this example we show how we can also access functions that are not directly a part of the core JavaScript namespace. This includes Functions and Objects that are not only a part of the JavaScript built in core but also libraries imported from other third party sources.
In this project, we make use of the js!
macro from the stdweb
library to directly call on the Math.floor
and Math.random
functions to allow us to generate the positional coordinates for the different components in our game. We use it to randomize the initial position of our snake head as well as generate randomly positioned apples each time the snake eats an apple. Since JavaScript is not typed by default, we have to use the try_into
method to attempt to cast these values into Rust types so that we can use them in our program.
Using RefCells and RCs to Deal with State Mutation
JavaScript does not have immutable variables by default and it also doesn't make use of pointers and references. This is in contrast to Rust which uses all of these concepts. The way that we can rectify this difference in design principles is by using wrapped types like the RefCell
and the RC
. An RC
is a reference counted pointer or a pointer that allows multiple variables to reference the same data. A RefCell
on the other hand is basically a single-threaded Mutex which allows multiple variables to borrow and mutate our data.
In this project, we wrap the main snake data inside of both the RC
and RefCell
types. This is done so that we can pass the snake data from our main function into the game loop and the event listener closure without worrying about the ownership of the structure. We are able to access this Snake data by using specialized methods like borrow
and borrow_mut
and this helps keep the state changes consistent across the application.
Creating Animation with Screen Wipes and Redraws
The core way that we create the HTML canvas animation for our snake in this project is by using a timeout period. This timeout period allows us to define the frequency by which we clear the entire canvas screen and then re-render the snake and apple. By doing this with a fairly small number, the snake looks as though it is moving and growing in size in response to quick actions such as keyboard presses and game events.
The snake moves in a relatively fluid motion across the canvas. Every 100ms however, the screen is completely cleared and redrawn with the new positions of the snake's head, snake's tail and the food. When the snake eats the food, the head of the snake is replaced with a new head that is one position in front of the original head which makes it look as though the snake has grown one tile even though the snake stops moving when it eats the apple. The same is true for when the snake turns in response to the user's input.
The source code for this project can be found here
Video Tutorial
Related Videos
Curriculum
- Intro to Rust Web Assembly with Rust's Wasm Bindgen Library
- Rust Web Assembly - Building a Simple Markdown Parser with Rust's Wasm Bindgen
- Rust Web Assembly - Using Stdweb to Build a Client side Application with Rust and WASM
@tensor you were flagged by a worthless gang of trolls, so, I gave you an upvote to counteract it! Enjoy!!
Thank you for that. It is annoying that these small bots keep downvoting me for no apparent reason.
Great work @tensor. Very fine tutorial series. I am sure a learner could start at the beginning to this and be controlling the snake at the end.
Your contribution has been evaluated according to Utopian policies and guidelines, as well as a predefined set of questions pertaining to the category.
To view those questions and the relevant answers related to your post, click here.
Need help? Write a ticket on https://support.utopian.io/.
Chat with us on Discord.
[utopian-moderator]
Hey @tensor
Thanks for contributing on Utopian.
We’re already looking forward to your next contribution!
Want to chat? Join us on Discord https://discord.gg/h52nFrV.
Vote for Utopian Witness!
@tensor, Are you a program developer