Skip to content

An adventure game engine in the 1980's pixelstyle, built on React.js via Create React App. Playable in its current form with an included sample game. Use the arrow keys to move the hero around! 👾⌨️

Notifications You must be signed in to change notification settings

PatD/react-adventure-game-engine

Repository files navigation

Netlify Status

Thanks for checking out React Adventure Game Engine (R.A.G.E.), a browser-based, retro game engine built on React.js. Games developed in this engine will play in a modern web browser.

A React.js game engine - and a tribute to 1980s adventure games

This game engine is heavily derived from 1980/90's graphic adventure computer games. Games with four (CGA) or sixteen (EGA) color graphics, driven with arrow keys for player movement and a text parser for executing game commands.

⬆️⬇️⬅️➡️

Creating your first game

This is a Create React App project (not ejected). The engine itself is in the /src folder and the games themselves live in /public/games.

  1. Clone the repo, and start the Create-React-App project with npm start
  2. Create a copy of /public/games/gameTemplate in the /public/games folder. Rename the folder to something like the title of your game. This folder will contain code, styles, and assets specific to your game.
  3. Update the references to it in /public/games/gamelist.json.
{
    "Title": "My awesome adventure game",
    "Path": "../games/awesomegame/gamedata.json",
    "CSS": "../games/awesomegame/gameassets/gameStyles.css",
    "JS":"../games/awesomegame/gameassets/gameLogic.js"
}

In your new game folder, you'll find folders and files ready to edit:

  • /public/games/<folder name>/gamedata.json - A single JSON object containing game metadata (title, description), room data, display objects, inventory, main menu items, and hero graphic dimensions.

  • /public/games/<folder name>/gameassets/ - This folder will hold game-specific images, music files, code, and your custom CSS.

  • /public/games/<folder name>/gameassets/gameLogic.js - All non-engine logic code can live in here. In here you'll find two starter functions, one that fires when a room is loaded, and another that listens for test parser input and routes it to either in-engine responses or custom responses in this file.

  • /public/games/<folder name>/gameassets/gameStyles.css - You can use this file to reference all your graphic assets - backgrounds, objects, animations, etc. On load, the game automatically parses every image in there and loads it into the browser cache for faster loading.

In the /src folder you'll find the game engine itself. It's set up such that no changes are needed in this folder to make a game.

In theory, your could run a game without anything a gameLogic.js - the engine will build out the rooms in gamedata.json. Your hero could walk around and look at things, get things, and enjoy the scenery.

Building your game

npm run build or the build function of Create-React-App will build the game out to the /build folder. At this point you can deploy (or upload) it to your web host of choice.

Configuration over code

The gamedata.json file is a single, giant nested object. Here are some important parts of it:

Inventory items:

    "inventory": [
        {
            // Name as it appears in game inventory
            "Name": "Taco",   

            // CSS class applied to the div that's rendered.  Use this to apply an image to it
            "cssName": "taco",

            // If the player has the item in inventory
            "owned": false,

            // If the player can pick it up yet or not.
            "available": true,

            // Text for the modal when you look at the item
            "Description": "You see a delicous taco and want nothing more than to eat it.",
            
            // What room the item exists in
            "FoundRoom": 3,

            // Shown on the screen or not
            "Visible": true,
            "x": 290,
            "y": 480,
            "zIndex": 5,
            "width": 60,
            "height": 40
        },

Rooms

Each game scene is considered a room. Each room has a name, description, defined exits (top, bottom, left, right) and display objects. Display objects are the scenery in the room. A chair or a door. Display objects can also be the invisible walls the walking character bumps into.

    "rooms": [
        {
            "Name": "Sample Room",
            "Description": "The text displayed when character types 'look room'.",
            
            // Room number must be unique.
            "Room": 2,

            // These two are just for the title screen room
            // no exists or displayObjects are needed in that room:
            "titleScreen":true, 
            "gameStartRoomNumber":2,

            // Side of the room the character starts on
            "starting": "left",

            // Hot spots that send the character to another room. 
            // Each hot spot is an object inside this array
            "roomExits": [
                {
                    "exit": "left",
                    "goto": 10,
                    "width": 3,
                    "height": 75,
                    "x": 220,
                    "y": 0
                }
            ],

            // Things shown (or are invisible) on screen
            "displayObjects": [
                {
                    "Name": "Some character",
                    "Description": "You see a guy in a space-looking jump suit",
                    "id": "npcSpaceMan",
                    "NPC": true, // usually false
                    // "NPCdefaultText" can be a string for a single line, or an object for many dialog boxes.
                    "NPCdefaultText": [
                        {
                            "modalText": "Well HELLO fellow space enthusiast!",
                            "modalWidth": 500,
                            "modalTop": 200
                        },
                        {
                            "modalText": "Make no mistake, YOU have arrived at the right cargo bay for space action and adventure",
                            "modalWidth": 300,
                            "modalTop": 220
                        },
                        {
                            "modalText": "Come back and find me when you have the keycard. That's what you'll need to go on your adventure!",
                            "modalWidth": 450,
                            "modalTop": 180
                        }
                    ],

                    // Stops the player if they walk into the object
                    "colide": true,
                    
                    "width": 28,
                    "height": 66,
                    "x": 150,
                    "y": 530,
                    "zIndex": 2,

                    // Applies color or CSS class to the object. 
                    "bgcolor": "#EFEFEF",
                    "class": "dither_bottom"

                    // Use "bgcolor": "none" to make an invisible hit area.


                }
            ]
        }
    ]

What's tracked in game state

In the root component (app.js), state drives the user interface and interactivity. Every component and custom function serves to update state, and React renders the game based on that.

General game state

State Type Notes
title string Game title
subTitle string Game sub title
description string Game description, shown in 'About' menu link
version number Game version, shown in 'About' menu link
pausedgame boolean Is the game paused or not
soundOn boolean Sound on (true) or muted (false)
menuBarActive boolean When false, the main menu is closed, when true it is open.
mainMenuItems array An array objects to define the main menu. A reasonable default is provided by the engine.
inventory array An array of objects, the player's game inventory and whether they have it on them or not
inventoryVisable boolean If false, the inventory interface is closed. If true, it is shown
highScore number Maximum possible score in the game. Shown in the UI
currentScore number Player's current score.
gameLogic string Path to custom JS file for the game.
playfieldX number Width of the game play area.
playfieldY number Height of the game play area.
textParserValue string whatever is currently on screen in the text parser
submittedText string Value of the text that is submitted when player hits 'enter'
helpText string Help text for the game, shown when player types 'help' or selects help from menu
flags object Free-form keyvalue store to mark progress in the game.

Hero state

State Type Notes
heroHeight number Hero height in pixels
heroWidth number Hero width in pixels
heroSprite string Base64 enocded version of hero graphic sprite. Like "url('data:image/png;base64,iVBORwc..." except way longer.
heroAlive boolean Alive (true) or dead (false)
heroDirection string Current direction, one of four values ArrowLeft, ArrowRight, ArrowUp, ArrowDown
heroLastDirection: string The previous direction the hero character is facing
heroMoving string One of two values, either moving or stopped
heroPositionX number Current position of player, relative to top edge of the play area
heroPositionY: number Current position of player, relative to left edge of the play area
heroPositionCollided boolean Has the player collided with an object?
heroMovementDisance number Configurable number to control how far hero moves each render
heroMovementUpdateSpeed: number Configurable number to control speed hero moves each render
heroMovementSpeeds array Array of numbers used by speed setting in main menu

Modal dialog box state

State Type Notes
modalStatus boolean When true, the modal is open. When false it is closed
modalClickToClose boolean When true, the modal is open. When false it is closed
modalWidth number Width of the modal. Height cannot be set.
modalTop number Distance of the modal from the top of the screen.
modalWidthDefault number When the modal is reset, this number is re-applied to modalWidth
modalTopDefault number When the modal is reset, this number is re-applied to modalTop
modalText string Modal text. Most of the time, you'll just use this one. The other three slots are optional.
modalTextSlot2 string 2nd line of modal text (if passed)
modalTextSlot3 string 3rd line of modal text (if passed)
modalTextSlot4 string 4th line of modal text (if passed)
modalTextScript array An array of objects, passing mulitple lines of dialog to be shown in sequence.
modalConfirmation string A string of text that is used to optionally execute code after the user hits enter in a modal box.

Room-related state

State Type Notes
rooms array Array of objects. All the rooms in the game. Probably the biggest object in the game.
roomExits array Array of objects. Defines where on the screen the hero exits the room and moved to the next room by the game engine
roomCurrent string Name of the current room, per its name in gamedata.json
roomPrevious string The prior room the user was in
roomCurrentObjects array Array of objects, all the scenery and trees and images in a room. Not for inventory items
roomVisibleInventory array Array of objects of inventory items that are visible on screen
roomNearbyInventoryItems array Array of strings. Inventory items that are close enough for the player to get.

Built in keyboard controls

In the spirit of the 1980s, this engine is strictly keyboard driven. No mouse support is provided. The engine's functions are coded to suport:

  • Tab key opens the inventory (and any other key closes it)
  • Escape key
    • Opens the main menu
    • Closes the main menu (if it is open)
    • Dismisses any open modal dialog box
  • Enter key:
    • Dismisses an open modal dialog box
    • Submits text parser words
    • Selects a main menu item
    • Confirms a choice modal dialog box action (like saving or loading a saved game)
  • Arrow keys (not WASD):
    • Move the hero character around the screen
    • Controls the main menu when open
    • Diagonals on the num pad aren't supported currently

Text command input

As the player adventures around, they must ineract with their environment. Since no mouse support is provided, the player must type commands like open door or get the taco or give taco to horse to make progress in the same.

There is built in support for these commands:

  • Get - As in "get taco" or "get the keycard". There's support for getting any item in the gamedata.json Inventory array, as long as the room matches. Error messaging is available for when items aren't in the right room.
  • Help - Opens a modal dialog box with the help text from gamedata.json.
  • Inventory - Opens the inventory screen.
  • Look - As in "look" or "look at the monster". There's support for just typing it alone, as well as support for looking at any display object in gamedata.json.
  • Talk - As in "talk to blacksmith". As long as the NPC is labled as such in the gamedata.json file, a reponse with automatically be returned. There's error handling for players to try to talk to inanimate objects.

There's support for custom commands as well. The engine will check

FAQ

How does the engine work?

Most of the game's current status (player position on screen, inventory, flags) is maintained, during play, in app.js' state. Most components and custom code work to update this root-level state. There are probably enough things tracked in state aross multiple components to justify using some state management system, but that was overhead I didn't want in this learning effort.

But... why?

The primary reason was to give me a chance to learn React without making a CRUD form or TODO list. I hoped a game engine would afford me a much broader awareness of why people used React.js over vanilla JavaScript.

Why didn't you use?

There are a ton of great React libraries and tools that would have made this effort significantly easier. But learning and understanding require doing the hard part first, before you can appreciate the value of a good state management library or animation library.

Should I use it to make a game?

I mean, why not? If 1980s style advernture games are the style you want to mimic, and you're already comfortable with HTML5, CSS, JavaScript (especially reactive JavaScript frameworks like React and Vue), this might be the engine for you. It doesn't promise 60FPS, nor state of the art 3d graphics.

About

An adventure game engine in the 1980's pixelstyle, built on React.js via Create React App. Playable in its current form with an included sample game. Use the arrow keys to move the hero around! 👾⌨️

Topics

Resources

Security policy

Stars

Watchers

Forks

Releases

No releases published