Skip to content

A First Person game that runs on a terminal window. Player will get to choose between an easy maze or a difficult one. The rule is simple. Find the red door in the maze and escape as fast as possible. The player is only allowed to use the map a limited number of time. The time taken to finish a single is also recorded.

Notifications You must be signed in to change notification settings

senputra/maze-runner

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

17 Commits
 
 
 
 
 
 

Repository files navigation

Maze Runner [DW Final Assignment]

Introduction

Maze Runner is a First Person game that runs on a terminal window. The Player will get to choose between an easy maze or a difficult one. The rule is simple. Find the red door in the maze and escape as fast as possible. The player is only allowed to use the map for a limited number of times. The time taken to finish one round is recorded.

I made this project to learn more about the usage of the very basic state machine in python and also the rendering technique that many game engines use, Ray Tracing.

Ray Tracing

Ray Tracing is one of many rendering techniques. Steps on how it works are as follows:

  1. Light rays are shot out from the player's point of view.
  2. For every light ray, trace where each of them is going to.
  3. When a collision with an object is detected, a portion of the light ray will be absorbed and some will bounce off in different directions.
  4. The light ray keeps being absorbed and bouncing until it reaches the light source or a very dark opaque object.
  5. The aggregated value from those bounces will give the amount of light or shadow that should be shown for each pixel on the screen.

With the constraint that I have in this coding project; a terminal window as the display and a must to use python, an interpreted language (which may run less efficiently as compiled programming language like C++), I limit the extend of ray tracing the game uses.

In Maze Runner, the light rays only bounce off once from the wall and the distance of the wall from the players determines how bright or dark the pixel is.

The size of the wall is scaled with a linear inverse relationship with the distance of the object. This is similar to the effect that cameras in real life.

State Machine

In Maze Runner, the state machine manages the upper-level state of the game. The upper-level state consists of the state of the screen that is displayed to the player and how the screen should change with the keyboard input from the player.

I tried to use the state machine to manage all of the states of the game. However, it hits the performance very badly; the game ran for around 5 frames per second (FPS)instead of the normal 20 frames per second (FPS) on average. Therefore, I keep some of the in-game controls such as movement and trigger actions inside the variables of the main function not inside the state of the state machine object.

Dependencies:

  • libdw
  • asciimatics – Install by running conda install -c conda-forge asciimatics.

How to play

  1. Ensure that asciimatics and libdw are installed. The game will run into an error if these libraries are not installed properly. See below for instructions to install asciimatics.

  2. Open power shell (Win X + A) or any of your favorite terminal or Anaconda Prompt.

    # Move to the project directory.
    $ cd </project/folder>
    # Run the game.
    $ python ./main.py

How to play - if you have git installed

Ensure that asciimatics and libdw are installed. The game will run into an error if these libraries are not installed properly. See below for instructions to install asciimatics.

  1. Open power shell (Win X + A) or any of your favorite terminal or Anaconda Prompt.

    # Clone the whole repository.
    $ git clone https://github.com/ulaladungdung/maze-runner.git
    # Run the game.
    $ python ./src/main.py

How to install asciimatics

Install from anaconda

  1. Open your Anaconda Prompt with Admin privilege.

  2. Copy and paste this line of command:

    conda install -c conda-forge asciimatics
  3. Press Enter.

  4. Close this window and reopen Anaconda Prompt.

Install from Pip

  1. Open your Command Prompt with Admin privilege.

  2. Copy and paste this line of command:

    pip install asciimatics
  3. Press Enter.

  4. Restart ANao

Documentation

class GPU()

GPU is a wrapper for asciimatic library.GPU allows other classes to print any ASCII character on the terminal window and to get the keyboard and mouse input event from the terminal window.

Properties:

  • screen - get the Screen object of the terminal window.
  • height - The number of lines in the window.
  • width - The number of character in one line.

Constants:

  • __DISABLE_KEYBOARD_INTERRUPT - Disable keyboard interruption in terminal. For example, ignoring ^Z or ^C.

start()

Grab the lower lever control of the terminal window it is on.

shutdown( restore=True )

Close the current screen and clear buffer to prevent memory leaks.

Parameters:

  • restore – If True, only discard the display buffer of the terminal window. Otherwise, remove buffer and closes all the opened input to the terminal window

Returns: None

print_at( char: str, x: int, y: int, color=7, attr=0, bg=0, transparent=False )

Print the text at the specified location using the specified colour and attributes.

Parameters:

  • char – The (single line) text to be printed.
  • x – The column (x coord) for the start of the text.
  • y – The line (y coord) for the start of the text.
  • colour – The colour of the text to be displayed.
  • attr – The cell attribute of the text to be displayed.
  • bg – The background colour of the text to be displayed.
  • transparent – Whether to print spaces or not, thus giving a transparent effect.

Returns: None

The colours and attributes are as follow. Note that not all terminal supports the colour and attributes.

COLOUR_RED = 1
COLOUR_GREEN = 2
COLOUR_YELLOW = 3
COLOUR_BLUE = 4
COLOUR_MAGENTA = 5
COLOUR_CYAN = 6
COLOUR_WHITE = 7

A_BOLD = 1
A_NORMAL = 2

get_event()

Check for any events (e.g. key-press or mouse movement) without waiting.

Returns: An Event object if anything was detected, otherwise it returns None.

refresh()

Flush the buffer to the terminal window

Returns: None

set_title( title:str )

Set the title for this terminal window. This will typically change the text displayed in the window title bar.

Parameters:

  • title – The title to be set.

Returns: None

playScene( effect_list:list, duration=-1, stop_on_resize=True, input_handler=None )

Loop through the list of effect.

Parameters:

  • effect_list – The list of preset effect to be playes
  • duration – The amount of time the scene will play for. A value of –1 means don’t stop.
  • stop_on_resize – Whether to stop when the screen is resized. Default is to carry on regardless – which will typically result in an error.
  • input_handler – Function to call for any input. The input_handler input function just takes one parameter – the input event that was not handled.

Returns: None


class Coordinate( x:float, y:float )

A point object in a 2D space.

Parameters:

  • x – The x coordinate.
  • y – The y coordinate.

Properties:

  • x – The x coordinate in float.
  • y – The y coordinate in float.
  • x_int – The x coordinate in integer.
  • y_int – The y coordinate in integer.

translate( distance:float, angle:float )

Move the point towards a direction.

Parameters:

  • distance – The magnitude of how far the point moves.
  • angle – The direction where the point moves to

Returns: None


class MazeRunner()

main_screen()

This is the main screen of the game. The concept of Ray Tracing is used to estimate the color of a every pixel rendered from the map.

mapGenerator( difficulty:str )

Generate maze depends on the difficulty set.

Parameters:

  • difficulty – The set difficulty of the map. EASY for easy map and HARD for a more difficult map.

Returns: The maze in a list of string.

start_screen()

Display the main menu for user to see when the game starts.

wait_screen()

Display the rules and objectives of the map to the user.

result_screen()

Display the result of the round to the user

pause_popup()

Pop up a screen that pauses the game. Time is stopped also.

map_popup( player_pos:Coordinate, map:list )

Pop up a screen that shows the map of the maze, the location of the player and the location of the objective. There is a limited amount of time the user can use the map.

run()

Start the game.

end()

Shutdown the GPU object and clear up all the used memory. Exit the game.

Parameters:

  • player_pos – The coordinate object of the player.
  • map – The map of the round.

Returns: None


class StateMachine

The object that stores the machine state and is responsible for upper level state management.

Properties:

  • start_state – The initial state of the machine.

get_next_values(state, inp_key_code)

Process the input with the current state of the machine.

The extension function of get_next_values().

__screen_menu(self, state, inp_key_code)
__screen_wait(self, state, inp_key_code)
__screen_play(self, state, inp_key_code)
__screen_pause(self, state, inp_key_code)
__screen_result(self, state, inp_key_code)
__screen_map(self, state, inp_key_code)
__screen_default(self, state, inp)

Properties:

  • state – The current state of the machine.
  • inp_key_code – The input key pressed on the keyboard.

Returns:

  • next_state – The next state of the machine.
  • output – The output from the input and the current state machine.

Appendix

Development checkpoints

  • use asciimatics to try make a splash screen
######################################################################
#                                                                    #
#                                                                    #
#                                                                    #
#                                                                    #
#                                                                    #
#                                                                    #
#                                                                    #
#                                                                    #
#                                                                    #
#                                                                    #
#                                                                    #
#                                                                    #
#                                                                    #
#                       PRESS ENTER TO START                         #
#                                                                    #
######################################################################
  • make level 1 map (Bird view)

  • use get_input() to move user from the level 1 map

  • make a 3d perspective

    • Use ray collision detection. Further one less shady then the nearer one (see if can apply anti aliasing)
    • option B:
      • Use premade perspective ascii to make the map.
  • Testing

  • Optimize


Future Improvements

  1. Migrate to a more efficient programming language. Currently it performs at 20 FPS in average.
  2. Add an online leaderboard where different players can compete.

Brain Storming

User Flow

  1. click enter to start
  2. start from level 1 - 10
  3. there is a timer that starts counting
  4. level 1 is to get used to the control
  5. keyboard A, W, S, and D to move
  6. mouse dragging to rotate camera.

Focal length vs perspective

https://photo.stackexchange.com/questions/40981/what-is-the-relationship-between-size-of-object-with-distance

image-20200412140041440

About

A First Person game that runs on a terminal window. Player will get to choose between an easy maze or a difficult one. The rule is simple. Find the red door in the maze and escape as fast as possible. The player is only allowed to use the map a limited number of time. The time taken to finish a single is also recorded.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages