# 2.2.2 Cycle 2

## Design

### Objectives

In this development cycle my main aim is to create characters that move and interact with keyboard inputs as well as giving them collision properties to interact with the existing map from [Cycle 1](https://marling-school.gitbook.io/arthur-freebrey-project/Mj2I68ZOKe1UymCYBtl6/design-and-development/cycle-1).  I aim for the characters also to have sprites that change depending on the user input and how they respond to the movement.

* [x] Create collision properties for certain parts of the map
* [x] Create a character
* [x] Make the character move on keyboard inputs
* [x] Assign the character a sprite that interacts with movement
* [x] Allow the character to respond to the collision properties in the map

### Usability Features

### Key Variables

| Variable Name         | Use                                                                                               |
| --------------------- | ------------------------------------------------------------------------------------------------- |
| velocity(X,Y)         | The speed assigned to the player when key inputs are pressed determining how fast they move       |
| player / faune        | Variable that stores all of the information and properties about the character.                   |
| left, right, up, down | Stores the information about keyboard inputs allowing them to be assigned to player movement      |
| config                | Stores information about the game resolution, physics and other data to start the game correctly. |
|                       |                                                                                                   |

### Pseudocode

```
// create config and information about the games properties
config
    height: 1120
    width: 640
    physics: no gravity
    scene: preloader, game
end object

// initialise variables and attributes for the game
procedure create
    player = generatePlayer
    camera.follow(player)
    player.collideWorldBounds = true
    
    
    // create the variables for the keyboard input values
    left = key bind for left arrow key
    right = key bind for right arrow key
    up = key bind for arrow key
    down = key bind for down key
    
    // what the character should do upon given keyboard inputs
    if (input = up) {
        velocity.x = 0
        velocity.y = -velocity
        this.player.animations.play('up');
    
    if (input = down) {
        velocity.x = 0
        velocity.y = -velocity
        this.player.animations.play('down');
    
    if (input = left) {
        velocity.x = -velocity
        velocity.y = 0
        this.player.animations.play('left');
        
    if (input = right) {
        velocity.x = -velocity
        velocity.y = 0
        this.player.animations.play('right');
        
    // stationary    
    if (input = none) {
        velocity.x = 0
        velocity.y = 0
        this.player.animations.play('standing');
    
end procedure
```

## Development

### Outcome

Lots of the parts of the code such as the index.html file remain the same in this second cycle but most of the change will take place in the game.ts file since that contains most of the player and world attributes. I have also separated out parts of the code into their own files such as the Preloading features to make the game.ts and main.ts less crowded and easier to read.

{% tabs %}
{% tab title="Preloader.ts" %}

```typescript
import Phaser from "phaser";

export default class Preloader extends Phaser.Scene
{
    constructor()
    {
        super('preloader')
    }
// Preloading now loads sprites for the character and the JSON
// that has information on the frames to work with the animations 
    preload()
    {
        this.load.image('tiles', 'tiles/Serene_Village_16x16_extruded.png');
        this.load.tilemapTiledJSON('mainmap', 'tiles/mainmaptest.json');
        this.load.atlas('faune', 'character/faune.png', 'character/faune.json')
    } 

    create()
    {
        this.scene.start('game')
    }
}
```

{% endtab %}

{% tab title="main.ts" %}

```typescript
import Phaser, { Scale } from 'phaser'

import Preloader from './scenes/Preloader'
import Game from './scenes/game'

const config: Phaser.Types.Core.GameConfig = {
	type: Phaser.AUTO,
	width: innerWidth,
	height: innerHeight,
	physics: {
		default: 'arcade',
		arcade: {
			gravity: { y: 0 },
			// debug: true
		}
	},
	scene: [Preloader, Game],
	scale: {
		zoom: 2
	}
}

export default new Phaser.Game(config)

```

{% endtab %}

{% tab title="game.ts" %}

```typescript
(Lines 39-120)   
       House.setCollisionByProperty({ collides: true})
       Housedecor.setCollisionByProperty({ collides: true })
       Houseontop.setCollisionByProperty({ collides : true })
       Bushes.setCollisionByProperty({collides: true})
       Rocks.setCollisionByProperty({ collides: true })
       Island1.setCollisionByProperty({ collides: true })
       water.setCollisionByProperty({ collides: true})
       Island2.setCollisionByProperty({ collides: true})
       Bushes.setCollisionByProperty({ collides: true })
       Tree1.setCollisionByProperty({ collides: true })
       Tree2.setCollisionByProperty({ collides: true })
       Tree3.setCollisionByProperty({ collides: true })
       Tree4.setCollisionByProperty({ collides: true })

// Creates physics object for the character and setting the idle frame
// Also setting the property of the object and sizes for the collision border
    this.faune = this.physics.add.sprite(480, 235, 'faune', 'walk-down-3.png')
    this.faune.body.setSize(this.faune.width * 0.8, this.faune.height * 0.7)

    this.anims.create({
        key: 'faune-idle-down',
        frames: [{ key: 'faune', frame: 'walk-down-3.png'}]
    })

    this.anims.create({
        key: 'faune-idle-up',
        frames: [{ key: 'faune', frame: 'walk-up-3.png'}]
    })

    this.anims.create({
        key: 'faune-idle-side',
        frames: [{ key: 'faune', frame: 'walk-side-3.png'}]
    })
    

    this.anims.create({ 
        key: 'faune-run-down',
        frames: this.anims.generateFrameNames('faune', {start: 1.0, end: 8.0, prefix: 'run-down-', suffix: '.png'}),
        repeat: -1,
        frameRate: 15

    })

    this.anims.create({ 
        key: 'faune-run-up',
        frames: this.anims.generateFrameNames('faune', {start: 1.0, end: 8.0, prefix: 'run-up-', suffix: '.png'}),
        repeat: -1,
        frameRate: 15

    })

    this.anims.create({ 
        key: 'faune-run-side',
        frames: this.anims.generateFrameNames('faune', {start: 1.0, end: 8.0, prefix: 'run-side-', suffix: '.png'}),
        repeat: -1,
        frameRate: 15

    })

//Adding colliders to the layers neccersary
    this.faune.anims.play('faune-idle-down')
    this.physics.add.collider(this.faune, Island1)
    this.physics.add.collider(this.faune, Rocks)
    this.physics.add.collider(this.faune, Island2)
    this.physics.add.collider(this.faune, water)
    this.physics.add.collider(this.faune, House)
    this.physics.add.collider(this.faune, Housedecor)
    this.physics.add.collider(this.faune, Tree1)
    this.physics.add.collider(this.faune, Tree2)
    this.physics.add.collider(this.faune, Tree3)
    this.physics.add.collider(this.faune, Tree4)
    this.physics.add.collider(this.faune, Houseontop)

    this.cameras.main.startFollow(this.faune, true,)
    this.cameras.main.setBounds(-436, -200.5, 1833, 887, true)
    // this.cameras.main.centerOn(innerWidth, innerHeight)

    }
    
//Updates every frame to check for whether any keys are being pressed and 
//if they are update with the corresponding animation defined earlier
    update(t: number, dt: number){
        if (!this.cursors || !this.faune)
        {
            return
        }
        const speed = 100;
        if (this.cursors.left?.isDown)
        {
            this.faune.anims.play('faune-run-side', true)
            this.faune.setVelocity(-speed, 0)
            this.faune.scaleX = -1
            this.faune.body.offset.x = 12
        }
        else if (this.cursors.right?.isDown)
        {
            this.faune.anims.play('faune-run-side', true)
            this.faune.setVelocity(speed, 0)
            this.faune.scaleX = 1
            this.faune.body.offset.x = 4

        }
        else if (this.cursors.up?.isDown) {
            this.faune.anims.play('faune-run-up', true)
            this.faune.setVelocity(0, -speed)
        }

        else if (this.cursors.down?.isDown) {
            
            this.faune.anims.play('faune-run-down', true)
            this.faune.setVelocity(0, speed)
        }
        else
        {
            const parts = this.faune.anims.currentAnim.key.split('-')
            parts[1] = 'idle'
            this.faune.anims.play(parts.join('-'))
            this.faune.setVelocity(0, 0)
        }

    }
}

```

{% endtab %}
{% endtabs %}

### Challenges

Throughout this development cycle I faced many challenges since I now had to work with new aspects such as player inputs as well as responding collision to the character. Problems arose when trying to create these aspects of the game due to some outdated functions and documentation regarding the phaser library. An example of this I found was the way layers with collisions in Phaser used to be initialised by **`createStaticLayer.map('name', tileset)`**&#x20;

However my solution to this old outdated function was to instead initialise the layers as their own independent variables by writing **`const name = map.createLayer('name', tileset)`**. This also was useful later on when trying to group different layers that needed collision together for more readable code. \
\
Another problem I had with this development cycle was trying to get the camera to follow the camera but then not go outside the boundaries I had set. For some reason the game boundaries were not being set to the pixel measurements I had provided so having to find a workaround for this was quite difficult.

## Testing

Evidence for testing

### Tests

<table><thead><tr><th width="150">Test</th><th width="156">Instructions</th><th width="150">What I expect</th><th width="168">What actually happens</th><th>Pass/Fail</th></tr></thead><tbody><tr><td>1</td><td>Run code</td><td>Character should appear on screen on top of the map</td><td>Character texture not loaded with texture frame missing</td><td>Fail</td></tr><tr><td>2</td><td>Press keys / WASD</td><td>The player should respond by moving around the screen in the given direction</td><td>As expected</td><td>Pass</td></tr><tr><td>3</td><td>Press arrow keys</td><td>Characters sprite to change to a different corresponding animation</td><td>Character's sprite was half cut off implying the amount the sprite needs to change was too much or too little</td><td>Fail</td></tr><tr><td>4</td><td>Move character into an object with collision properties</td><td>Character to stop moving and not get past the object or wall</td><td>As expected</td><td>Pass</td></tr></tbody></table>

After this I went back to work out why the sprite issues weren't working and was due to the increments of how the image sprite stages were going up, to fix this I changed them from decimal increments to integer stages.

{% code title="game.ts" %}

```typescript
   //Changing the border to size to feel more responsive 
    this.faune = this.physics.add.sprite(480, 235, 'faune', 'walk-down-3.png')
    this.faune.body.setSize(this.faune.width * 0.5, this.faune.height * 0.7)

    this.anims.create({
        key: 'faune-idle-down',
        frames: [{ key: 'faune', frame: 'walk-down-3.png'}]
    })

    this.anims.create({
        key: 'faune-idle-up',
        frames: [{ key: 'faune', frame: 'walk-up-3.png'}]
    })

    this.anims.create({
        key: 'faune-idle-side',
        frames: [{ key: 'faune', frame: 'walk-side-3.png'}]
    })
    

// Changing the animations to go up in integers that correspond with the correct frames of the animation
    this.anims.create({ 
        key: 'faune-run-down',
        frames: this.anims.generateFrameNames('faune', {start: 1, end: 8, prefix: 'run-down-', suffix: '.png'}),
        repeat: -1,
        frameRate: 15

    })

    this.anims.create({ 
        key: 'faune-run-up',
        frames: this.anims.generateFrameNames('faune', {start: 1, end: 8, prefix: 'run-up-', suffix: '.png'}),
        repeat: -1,
        frameRate: 15

    })

    this.anims.create({ 
        key: 'faune-run-side',
        frames: this.anims.generateFrameNames('faune', {start: 1, end: 8, prefix: 'run-side-', suffix: '.png'}),
        repeat: -1,
        frameRate: 15

    })
    

    update(t: number, dt: number){
        if (!this.cursors || !this.faune)
        {
            return
        }
        const speed = 100;
        if (this.cursors.left?.isDown)
        {
            this.faune.anims.play('faune-run-side', true)
            this.faune.setVelocity(-speed, 0)
            this.faune.scaleX = -1
            this.faune.body.offset.x = 24
        }
        else if (this.cursors.right?.isDown)
        {
            this.faune.anims.play('faune-run-side', true)
            this.faune.setVelocity(speed, 0)
            this.faune.scaleX = 1
            this.faune.body.offset.x = 8

        }
        else if (this.cursors.up?.isDown) {
            this.faune.anims.play('faune-run-up', true)
            this.faune.setVelocity(0, -speed)
        }

        else if (this.cursors.down?.isDown) {
            
            this.faune.anims.play('faune-run-down', true)
            this.faune.setVelocity(0, speed)
        }
        else
        {
            const parts = this.faune.anims.currentAnim.key.split('-')
            parts[1] = 'idle'
            this.faune.anims.play(parts.join('-'))
            this.faune.setVelocity(0, 0)
        }

    }
}

```

{% endcode %}

### Tests

<table><thead><tr><th width="150">Test</th><th width="156">Instructions</th><th width="150">What I expect</th><th width="168">What actually happens</th><th>Pass/Fail</th></tr></thead><tbody><tr><td>1</td><td>Run code</td><td>Character should appear on screen on top of the map</td><td>As expected</td><td>Pass</td></tr><tr><td>2</td><td>Press keys / WASD</td><td>The player should respond by moving around the screen in the given direction</td><td>As expected</td><td>Pass</td></tr><tr><td>3</td><td>Press arrow keys</td><td>Characters sprite to change to a different corresponding animation</td><td>As expected</td><td>Pass</td></tr><tr><td>4</td><td>Move character into an object with collision properties</td><td>Character to stop moving and not get past the object or wall</td><td>As expected</td><td>Pass</td></tr></tbody></table>

{% embed url="<https://youtu.be/i8In5QcQUnI>" %}

Here is a video of me demonstrating working character movements on a map made for testing and demonstrating working collisions too through debugging the player hitbox to make it more visual.
