Quantcast
Channel: Envato Tuts+ Game Development
Viewing all articles
Browse latest Browse all 728

Let’s Prototype a Game: Trainpunk

$
0
0

Making quick, simple prototype games is a great way to test out new gameplay ideas quickly, without committing to creating a full-blown game. I like to use Game Maker for this, and in this post I’ll share one such game with you: Trainpunk, a train-based strategy game.

Editor’s Note: This is a new type of post we haven’t tried before. Please let us know what you think, and whether you’d like to see similar posts in the future!


Concept and Gameplay Demo

Here’s a video of me sketching out the original concept for the game, and then of me playing the prototype game itself:

I’d show myself drawing the art as well, but it’s so simple that there’s no real reason to.

In the final game, two teams of trains try to attack the enemy base while being shot at by turrets. You play by applying upgrades using the buttons at the bottom.

Please download the final game (plus the source code and sprites) and tweak the gameplay as much as you like! You will need a copy of Game Maker 8.


Building the Game

Here’s a rough outline of the steps I took to build the game. You could follow along from scratch, or use this to better understand the full source.

Step 1

Download Game Maker 8, and open it.

Step 2

Create a new GAME object, with these properties:

  • Sprite: "No sprite"
  • Solid: false
  • Visible: true
  • Depth: -999
  • Persistent: true
  • Parent: (no parent)
  • Mask: (same as sprite)

Give it these events:

#Create Event:
execute code:

alarm[0] = 150;

#Alarm Event for alarm 0:
execute code:

alarm[0] = 150;
global.points += 1;
global.pointsB += 1.25;

#Step Event:
execute code:

if !instance_exists(oUpgradeHP) 
if !global.points = 0
{
global.points -= 1;
instance_activate_object(oUpgradeHP);
instance_activate_object(oUpgradeRA);
instance_activate_object(oUpgradeSS);
instance_activate_object(oUpgradeAS);
}

if !global.pointsB = 0
{
ID=choose(1,2,3,4);
//
if ID = 1 {global.hp2 += 1;}
if ID = 2 {global.ra2 += 4;}
if ID = 3 {global.ss2 += 1;}
if ID = 4 {global.as2 = global.as2/1.1;}
//
global.pointsB -= 1;
}

if !instance_exists(oTurretA) {
instance_deactivate_all(true);
sleep(500);
game_restart();
}
if !instance_exists(oTurretB) {
instance_deactivate_all(true);
sleep(500);
game_restart();
}

#Other Event: Game Start:
execute code:

// Train Team A
global.hp1 = 5; // Health Points
global.ra1 = 64; // Range
global.ss1 = 6; // Shoot Speed
global.as1 = 30; // Attack Speed
// Train Team B
global.hp2 = 5; // Health Points
global.ra2 = 64; // Range
global.ss2 = 6; // Shoot Speed
global.as2 = 30; // Attack Speed

global.points = 1;
global.pointsB = 1;

room_goto_next();

#Draw Event:
execute code:

draw_set_color(c_black);
draw_set_font(font0);
//
draw_text(x+4,y+4,"TEAM [PLAYER] - HP="+string(global.hp1)+" - RA="+string(global.ra1)+" - SS="+string(global.ss1)+" - AS="+string(global.as1));
draw_text(x+4,y+18,"TEAM [ENEMY_] - HP="+string(global.hp2)+" - RA="+string(global.ra2)+" - SS="+string(global.ss2)+" - AS="+string(global.as2));

Step 3

Create another new object, _Block, and make it solid. It’s just for looks – it doesn’t do much itself.

Step 4

Create yet another new object, called _BaseA, with these properties:

  • Sprite: _BaseA
  • Solid: true
  • Visible: true
  • Depth: -1
  • Persistent: false
  • Parent: (none)
  • Mask: (none)
  • The sprite is just a 16×16 block. Now, give it these events:

    #Create Event:
    execute code:
    
    hp = 100;
    
    
    #Step Event:
    execute code:
    
    if hp < 0.9
    instance_destroy();
    

    Step 5

    Here’s an image of the final game, for reference:

    This time, create a new object to represent one of the player’s trains (a white rectangle on the tracks). Call it _TrainA and give it these properties:

    • Sprite: _TrainA
    • Solid: false
    • Visible: true
    • Depth: 0
    • Persistent: false
    • Parent: Make it the parent of _BaseA
    • Mask: (none)

    The sprite should be a 16×16 train, facing right. Give the object these events:

    #Create Event:
    execute code:
    
    // Train Team A
    // Sets stats to global variables decided by upgrades.
    hp = global.hp1; // Health Points
    ra = global.ra1; // Range
    ss = global.ss1; // Shoot Speed
    as = global.as1; // Attack Speed
    
    direction = 360;
    speed = 2;
    
    
    #Alarm Event for alarm 0:
    exit this event
    
    #Step Event:
    execute code:
    
    n = instance_nearest(x,y,oBaseB);
    
    if distance_to_point(n.x,n.y) < ra
    {
       if alarm[0] < 1 {
       i=instance_create(x,y,oBulletA);
       i.speed = ss;
       alarm[0] = as; 
       speed = 0;
       }
    }
    else
    speed = 2;
    
    if hp < 0.9
    instance_destroy();
    /*
    hp = global.hp1; // Health Points
    ra = global.ra1; // Range
    ss = global.ss1; // Shoot Speed
    as = global.as1; // Attack Speed
    */
    

    Step 6

    We’ll make the player’s turrets now. Create a new object called _TurretA, and give it these properties:

    • Sprite: _TrainA
    • Solid: false
    • Visible: true
    • Depth: 0
    • Persistent: false
    • Parent: oBaseA
    • Mask: (none)

    I used the same sprite as for the player’s train, here, but feel free to change it to a actual turret. It should be 16x16px. Add the events:

    #Create Event:
    execute code:
    
    hp = 25; // Health Points
    ra = 128; // Range
    ss = 15; // Shoot Speed
    as = 20; // Attack Speed
    
    #Alarm Event for alarm 0:
    exit this event
    
    #Step Event:
    execute code:
    
    n = instance_nearest(x,y,oBaseB);
    
    if distance_to_point(n.x,n.y) < ra
    {
       if alarm[0] < 1 {
       i=instance_create(x,y,oBulletA);
       i.speed = ss;
       alarm[0] = as; 
       }
    }
    
    if hp < 0.9
    instance_destroy();
    

    Step 7

    The turrets have to shoot bullets, so create a new object to represent these. Call it oBulletA, and give it these properties:

  • Sprite: _BulletA //A thin
  • Solid: false
  • Visible: true
  • Depth: 1
  • Persistent: false
  • Parent: (no parent)
  • Mask: (same as sprite)
  • The sprite should be a thin bullet (1px tall by 16px wide, within a 16x16px transparent square), facing to the right. Here are its events:

    #Create Event:
    execute code:
    
    n = instance_nearest(x,y,oBaseB);
    direction = point_direction(x,y,n.x,n.y);
    
    
    #Step Event:
    execute code:
    
    image_angle = direction;
    
    
    #Collision Event with object o_Block:
    destroy the instance
    
    #Collision Event with object oBaseB:
    execute code:
    
    #instance_destroy();
    other.hp -= 1;
    
    </small>
    
    <p>8. Create a New Object (oSpawnerA)
    <br><small>Information about object: oSpawnerA
    
    Sprite: _TrainA //Still using the train sprite
    Solid: false
    Visible: false
    Depth: 0
    Persistent: false
    Parent: <no parent>
    Mask: <same as sprite>
    
    Create Event:
    execute code:
    
    alarm[0] = 180;
    instance_create(x,y,oTrainA);
    
    
    Alarm Event for alarm 0:
    execute code:
    
    alarm[0] = 180;
    instance_create(x,y,oTrainA);
    

    Step 9

    When the player can update their HP, the relevant button lights up:

    We’ll create this button now. Create a new object called oUpgradeHP, and give it these properties:

    • Sprite: _UpgradeHP
    • Solid: false
    • Visible: true
    • Depth: -99
    • Persistent: false
    • Parent: (no parent)
    • Mask: (same as sprite)

    Give it these events, too:

    #Create Event:
    execute code:
    
    image_alpha = 0.5;
    
    Mouse Event for Left Released:
    execute code:
    
    global.hp1 += 1;
    instance_deactivate_object(oUpgradeHP);
    instance_deactivate_object(oUpgradeRA);
    instance_deactivate_object(oUpgradeSS);
    instance_deactivate_object(oUpgradeAS);
    
    
    Mouse Event for Mouse Enter:
    execute code:
    
    image_alpha = 1;
    
    Mouse Event for Mouse Leave:
    execute code:
    
    image_alpha = 0.5;
    

    Step 10

    Duplicate oUpgradeHP three times so you have four objects – one button each for upgrading HP, RA, SS and AS. (oUpgradeHP, oUpgradeRA, oUpgradeSS, oUpgradeAS).

    Change the Left Released event’s code for each:

    oUpgradeHP -> global.hp1 += 1;
    oUpgradeRA -> global.ra1 += 4;
    oUpgradeSS -> global.ss1 += 1;
    oUpgradeAS -> global.as1 = global.as1/1.1;
    

    Step 11

    Duplicate oBaseA, oTrainA, oTurretA, oSpawnerA and oBulletA to create oBaseB, oTrainB, oTurretB, oSpawnerB and oBulletB.

    Change their Parents (from “A” to “B”) and change all their code from:

    n = instance_nearest(x,y,oBaseB); 
    

    …to:

    n = instance_nearest(x,y,oBaseA); 
    

    …as required.

    Also set oTrainB to have direction = 180; in the create event, instead of direction = 360;. Last, choose left-facing sprites for each, where appropriate.

    Step 12

    Add all your tilesets, sprites, art and so on and create two new rooms: one is rm_intro, where you should only put the obj_Game, and the other one is the main room (rm_main).

    Build your rm_main like so:

    1. Place bases on either side.
    2. Place train tracks running from the bases (you can use the tileset in the source download).
    3. Place turrets to defend; when all turrets are dead the other team wins.
    4. Place spawners, which spawn new trains at intervals.
    5. Place the four Upgrade buttons.

    You could try to make the room symmetrical so it’ll be somewhat fair, or place more turrets on the Enemy side for harder gameplay. It’s up to you – the whole point of a prototype is to test things!

    Now play the game. As you play, consider what needs changing. Should the trains be faster or slower? Should upgrades come more frequently? Should the computer have an unfair advantage? Should the player have more input other than just applying upgrades? Tweak away!

    I hope you learned a little something about making games – but more importantly, I hope you learned how any idea can be quickly smashed together into a prototype.

    Editor’s Note: This is a new type of post we haven’t tried before. Please let us know what you think! Is there anything you’d like to see us do differently with the format in the future? Would you like more detail in the video, or a fuller set of instructions for actually building the game?


    Viewing all articles
    Browse latest Browse all 728

    Trending Articles