About 4D Systems PTY LTD
4D Systems, Australia
Home Company Products 4DGL Developers Center Support forum Distributors News & Events Contact us App Notes
4DGL - Sharing our bytes to the world

Planet Lander


Codebase / GOLDELOX-GFX / Games

A 4DGL script for planet landing game where each planet, with different gravity, has to be landed on the red pad.
Code is exclusive to 96 G1, 128 G1 and 160 G1.

A joystick is also required for control.
About this code
Author: Anna Ceguerra
Uploaded on: 14/04/2009

Back to previous page

Source code:

#platform "uOLED-GOLDELOX"

/**********************************************************************      
*    
* Filename:     Lander-G1.4dg    
* Created:      2009/03/28      
* Author:       Anna Ceguerra     
* Description:  This is a game where you land a space ship onto the 
*               surface of a planet or other heavenly body
*               Different planets have different gravities
* Platform:     Goldelox          
*  
**********************************************************************/    


#inherit "4DGL_16bitColours.fnc"

#CONST
    NUM_BODIES 9
    g 1 // x10^-1 m/s^2
    SHIP_X_LENGTH 1
    SHIP_Y_LENGTH 8
    thrust_x 1 // acceleration from thrust in x direction
    
    time_divisor 50
    multiplier 100
    //g_divisor 10
    //MAX_VAR 10000 //32767
    MAX_ALLOWED_V 100
#END
#DATA
    byte ship 1, 8,
        0b00011000,
        0b00111100,
        0b01111110,
        0b01111110,
        0b11111111,
        0b11111111,
        0b10111101,
        0b10011001
    byte thruster_soundfx "d=4,o=5,b=3 ",
        "c,d,e,f,g,a,b,c6,R",0
    byte next_level_sfx "d=4,o=7,b=10 ",
        "16c,16p,1c",0
    byte game_over_win_sfx "d=4,o=7,b=5 ",
        "c,d,e,f,g,a,b,c8",0
    byte game_over_lose_sfx "d=4,o=7,b=5 ",
        "c8,b,a,g,f,e,d,c",0
#END
var gravity[NUM_BODIES], planet_name[NUM_BODIES]; // in 10^-1 g's
var a_x, a_y; // 10^-1 meters/second^2
var v_x, v_y, v; // x time_divisor x 10^-3 x 10^-1 meters/second
var x, y, old_x, old_y, t; // x time_divisor^2 x 10^-6 x 10^-1 meters, x 10^-3 seconds
var max_x, max_y; // in pixels
var planet;
var platform_left, platform_right;

// for game settings
var selected_settings_line;
#constant NUM_LINES 2
var settings_lines[NUM_LINES];
var settings_lines_value[NUM_LINES];

/*
 * Initialises gravity for each heavenly body
 */
func init_gravity()
    var i;
    i := 0;
    planet_name[i] := "MOON";       gravity[i++] := 2; // Moon    
    planet_name[i] := "MERCURY";    gravity[i++] := 4; // x 10^(-1) Mercury 0.38g
    planet_name[i] := "VENUS";      gravity[i++] := 9; // Venus 0.904g
    planet_name[i] := "EARTH";      gravity[i++] := 10; // Earth 1g
    planet_name[i] := "MARS";       gravity[i++] := 4; // Mars 0.376g
    planet_name[i] := "JUPITER";    gravity[i++] := 25; // Jupiter
    planet_name[i] := "SATURN";     gravity[i++] := 9; // Saturn
    planet_name[i] := "URANUS";     gravity[i++] := 9; // Uranus
    planet_name[i] := "NEPTUNE";    gravity[i++] := 11; // Neptune
endfunc

/*
 * Updates the acceleration of the ship based on the joystick control
 */
func update_acceleration()
    var control;

    control := sys_Get(JOYSTICK);
    a_x := 0;
    a_y := gravity[planet] * g;
    if (control == RELEASED)
        tune_End();
    else if (control == UP)
        // accel in -y direction
        a_y := -gravity[planet];
        if (!tune_Playing())
            tune_Play(thruster_soundfx);
        endif
    else if (control == LEFT)
        // accel in -x direction
        a_x := -thrust_x;
    else if (control == RIGHT)
        // accel in x direction
        a_x := thrust_x;
    endif
/*to(COM0);print("a: ");
to(COM0);print(a_x);
to(COM0);print(" ");
to(COM0);print(a_y);
to(COM0);print(" ");
to(COM0);print(a_y * t);
to(COM0);print("\n");*/
    return (control);
endfunc

/*
 * Updates the velocity of the ship based on the velocity
 */
func update_velocity(var time)
    v_x := v_x + a_x * time;
    v_y := v_y + a_y * time;
    v := (ABS(v_x) + ABS(v_y))/2;// this is the closest i can get to a quadrature without sqrt
/*to(COM0);print("v: ");
to(COM0);print(v_x);
to(COM0);print(" ");
to(COM0);print(v_y);
to(COM0);print("\n");*/
endfunc

/*
 * Updates the position of the ship based on the joystick control
 */
func update_position(var time)
    old_x := x;
    old_y := y;
    x := x + v_x * time / 2;
    y := y + v_y * time;
/*to(COM0);print("x: ");
to(COM0);print(x);
to(COM0);print(" ");
to(COM0);print(y);
to(COM0);print(" ");
to(COM0);print(v_y * t);
to(COM0);print(" ");
to(COM0);print(v_y * t / (time_divisor));
to(COM0);print("\n");*/
endfunc

func has_landed()
    var landed;
    landed := y > (max_y - 8) * multiplier;
    return (landed);
endfunc

func is_on_platform()
    var on_platform;
    on_platform := (platform_left <= x) && (x < platform_right);
    return (on_platform);
endfunc

/*
 * Erases the ship from the module
 */
func display_erase_ship(var x, var y)
    gfx_Bitmap(ship, x, y, BLACK);
endfunc

/*
 * DIsplays the ship on the module
 */
func display_update(var x, var y)
    // display the ship
    gfx_Bitmap(ship, x, y, WHITE);
endfunc

/*
 * Displays the game info on the module
 */
func game_info()
    var col, line;
    // display level
    txt_Set(FONT_SIZE, FONT_SMALL);
    txt_Set(TEXT_OPACITY, OPAQUE);
    txt_Set(TEXT_COLOUR, WHITE);
    line := 15;
    if (gfx_Get(X_RES) == 96)
        line := 7;
    endif
    txt_MoveCursor(line, 0);
    print("LEVEL: ");
    print(planet + 1);

    if (gfx_Get(X_RES) == 160)
        col := 13;
    else if (gfx_Get(X_RES) == 128)
        col := 10;
    else if (gfx_Get(X_RES) == 96)
        col := 9;
    endif
    txt_MoveCursor(line, col);
    print("v: ");
    print(v);
    print("    ");
endfunc

/*
 * Displays the ground on the module
 */
func background_render()
    gfx_Cls();
    // display the ground
    gfx_Line(0, max_y, platform_left, max_y, WHITE);
    gfx_Line(platform_right, max_y, max_x, max_y, WHITE);
    gfx_Line(platform_left, max_y, platform_right, max_y, RED);
    txt_Set(FONT_SIZE, FONT_SMALL);
    txt_Set(TEXT_OPACITY, OPAQUE);
    txt_Set(TEXT_COLOUR, WHITE);
    txt_MoveCursor(0, 0);
    putstr(planet_name[planet]);
endfunc

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

// Initialise the lines for the settings page

////////////////////////////////////////////////////////////////////////////////////////////////////
func init_settings()
    var i;
    
    selected_settings_line := 0;
    i := 0;
    settings_lines[i] := "SOUND";
    if (gfx_Get(X_RES) != 96)
        pin_Set(SOUND, PIN_2);
    endif
    settings_lines_value[i++] := 1;
    settings_lines[i] := "LEVEL";
    settings_lines_value[i++] := 1;
endfunc

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

// Draw the settings page

////////////////////////////////////////////////////////////////////////////////////////////////////
func settings()
    var i;
    i := 0;

    // SOUND
    txt_MoveCursor(i, 0);
    txt_Set(TEXT_COLOUR, WHITE);
    if (selected_settings_line == 0)
        txt_Set(HIGHLIGHT_COLOUR, GRAY);
    else
        txt_Set(HIGHLIGHT_COLOUR, BLACK);
    endif
    putstr(settings_lines[i]);
    txt_MoveCursor(i, 8);
    if (settings_lines_value[i] <= -1)
        txt_Set(HIGHLIGHT_COLOUR, GRAY);
    else if (settings_lines_value[i] >= 0)
        txt_Set(HIGHLIGHT_COLOUR, BLACK);
    endif
    print("OFF");

    txt_Set(HIGHLIGHT_COLOUR, BLACK);
    print("  ");

    if (settings_lines_value[i] == 1)
        txt_Set(HIGHLIGHT_COLOUR, GRAY);
    else
        txt_Set(HIGHLIGHT_COLOUR, BLACK);
    endif
    print("ON");
    txt_Set(HIGHLIGHT_COLOUR, BLACK);

    if (settings_lines_value[i] == 1)
        if (gfx_Get(X_RES) != 96)
            pin_Set(SOUND, PIN_2); //  uncomment for uOLED-128-G1, uOLED-160-G1
        endif
    else
        pin_Set(SOUND, PIN_1);
    endif
    i++;
        
    // LEVEL
    txt_MoveCursor(i, 0);
    txt_Set(TEXT_COLOUR, WHITE);
    if (selected_settings_line == 1)
        txt_Set(HIGHLIGHT_COLOUR, GRAY);
    else
        txt_Set(HIGHLIGHT_COLOUR, BLACK);
    endif
    putstr(settings_lines[i]);
    txt_MoveCursor(i, 8);
    if (settings_lines_value[i] == -1)
        txt_Set(HIGHLIGHT_COLOUR, GRAY);
    else
        txt_Set(HIGHLIGHT_COLOUR, BLACK);
    endif
    planet := settings_lines_value[i] - 1;
    putstr(planet_name[planet]);
    print("   ");
    i++;
    
    i++;
    txt_MoveCursor(i, 0);
    print("FIRE to exit");
endfunc

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

// Input loop to adjust game settings

////////////////////////////////////////////////////////////////////////////////////////////////////
func settings_loop()
    var control, dirx1;
    pause(100);
    gfx_Rectangle(0, 0, gfx_Get(X_RES), gfx_Get(Y_RES), BLACK);
    repeat
        settings();
        control := sys_Get(JOYSTICK);
        if (control == FIRE)
            // exit
            break;
        else if (control == UP)
            // UP pressed
            selected_settings_line--;
            if (selected_settings_line < 0)
                selected_settings_line := 0;
            endif
        else if (control == DOWN)
            // down pressed
            selected_settings_line++;
            if (selected_settings_line >= NUM_LINES)
                selected_settings_line := NUM_LINES - 1;
            endif
        else if (control == LEFT || control == RIGHT)
            if (control == LEFT)
                dirx1 := -1;
            else
                dirx1 := 1;
            endif
            
            if (selected_settings_line == 0)
                settings_lines_value[selected_settings_line] := dirx1;
            else if (selected_settings_line == 1)
                settings_lines_value[selected_settings_line] := settings_lines_value[selected_settings_line] + dirx1;
                if (settings_lines_value[selected_settings_line] <= 1)
                    settings_lines_value[selected_settings_line] := 1;
                else if (settings_lines_value[selected_settings_line] > NUM_BODIES)
                    settings_lines_value[selected_settings_line] := NUM_BODIES;
                endif;
            endif
        endif
        settings();
        pause(10);
    forever
endfunc

/*
 * Displays the help screen
 */
func help()
    var control;
    
    gfx_Cls();

    txt_Set(TEXT_COLOUR, WHITE);
    txt_Set(HIGHLIGHT_COLOUR, BLACK);
    txt_Set(FONT_SIZE, FONT_SMALL);


    txt_Set(TEXT_WIDTH, 1);
    txt_Set(TEXT_HEIGHT, 1);
    txt_MoveCursor(0, 0);
    print("HELP\n\n");
    print("UP    - apply upward\n      - thrust\n");
    print("LEFT  - move ship\n      - left\n");
    print("RIGHT - move ship\n      - right\n");
    print("FIRE  - help screen\n\n");
    print("You must land on the\nred line to continue\n");
    print("Press FIRE to\nenter settings menu\n");

    repeat
        control := sys_Get(JOYSTICK);
    until (control != RELEASED);
    if (control == FIRE)
        settings_loop();
    endif
    while (sys_Get(JOYSTICK) != RELEASED);
endfunc

/*
 * Welcome screen for the uOLED-96-G1
 */
 func welcome_screen_96()
    var title_offset;
    
    // clear the screen
    gfx_Cls();
    txt_Set(TEXT_COLOUR, WHITE);
    txt_Set(HIGHLIGHT_COLOUR, BLACK);
    txt_Set(FONT_SIZE, FONT_LARGE);


    txt_Set(TEXT_WIDTH, 1);
    txt_Set(TEXT_HEIGHT, 1);
    txt_MoveCursor(0, 5);
    print("4D");
    txt_Set(TEXT_WIDTH, 1);
    txt_Set(TEXT_HEIGHT, 1);
    txt_MoveCursor(2, 3);
    print("LANDER");

    txt_Set(FONT_SIZE, FONT_SMALL);
    txt_MoveCursor(6, 0);
    print("by Anna Ceguerra");
    txt_MoveCursor(7, 3);
    print("(c) 2009");

endfunc

/*
 * Welcome screen for the uOLED-128/160-G1
 */
func welcome_screen()
    var col;

    gfx_Cls();
    
    txt_Set(TEXT_COLOUR, WHITE);
    txt_Set(HIGHLIGHT_COLOUR, BLACK);
    txt_Set(FONT_SIZE, FONT_LARGE);


    txt_Set(TEXT_WIDTH, 2);
    txt_Set(TEXT_HEIGHT, 2);
    if (gfx_Get(X_RES) == 160)
        col := 4;
    else if (gfx_Get(X_RES) == 128)
        col := 3;
    endif
    txt_MoveCursor(2, col);
    print("4D");
    txt_Set(TEXT_WIDTH, 2);
    txt_Set(TEXT_HEIGHT, 2);
    if (gfx_Get(X_RES) == 160)
        col := 2;
    else if (gfx_Get(X_RES) == 128)
        col := 1;
    endif
        txt_MoveCursor(5, col);
    print("LANDER");

    txt_Set(FONT_SIZE, FONT_SMALL);
    if (gfx_Get(X_RES) == 160)
        col := 6;
    else if (gfx_Get(X_RES) == 128)
        col := 3;
    endif
    txt_MoveCursor(12, col);
    print("by Anna Ceguerra");
    if (gfx_Get(X_RES) == 160)
        col := 10;
    else if (gfx_Get(X_RES) == 128)
        col := 7;
    endif
    txt_MoveCursor(14, col);
    print("(c) 2009");
endfunc

/*
 * Displays new game information
 */
func new_game()
    planet := 0;

    if (gfx_Get(X_RES) == 96)
        welcome_screen_96();
    else
        welcome_screen();
    endif
    while(sys_Get(JOYSTICK) != FIRE);
    help();
endfunc

/*
 * Initialise variables for the new level
 */
func new_level()
    var col, line;
    
    tune_End();
    a_y := 0;
    a_x := 0;
    v_x := 0;
    v_y := 0;
    x := max_x / 2;
    y := 0;
    platform_left := ABS(RAND() % (max_x - (8 * 3)));
    platform_right := platform_left + (8 * 3);

    if (planet > 0)
        line := 7;
        if (gfx_Get(X_RES) == 160)
            col := 8;
        else if (gfx_Get(X_RES) == 128)
            col := 6;
        else if (gfx_Get(X_RES) == 96)
            line := 4;
            col := 2;
        endif
        txt_MoveCursor(line, col);
        print("NEXT LEVEL");
        tune_Play(next_level_sfx);
        while(sys_Get(JOYSTICK) == RELEASED);
        while(sys_Get(JOYSTICK) != RELEASED);
    endif
    gfx_Cls();
    background_render();
    sys_Set(TIMER, 0);
endfunc

/*
 * Displays end game information
 */
func game_over(var win)
    var col, line;
    
    tune_End();
    line := 7;
    if (gfx_Get(X_RES) == 160)
        col := 8;
    else if (gfx_Get(X_RES) == 128)
        col := 6;
    else if (gfx_Get(X_RES) == 96)
        line := 4;
        col := 4;
    endif
    txt_MoveCursor(line, col);
    print("GAME OVER");
    if (win)
        if (gfx_Get(X_RES) == 160)
            col := 9;
        else if (gfx_Get(X_RES) == 128)
            col := 7;
        else if (gfx_Get(X_RES) == 96)
            col := 5;
        endif
        txt_MoveCursor(line + 1, col);
        print("you win!");
        tune_Play(game_over_win_sfx);
    else
        if (gfx_Get(X_RES) == 160)
            col := 7;
        else if (gfx_Get(X_RES) == 128)
            col := 5;
        else if (gfx_Get(X_RES) == 96)
            col := 3;
        endif
        txt_MoveCursor(line + 1, col);
        print("you crashed!");
        tune_Play(game_over_lose_sfx);
    endif
    while(sys_Get(JOYSTICK) != FIRE);
    gfx_Cls();
endfunc

/*
 * main loop
 */
func main()
    var win, lose, control;
    
    sys_Set(TIMER, 0);
    max_x := gfx_Get(X_RES);
    max_y := gfx_Get(Y_RES) - 10;
    init_gravity();
    init_settings();
    
    repeat // start/end game loop
        new_game();
        SEED(sys_Get(TIMER));
        repeat // level incrementor loop
            new_level();
            win := 0;
            lose := 0;
            repeat // input & position update loop
                // get button press
                control := update_acceleration();
                if (control == FIRE)
                    tune_Stop();
                    help();
                    background_render();
                    display_update(x, y/multiplier);
                    game_info();
                    tune_Continue();
                    sys_Set(TIMER, 0);
                endif
                
                t := sys_Get(TIMER);
                if (t >= time_divisor)
                    // update velocity vector
                    update_velocity(t / time_divisor);
                    
                    // update position
                    update_position(t / time_divisor);

                    // see whether the ship has landed or not
                    
                    if (has_landed())
                        if (is_on_platform())
                            // the eagle has landed
                            y := (max_y - 8) * multiplier;

                            // check that the velocity is OK for landing
                            if (v > MAX_ALLOWED_V)
                                lose := 1;
                            else
                                win := 1;
                            endif
                        else
                            lose := 1;
                        endif
                    endif
                    
                    sys_Set(TIMER, 0);
                
                    // update display
                    display_erase_ship(old_x, old_y/multiplier);
                    display_update(x, y/multiplier);
                    game_info();
                endif
                pause(time_divisor);
            until (win || lose);
            if (win)
                planet++;
            else if (lose)
                planet := NUM_BODIES;
            endif
        until (planet >= NUM_BODIES);
        game_over(win);
    forever;
endfunc


Copyright © 2007 4D Systems Pty Ltd, Sydney, Australia - All Rights Reserved | Terms and Conditions