A downloadable game for Windows

Switch through three different characters to work together and escape the eerie Antarctic ruins in this short platform inspired by the titular story by H.P. Lovecraft. Get to the top of the map and shoot down the ice block to seal off the shoggoths in the tunnels below.

All assets and code were created by myself within the space of a single week.

Controls

  • A/D or Left/Right to move
  • J, Up or Space to jump
  • K or Shift to enter aiming mode with the starting character
  • L or Enter to interact with the female character
  • I to switch characters
  • LMB to fire while aiming or to break ice with the large character

WARNING: The doors aren't 100% perfect, so make sure characters aren't standing under one when you activate it or you'll have to quit and restart!

The platforming code for this game is borrowed in large part from my earlier Shell Platformer game, just with a few upgrades. This game introduces several new and useful mechanics, most notably the character swap, aiming modes and hanging mechanics. 

The character swap was by far the easiest mechanic to implement, and was done with the following code. The controlled character index simply cycles when I is pressed and, if the ice block has not been released, the camera is then set to follow the controlled character.

Relevant character controller code:

// cycle controlled character
if (keyboard_check_pressed(ord("I")))
{
    controlling += 1;
    if (controlling > pc_count)
    {
        controlling = 1;
    }
}
// camera follow controlled character
if (!obj_breakable_slab.hanging)
{
    camera_set_view_target(view_camera[0], obj_breakable_slab);
    timer += delta_time / 1000000;
    if (timer >= 3)
    {
    room_goto_next();
    }
    }
else if (controlling == 1)
{
    camera_set_view_target(view_camera[0], obj_pl1);
}
else if (controlling == 2)
{
    camera_set_view_target(view_camera[0], obj_pl2);
}
else if (controlling == 3)
{
    camera_set_view_target(view_camera[0], obj_pl3);
}

The other two mechanics were far more difficult. The aiming mechanic required the use of a separate arm object, which is actually always swiveling invisibly in the background, but  can't fire unless the player is also aiming. The aiming is definitely something to clean up in any further editions to this game, as it is slow and awkward, but this was the best I could do on a time crunch. 

Relevant player 1 code:

if (hsp == 0)
{
    if (key_interact && place_meeting(x, y + 1, obj_collisionBox))
    {
        image_index = 4;
        aiming = !aiming;
    }
    else if (!aiming)
    {
        image_index = 0;
    }
}

Most of the actual code is contained on the arm object -- the player simply starts aiming if they are stopped and the correct key is pressed. Once the player is aiming, the arm makes itself visible and has its fire functionality enabled.

Relevant arm code:

image_xscale = obj_pl1.image_xscale;
if (image_xscale == 1)
{
    x = obj_pl1.x + 4;
}
else if (image_xscale == -1)
{
    x = obj_pl1.x - 4;
}
y = obj_pl1.y - 11;
// sets rotation of aiming arm
if (keyboard_check_pressed(ord("D")) || keyboard_check_pressed(vk_right))
{
    image_angle = 90;
}
else if (keyboard_check_pressed(ord("D")) || keyboard_check_pressed(vk_left))
{
    image_angle = 270;
}
else if (image_xscale == 1)
{
    if (point_direction(x, y, mouse_x, mouse_y) >= 0 && point_direction(x, y, mouse_x, mouse_y) <= 90)
    {
        image_angle = clamp(point_direction(x, y, mouse_x, mouse_y) + 90, 90, 180);
    }
    if (point_direction(x, y, mouse_x, mouse_y) >= 290 && point_direction(x, y, mouse_x, mouse_y) <= 360)
    {
        image_angle = clamp(point_direction(x, y, mouse_x, mouse_y) + 90, 380, 450);
    }
}
else if (image_xscale == -1)
{
    if (point_direction(x, y, mouse_x, mouse_y) >= 90 && point_direction(x, y, mouse_x, mouse_y) <= 250)
    {
    image_angle = clamp(point_direction(x, y, mouse_x, mouse_y) + 90, 180, 340);
    }
}

The fire function occurs when the mouse is pressed, and simply destroys any breakables in the direction of the mouse click and spawns in a bullet sprite that moves in the same direction for some visual feedback.

The most difficult functionality to implement -- and one that is admittedly not quite complete in this version of the game -- was the hanging pot mechanic. The current implementation may not be a sophisticated and accurate physical model, but I am quite proud I managed to get it working within the game's short development cycle and think it should serve as a good basis for improvement should I develop this prototype more in the future.

Relevant rope code:

if (hanging)
{
    vsp = 0;
}
else if (vsp < maxFallSpd)
{
    vsp += grav;
}
if (instance_exists(anchor))
{
    hanging = 1;
}
else
{
    hanging = 0;
}

Effectively, if the rope's anchor has been destroyed, it will start falling. The current issue is that a rope must fall all the way to the ground and be destroyed before anything "attached" to it will start falling. This results in some weird physics where pots can briefly hang in midair after their ropes have been shot out. Now that I can see the issue with the benefit of hindsight, I could likely fix this little issue if I return to this prototype in the future.

Download

Download
AtTheMountainsOfMadness-Windows.zip 2 MB

Install instructions

Run executable to play.

Leave a comment

Log in with itch.io to leave a comment.