Pong with Cheerp
Let’s create a new C++ file
pong.cpp as follows:
webMain represents the main entry point of the compiled application. Since WebAssembly cannot manipulate the DOM directly, we are instructing Cheerp to compile
[[cheerp::genericjs]] attribute tag. To compile this file to WebAssembly, this simple command will suffice:
pong.js) and a WebAssembly binary (
All we need to run this Hello World is a simple HTML page:
You now need to start a local HTTP server in the directory containing pong.html, pong.js and pong.wasm. Node’s
http-server -p 8081 command work well, but any server will do.
Visit your page, for example “http://127.0.0.1:8081” with any browser, and you should see something like this:
Great! We can now move on to build an Hello World that writes on the Canvas.
Hello World (Canvas)
Let’s have a look a this example:
We have created a new
Graphics class and tagged it using the
Compile this new code like we did before and refresh the browser tab, you should now see something like this:
Drawing on the Canvas
Let’s get started on our game. We will now focus on drawing the paddle.
For this, we will create a
Platform object, which will be the only controllable entity in the game. The object will be moved to the left and to the right using the keyboard and will be rendered as white box on a black background.
Let’s create a new class for the Platform. We will not use the [[cheerp::genericjs]] attribute on this class so that all it’s code will be compiled in WebAssembly.
The class has some basic properties and a render function which then delegates the actual rendering to the
Graphics class since on the WebAssembly side we don’t have access to the DOM. Let’s add the drawRect function to the Graphics class:
We now need an instance of the Platform object, let’s put it in the global scope for convenience, and also add a top level function
mainLoop to handle the main loop of the application. This function will clear the background and then render the platform:
Lastly, we need to add a handler for drawing an animation in our
Graphics class. The browser will call the handler in sync with the display refresh rate, which generally is at 60 fps.
We then need to call the handler one first time in
Let’s recompile, and the result should look like this:
Animation and Keyboard events
We now need to be able to move the platform around. We will add a
keydown event handler for this purpose. Since it’s a DOM interaction, this code will be tagged as
genericjs, but it will update the values of the
Platform object which is compiled to WebAssembly.
Let’s add two new methods to
as well as a keyDown event handler to the Graphics class which lives in
Notice that we are using
fmax instead of the usual
std::max. In general, standard library (STL) functions are compiled to Wasm. We can use STL functions from the JS code but there are restrictions. One of these dictates that Wasm functions that have pointers or references to basic types are not available in the JS-annotated part of the code. Indeed,
std::max get references to basic types while
std::fmax get their inputs by copy. Another solution would have been to wrap
std::max in non-JS-annotated functions that take
ints by copy. This limitation will hopefully disappear at some point in the future.
Let’s also register an
You should now be able to move the paddle around like this:
We’ll now focus on the ball. We will create a
Ball class, including a basic physical model of position and velocity. We will keep this class in WebAssembly, so no need for a
Ball class has methods to update its position, check for collisions and for rendering.
To visualize our ball on screen we need to implement
And, as with
Platform, instantiate a
Ball object in the global scope.
We will now expand the
mainLoop method to call them in sequence.
Ball::collide also checks if the ball has gone past the bottom of the screen, which is our losing condition, and
mainLoop is going to report that by drawing some text.
And that should be it! The game should look like this: