Aug 28, 2017

Medjed's Arena of Madness - #PaintGameJam entry

5:36 PM Posted by Lucas Izumi , , , , , No comments

Medjed's Arena of Madness is a chaotic twin stick shooter created during #PaintGameJam. You can play through your browser or by downloading the Windows version. The game supports gamepads and can also be played with a keyboard and mouse.

The MS Paint Game Jam started on August 24 and will go until August 31. The proposal was to create a game using MS Paint art style, to honor the legacy of the software.

Since the day I joined this jam, I has some sort of theme to work on in mind. This month I discovered this egyptian god name Medjed through the game Fate Gran Order. I had seen him before but never thought he was actually a god. Due to his looks, he even became an internet meme in Japan. I loved him so I decided to use him in this game. I had no idea, however, what kind of game to make.

There is absolute no information on Medjed, besides him being able to shoot lasers from his eyes. Based on this information I first thought of a game where the player would have to do everything by just using the lasers: moving, jumping, attacking, etc. It could result in something really interesting: a simple platformer where the challenge would be controlling the intensity and direction of the lasers so you can travel though the level. Then I thought of a Twin Stick Shooter. Even being a well known genre (and a little cliché), the idea of working with gamepads (something I didn't have the opportunity to do yet) plus the idea of designing enemies for it (I just love it) led me this way.

Character and Enemy Design
Let's talk about Medjed first. His appearance is already funny, but I wanted to go beyond that. Then I remebered this guy:

Sanic's walking cycle would fit perfect in all of Medjed's goofiness. This was the result:

With that done, it was time to focus on the enemies. Twin Stick Shooters kind of have a default set of enemies: a big guy that explodes and help clear the mobs, regular guys with no special effects but in large quantity and the tough one, something big and strong. I decided to skip the tough one and focus on enemies with special abilities.

Disclaimer: I was drawing the enemies without thinking, really. I was just having fun, just like I did when drawing on Paint when I was a kid. Because of that I can't quite explain why Rah is sitting in a bathtub with the sun in it while riding a BeyBlade nor why there is a Xatu Salaryman in this game.

Enemy 1: Xatu Salaryman
This is the regular guy I was talking about. All they do is follow the player, damaging him when in contact. They appear in numbers.

Enemy 2: BeyBlade Rah
At first I was going to place boss fights every 10 waves and the first boss I was going to add was this guy that just spints through the screen randomly. When I discarded the boss fight idea, I still used this 'boss' as a regular minion. BeyBlade Rah just bounces off walls, damaging the player when in contact. This enemy is kind of important to add variety and to create a chaotic sensation to the game environment (we can't make everything just follow the player).

Enemy 3: Minigun Anubis
Why is Anubis holding a minigun? Is he pissed? Maybe. With this enemy I tried to add a "bullet hell" element to the game. The bullets do not follow the player, but when shot, they go in the player's direction, just adding to the hazards the player will need to avoid. An Anubis enemy do not move, and each spawn point can only have one Anubis at a time. This rule was necessary so the players won't be overwhelmed by thousands of bullets in the screen at the same time.

Enemy 4: Fangirl Isis
Isis concept is really simple and perhaps the one I like the most in this game. Isis basically grabs the player when in contact for a few seconds. While grabbed the player can't do anything, which means: they can't dodge other enemies and projectiles. Isis itself doesn't damage the player. She just wanna hug this cute little god.


Enemy 5: Bomb Carrier Slave
This is the "big guy" of this game. He is slow, have very low health and when he dies an explosion occurs, damaging all enemies (and player) around it. He also explodes if in direct contact with the player, so be careful!

Enemy 6: Tourist Zeus
Well... yeah. He shoots lightning bolts that follow the player until it hits or until Zeus is killed. Just like Anubis it helps adding hazards to the game. He also stands still and only one Zeus can be spawned at a time. In order to balance him there is also a delay between each of his attacks so the player have time to deal with it.

What I learned by making this game
Besides having fun, in each game jam I participate I try to learn something new. Sometimes I know what I will learn when making the game, sometimes I learn something I could never imagine. While I was making the game, both things happened. I will use this section to share it with you.

Please note that the engine used here was GameMaker Studio and while the following tips may be heavily engine based, the overall knowledge can still be used elsewhere.

Fixing Diagonal Movement when Using a Gamepad
First, it is important to know how movement work in GameMaker. Let's assume our character's movement speed is set to 7. This means that every time you press a movement button, the character will move 7 pixels.

So how do you know if the character needs to move 7 pixels to the left or to the right?
A 2D environment is built upon a cartesian plane, with a x-axis and a y-axis. This plane however is slightly different from the usual cartesian plane we see in Math. Computer Graphics use the 4th quadrant of the cartesian plane (see figure below).

Which means that the coordinate (0,0) is located ate the top left corner of the screen. If you notice, in this quadrant, y values are all negative. In order to make it easier to work with it, they inverted the y-axis.

In this setting:
- If something moves LEFT, its value is descreased;
- If something moves RIGHT, its value is increased;
- If something moves DOWN, its value is increased;
- If something moves UP, its value is decreased;

Now it is possible to know the direction our character will be moving.
- If it's UP, then it needs to move -7 pixels in the y-axis
- If it's DOWN, then it needs to move 7 pixels in the y-axis
- If it's RIGHT, then it needs to move 7 pixels in the x-asis
- If it's LEFT, then it needs to move -7 pixels in the x-asis

When using a keyboard we know exactly when the player pressed each of the keys. So assuming our movement keys are the arrow keys, we can create a basic logic. We can evaluate if a key is being pressed in real time by checking the value returned by them: 0 or 1. If the value is 1 then that key is being pressed. If the value is 0 then that key is not being pressed.

Our horizontal movement can be expressed by the following formula:
HSPEED = ((KEY_LEFT*-1) + KEY_RIGHT) * SPEED
Where:
HSPEED: Horizontal Speed
KEY_LEFT: the value returned by the left arrow key. This value must be multiplied by -1 because to move left we use negative values, remember?
KEY_RIGHT: the value returned by the right arrow key.
SPEED: the player's movement speed (we are using the value 7 in this example)

Let's assume only the Left Arrow Key is being pressed. The result would be:
HSPEED = ((1*-1) + 0) * 7
HSPEED = (-1 + 0) * 7
HSPEED = -1 * 7
HSPEED = -7

For vertical movement we use this very same idea.
VSPEED = ((KEY_UP*-1) + KEY_DOWN) * SPEED

If only the Left Arrow Key is being pressed, then it's safe to assume that VSPEED = 0. We can conclude then:
UP: VSPEED = -7, HSPEED = 0
DOWN: VSPEED = 7, HSPEED = 0
LEFT: VSPEED = 0, HSPEED = -7
RIGHT: VSPEED = 0, HSPEED = 7

Now that we know this, let's talk about Diagonal Movement. When using a keyboard, we need to press two keys in order to move diagonally. For example, Left Arrow Key + Up Arrow Key to move diagonally up left, etc. Knowing this, when this setting is applied to the mentioned formulas, we get the following:
HSPEED = ((1*-1) + 0) * 7 = -7
VSPEED = ((1*-1) + 0) * 7 = -7

This means that we are telling the game that our character must move -7 pixels in the y-axis e -7 pixels at the x-axis at the same time. This way we will maintain the movement speed (in this example, 7) and the character will move diagonally.

This concept, however, is slightly different when using a gamepad. When evaluating if a direction is being pressed in a gamepad stick we get 0 if nothing is being pressed, 1 if Up, Left, Right or Down is being pressed AND a value between 0.99 and 0.5 if any other direction is being pressed (and this includes the diagonals).

A gamepad stick uses this setting because it must be very precise so it can deal with all kinds of games (3D most of all). Because of that we can't just jump from one state to another. The image below illustrate the states.

Let's assume we are pressing the up left diagonal. If we place the stick in the exact spot it will return:
KEY_LEFT = 0.5
KEY_RIGHT = 0
KEY_UP = 0.5
KEY_DOWN = 0

Let's return to those formulas to check the consequences of this:
HSPEED = ((0.5*-1) + 0) * 7 = -3.5
VSPEED = ((0.5*-1) + 0) * 7 = -3.5

Our character will be moving -3.5 pixels on the y-axis and -3.5 pixels on the x-axis, which is half the speed he was supposed to move.

Now, fixing this is very simple: after calculating the HSPEED and VSPEED, we just need to evaluate them:
- To move diagonally up left
if both HSPEED and VSPEED are less than 0 and greater than -SPEED (in this case, -7), then we set both HSPEED and VSPEED to -SPEED (-7).

Let's pick the previous example: HSPEED = -3.5 and VSPEED = -3.5
Is HSPEED less than 0? Yes.
Is HSPEED greater than -7? Yes.
The same applies to VSPEED, so now we manually set their values:
HSPEED = -7
VSPEED = -7

To the other diagonals, the requirements are as follows:
- To move diagonally up right
if HSPEED is greater than 0 and less than SPEED and VSPEED is greater than -SPEED and less than 0, then we set HSPEED to SPEED and VSPEED to -SPEED.

- To move diagonally down left
if HSPEED is less than 0 and greater than -SPEED and VSPEED is greater than 0 and less than SPEED, then we set HSPEED to -SPEED and VSPEED to SPEED.

- To move diagonally down right
if both HSPEED and VSPEED are greater than 0 and less than SPEED, then we set both HSPEED and VSPEED to SPEED.

All of this is just to check whether the gamepad stick is in the "diagonal region", so we can normalize the movement. Please note that this solution "removes" the precision the gamepad stick offers by basically "transforming" it in a 8-direction pad which is what I wanted for this game.

Scaling Game Screen for Browsers
This was a problem I faced when publishing the game as HTML 5. The game's resolution is 1280x720 which is really large to play in a browser. I tried setting it to a lower resolution on itch.io website but the game did not scale. In the lower resolution you could only see a piece of the screen.

I ended up finding this article that covers how scaling works and how to do that with your game:
https://www.yoyogames.com/blog/67/scaling-for-html5
In my case I was working with views and it all worked very well. The GUI however, did not scale. After some seaching I found out about the display_set_gui_size() function. By adding it to my script, the whole game scaled perfectly. This is my scale_canvas() script updated to scale the GUI as well.

/// scale_canvas(base width, base height, current width, current height, center);
//argument0 = base width;
//argument1 = base height;
//argument2 = current width
//argument3 = current height
//argument4 = center window (true, false);
var aspect = argument0 / argument1;
if ((argument2 / aspect) > argument3)
    {
    window_set_size((argument3 * aspect), argument3);
    }
else
    {
    window_set_size(argument2, (argument2 / aspect));
    }
if (argument4) window_center();
view_wport[0] = window_get_width();
view_hport[0] = window_get_height();
display_set_gui_size(view_wview[0], view_hview[0]);
surface_resize(application_surface, min(window_get_width(), argument0), min(window_get_height(), argument1));

This concludes this postmortem. I hope you enjoy the game! Don't forget to share your highscores in the comments section!