350 views
# Artful Coding 2 - Session Plans (2023 ST edition) ## Session overview 6 input and learning sessions: - HTML Canvas: intro - HTML Canvas: animated and interactive - Jumping Block in Canvas - Live Server & Phaser init & Jumping Block in Phaser - Website Mini Game 7 concept & work sessions: - Mid-term reflection & workshop session - Brainstorming game ideas and team formation - Concept refinement & first implementation steps - Implementation & project discussion 1 closing session ## Grading Grade points breakdown: - 20 pts for attendance: - 1 pt for every session - additional 5 points, if attended 10 or more sessions - 40 pts for exercises in first part of semester: - 10pts x 4 exercises along the 7 input and learnign sessions - 40 pts for final project: - 20 pts for the game concept - 20 pts for the implementation of a prototype Your final grade then will be based on the total points you got in the course: * 80-100 points: 1 * 70-80 points: 2 * 60-70 points: 3 * 50-60 points: 4 * 0-50 points: 5 ## 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 2.1. a diagonal line 2.2. some more random lines with different widths and colours 2.3. a full circle 2.4. a half filled circle 2.5. a filled hexagon of any colour 2.6. 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 [W3schools canvas clock tutorial](https://www.w3schools.com/graphics/canvas_clock.asp) 3. Workshop stage: recreate the clock from the clock tutorial ### Exercise 1: the canvas clock - Customise the clock created in the clock tutorial, e.g.: - make it more colourful - 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. **Deadline:** Hand in this assignment until Sun, April 2nd 2023 23:42 to get the full points - or ask for an extension beforehand. Late submission (if not asked for an extension beforehand) will only get you half the points. ## Session 4 - HTML Jumping Block General outline: 1. Short note on session rescheduling (updates schedule is on the web page) 2. Recap from last session 3. Jumping Block part 1 - setup, update loop and block drawing 4. Jumping Block part 2 - adding controls & left/right movement 5. Jumping Block part 3 - adding jump 6. 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 & 7 - 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/2023st). 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 sprite sheet for the player and to create walking animation from * several text objects to place collectable letters around the scene * a function to handle collisions 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. The specific approach here is inspired by the [Infinite Jumper in Phaser 3 with Modern JavaScript](https://ourcade.co/books/infinite-jumper-phaser3/) tutorial book from _ourcade_. 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 modularised 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/). Generally the code structure of the website mini game follows the one suggested in the [Infinite Jumper in Phaser 3 with Modern JavaScript](https://ourcade.co/books/infinite-jumper-phaser3) by [ourcade](https://ourcade.co). ### 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 can 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 collision, 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 corresponding 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 8 - Brainstorming game ideas **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 learning and refining our coding skills to ideation and game creation. **5min:** 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) **45min (3x(5+10)):** 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. **30min:** 15 min refinement of one of the three ideas into a very rough concept (or creation of a new game concept), then sharing ideas and exchanging thoughts. ## Session 9/10/11 - Concept refinement, prototyping & first implementation steps These sessions are intended as workshop sessions, where participants continue on refining their game concepts and start to build first prototypes. 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. --- This page is part of the course website at https://tantemalkah.at/artful-coding 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).