Prototyping – Week 2 Testing and Reflection

This week, I finished my prototype to a playable standard, and had five people test it. Quite a few of the tasks I did this week were originally planned to be extensions, and I am pleased that I managed to move on to them. Each day I completed the tasks I had assigned myself to, some I even completed a day earlier which allowed me to get ahead on other aspects of the project:

  • (05/10) – Finish the interaction, element assumption and game over features.
  • (06/10) – Bush bonus object, level file reader.
  • (07/10) – Second level design and implementation.
  • (08/10) – Testing the game and a last minute bug fix on the second level.

Before I started testing on Thursday 08/11/18, I wrote out some objectives that I wanted to achieve through testing:

  • To see if players are capable of solving the puzzles without hints.
  • To discover if players quickly understand the core mechanics of the game and how to use them.
  • To find out if players find the game frustrating in any ways.
  • To check if the controls feel natural or if they need adjusting.

From these testing aims, I derived a key set of questions that I wanted to ask of my five testers:

  1. Did you complete both levels? If not, why?
  2. If you had to sum up the core of the game, what would you say?
  3. Were the mechanics new and engaging or had you seen it before?
  4. How easy were the controls to pick up? Would an entire game with these controls be frustrating or manageable?
  5. Was the game fun? Why?
  6. Were any parts of the game frustrating? If so, how could they be improved?
  7. Any final comments?

I had an interesting range of feedback from my testers, with some varying opinions. For example, everyone agreed the control scheme was fairly easy to pickup, but two found using elements challenging and thought hit boxes should be bigger. All the testers got a good sense of what the game was about from the prototype levels, and no one had seen environment interaction puzzles combined with controlling more than one character.

The main point that was echoed throughout was that the game would benefit greatly from some form of tutorial or a dialogue box that popped up to explain the controls to the player before the game began. I agree with this sentiment, as I had to explain the controls every time a new tester sat down, as they are not quite standard WASD.

In conclusion, I found this week beneficial to extending my project beyond what I had originally thought was feasible, which allowed me to gain better feedback from my testers as they had more to play through and compare.

Prototyping – Week 1 Reflective Journal

During this week of the prototyping project, I completed all the tasks that I had assigned to myself for this week. These were:

  • (30/10) To create a basic level design on paper and a production plan.
  • (30/10) To create basic shapes to represent the Tyler and Mike characters that meant it was easy to identify which character was which.
  • (31/10) To implement the mechanic that allows you to switch between each character.
  • (01/11) To get Mike’s movement working as he had a smaller range of movement.
  • (02/11) As Tyler’s movement was more complex involving a jetpack-style jump motion I gave myself an extra day to do it.
  • (04/11) Write up the production diary for the week and write a reflective journal.

 

I used Asana to organise myself during this project. It is an online team organisation service, and I have used it in the past for both long and short-term projects. It has a board format that I used to create tasks, and then assign them deadlines to give myself a timeline.

 

I decided to do my initial designs for the level on paper, to allow myself to create a few iterations of the design quickly. After deciding on the final layout, I created a 10×10 grid on the page to make a tile accurate level design to be used when creating my tile and collision maps later. I created two main level ideas, labelled 1 and 2, for which I created a series of steps that the player might follow to solve the level’s puzzle. This was so that I could ensure it was fairly easy to follow how to solve the puzzle, as if it was unsolvable, the game would not be fun.

I struggled a little with the jetpack jump initially, however, I decided to implement all of my movement differently, allowing the jetpack to feel smoother and cohesive with how the player moves side to side. The switch character mechanic was surprisingly easy to implement, and gave me extra time to work on other aspects of the project on the day it was assigned. I used a string which would be checked if it read “Tyler” or “Mike” when key press checks were being performed and other character-dependent actions.

Overall, I have made good progress on the project this past week, and I am happy with what I have achieved so far in the time. I believe I could have assigned more tasks to the first week, however I did fall ill at one point and lost time there, so it worked out that I had given myself less tasks as I had less time than originally anticipated.

 

Wireframes for Mech Builders

Mech Builders is puzzle game where you unlock mech parts to build a fighting robot with which to crush your enemies! At the start of the game, you are shown the power level and stats of the mech you will be battling against, before being taken to a puzzle select screen. If you are successful in beating the puzzle you gain a new part to use for your mech. However, you can choose to try a harder version of the same puzzle to have a chance of receiving an upgraded part. If you opt to do so, and fail to complete the puzzle, then you will lose the part you chose to risk.

Once you have completed all the possible levels for the mech match, the two mechs will fight each other until one of them falls apart and loses. To progress in the game you have to build bigger and better mechs, defeating powerful foes along your way to dominance.

My initial sketches

I initially designed my wireframes on paper, so I could get my first ideas down to be iterated upon. Then, I moved into Axure to create digital wireframes of each of the five screens.

Title Screen

The first screen I created was the title screen. I kept all the key buttons the player would need in the centre of the screen. By surrounding those buttons with cogs on either side and an image of a selection of mechs in the game at the bottom, I can draw the eye into the middle of the screen, making the menu options easy to find.

Enemy Mech Stats

Once the player has opted to start a new level, they are shown the stats of the enemy that they are going to be attempting to defeat. They can view this screen any time from the pause menu, so that players do not need to memorise a lot of information as they play. On the left, there will be an image of the mech in its signature pose, ready for battle. The same image will be used later in the mech comparison screen, to give the game consistency. On the right, there will be a slowly rotating model of the mech, giving the player a 360 view of what the mech looks like. I put the challenge them button at the bottom of the screen to encourage the player to at least skim-read the enemy stats before starting the level.

Puzzle Selection

After the player has hit challenge them on the enemy mech stats screen, they will be taken to the pick a puzzle screen. The exact number of puzzles that the players will be able to choose from is currently unknown, however it could change based on how far through the game the player is. When they are facing more challenging mechs, they will have less puzzles to choose from so they have to be more careful when it comes to risking components.

Each image for a puzzle will give a vague hint as to the type of puzzle it is, as well as what component you are likely to get from completing the puzzle. I gave the player the option of viewing their mech and the enemy mech at the bottom of the screen so that they have a better understanding of which parts they still need to collect or if they have one of each part, which ones they should try another puzzle for to get a better version.

Use It or Risk It

This screen is shown to the player each time they successfully complete a puzzle. On the left, the enemy mech is shown to keep the layout consistent, as in other comparison screens the enemy is also shown to the left. Players have the option to either read a detailed description of each components with their strengths and weaknesses, or they can quickly glance at the overall component ratings given underneath the picture of each part. I made the use it and risk it buttons bold and large on the screen, to draw the player’s attention to the decision that they have to make before they can continue.

Mech Comparison

The mech comparison screen is shown to the player right before the mechs go head to head in battle. It gives a detailed description of each mech, as well as a bar chart which gives a direct comparison of specific key stats that will show which way the battle may swing. The placeholder on the left is the same posed image of the enemy mech that the player is shown on the enemy mech stats screen. The placeholder on the right serves a similar function for the player created mech, except the pose is generated based on the overall rating of the mech so that weak mechs will pose in ways that makes them look delicate whereas high-tier mechs will pose like a stereo-typical wrestler.

 

I found working out a basic layout idea on paper was beneficial to my overall designs as it allowed me to get my initial ideas out to be refined further. This is useful particularly if you want to iterate upon your sketches before moving onto the wireframing stage. Wireframes are useful as they allow you to see how the game will flow between screens and identify how large different elements have to be on the screen to make them usable.

From this wireframing project, I have learnt how to use Axure to create pixel accurate wireframes. I have also spent time considering how layouts can change based on platforms, as well as how much information you can fit on a single screen based on the size of that screen.

Reflection on Car Project

You can find this project here

For the past week, we have been working in pairs to create a simple car mini-game using Javascript. Initially, we programmed in movement functions and a cross-hair pattern before moving on to more advanced features.

The first change we made was creating a car object, to make the code easier to read and to clean up the code base. As we added new features to the game, such as collision detection, we needed to add more properties and methods to the object. The second feature we implemented was quadrant detection, where different sections of the canvas would change colour when you entered them, along with changing the image of the car. While Zoe cleaned up the image, I began creating the basic if statements for the quadrant detection before we came back together to tackle the rest of the code work together.


function get_car_quadrant() {
    context.beginPath();
    context.fillStyle = "#58c8a9";      //colour of border
    if (car.x < canvas.width / 2) {
        if (car.y > canvas.height / 2) {
            //bottom left           
            context.fillRect(0, canvas.height / 2, canvas.width / 2, canvas.height);     //create a filled rectangle
        } else {
            //top left
            context.fillRect(0, 0, canvas.width / 2, canvas.height / 2);
        }
    } else {
        if (car.y > canvas.height / 2) {
            //bottom right
            context.fillRect(canvas.width / 2, canvas.height / 2, canvas.width, canvas.height);
        } else {
            //top right
            context.fillRect(canvas.width / 2, 0, canvas.width, canvas.height / 2);
        }
    }
    context.closePath();
}



This worked by checking if the car was in various quadrants using if statements comparing the x and y values to the width and height properties of the canvas. We then created filled rectangles the size of the quadrants to make it appear as if they lit up when the car was in them.

The next feature we added was acceleration and deceleration. When you press the same key more than once in a row, the car will speed up. If you change keys, the car will move off at a slower pace. We didn’t get the car to slow to a stop, but we are otherwise happy with our use of basic acceleration and deceleration.

In the car object, we stored the following properties:

  • x and y co-ordinates as well as x & y speed (dx, dy)
  • speed and angle of travel
  • width and height of car
  • 4 flags for if the car is at the edges of the canvas
  • the co-ordinates of the corners of the car in a two-dimensional array.

We also gave the car object two methods:

  • corner update that calculates the current position of the car’s four corners
  • detect collision which resets the collision flags before detecting if the car is at the edge of the canvas on any side.

    corner_update: function () {
        car.corners[0] = [car.x, car.y];
        car.corners[1] = [car.x + car.width, car.y];
        car.corners[2] = [car.x, car.y + car.height];
        car.corners[3] = [car.x + car.width, car.y + car.height];
    },
    detect_collision: function () {
        this.blocked_left = this.blocked_right = this.blocked_up = this.blocked_down = false;
        var corner = [];
        for (i = 0; i < 4; i++) {
            corner = this.corners[i];
            if (corner[0] <= 50) { //left side this.blocked_left = true; } else if (corner[0] >= canvas.width) {
                this.blocked_right = true;
            }
            if (corner[1] <= 50) { this.blocked_up = true; } else if (corner[1] >= canvas.height) {
                this.blocked_down = true;
            }
        }
    }

These methods were the last code sections we added to the game, as the collision detection was the last feature we added. We decided on corner based collision detection, as we felt it was the most accurate method of keeping the car from going off the edge of the map. By creating methods rather than functions, we kept relevant code inside of car object, making our code easier to understand.

From this project, I have learnt how to use corner-based collision detection, as well as how to implement more advanced movement methods involving angles. I enjoyed working with Zoe, and we successfully split the workload as well as bouncing ideas off of each other.

Reflection on Snake Game

You can find this project here

During the snake game project, I have used a few programming techniques introduced in the bouncing ball animation as well as some new ones. Here is a list of the new techniques shown during this project:

  • Methods of objects
  • helper vs control functions
  • taking key press inputs
  • taking touchscreen inputs

When creating an object, it can have properties and methods. Properties are values and methods are functions of the object. These can be called using ObjectName.Property or ObjectName.Method() and are useful for encapsulating values.

function create_snake() {
    var new_snek = {
        colour: generate_hex(),
        x: grid * 2,
        y: grid * 2,
        dx: grid,
        dy: 0,
        cells: [],
        max_cells: 4,
        move_left: function () {
            if (this.dx === 0) {
                this.dx = - grid;
                this.dy = 0;
            }
        },
        move_right: function () {
            if (this.dx === 0) {
                snake.dx = grid;
                snake.dy = 0;
            }
        },
        move_up: function () {
            if (this.dy === 0) {
                snake.dy = -grid;
                snake.dx = 0;
            }
        },
        move_down: function () {
            if (this.dy === 0) {
                snake.dy = grid;
                snake.dx = 0;
            }
        }

    }
    return new_snek
}

In this function, I create and return an object called new_snek. It has the properties:

  • colour – stores the randomly generated colour of the snake. This is used to draw the snake in the same colour every time the position of the snake is updated on-screen.
  • x – stores the current x co-ordinate of the snake’s head.
  • y – stores the current y co-ordinate of the snake’s head.
  • dx – stores if the snake is moving along the x axis and if it is moving in a positive or negative direction.
  • dy – stores if the snake is moving along the y axis and if it is moving in a positive or negative direction.
  • cells – is an array that holds information about each segment of the snake’s body. Each time the snake consumes an apple, a new cell is added to the array.
  • max_cells – stores the maximum number of cells the snake can have. When the snake reaches this point, each time it eats an apple it loses a cell to keep it’s size consistent.

To allow my snakes and apples to have random colours, I directly copied my generate_hex function from the bouncing ball animation. I chose to have random snake colours as I felt it would be easier for players to determined that they died and are starting over once more with a new snake. I made the apples random colours to keep things visually interesting.

The object new_snek also has the following methods:

  • move_left
  • move_right
  • move_up
  • move_down

These methods allow you to directly move the snake object in 4 different directions as long as you weren’t previously moving along the same axis. These are called by event listeners that are detecting arrow/WASD key presses or touch inputs.

function add_listeners() {
    var start_x, start_y, distance_x, distance_y;

    document.addEventListener("keydown", function (e) {
        //left (A) 65 | right (D) 68 | up (W) 87 | down (S) 83
        if (e.keyCode == 65 || e.keyCode == 37) {
            snake.move_left();
        } else if (e.keyCode == 68 || e.keyCode == 39) {
            snake.move_right();
        } else if (e.keyCode == 87 || e.keyCode == 38) {
            snake.move_up();
        } else if (e.keyCode == 83 || e.keyCode == 40) {
            snake.move_down();
        }
    })
    document.addEventListener("touchstart", function (e) {
        var touch = e.changedTouches[0];
        start_x = Math.round(touch.clientX);
        start_y = Math.round(touch.clientY);
        e.preventDefault();
    }, { passive: false });
    document.addEventListener("touchmove", function (e) {

        e.preventDefault();
    }, { passive: false });
    document.addEventListener("touchend", function (e) {
        var touch = e.changedTouches[0];
        distance_x = Math.round(touch.clientX) - start_x;
        distance_y = Math.round(touch.clientY) - start_y;
        if (Math.abs(distance_x) > Math.abs(distance_y)) {
            if (distance_x > 0) {
                snake.move_right();
            } else if (distance_x < 0) {
                snake.move_left();
            }
        } else {
            if (distance_y > 0) {
                snake.move_down();
            } else if (distance_y < 0) {
                snake.move_up();
            }
        }
        e.preventDefault();
    }, { passive: false });
}

I use the OR || operator to allow the user to control the snake using WASD or the arrow keys at any time depending on their personal preference. This gave my game additional flexibility as some players would default to WASD while others find the arrow keys easier to use.

By calculating the distance between the beginning and end of a touch event, I can determine which direction the player swiped in. This allows me to then call the appropriate move property of the snake using nested if statements.

The key techniques that I learnt during this project were how to detect key presses and touch input. I can use these in future web-based game projects to ensure that the game is playable across multiple platforms. I found creating objects without using a class an unusual experience, as the way I learnt OOP was using a stricter language where to create an object you had to have created a class.

Reflection on Ball Animation

You can find this project here

Since the beginning of the 2D development toolkit unit, I have encountered programming techniques both familiar and new. Some of the programming techniques I used during this project were:

  • overlap detection
  • drawing API
  • basic 2D physics
  • random number generation
  • random colour generation
  • event listeners
  • recursion
  • objects

In the past, I have used a lot of random number generation as well as recursion to create game loops and random encounters. I found the random colour generation a logical step up from generating random numbers.


function generate_hex() {       //generates a random hexadecimal colour value and returns it
    var str = "0123456789ABCDEF";
    var random_int = 0;
    var result = "#";
    //loops to generate 6 random values between 0-15 to use to pick a hex value
    for (var i = 0; i < 6; i++) {
        random_int = Math.floor((Math.random() * 16));
        result += str[random_int];
    }
    return result               //returns the hexadecimal colour value
}

Despite coding for the past four years, I have never created a program with a graphical user interface, so I haven’t needed to create random hex values before. I was surprised at how easy it was to take a basic loop and Math functions and get a value back which can be used for visual objects.


function render() {
    for (var i = 0; i < total_balls; i++) {
        update(balls[i]);
    }
    draw_ball();
    requestAnimationFrame(render);
}

Creating a drawing API from scratch was shockingly easy, and the steps we followed to create it were logical. To continually update the image on-screen, we utilised recursion, a technique in which a function makes a call to itself. Without an exit case or a limit on resources, these can theoretically loop forever.

The render() function operates by looping through each ball on-screen and updating its position by calling the update() function and passing a ball from the balls array to it. The balls array stores objects which contain information about each individual ball on-screen at any time.

Once it has looped through each ball on-screen, the is_overlapped() function is called to check if any balls are overlapping one another, so that they can change colour if they are. draw_ball() is called so that all the balls are now redrawn in their new positions as calculated by the update() function. requestAnimationFrame(render) works by calling the render() function every time the screen refreshes, ensuring that the visuals are always up-to-date.

In conclusion, I found this animation section very useful, as it opened me up to the ease with which visuals can be created and displayed to the user on a webpage. In the past, I have been intimidated by the idea of creating a program with graphics, thinking that it was more complex than it has proven to be. I am pleased to say that I am excited about seeing what else I can create in the future using 2D animation.