This End Up

Year
Jan 2009 - Mar 2009

Tools:
3d Gamestudio / C Script

Role:
Programmer/ Lead Deasign

Description:

A 3D adventure where the player must scale and rotate his environment to complete puzzles and defeat enemies. The game is a puzzle platformer. I scripted the rotation mechanic using C-Lite, a flavor of C. The original concept was created for a student project.

Number of Students: 10

 

Project Goals: Create a full game design implementing two different gameplay mechanics.

What I did: I used my extensive knowledge of the 3D Gamestudio game engine to code a player movement, Enemy AI, Sound, Shader Rendering, Animation,  and  UI.

This End Up Unique Gameplay

Explanation of Rotation

The rotation mechanic in This End Up was born by committee. The original idea came from the prototype from Bob the Blob – that game the prototype asked the question – what happens if you are able to manipulate yourself and the environment to solve puzzles. (See Bob the Blob For more details on that project)  We ran out of time to implement the full feature in that project. (We were able to make the blob change his shape, but we were unable to give the player the ability to manipulate the world)  When the group reconvened,  we decided that we wanted to explore manipulating the world further.

We decided that we needed to lock down how the player would actually control this rotation. We settled on the player being able to rotate his world by hitting special gears or cogs that were placed throughout the world. The player is temporarily lifted up while the entire level around him rotates. Depending on the gear, each room can rotate multiple ways. The player can use this to escape rooms and defeat enemies.  Each time the player rotates the room, enemies are thrown into spikes and other hazards. The player has to be careful not to throw himself into these obstacles however. This is where the interesting choice comes into play.

I implemented the script to allow the player to rotate each room around him. I also implemented the scripting to allow enemies to die when they fall from high ceilings.

Example Code

 #define PRAGMA_PATH "shade-c"
#include "sc_core.c"; 
#define PRAGMA_PATH "shade-c"
#include <acknex.h>
#include <default.c>
#include "sc_core.c"; 
/////////////////////////////Starting Variables////////////////////////////////////////////////////////

var video_mode = 7; // 800x600 pixels
var video_depth = 32; // 32 bit mode
var video_screen = 1; // start the engine in full screen mode
var player_close = 0;
var attackstatus = 0;
var move_vec[3] = 0,0,0;
////////////////////////////////PATHS//////////////////////////////////////////////////////////////////////////////
path "C:\\robodemo\\models";    // Path to models subdir
path "C:\\robodemo\\scripts";
path "C:\\robodemo\\levels";
path "C:\\robodemo\\sounds";
path "C:\\robodemo\\images";

////////////////////////////////////Includes/////////////////////////////////////////////////////////////

include <player.wdl>;
include <glowing.wdl>;
include <enemy.wdl>;
include <specular.wdl>;

function start_level1();

//////////////////////////////////Bmap///////////////////////////////////////////
bmap main_tga = <startmenu.pcx>; // main panel
bmap start_pcx = <start.pcx>;
bmap pointer1_tga = <pointer1.tga>; // mouse pointer
bmap pointer2_tga = <pointer2.tga>;


/////////////////////////////////////////Strings///////////////////////////////////////
string dummy_wmb = <dummy.wmb>;
string demo_wmb = <demo.wmb>;
 

////////////////////////////////////////////////////////////////////////////////////
var game_started = 0; // will be set to 1 when the game starts

////////////////////////////////////////////////////////test zone


///////////////////////////////////////Starters/////////////////////////////////////////////////



//// so aparantly this only works when it's directed toward you. It also looks like to use it you need to have the file tiles floor attached to the entity you want

bmap tilesfloorDOT3 = <floor1_Nrm.tga>;

material tilesfloor
{
 skin1 = tilesfloorDOT3;
 flags = tangent;
}


starter load_shaders()
{ 
d3d_automaterial=1;

effect_load(tilesfloor,"bumpmap.fx");
effect_load(tilesfloor,"bumpmap.fx");


wait(5);
}







material robonormal
{
 skin1 = tilesfloorDOT3;
 flags = tangent;
}



///////////////////////////////////////// Do All stuff you are unsure that works here

panel main_pan // main panel
{
    bmap = main_tga;
    layer = 20;
    pos_x = 0;
    pos_y = 0; // for now
    button = 397, 475, start_pcx , start_pcx, start_pcx, start_level1, start_level1, start_level1;
//  button = 559, 431, help2_tga, help1_tga, help2_tga, show_help, null, mouse_over;
//  button = 647, 329, load2_tga, load1_tga, load2_tga, load_game, null, mouse_over;
//  button = 681, 226, save2_tga, save1_tga, save2_tga, save_game, null, mouse_over;

    flags = overlay, refresh, visible;
}



function start_level1()
{
    mouse_mode = 0; // hide the pointer
    main_pan.visible = off; // hide main_pan
    level_load (demo_wmb); // load the first playable level (runs level1.wdl when it is loaded)
}






//////////////////////////Functions///////////////////////////////////////////////





 
 
 action trap_trigger
 {
    my.enable_touch = on;
 // my.event = trap_player;
    while(player == null){wait(1);}
    while(vec_dist(player.x, my.x) > 100) {wait(1);} // player with the 40
    player_close = 1;   
    
  }


// this is the basis for our game 
// with action trap player 
/// this basically looks at the trigger and causes it to either tilt(rotate) pan (rotate horizonatlly) or scale

  
  action trap_player
  {
        
        
        while(player_close ==0){wait(1);}
            // the way this should work is that it checks to see if the player is clse  
        while (my.z > 180) // this shouldn't work until the player_close is equal to 1
        {
            my.z -= 50 * time;
            wait(1);        
        }
         my.pan = my.pan + 360;
         
    }
    
     action test1
  {
        
        while(player_close ==0){wait(1);}
            // the way this should work is that it checks to see if the player is clse  
         my.tilt = my.tilt  + -720 * time; // tilt is up pan is horizontal
                 
        
        player.z  += 50;
        
        my.scale_x = 2 + random(5);
        my.scale_y = 2 + random(5);
        my.scale_z = 2 + random(5);
         
         if player_close == 2
         {
         
         my.tilt = my.tilt + 180 * time;
            
        }
         
    }
    
    


///////////////////////////////////////////////////////////////////////////

action spikes
{
              if (you != null) // kill the player if he touches you
     {
          you.health = -100;
     } 
        
}
  







function main()
{
    
    

    camera.arc -= 30; // set the default zoom factor
    
    level_load (dummy_wmb);
    wait(3);
    
//  sc_setup();
    
//  camera.x = 0; // choose a convenient camera position
//  camera.y = 0;
//  camera.z = 350;
    camera.tilt = -90; // and angle
    mouse_spot.x = 50; // ~ 63 / 2
    mouse_spot.y = 25; // ~ 35 / 2
    camera.tilt = -90; // and angle
    mouse_mode = 2; // show the pointer
    
        while (game_started == 0) // as long as we haven't started the game
    {
        mouse_pos.x = pointer.x;
        mouse_pos.y = pointer.y;
        if (random (1) > 0.95) // use the second bitmap for the pointer every 20 frames (or so)
        {
            mouse_map = pointer2_tga;
        }
        else
        {
            mouse_map = pointer1_tga;
        }
        wait (1);
    
    while (player == null) {wait (1);} // wait until the player appears in the level
    
}

}

 

Code to handle rotation. I set up a loop to check the distance of the player. If the player was close enough, the trigger would rotate the object that this is attached to. 

// this is the first rotation. This is for the first rotation in the game 


  action 1strotatetrigger
  {
        
        
        while(player_close ==0){wait(1);}
            // the way this should work is that it checks to see if the player is clse  
        while (my.z > 180) // this shouldn't work until the player_close is equal to 1
        {
            my.z -= 50 * time;
            wait(1);        
        }
         my.pan = my.pan + 360;
         
    }
    
     action 1strotate    // this is the first rotate for memo's room. There should only be one. 
  {
        
        
        while(player_close ==0){wait(1);}
            // the way this should work is that it checks to see if the player is clse  
         my.tilt = my.tilt - 180 * time; // tilt is up pan is horizontal
         player.z += 5; 
        
    }