1.0.2 • Published 4 years ago

game-ml v1.0.2

Weekly downloads
2
License
ISC
Repository
github
Last release
4 years ago

Quick Game Markup Language

npm.io

QGML is a tool that allows you to structure your game with an HTML-like language and script it using JavaScript.

What it is

a quick way to prototype little web games

What it isn't

a fully-fledged game engine meant for polished games

Installation

$ npm i -g @qgml/cli

CLI Quick Start

Compilation

$ qgml --source myFile

Serve

$ qgml --source myFile --serve 8000

This will serve the compiled game at localhost:8000

note: serving also provides hot-reloading, so, if you modify the qgml file it should automatically reload and apply the changes in your web browser

For a full list of commands use

$ qgml --help

Quick Start

<qgml
	width = 300
	height = 300
>
	<world default>
		<actor
			id = "my-rect"
			state = ({
				position: { x: 20, y: 20 },
				size: { width: 50, height: 50 },
				color: 'blue'
			})
		/>
	</world>
</qgml>

pro tip: you can save qgml files as .html so that you get syntax highlighting in your favourite code editor!

Tags

QGML

<qgml></qgml>

Think of this as the root element; all other tags are children of it. It contains the configuration for the canvas

Props

propdata typedescription
widthnumberthe width of the canvas (default: 300)
heightnumberthe height of the canvas (default: 300)
rootElementIDstringthe id of the HTML element in your web page that the canvas should be appended to (default: 'qgml-game')

World

<world></world>

Worlds are basically screens or scenes in your game; an example of worlds would be menu, level1, level2

Props

propsdata typedescription
idstringthe id of the world; this will be used in scripting to switch between worlds
defaultbooleanif this prop is present the world will be the one loaded as soon as the game starts. If your game has a menu screen, that one would be the default world

Actor

<actor/>

An actor is anything that appears on the screen: the player, the ground, an object, etc

actor is a self closing tag because it cannot contain anything itself.

Props

propdata typedescription
idstringthe id of the player; this is useful if you want to do anything in script to this actor
stateobjecta state object
spritestringthe path relative to the qgml file to an image file
animatorobjectan animator object
setupfunctiona function that is called once when the world is loaded
updatefunctiona function that is called every frame

Animator

The animator overrides the sprite prop. This is used to add animations to certain actors

propertydata typedescription
spritesheetsobjectthe spritesheets object
Spritesheets
spritesheets: {
    idle: {
        frames: ['path/to/frame0', 'path/to/frame/1', etc],
        frameTime: 10
    },
    //or
    run: {
        strip: 'path/to/animation/strip.png',
        frames: 8,
        frameTime: 10
    },
    etc
}

frames - an array containing the relative paths to frames (images) or the number of frames in a strip

frameTime - the number of game ticks (frames) each animation frame should stay on screen 1 - change each frame (fastest), 10 - change every 10 frames, etc

strip - the path to an animation strip

! Note about setup and update

If the function you pass to setup or update uses classic notation (function () { ... }), the context within it (this) will be the actor itself; so, you will be able to write this.state.position which will return the actor's position, or this.animator which will return the actor's animator.

If the function you pass uses arrow notation (() => { ... }), the context (this) will be the QGML context.

TLDR: it is recommended that you use classic notation for functions passed to setup and update

Group

<group>{children}</group>

Groups can be used to group together multiple Actors or Groups so that they can move all at once.

Props

propdata typedescription
idstringjust like the id of an actor, this can be used to access this group in a script
stateobjecta state object
setupfunctiona function that is called once when the world is loaded
updatefunctiona function that is called every frame

Modifying a group's position will move all of its children accordingly

<group id = "player">
	<actor id = "player-body"/>
	<group id = "nested" >
		<actor/>
	</group>
</group>

! Note about setup and update

If the function you pass to setup or update uses classic notation (function () { ... }), the context within it (this) will be the group itself; so, you will be able to write this.state.position which will return the group's position.

If the function you pass uses arrow notation (() => { ... }), the context (this) will be the QGML context.

TLDR: it is recommended that you use classic notation for functions passed to setup and update

Var (Variables)

<var name = value />

Variables declared in a certain World are only accessible in that world, while variables declared outside of all worlds are considered global and can be accessed and modified from any world.

A single var tag can be used to declare multiple variables, for example

<var
	score = 0
	playerPosition = {
		x: 0,
		y: 0
	}
	playerName = "base name"
/>

Text

<text>text to display</text>

It is used to display text on the canvas

propdata typedescription
stateobjecta state object
fontstringthe name of a web-safe font or the name of a font that you're already loading on your web page

You can use placeholders inside of it to display the values of variables

<text state = { position: { x: 50, y: 100 } }>
	hello! your position is ${playerPosition.x} , ${playerPosition.y}
	and your score is ${score}
</text>

State Objects

propertydata typedescriptionapplies to
positionObject { x : Number, y : Number}the initial positionactor, group, text
sizeObject { width: Number, height: Number }the initial actor sizeactor
sizeNumberthe font sizetext
colorStringthe fill coloractor, text
strokeObject { weight: Number, color: String }the stroke / outlineactor, text
styleStringthe style of the texttext
alignStringthe text alignmenttext

color

any of the following formats are okay:

  • "rgb(255, 125, 60)"
  • "rgba(0, 25, 125, 0.5)"
  • "rgba(0,0,0,0)"
  • "red", "blue", "lightblue", etc.
  • if color is omitted or set to false the rectangle will be transparent

style

  • "normal"
  • "bold"
  • "italic"
  • "bolditalic"

align

  • "right"
  • "center"
  • "left"

Modifying the state in script

The state of an actor or group cannot be altered after compilation, but you can use variables instead of literal values for any of the properties, or for the whole state object

<var
	playerState = {
		position: {
			x: 0,
			y: 0
		},
		size: {
			width: 20,
			height: 60
		},
		color: 'gray'
	}
/>
<actor
	id = "player"
	state = playerState
/>

or

<var
	playerPosition = {
		x: 15,
		y: 85
	}
/>
<actor
	id = "player"
	state = {
		position: playerPosition,
		size: {
			width: 50,
			height: 50
		}
	}
/>

Keymapper

<keymapper/>

The keymapper is used to bind functions to certain keyboard events. Keymappers are specific to the world they are declared inside.

Each prop has the following structure: <key or group of keys>|<event> = (<function>)

key:

  • literal value of the key (w, a, s, d, etc)
  • keycode of the key (32, 87, etc)
  • one of the following special keys: backspace, delete, enter, return, tab, escape, shift, control, option, alt, up_arrow, down_arrow, left_arrow, right_arrow, space

group of keys

it's represented as [<key>,<key>,<key>,...]

event - for keys

  • down - will fire every frame while the key is held down

  • up - will fire every frame while the key is not held down

  • pressed - will fire once when the key is pressed DEFAULT

  • released - will fire once when the key is released

event - for groups of keys

  • down - will fire every frame while all the keys are held down

  • up - will fire every frame while none of the keys are held down

  • pressed - will fire once after each key has been pressed at least once

  • released - will fire once after every key has been released

example:

<keymapper
	a|down = (() => {
		console.log ('this will fire every frame while the A key is down');
	})
    
	space|pressed = (() => {
		console.log ('this will fire every time space is pressed');
	})
    
	16|released = (() => {
		console.log ('16 is the keycode for shift so this will fire everytime shift is released');
	})
    
	[q,e]|up = (() => {
		console.log ('this will fire every frame while Q and E are both up');
	})
/>

Script

<script></script>

Scripts are used to add JavaScript code that is executed either in setup (once, when the world is loaded) or in update (every frame)

Scripts are specific to the world they are declared in.

<script setup>
	console.log ('this is executed once when the world is loaded');
</script>
<script update>
	console.log ('this is executed every frame');
</script>

API

Actors

getActor (id: String) - returns the actor with the specified ID

<Actor>.state - returns the state of the actor - this is read-only, the state is not meant to be modified

<Actor>.direction - returns the direction that actor is facing on both axis

getPosition (actor: Actor) - returns a { x: Number, y: Number } object of the actor's position

<Actor>.direction.set (axis: String, value: String || Number)

  • axis can be either 'horizontal' or 'vertical'
  • value can be:
    • 'left' or -1 - for axis == 'horizontal'
    • 'right' or 1 - for axis == 'horizontal'
    • 'up' or 1 - for axis == 'vertical'
    • 'down' or -1 - for axis == 'vertical'

<Actor>.flip.horizontal () - flips the direction horizontally

<Actor>.flip.vertical () - flips the direction vertically

<Actor>.animator - returns the animator of an actor

Animator

<Animator>.set (animation: String) - sets the animator's animation to the specified one (ex: 'idle', 'run' - depending on how you declared the animator)

Group

getGroup (id: String) - returns the group with the specified ID

<Group>.state - returns the state of the group - this is read-only, the state is not meant to be modified

getPosition (group: Group) - returns a { x: Number, y: Number } object of the group's position

Entity

Entity = either Actor or Group

dist (x1: Number, y1: Number, x2: Number, y2: Number) - returns the distance between the points (x1, y1) and (x2, y2)

dist (e1: Entity, e2: Entity) - returns the distance between the two entities' positions