# Artful Coding 2 - Session Plans
## Session overview
7 x 1.5 hours input and learning sessions:
- HTML Canvas: intro , 16 March 2022
- HTML Canvas: animated and interactive , 23 March 2022
- Jumping Block in Canvas , 30 March 2022
- Live Server & Phaser init & Jumping Block in Phaser, 06 April 2022
- Website Mini Game , 27 April 2022
- Infinite Duality Jumper , 04 May 2022
- [buffer] , 11 May 2022
3 x 3.0 hours concept & work sessions
- Brainstorming game ideas and team formation , 25 May 2022, 15:00–18:00 Conference Room 11
- Concept refinement & first implementation steps , 08 June 2022, 15:00–18:00 Conference Room 11
- Implementation ctd. , project discussion , closing review , 22 June 2022, 15:00–18:00 Seminar Room 23
## Session 2 - HTML Canvas: intro
Reference documents for this session:
* W3schools Canvas Tutorial: https://www.w3schools.com/graphics/canvas_intro.asp
* MDN Canvas API docs: https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API
- including the Canvas tutorial: https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API/Tutorial
Session plan:
1. Input stage: walk through the W3schools tutorial with some side notes on the more extensive MDN tutorial
2. Workshop stage: create an HTML page with a canvas and draw the following into the canvas
- a diagonal line
- some more random lines with different widths and colors
- a full circle
- a half filled circle
- a filled hexagon of any color
- two different unfilled hexagons with different corner shapes
Task until next session:
- continue to work on the examples and experiment with them, so we can share
and discuss our filled canvases next time.
## Session 3 - HTML Canvas: animated and interactive
1. Recap stage: sharing and discussion of canvas examples from last time
2. Input stage: walk through the clock tutorial
3. Workshop stage: recreate the clock from the clock tutorial
### Exercise 1: the canvas clock
- Customize the clock created in the clock tutorial, eg.:
- make it more colorful
- add a clock ticking sound (not actually canvas related)
- add a function to stop and start the clock
- If you already work on the exercise 2 hours or longer:
- instead of finishing the exercise please just add a comment in your code,
where you stopped, what you still wanted to do and why it did not work
as expected (if time was not the only factor keeping you to finish the example)
- Submit your code in the `Exercise 1` folder in our base cloud share for this course.
To do so, create a folder with your student id and put your code in it
- Keep in mind that you get the full points also if you cannot complete it, but if
you add the comment as described above after 2 hours working on the exercise.
## Session 4 - Jumping Block in Canvas
General outline:
1. Recap from last session
2. Jumping Block part 1 - setup, update loop and block drawing
3. Jumping Block part 2 - adding controls & left/right movement
4. Jumping Block part 3 - adding jump
5. Jumping Block part 4 - adding ground, game boundaries and one obstacle
This time we will be more iterative and mix input and experimentation in
short cycles, along the 4 parts of creating our simple jumping block game
prototype.
### Part 1 - setup, update loop and block drawing
Use the scaffold folder in course's base cloud folder and add a canvas to the HTML with a width of 800px and a height of 400px.
In the `main.js` then create the following:
- a `gameState` object that can store the players x and y position, as well as a reference to the canvas and the drawing context
- a `drawPlayer` function that receives the players position and the drawing context and then draws a filled rectangle as the player (suggested width and height: 40 pixels)
- an `update` function that clears the canvas (e.g. using `clearRect()`), adds 10 pixels to the players x position and then draws the player calling the `drawPlayer` function.
- an `init` function that receives a `state` parameter and uses it to initialise the game state, draws the player for the first time and sets up an interval of 1 second, that calls the update function with the game state as an argument
In the end you will need to call the `init` function, once the document is set up. Basically you could just add a call to `init()` somewhere in the main.js file, or in a separate script in the html that is loaded at the end. A good practice though is to check whether the document has been fully loaded and only then call the init function. To do that just put the following code at the end of your main.js (actually you could put it anywhere, but the end of the file seems to be a good place):
```javascript
document.onreadystatechange = () => {
if (document.readyState === 'complete') {
init(gameState)
}
}
```
Under the following link you will find a reference solution for this part:
https://tantemalkah.at/artful-coding/2022st/session-content/session-4/part1/
### Part 2 - adding controls & left/right movement
Building on the last part we now want to add some controls to be able to move the player to the left and right. What you need to do for that is:
- add a `controls` object to your `gameState` that stores whether the left, right or up keys are currently pressed
- add a `handleKeys` function that receives an `event` and a `state` parameter and then checks whether any of the three buttons is currently pressed and sets the values in `gameState.controls` accordingly
- add the _handleKeys_ function as an event handler for the _onkeydown_ and _onkeyup_ events with the state as a second parameter. This could be done with the following code (using an arrow function so that the event handler gets access to the state object):
```javascript
window.onkeydown = (event) => { handleKeys(event, state) }
window.onkeyup = (event) => { handleKeys(event, state) }
```
- in the _update_ function instead of the code that just adds 10 pixels to the players x position you should now check if the left or right controls are true and then either add or subtract a certain amount of pixels from the players x position. Even better would be to add a separate parameter for the players x velocity in the game state. Then we can set the velocity and just before we draw the player add whatever is set in the velocity to the actual x position.
- finally you might want to speed up the interval, and instead of 1 second choose a fraction of a second, e.g. `1000/50` (which is 20 ms) to get a game/rendering speed of 50 fps.
Under the following link you will find a reference solution for this part:
https://tantemalkah.at/artful-coding/2022st/session-content/session-4/part2/
### Part 3 - adding jump
Building on the last part, we now also want to be able to jump, when the up key is pressed.
Here we have to add a y velocity to the player, because we need some form of gravity that pulls the player down, once they start jumping up. Also the player should only be allowed to jump, if they are standing on the ground. If (in the last part) you already set the controls also for the up button, now you only need to add some code to the `update` function that calculates the y velocity and the y position on the player, before the player gets redrawn.
For a very simple gravity model we could just set the y velocity e.g. to -20 when the player starts jumping. The y position then is calculated similarly to the x position just by adding the current y velocity to the y position. In order for the player to not indefinitely jump upwards, we have to reduce the upwards velocity. Or in other terms, we have to add some gravitational pull. So whenever the player is not standing on the ground, we can just add 1 to the y velocity. As soon as the player reaches the ground again, we can set the y velocity to 0 again.
Under the following link you will find a reference solution for this part:
https://tantemalkah.at/artful-coding/2022st/session-content/session-4/part3/
### Part 4 - adding ground, game boundaries and one obstacle
Wow, we can already run around and jump. This is quite nice. But for the final prototype we should also add game boundaries, so the player cannot run out of the screen. Also some visual ground would be nice. And to top all of that, one obstacle would be nice too.
So what you'll have to do is:
- add a `drawGround` function, that just draws a line (or a long and thin rectangle) below where the player is standing, and call this function in your update loop
- add some code to the update loop that checks whether the newly calculated x position is out of bounds and just set it to the most left or right position there is
- finally add a `drawObstacle` function that draws a rectangle at a certain position in a different colour than the player. This too has to be called in the update loop. Additionally we have to add some code that checks whether the player is colliding with the obstacle and in that case not let them move further to the left/right, if the obstacle would be in the way.
Under the following link you will find a reference solution for this part:
https://tantemalkah.at/artful-coding/2022st/session-content/session-4/part4/
### Exercise 2: recreate and improve the jumping block prototype
- Make sure to have a prototype of your own, with all of the above functionality. Then play around with some of the parameters. E.g.:
- try out different fps values for the update loop interval
- try out different values for the x and y velocity and the gravity calculation
- try out different canvas and object sizes
If you feel up to it, try to improve the collision handling for the obstacle, so that the player could actually land on the obstacle and move left and right from there, maybe even jump from there. Or just try to add another obstacle and add collision handling for that as well.
- Burnout-prevention shortcut (if needed): if you already work on the exercise for 2 hours or longer:
- instead of finishing the exercise add a comment in your code, where you stopped, what you still wanted to do and why it did not work as expected
- Submit your code in the `Exercise 2` folder in our base cloud share for this course. To do so, create a folder with your student id and put your code in it
- Keep in mind that you get the full points also if you cannot complete it, but if you add the comment as described above after 2 hours working on the exercise.
## Session 5 - Live Server & Phaser init & Jumping Block in Phaser
General outline:
1. Recap from last session
2. Live Server
3. Phaser init
4. Jumping Block
### Live Server
While our code so far (also in Artful Coding 1) could always be run by opening
the files directly from your hard drive with a browser, usually at some point
you might want to put your code onto a webserver. Additionally, for more complex
projects and in modern web development in general, we might want to use modules.
Modules are a neat way to structure our code into different files, and to import
only those parts, we need at a certain point in our application. The MDN Web Docs
has a guide on [JavaScript modules](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules)
that explains why modules can be very helpful, and how they work.
The important thing is, that most browsers will - for security reasons - not load
modules when you open your HTML file directly from your harddrive.
We would have to actually put the code on a web server to make it work. This would
be of course tedious to do, everytime we change and test our code. That is what
development servers are good for.
There are many different options out there. And there are also a lot of guides out
there how to do that. For example the [Getting Started with Phaser 3 Guide](https://phaser.io/tutorials/getting-started-phaser3)
talks about this right away in the intro section. If you already have a setup with
any developmen/live server, feel free to reuse this. Or try out those things mentioned
in the Phaser 3 Guide.
But if you are already using VSCode as your editor, the probably best and least
effort solution is to install the [Live Server](https://github.com/ritwickdey/vscode-live-server)
extension by Ritwick Dey.
### Phaser init
Next we will download the current stable Phaser 3 release in its minified version.
For more details on the Phaser 3 setup, follow the Getting Started guide linked
above. As a shortcut, you can go to https://phaser.io/download/stable and download
the linked _phaser.min.js_ file. Put this into the assets folder of a fresh
project (based e.g. on our scaffold).
Then just add a `<script src="assets/phaser.min.js"></script>` right before you load
your own _main.js_ file. In the _main.js_ we can work with Phaser 3. For a start
we'll follow the Getting Started with Phaser 3 guide and create the Hello World
from there.
To start we have to create a game config by adding the following:
```javascript
var config = {
type: Phaser.AUTO,
width: 800,
height: 600,
physics: {
default: 'arcade',
arcade: {
gravity: {
y: 200
}
}
},
scene: {
preload: preload,
create: create
}
};
```
Then we have to create a new instance of a game with this config:
```javascript
var game = new Phaser.Game(config);
```
Once we did this, we can use the `preload` and `create` functions
(configured as defaults for preloading and creating the first game
scene in the `config.scene` object):
```javascript
function preload () {
}
function create () {
}
```
The `preload` function is used to load all game assets that will be
used in a scene, for example images, sounds, etc. Everything that
should be available right away when we later render it in the game.
For this Hello World three images will be loaded from the Phase Labs
website. So let's put the following into our `preload` function.
```javascript
this.load.setBaseURL('http://labs.phaser.io');
this.load.image('sky', 'assets/skies/space3.png');
this.load.image('logo', 'assets/sprites/phaser3-logo.png');
this.load.image('red', 'assets/particles/red.png');
```
This does not change anything yet, it just makes sure that we can
use those images by using the strings `'sky'`, `'logo'` and `'red'`
later on in our `create` function.
To actually create some things happening on the screen we now put
the following code into the `create` function:
```javascript
this.add.image(400, 300, 'sky');
var particles = this.add.particles('red');
var emitter = particles.createEmitter({
speed: 100,
scale: { start: 1, end: 0 },
blendMode: 'ADD'
});
var logo = this.physics.add.image(400, 100, 'logo');
logo.setVelocity(100, 200);
logo.setBounce(1, 1);
logo.setCollideWorldBounds(true);
emitter.startFollow(logo);
```
You should now see a Phaser 3 logo moving around the sky,
emitting pinkish red particles.
### Jumping Block
Now that we can use the code from above as our first Phaser 3 boilerplate.
Just remove everything again from the `preload` and the `create` functions,
so that they are empty. The we will also add an `update` function similar
to the other two. And we also have to add it to our scene config, which
then should read:
```javascript
scene: {
preload: preload,
create: create,
update: update,
}
```
One more little thing you might want to do is to explicitly place the
canvas in your page, so that you can also center it.
In our course scaffold folder we could just add the canvas between the
header and footer in the index.html like this:
```html
<div class="centered">
<canvas id="game-canvas"></canvas>
</div>
```
Then in the main.js we have to add a canvas option to our game config,
telling phaser which HTML element to use as the cavas, as well as explicitly
set the render type to the canvas engine:
```javascript
type: Phaser.CANVAS,
canvas: document.getElementById('game-canvas'),
```
Now we are ready to implement our Jumping Block prototype in Phaser.
First, let's add some of the game objects in the `create` function.
As our ground, obstacle and player all are just rectangles of a
different color, we can easily add them to the scene like this:
```javascript
function create () {
// add the ground
this.add.rectangle(0,300, 800,5, 0xCCCCCC).setOrigin(0,0)
// add the player
this.add.rectangle(100,200, 40,40, 0xff00ff).setOrigin(0, 0)
// add the obstacle
this.add.rectangle(200,230, 30,70, 0x00aa00).setOrigin(0,0)
}
```
Now we already see the first static image of the scene. But it does
not do anything. Now we have to add all the movement and collission
magic to make our scene dynamic. While this was quite tedious in our
Canvas Jumping Block example last session, Phaser with its physics
model can do a lot of the tedious work for us.
Before we do that, one important thing to keep in mind: we are adding
the Game objects here by using `this`. While we just defined a simple
function, outside of any object, the function will be called from
the Scene object, as we configured it in our game config. This is
why `this` in context of the `preload`, `create`, and `update` function
always refers to the current scene. This way we can also store our
own objects (e.g. a reference to our player) on the scene, e.g.
by setting `this.player`.
Now, lets continue, by creating a group of static physics objects,
which we'll call ground. And then add our actual ground and the
obstacle to it.
```javascript
function create () {
// create a static physics object group to fill with our non-movable objects
const ground = this.physics.add.staticGroup()
// add the ground
const ground_rect = this.add.rectangle(0,300, 800,5, 0xCCCCCC).setOrigin(0,0)
ground.add(ground_rect)
// add the player
this.add.rectangle(100,200, 40,40, 0xff00ff).setOrigin(0, 0)
// add the obstacle
const obstacle1 = this.add.rectangle(200,230, 30,70, 0x00aa00).setOrigin(0,0)
ground.add(obstacle1)
}
```
So the only thing we did is to use `this.phyics.add.staticGroup()` to
create a statics physics group, store it in a `ground` variable, and
then use its `ground.add()` function to add the rectangles we have
already drawn for the ground and the obstacle.
Not that here we used `const ground`, as we will not need the ground
elsewhere later. But in case we would want to use it also in our
`update` function we should rather store it on the Scene object,
e.g. as `this.ground`. You'll see in a minute why this is important
when we create the player's dynamic physics object and the movement
controls.
For now nothing really changed. We still see the same thing as before.
Only now Phaser knows that that the ground and obstacle rectangles
are not just two simple drawings on the canvas, but actual physical
objects that will not move. So we can later do stuff with it.
But first, let's create an actual physics object for our player.
Instead of the standalone `this.add.rectangle` line for our player
we now write it like this:
```javascript
// add the player
const player_rect = this.add.rectangle(100,200, 40,40, 0xff00ff).setOrigin(0, 0)
this.player = this.physics.add.existing(player_rect)
```
So we call `this.physics.add.existing()` to create a new dynamic physics
object, as we did use `this.physics.add.staticGroup()` to create an
empty group for static physics object. A difference her ist, that
we use the group to add objects afterwards. With the `add.existing`
we can take a GameObject we already create (our player rectangle)
and make a dynamic physics object out of it. That is why we store
it as `this.player`, so we can later access it in our `update` function.
Take look. Now we will only see our player shortly, because as soon
as we load the page and the game starts, the player starts falling.
Well, because it is a dynamic physics object, and we have a physics
set with a gravity. And gravity usually pulls down objects towards
the bottom.
But, you may wonder, what do we have our ground for? This is a good
question, because this is exactly what we created our ground for,
as a static physics object group. So first of all the ground does
not fall down, because it is static and therefore not affected by
gravity. Secondly, we now want to use the ground to stop the player
falling. We can do that by telling Phaser that those two things,
our player, and our static objects group called ground, can actually
collide.
We only need to add a `collider` to the physics of our scene:
```javascript
// add a collider between ground and player
this.physics.add.collider(ground, this.player)
```
Awesome, so the player starts falling, but stops on the ground.
And this is also the reason why, in our little prototype, `ground`
was created as local variable in the `create` function, and not
stored on the scene object itself. Because all we set up, is
done in the create. Phaser then keeps track of everything. But
imagine you add some features to the game, so that another
obstacle could suddenly show up, after the player jumped over
the first obstacle. We would have to check for that in our
`update` function. Then it would be handy to have a quick reference
to the ground again.
Now, it would be nice if we could actually move the player. So
let's add some controls. Remember how tedious it was in the last
session when we had to do that manually?. The proces is somewhat
similar in Phaser, only it is soooo much less tedious.
In our `create` function we just need to create an object that
keeps track of the keys we want to use:
```javascript
// add a cursors object that keeps track of our cursor key status
this.cursors = this.input.keyboard.createCursorKeys()
```
That is all. No tedious writing of event handlers. Phaser handles
if for us. Now in our `update` function we can check whether the
left, right or up arrows are pressed and instruct the player to
move.
Let's start with left/right movement:
```javascript
function update () {
if (this.cursors.left.isDown) {
this.player.body.setVelocityX(-200)
} else if (this.cursors.right.isDown) {
this.player.body.setVelocityX(200)
} else {
this.player.body.setVelocityX(0)
}
}
```
Whenever the left button is pressed down, we set a negativ x velocity
to the player, so the player object will automatically start to move
to the left. In case left is not pressed, but right, we set a positive
x velocity, so the player moves right. And then we also need to check
if non of those two buttons is pressed, in which case the player should
stop again, so we set the velocity to 0.
Wonderful, now we can run left and right, and we can already bump into
our obstacle, which will stop as. Because we added it to the ground
objects group, which is configured to collide with the player. Remember,
how tedious the collission handling was in the last session?
But there is a problem. We can run out of the frame on the left. And we
can't even return. Well, because the ground really only goes to the
left side of the frame (x-position: 0). If you go beyond that, you'll
just fall, because there is no ground, but there is gravity all around.
Try it out, if you go left, and quickly go right again after you are
outside the frame, you will see the player falling down below the ground.
So we have to add another collission check. We coul create another
obstacle, that is just outside the visible area, and add it to the ground.
But there is an even easier way to do that. Because dynamic physics objects
have a function `setCollideWorldBounds()`, which we can call to set whether
the object collides with the visible bounds of our scene. We can do
that in the `create` function just after creating the player, by adding:
```javascript
this.player.body.setCollideWorldBounds(true)
```
Note that this function is defined on the player's body, that was added
to the rectangle after we created with `add.existing`. You might come
accross many examples where this is done directly on the player or
other physics object. We'll see examples in the next session. This
has to do with how the physics object was created. For now it is just
important to keep in mind that physics objects always have a Body
(which is its own class in the Phaser physics system), and this is
used to handle all collissions, movements, etc.: physics stuff, you
need a body for.
Ok, so, now we are only missing the capability to jump, in order to
also cross the obstacle. There is not a lot left to do now. We only
have to check whether the up key is pressed (AND if the player is
standing on the ground), and then set a negativ y velocity:
```javascript
if (this.cursors.space.isDown && this.player.body.touching.down) {
this.player.body.setVelocityY(-200)
}
```
Wow, that's it. Our game is done. And we can even land on the
obstacle and jump again from there.
Now you can also play around with the values for gravity and
velocities, to find your preferred jump height and velocity.
And why did we check for the player touching the ground?
Well, try it out and fly to get high.
If you are puzzled by what other things all of those game objects
could to, take a look at https://phaser.io/learn
There you'll find, among other things, the
[Making your first Game](https://phaser.io/tutorials/making-your-first-phaser-3-game)
guide as well as the [API Docs](https://newdocs.phaser.io/). While
the API Docs might be quite intimidating at first, they can be helpful
when you already know a few things but just can't remember how the
parameters are used, or how it is actually called. Try to go there,
and click on the [Game Objects](https://newdocs.phaser.io/docs/3.55.2/gameobjects)
section, just to get a peek at what different game objects there are.
There you already see that you could use a lot of different things
instead of our boring rectangles. Or just try to search for a term,
e.g. "body" and you will quickly get to the page for the
[Phaser.Physics.Arcade.Body](https://newdocs.phaser.io/docs/3.55.2/Phaser.Physics.Arcade.Body),
on which you can see what other properties and methods your player body has.
Under the following link you will find a reference solution for this session:
https://tantemalkah.at/artful-coding/2022st/session-content/session-5/
### Exercise 3: recreate and improve the jumping block prototype
- Make sure to have a prototype of your own, with all of the above functionality.
Then play around with some of the parameters. E.g.:
- try out different values for gravity and velocity
- try out different canvas and object sizes
Then add one or more other obstacles. If you feel playful, try to add obstacles
in way so that the player could actually jump from obstacle to obstacle until
they reach a higher ground.
- If you already worked on this exercise for 2 hours or longer:
- instead of finishing the exercise add a comment in your code,
where you stopped, what you still wanted to do and why it did not work
as expected
- Submit your code in the `Exercise 3` folder in our base cloud share for this course.
To do so, create a folder with your student id and put your code in it
- Keep in mind that you get the full points also if you cannot complete it, but if
you add the comment as described above after 2 hours working on the exercise.
## Session 6 - reflection & workshop session
This session is used to reflect on what we have done so far, and elaborate
on particular topics the participants want to know more about, or are struggling
with.
It is also used as a common working session to finish and experiment with
the recent exercises.
## Session 7 & 8 - website mini game
In these two final sessions we will recreate the mini game featured on the
[Artful Coding 2 website](https://tantemalkah.at/artful-coding/2022st).
The idea of the mini game is that the player can run around and jump to collect
the randomly distributed letters, which are contained in the the title
"Artful Coding 2". To make it a bit more interesting, the there are some
obstacles (rocks on the ground) the player has to jump over. Also the ground ends after some time walking
to the left and right. If the player falls down, they will respawn centered
above the ground again. Every letter that is collected will the be highlighted
in the pages main heading, which is initially set to 10% opacity.
To achieve this we we will use:
* a simple rectangle for the ground, as basis for a static physics group
* some images for rocks which can be added to the ground
* a spritesheet for the player and to create walking animation from
* several text objects to place collectible letters around the scene
* a function to handle collissions between the player and the letters,
which removes the letter from the scene, but highlights the letter on
the web page (as an example how the Phaser based game can interact with
just anything else on the website in which it is integrated)
### Before we start: a new setup
Previously we created the Jumping Block in Phaser simply in
one single _main.js_ file and without any sophisticated help by our
IDE. But for this session we'll create a more modern, and especially more
scalable setup. Because at some point, having everything in one
main.js file, without structuring things into different classes and
objects, will become immensely unwieldy. It will also hamper your
development progress.
Let's start by creating a new scaffold folder for Phaser games. We could
simply call it `scaffold-phaser`. In it we need:
- an `assets` folder containing:
- the `phaser.min.js`, downloaded from https://phaser.io/download/stable
- a `src` folder containing (for now):
- an empty folder `lib`
- an empty folder `types`
- an `index.html` file, containing our game canvas - more on that later
- a `style.css` that gets included by the index.html
- a `jsconfig.json` file containing the following configuration:
```json
{
"compilerOptions": {
"module": "es6",
"target": "es6"
}
}
```
This is used to tell VS Code that it should treat our code as modularized
ES6 (ECMAScript 2015) code. Combined with the Phaser type definitions we
will also add in a few minutes, VS Code then is able to provide us a lot of
help when writing code using all the different Phaser components.
The content of the _index.html_ could look something like the following:
```html
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="utf-8">
<link rel="stylesheet" href="styles.css">
<title></title>
</head>
<body>
<header class="centered">
header-content
</header>
<section class="centered">
<canvas id="game-canvas">
Your browser does not seem to support the HTML 5 Canvas element, sorry.
</canvas>
</section>
<footer class="centered">
footer-content
</footer>
<script src="assets/phaser.min.js"></script>
<script type="module" src="src/main.js"></script>
</body>
</html>
```
**Important:** note the subtle difference in loading the _main.js_ file here
vs. how we did it so far. Here we use a `type="module"` attribute in the `script`
tag, to tell the browser, that this is not just a single Javascript file
to load and execute, but a module that can use `import` statments to load stuff
from other modules and `export` to provide stuff to other modules.
The _style.css_ in this scaffold then does not contain anything other then
a rule for the `centered` class to center our header, footer and game canvas:
```css
.centered {
margin: auto;
width: fit-content;
}
```
Now, for that to work, we also need the actual `src/main.js` file, in which
we create a new Phaser game with a basic configuration:
```javascript
import Phaser from './lib/phaser.js'
// import Scene from './Scene.js'
export default new Phaser.Game({
type: Phaser.CANVAS,
width: 1000,
height: 280,
canvas: document.getElementById('game-canvas'),
// scene: [Scene],
physics: {
default: 'arcade',
arcade: {
gravity: {
y: 600,
},
//debug: true,
}
}
})
```
The only thing still missing for this to be functional is the `src/lib/phaser.js` file.
You see in the code above, that we are importing the `Phaser` class from it. But
how does that work? The only thing we have to out into the `src/lib/phaser.js` file is:
```javascript
export default window.Phaser
```
This is, because our setup now facilitates ES6 modules. But Phaser itself was just
included as an unmodularised script tag in the index.html, just before our main.js
was included as a module. So `Phaser` already exists on the `window` object, but we
want to be able to import it consistently everywhere in our modules. That is what
the `src/lib/phaser.js` does: it takes `window.Phaser` and exports it as a default.
So we can use `import Phaser from './lib/phaser.js'` in our main.js (and other modules),
to use the Phaser class.
Once this is done, the (empty) game should load, and the browser console should
tell you that Phaser (and which version of it) is loaded.
Now the only convenience thing still missing to guide us when writing code, are
the type definitions for Phaser.
These are files provided by Phaser, which help your IDE (e.g. VS Code), to
provide you with more context info when coding. They can be found in the
[`types` folder of the official Phaser repository](https://github.com/photonstorm/phaser/tree/master/types).
To use those type definitions with the [IntelliSense](https://code.visualstudio.com/docs/editor/intellisense)
feature in VS Code, we need to get the `phaser.d.ts` file from there and put it into the
`src/types` folder.
Once you have that set up, you can type `Phaser.` in your code (e.g. in the main.js)
and VS Code will provide you with a lot of things you could do with the Phaser object.
You can find a reference _scaffold-phaser_ folder, also packed into a .zip or .tgz file,
on the website in [session-content/session-6](https://tantemalkah.at/artful-coding/2022st/session-content/session-6/).
### Part 1 - Making a scene!
Now, before you change any code, create a copy from your scaffold folder, so you
can later reuse it.
In the previous Jumping Block prototype in Phaser our game config contained the
following:
```javascript
const config = {
// ...
scene: {
preload: preload,
create: create,
update: update,
}
}
```
This implicitly set up the game with a single scene, linking the `preload`,
`create` and `update` functions of that scene to the three similarly named
functions defined in the main.js.
Now we still will only need one scene, but we want to go big about that!
Also, this is already a good preparation if we want to add additional scenes.
E.g. we might want to add an intro scene for the game, or a scene for displaying
an outro, credits, or a success / game over screen.
This is why we'll modify our game config and remove the three comments that
have been set in the _src/main.js_ of the scaffold folder. It now should look
like this:
```javascript
import Phaser from './lib/phaser.js'
import Scene from './Scene.js'
export default new Phaser.Game({
type: Phaser.CANVAS,
width: 1000,
height: 280,
canvas: document.getElementById('game-canvas'),
scene: [Scene],
physics: {
default: 'arcade',
arcade: {
gravity: {
y: 600,
},
debug: true,
}
}
})
```
So our`scene` configuration is now just a list with one scene class: `[Scene]`. And
this `Scene` is loaded from the _Scene.js_ file, so we'll have to create it. Note,
that I also removed the comment in the physics config for the `debug: true`. Having
set debug to true will help a lot throughout development to see how physics objects
behave and interact. But don't forget to turn it back to false (or comment this line)
in your finished game.
But now, let's create the `src/Scene.js` file from which `Scene` gets imported:
```javascript
import Phaser from './lib/phaser.js'
export default class Scene extends Phaser.Scene {
constructor () {
super('scene')
}
init () {
}
preload () {
}
create () {
}
update () {
}
}
```
Here we create a new class `Scene` which is derived from the `Phaser.Scene` class.
So it will do everything as a regular Phaser Scene. That is why in the constructor
we also call `super('scene')` to do all the initialisations Phaser has in place for
a standard Scene.
Then we add four methods to our Scene class: init, preload, create, and update.
Check out the Phaser API docs for [Phaser.Scene](https://newdocs.phaser.io/docs/3.55.2/Phaser.Scene).
It tells us that we
> can also define the optional methods
> [init()](https://newdocs.phaser.io/docs/3.55.2/Phaser.Types.Scenes.SceneInitCallback),
> [preload()](https://newdocs.phaser.io/docs/3.55.2/Phaser.Types.Scenes.ScenePreloadCallback),
> and [create()](https://newdocs.phaser.io/docs/3.55.2/Phaser.Types.Scenes.SceneCreateCallback).
We can also see that the Phaser.Scene has only one method: [update()](https://newdocs.phaser.io/docs/3.55.2/Phaser.Scene#update).
And it also tells us:
> This method should be overridden by your own Scenes.
>
> This method is called once per game step while the scene is running.
While we already kind of know what these methods do from our previous Jumping Block example,
it is always good to have the docs ready, in case we want to be sure. Also it tells us,
that `init` will be called before `preload` and `create`, and can be used to set up everything
that can be set up before we load our assets and create our game objects.
We will use the init later to set up the letters of the title, which will be highlighted
whenever the player collects the letters in the game.
For now we'll just load some assets and create a ground. To load the assets put the
following into the `preload` function:
```javascript
preload () {
this.load.spritesheet(
'player', 'assets/character_spritesheet.png',
{ frameWidth: 125, frameHeight: 125 },
);
this.load.image('rock1', 'assets/rock_50x50.png')
this.load.image('rock2', 'assets/rock_75x50.png')
this.load.image('rock3', 'assets/rock_50x75.png')
this.load.image('rock4', 'assets/rock_75x75.png')
}
```
To be able to load those files you have to create them first. Or use the ones in
the [assets folder of the website](https://tantemalkah.at/artful-coding/2022st/assets/).
Now we can use them to create the ground and some obstacles. This is done in the
`create()` method, but we'll also add an `addRocks()` method, which handles all the
obstacle creation:
```javascript
create () {
this.ground = this.physics.add.staticGroup()
let rect = this.add.rectangle(-500,260, 1500,10, 0xffffff).setOrigin(0, 0)
this.ground.add(rect)
this.addRocks()
}
addRocks () {
this.ground.create(-700,240, 'rock2')
this.ground.create(-100,240, 'rock1')
this.ground.create(20,230, 'rock4')
this.ground.create(700,240, 'rock1')
this.ground.create(1200,230, 'rock3')
}
```
While this is functionally enough and you should see the two most central
obstacles in your game canvas, we should also add the declaration for the
ground to the class definition. Add the following to the top of the
_Scene_ class:
```javascript
/** @type {Phaser.Physics.Arcade.StaticGroup} */
ground
```
This tells the class, that it contains a property `ground`. And the comment
tells VS Code, that the type of whatever `ground` will be initialised with
(later in the the create method) is a
[Phaser.Physics.Arcade.StaticGroup](https://newdocs.phaser.io/docs/3.55.2/Phaser.Physics.Arcade.StaticGroup).
With that, whenever we use e.g. this.ground.create() or this.ground.add() in our methods,
VS Code will provide us useful context information with what the expected parameters are
and what the method does.
That's it for part 1. We have a scene, containing a ground and some obstacles.
Under the following link you will find a reference solution for this part:
https://tantemalkah.at/artful-coding/2022st/session-content/session-6/part-1/
### Part 2 - Adding a player
For this second part let's add a player to the scene.
We'll add a class member definition for the player and the cursor keys, which
will be used to control the player. So just after the definition of the `ground`
add the following:
```javascript
/** @type {Phaser.Physics.Arcade.Sprite} */
player
/** @type {Phaser.Types.Input.Keyboard.CursorKeys} */
cursors
```
Now in the `create` function, after we have created the ground, we create a
player sprite and add a collider between ground and player:
```javascript
this.player = this.physics.add.sprite(400,200, 'player')
this.player.body.setSize(35)
this.physics.add.collider(this.ground, this.player)
```
Now let's initialise our cursors and add an event handler for when the
up key or space is pressed:
```javascript
this.cursors = this.input.keyboard.createCursorKeys()
this.cursors.up.onDown = (event) => { this.jump(event) }
this.cursors.space.onDown = (event) => { this.jump(event) }
```
Of course we now also have to add a `jump` function to our class:
```javascript
jump(event) {
if (this.player.body.touching.down) {
this.player.setVelocityY(-400)
}
}
```
To add some left and right movement we will use our tried and tested
approach of checking the keys in the update function. But we'll add three
helper functions to our class first: `walkLeft`, `walkRight` and `walkStop`:
```javascript
walkLeft(event) {
this.player.setVelocityX(-200)
}
walkRight(event) {
this.player.setVelocityX(200)
}
walkStop(event) {
if (this.cursors.left.isDown || this.cursors.right.isDown) return
this.player.setVelocityX(0)
}
```
Now the update function can be quite succinct (and later we cann add controls
for the player animation in the walk functions):
```javascript
update () {
if (this.cursors.left.isDown) {
this.walkLeft()
} else if (this.cursors.right.isDown) {
this.walkRight()
} else {
this.walkStop()
}
}
```
Now we can run left and right and jump. We can also run and jump out of the
screen. But in this case the player should be able to walk further than that.
Only we would like to follow them. For that we can use the [Scene.cameras](https://newdocs.phaser.io/docs/3.55.2/Phaser.Scene#cameras)
which Phaser provides for every scene. We only have to tell the main camera
to follow the player object. The only thing we need to do for that is to
add the following to lines in our `create` function:
```javascript
this.cameras.main.startFollow(this.player)
this.cameras.main.setDeadzone(200, 100)
```
Now we can move and the camera will follow the player, if they leave the
center by a defined amount (200, 100). Check the docs of the
[setDeadzone](https://newdocs.phaser.io/docs/3.55.2/Phaser.Cameras.Scene2D.Camera#setDeadzone)
function and play around with the values if you want.
Another cool thing we can do with cameras: Zoom! While this is not needed for
the game, it might help us while developing it. E.g. to place obastacles and
later all the letters, it might be nice to see a bigger part of the scene.
So let's add a zoom function which we can use to zoom out and in, by pressing
the Shift key - but only if debug is enabled. In the `create` we'll just add
one more event handler, similar to jump:
```javascript
if (this.game.config.physics.arcade.debug) {
this.cursors.shift.onDown = (event) => { this.zoom(event) }
}
```
Of course we also need to add the `zoom` function now to our Scene class:
```javascript
zoom(event) {
if (this.cameras.main.zoomX === 1) {
this.cameras.main.setZoom(0.3, 0.3)
} else {
this.cameras.main.setZoom(1, 1)
}
}
```
What the function does is to check whether the main cameras zoom is set to 1,
and in that case set a new zoom level to 0.3 in x and y direction. Otherwise
(if it is not 1, it will be 0.3), it will be set back to 1 in x and y direction.
Now we can use the Shift key to see the whole scene. Play around with the values
in the `setZoom` function, to see how it works. And check the documentation for the
[setZoom function](https://newdocs.phaser.io/docs/3.55.0/Phaser.Cameras.Scene2D.BaseCamera#setZoom),
if you want to know more how that works.
That's it for part 2. Now we can run and jump around the scene with our player.
Under the following link you will find a reference solution for this part:
https://tantemalkah.at/artful-coding/2022st/session-content/session-6/part-2/
### Part 3 - Animating and respawning the player
For this part we will use our spritesheet to create walking animations, so
that the character will not move around like a very stiff stick figure, but
a more animated one.
For this we have to first create some animations by telling the framework
which frames from the spritesheet to use. So let's put the following code
somewhere into our `create()` function, e.g. at the beginning:
```javascript
this.anims.create({
key: 'walk-right',
frames: this.anims.generateFrameNumbers('player', {start: 1, end: 4}),
frameRate: 7,
repeat: -1,
})
this.anims.create({
key: 'walk-left',
frames: this.anims.generateFrameNumbers('player', {start: 9, end: 6}),
frameRate: 7,
repeat: -1,
})
```
To get into the details on what is happening here check out the docs for the
[create() function of the AnimationManager](https://newdocs.phaser.io/docs/3.55.2/Phaser.Animations.AnimationManager#create)
and the [Animation config object](https://newdocs.phaser.io/docs/3.54.0/Phaser.Types.Animations.Animation).
Basically we are just setting up two animation cycles that we label `walk-right`
and `walk-left`, so we can easily apply it later to some GameObject - in this
case we will want to apply it to the player. The `frameRate` is used to set
the speed of the animation, the `repeat` parameter can be used to define how
often the animation should repeat (-1 is used here to repeat infinitely), and
the `frames` just define the single images/frames in the animation. This is
an array of [AnimationFrame](https://newdocs.phaser.io/docs/3.54.0/Phaser.Types.Animations.AnimationFrame)
objects, which we could set up manually. But there are different ways to easily
create the animation frames. We just use the AnimationManager's
[generateFrameNumbers()](https://newdocs.phaser.io/docs/3.54.0/Phaser.Animations.AnimationManager#generateFrameNumbers)
function, to generate this for us, based on the `player` sprite we loaded
in our `preload()` function.
So, once this animation is set up, we can use it. And we want to start the
animation whenever the player starts to move, and stop it when the player
stops. As we have been clever before, we already have some functions to
`walkLeft`, `walkRight`, and `walkStop`. So we'll just add some lines there to
start and stop the animation. The adapted code then should look like this:
```javascript
walkLeft(event) {
this.player.setVelocityX(-200)
this.player.anims.play('walk-left', true)
}
walkRight(event) {
this.player.setVelocityX(200)
this.player.anims.play('walk-right', true)
}
walkStop(event) {
if (this.cursors.left.isDown || this.cursors.right.isDown) return
this.player.setVelocityX(0)
this.player.anims.stop()
this.player.setFrame(0)
}
```
So we just added one line with a call to the AnimationManager's `play()` function
in the functions where we start walking. And a similar line with the corresponding
`stop()` function in _walkStop()_. Additionally we use the `setFrame()` function to
reset the animation state to the standing-still image for the player.
But try to play around with it. What happens, when you remove the stop or setFrame
functions again?
And of course this is just a simple, first version of walking animation. But it
already looks so much more appealing than the stiffly unanimated stick figure
from before.
So we are almost done for this part. The only thing we'll still tackle is the case
when the player falls down. So far, you'll just keep falling down, and the game
is basically over without telling you.
In our case we want the player to just fall a little bit, and then respawn above
the platform again, so they can keep collecting the letters, which we'll add in
the next and final part.
The only thing we really need to do for this, is add a little condition in the
`update()` function that just checks if the player is below a certain point
(or in corrdinates: above a certain y value). In that case we'll just reset
the player's y postion. And we'll also reset the x position, so that they
are on the center of the platform again:
```javascript
// when player jumps off the ground, they respawn above again
if (this.player.y > 1000) {
this.player.setX(400)
this.player.setY(0)
this.player.setVelocityY(0)
}
```
You'll notice that we also set the players y velocity back to 0. Try it
out without it. And also play around with the y values. It seems a bit
smoother this way, but maybe you find even better settings.
That was it for part 3.
Under the following link you will find a reference solution for this part:
https://tantemalkah.at/artful-coding/2022st/session-content/session-6/part-3/
### Part 4 - Create collectible letters
Now for the final part of this little game prototype we want to add some
letters to the scene, which can be collected to light up corresponding
letters in the HTML page.
For that, first of all, we need some content on the HTML page. So let's put
two headings into our `<header>`, and give it an id of `title` and `subtitle`:
```html
<h1 id="title">Artful Coding</h1>
<h2 id="subtitle">Web-based games development <span id="letter-2">2</span></h2>
```
You will notice, that I put the `2` inside a `<span>` tag. This is for two
reasons: first, this should be styled differently than the rest of the heading.
Second, we need some container for the letter, that we can address with an
ID. Because as soon as the player will collect the `2` in the game, we want
to light up this letter too.
Now, the same would actually also be needed for every letter in the "Artful Coding"
title. And I could do that just here, manually, in the HTML. To put a `<span>` with
some unique ID around every letter. But this would be quite tedious, and there is
a better, procedural way to do it: with a loop in our `init()` function. We'll
get to that in a minute.
First let's also add some styling to our _styles.css_, so that the 2 (and the spanned
letters we'll add shortly) are displayed with an opacity of 10%, a centered title, and
a white font on black background:
```css
body {
background-color: black;
color: white;
}
#title, #subtitle {
text-align: center;
}
#title span,
#subtitle span {
opacity: .1;
}
```
That already looks a little more like on the artful coding web page. Now let's create
the `<span>`s for the single letters in the title:
```javascript
init () {
const elTitle = document.getElementById('title')
let titleHTML = ''
for (const l of 'Artful Coding') {
if (l === ' ') {
titleHTML += ' '
} else {
titleHTML += `<span id="letter-${l}">${l}</span>`
}
}
elTitle.innerHTML = titleHTML
}
```
Here we are just addressing our HTML element as usual. Then we create a string
`titleHTML`, which starts out empty. In a loop through every letter of "Artful Coding"
(this includes the space), we'll add something to the `titleHTML` string. If it is
the space itself, just a space should be added. But if it is a letter, we'll add
a whole span tag, with an ID of `"letter-${l}"` and the letter itself inside it.
If you are unfamiliar with this syntax to create strings with dynamic content,
check out the MDN docs on [template literals](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals).
It would be similar to add a string like this: `'<span id="' + l + '">' + l + '</span>'`.
But template literals are a really neat way to contruct strings with content from
your variables.
So once we contructed the whole string, we just set it as the `.innerHTML` of our
element. Now also the letters in the title should be displayed with 10% opacity.
Next, we have to add letters to our scene. We'll do that in our `create()` function
like everything else, and we'll need to use the [Text](https://newdocs.phaser.io/docs/3.54.0/Phaser.GameObjects.Text)
GameObject from Phaser. But as our letters will have some unique properties, and
we have a modular setup already, we'll create our own GameObject.
For that we create a separate file _Letter.js_, next to our _Scene.js_ and the
_main.js_, and put the following in it:
```javascript
import Phaser from './lib/phaser.js'
export default class Letter extends Phaser.GameObjects.Text {
/**
*
* @param {Phaser.Scene} scene
* @param {number} x
* @param {number} y
* @param {string} text
*/
constructor (scene, x, y, text) {
const r = Phaser.Math.RND.integerInRange(128, 255)
const g = Phaser.Math.RND.integerInRange(128, 255)
const b = Phaser.Math.RND.integerInRange(128, 255)
/** @type Phaser.Types.GameObjects.Text.TextStyle */
const style = {
fontFamily: 'monospace',
fontSize: '48px',
color: `rgb(${r}, ${g}, ${b})`,
}
super(scene, x, y, text, style)
}
}
```
What you see here, could also be called a _wrapper_ around the standard
Phaser.GameObject.Text. The first part of the magic lies in the definition:
`export default class Letter extends Phaser.GameObjects.Text`. This is similar to
how we set up our Scene. So we are creating a `class Letter`, which
`extends Phaser.GameObjects.Text`. This means, that Letter has all the porperties
and methods Text already has - only that we can then add or change specific things.
And then we `export default` this class, so that it can be imported in our Scene
(and potentially every other Scene).
The comment block after the definition then is not necessary functionally, but
it tells VS Code (and other tools) how to interpret the parameters of our
contructor. This is helpfull wenn we use the Letter somewhere else, because
VS Code can provide some context info as help.
The second part of the magic then is our `constructor (scene, x, y, text)`, which
will be used to construct a new _Text_ object with a specific style.
In it we use Phasers random number generate to create three random RGB colour
values. Then we create a `style` object, where we instruct the _Text_ to
use a monospace font of 48px, with our random RGB value. Then we call
the constructor of our parent class with `super(scene, x, y, text, style)`.
That is similar if we would create a new [Text](https://newdocs.phaser.io/docs/3.54.0/Phaser.GameObjects.Text)
object.
Now this _Letter_ class can be used to create _Text_ objects, without the
need to provide a `style` configuration for every letter, and with every letter
getting a random colour.
So let's use this letter in our Scene. First we need to import it in the top
of our _Scene.js_ file:
```javascript
import Letter from './Letter.js'
```
Then we will also add a property `letters` to our class definition (just after
where we also defined `ground`, `player` and `cursors`). Similar to `ground` it
will be a static physics object group:
```javascript
/** @type {Phaser.Physics.Arcade.StaticGroup} */
letters
```
In our `create()` function, just after we create the `player`, we'll add some code
to initialise the `letters` group, and tell it that it will contain objects created
from the class `Letter`. We'll also call an `addLetters` function, which should handle
our letter creation code.
```javascript
this.letters = this.physics.add.staticGroup({classType: Letter})
this.addLetters()
```
Of course we have to add the `addLetters` method now to our class (similar to `addRocks`).
In a first version let's just try to place a single letter, to see how it works:
```javascript
addLetters() {
const l = new Letter(this, 400, 50, 'A')
this.add.existing(l)
this.letters.add(l)
}
```
You should see a single letter "A" now, a bit above the player. Now, why did we have
to add it two times? Try playing around with this code and comment out on of the
two add functions and see what it does.
The `this.add.existing()` function is responsible to add a GameObject to this scene,
so that it will be displayed. Because only creating the Letter does not do a lot. The
letter afterwards will exist in the whole games Phaser universe, but is not in any
way related to the scene. The `this.letters.add()` then is used only to add the letter
also to the static physics group. This does not matter very much at the current point.
You will only see (in debug mode), that a blue border will show up around the letter.
But we need this later, because we want to check collissions / overlaps between
letters and the player.
Good, now, we have one letter in the scene. We now could continue to use these three
lines over and over again, to place all other letters. If it would be important to us,
that every letter is placed at a very specific, carefully designed position, then that
would be a good option.
Also, to get a feel for it, try out to add some other letters manually, before you
continue.
But in the end we just want to have the letters (somewhat) randomly distributed
accross the scene. So, again, we'll use a procedural way to do it, and modify the
code of the `addLetters()` function as follows (I've included lots of comments to
walk you through this process):
```javascript
addLetters() {
// first we just want to randomise the order of the letters how they
// should appear in the game
let sortedLetters = []
for (const l of 'ArtfulCoding2') { sortedLetters.push(l) }
let randomLetters = []
// for every item in our sortedLetters array we will now take out a
// random one and add it to the randomLetters array, as long as there
// is something left to take out
while (sortedLetters.length > 0) {
const index = Phaser.Math.RND.integerInRange(0, sortedLetters.length-1)
randomLetters.push(sortedLetters.splice(index, 1))
}
// now we create a slightly random first x position on the very left
// of our scene
let x = Phaser.Math.RND.integerInRange(-1000, -900)
// and for every letter we will now create an actual Letter object
// at another (slightly) randomised postion from the left of the scene
// to the right
for (const letter of randomLetters) {
// for every letter just add something between 150 and 200 pixels
x += Phaser.Math.RND.integerInRange(150, 200)
// the y should always be between 0 and 50 (a bit above the player)
const y = Phaser.Math.RND.integerInRange(0, 50)
// now use this x and y to create a new Letter object for the letter
const l = new Letter(this, x,y, letter)
// add it to the scene explicityl, so that it shows up
this.add.existing(l)
// add it to our static physics group, so we can later handle
// collisions / overlaps with the player
this.letters.add(l)
}
}
```
Now you should have a scene filled with all the letters from the title,
plus the 2. And every time you reload the scene, the letters will be arranged
differently and have different colours.
Now, still in debug mode and having built in our nice zoom function, is a good
moment to test the zoom. Press Shift to see the whole scene and the distribution
of letters. If you don't like it, play around with the values in the _addLetters_
function.
The only thing still missing now is some function that gets called whenever the
player collides - or in this case overlaps - with the letters. This function then
should handle the removal of the letter from the scene, and the highlighting of
the corresponding letter in the heading.
While we already use a collider between the player and the ground, in this case
we don't want the player to actually collide with the letters. Because the letters
should not block the players jump. Instead of using a collider and a collision handler,
we'll add an `overlap` handler, just after we called the `this.addLetters()` method
in our `create()` method:
```javascript
this.physics.add.overlap(
this.player,
this.letters,
this.collectLetter,
undefined,
this,
)
```
This defines the `player` and the `letters` group as two things Phaser should check
for overlaps. And as soon as an overlap happens the `this.collectLetter` method
should be calle (which we still have to create). The `undefined` as the fourth
parameter tells Phaser not to start a _processCallback_ function, because we
already have a _collideCallback_ function. And the fifth parameter is the
_callbackContext_, which should be our scene, so `this`. Check the docs for the Phaser Arcade
[Factory.overlap](https://newdocs.phaser.io/docs/3.55.2/Phaser.Physics.Arcade.Factory#overlap)
function, if you want to know more how that works.
Now, whenever there is an overlap (or a collission, but without blocking the players
path), the `collectLetter` method of our scene will be called. So let's add this:
```javascript
collectLetter(player, letter) {
// remove the letter from the scene and disable the its physics body
this.letters.killAndHide(letter)
this.physics.world.disableBody(letter.body)
// now apply the letters colour to the corresponding letter in the
// header, and set its opacity to 1
const element = document.getElementById('letter-'+letter.text)
element.style.color = letter.style.color
element.style.opacity = 1
}
```
The `collectLetter` method will always get two parameters, when it is called by Phasers
event handling system: the two objects that are colliding/overlapping. And as we
defined it with the player first and the letters second, when we added the `overlap`,
here we'll have the same order. In this case we just don't do anything with the
player, because we only remove the letter object from the scene, and then highlight
the correspoding letter in the heading.
So, that's it. The game is done. You can now happily collect letters.
Or refine it and add some more obstacles, create your own assets and animations,
use different texts, add sounds, or whatever else comes to your mind.
And keep in mind that you can use the zoom option with Shift, when you work on the
scene. But also keep in mind to turn `debug: false` in the game config, once you are
done and want to release the game.
Under the following link you will find a reference solution for this final part:
https://tantemalkah.at/artful-coding/2022st/session-content/session-6/part-4/
Happy hacking and happy letter collecting!
### Exercise 4: recreate and improve the letter collector prototype
- Make sure to have a prototype of your own, with all of the above functionality.
Then play around with some of the parameters. E.g.:
- try out different ways of placing the letters
- try out different or additional placements for obstacles
- create your own assets
- If you already worked on this exercise for 2 hours or longer:
- instead of finishing the exercise add a comment in your code,
where you stopped, what you still wanted to do and why it did not work
as expected
- Submit your code in the `Exercise 4` folder in our base cloud share for this course.
To do so, create a folder with your student id and put your code in it
- Keep in mind that you get the full points also if you cannot complete it, but if
you add the comment as described above after 2 hours working on the exercise.
## Session 9 - Brainstorming game ideas and team formation
> Disclaimer: this session is tailored towards 2 participants, so you would need
> more time and probably less iterations in case of a bigger class
**10min:**
We start with a short recap on what we did so far (in Artful Coding 1 & 2). The
aim of this session now is to switch away from learing and refining our coding
skills to ideation and game creation.
**5min:**
To start with, everyone familiarizes themselves with out collab board on tryeraser.com
and doodles around in the designated "Doodle Area".
**5min:**
The we start a one minute exercise: "Draw a (perfect, of course) dog!"
Afterwards we share our drawings and tell a little bit about our dog's character.
(This is mainly to loosen up and to shift our minds away from trying to be perfect)
**30min (3x(5+5)):**
Now a first ideation sequence starts, where we'll generate three different game
ideas based on the contraints we get from a game jam idea generator:
https://steven-the-gamer.itch.io/game-jam-idea-generator
With one set of contraints everyone gets 5 minutes, to create one game idea.
Then we'll share those ideas, before we create new game contraints with the
generator. This repeats until everyone created 3 different game ideas.
**10min:**
Here we'll take a first little break, which participants can also use to think
about whether they want to take up one of the game ideas to develop further,
or if they already an idea of their own which they would like to implement
within the remainder of this course.
**20min (5+15):**
Intro to this sequence, where everyone gets 15 minutes to refine one of the
game ideas. Then the 15 min counter starts in which the participants extend one
of the game ideas by describing:
- the goal of the game
- the rule(s)
- feedback mechanism(s)
- optionally:
- what is needed to implement this idea? are there any specific requirements?
**20min:**
Sharing of ideas and discussion
## Session 10 - Concept refinement & first implementation steps
This session is intended as a workshop session, where participants continue on refining
their game concepts from the last session. The focus lies on developing the concept into
a concrete description of a minimal version of the game and to outline a first approach
to implementation.
## Session 11 - Implementation ctd., project discussion, closing review
---
This page is part of the course website at https://tantemalkah.at/artful-coding/2022st
All contents, where not otherwise noted, are licensed by [Andrea Ida Malkah Klaura](https://tantemalkah.at/) under a [CC-BY-SA 4.0 license](http://creativecommons.org/licenses/by-sa/4.0/?ref=chooser-v1).