Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .vscode/tasks.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
"hybrid",
"pixels",
"pong",
"quickstart",
"rendererTest",
"snake",
]
Expand Down
3 changes: 2 additions & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,9 @@ Working with the example apps (each example under `examples/<name>` is its own n
- `npm run build-examples` — build the engine, then build every example (`bsc` + zip via `roku-deploy`) — output zips land in `examples/<name>/out/bge-<name>.zip`
- `npm run validate-examples` — validate the engine, then `bsc --validate --create-package=false` in every example
- `npm run clean-all` — clean the engine and every example
- `npm run create-example -- <name> ["Display Title"]` — scaffold a new `examples/<name>` from `scripts/exampleTemplate` (manifest, bsconfig, generated icon/splash images, minimal `MainRoom`), and register it in the root `.vscode/tasks.json` example picker

All of the `*-examples` scripts fan out via `scripts/examples_command.sh`, which just `cd`s into each `examples/*/` directory and runs the given command. To act on a single example, `cd examples/<name>` and run its own npm scripts directly (`npm run build`, `npm run package`) instead.
All of the `*-examples` scripts fan out via `scripts/examples.js`, which iterates every `examples/*/` directory and runs the given command in each (a failure in one example doesn't stop the others, matching the original shell scripts this replaced). To act on a single example, `cd examples/<name>` and run its own npm scripts directly (`npm run build`, `npm run package`) instead. All `scripts/*.js` tooling is plain Node (no shell scripts) so it runs the same on Windows as macOS/Linux.

There is no automated test framework/spec runner in this repo. Confidence comes from `bsc` type-checking (`npm run validate`) plus manually running an example on a real Roku or the Roku simulator via the VSCode BrightScript extension debug configurations in `.vscode/launch.json` / each example's own `.vscode/launch.json` (requires a `.env` with `ROKU_USERNAME`/`ROKU_PASSWORD`/`ROKU_HOST`, or the `Launch Simulator` config).

Expand Down
108 changes: 103 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,103 @@
# BrighterScript Game Engine

An object oriented game engine for the Roku, written in [BrighterScript](https://github.com/rokucommunity/brighterscript), and (someday) available via [ROPM](https://github.com/rokucommunity/ropm).
An object-oriented game engine **and 2D/3D drawing library** for Roku, written in [BrighterScript](https://github.com/rokucommunity/brighterscript).

This project is designed to be used with VScode.
Build a full game with entities, rooms, collisions, input, and UI - or just pull in the renderer to draw sprites, shapes, billboards, and wireframe/solid 3D models on top of your own Roku app. Same engine, use as much or as little of it as you need.

This was originally forked from [Roku-gameEngine](https://github.com/Romans-I-XVI/Roku-gameEngine) by Austin Sojka, and converted into BrighterScript. This work owes a lot to this original project!
![Asteroids example](assets/screenshots/asteroids.jpg)
![3D example](assets/screenshots/3d.jpg)
![Snake example](assets/screenshots/snake.jpg)

## Introduction
## Why BrighterScript Game Engine?

The purpose of this project is to make it easy to develop games for the Roku in an object oriented fashion. Similar to how you would with an engine such as Phaser, HaxeFlixel, Gamemaker or Unity (minus any visual software that is).
- **Object-oriented, like the engines you already know.** `GameEntity`, `Room`, and lifecycle hooks (`onCreate`, `onUpdate`, `onCollision`, `onDrawBegin`/`onDrawEnd`, ...) give you the same shape as Phaser, HaxeFlixel, GameMaker, or Unity - minus the visual editor.
- **A real 2D/3D renderer, not just sprite blitting.** Draw images, sprites, animations, shapes, text, and billboards, or render actual 3D models (loaded from `.stl`) with wireframe, solid, and shaded draw modes - all built on Roku's `roCompositor`/`Draw2D`, so it runs on real hardware.
- **Built-in collisions, input, UI, and debug tooling.** Circle/rectangle colliders, a retained-mode UI widget tree, and debug overlays (FPS, colliders, memory, GC stats) come standard, so you're not rebuilding the basics for every project.
- **Use only what you need.** The `Renderer`/`Canvas` layer works standalone if you just want a capable drawing library for an existing Roku app, without adopting the full game loop.
- **Develop without a physical Roku.** This engine supports running under the [BrightScript Simulator](https://github.com/lvcabral/brs-desktop), Marcelo Lv Cabral's desktop BrightScript simulator, so you can iterate on your game without deploying to hardware every time.

## A quick taste

```brightscript
sub main()
game = new BGE.Game(1280, 720)
game.fitCanvasToScreen()
game.loadBitmap("player", "pkg:/sprites/player.png")

room = new MainRoom(game)
game.defineRoom(room)
game.changeRoom(room.name)

game.play()
end sub
```

```brightscript
class MainRoom extends BGE.Room

sub new(game as BGE.Game)
super(game)
m.name = "MainRoom"
end sub

override sub onCreate(args as roAssociativeArray)
m.game.addEntity(new Player(m.game))
end sub

end class
```

```brightscript
class Player extends BGE.GameEntity

sub new(game as BGE.Game)
super(game)
m.name = "Player"
end sub

override sub onCreate(args as roAssociativeArray)
m.position = m.game.canvas.renderer.getCanvasCenter()
bitmap = m.game.getBitmap("player")
region = CreateObject("roRegion", bitmap, 0, 0, bitmap.GetWidth(), bitmap.GetHeight())
m.addImage("sprite", region)
m.addCircleCollider("body", bitmap.GetWidth() / 2)
end sub

override sub onInput(input as BGE.GameInput)
m.velocity.x = input.x * 10
m.velocity.y = input.y * 10
end sub

override sub onCollision(myCollider as BGE.Collider, otherCollider as BGE.Collider, otherEntity as BGE.GameEntity)
m.game.postGameEvent("player_hit", {by: otherEntity})
end sub

end class
```

This exact code lives in [`examples/quickstart`](examples/quickstart) as a runnable app. See the [Documentation](https://markwpearce.github.io/brighterscript-game-engine) for the full API, and the examples below for complete, runnable projects.

## Examples

The `examples/` directory has full Roku channels you can build and run:

| Example | What it shows |
| --- | --- |
| [`quickstart`](examples/quickstart) | The minimal `MainRoom`/`Player` example from above, as a runnable app |
| [`asteroids`](examples/asteroids) | A complete 2D game - player movement, bullets, collisions, particle-style explosions, sound |
| [`pong`](examples/pong) | Classic 2D Pong, playable in both 2D and 3D camera modes |
| [`snake`](examples/snake) | Grid-based movement and growing collision shapes, in 2D and 3D |
| [`3d`](examples/3d) | Loading and rendering `.stl` 3D models with the pseudo-3D renderer |
| [`pixels`](examples/pixels) | A tour of drawables - polygons, rectangles, sprites, and more, one room per shape |
| [`canvas`](examples/canvas) | Using the engine's canvas/renderer as a standalone drawing surface |
| [`hybrid`](examples/hybrid) | Mixing this engine's Draw2D-based rendering with a SceneGraph app |
| [`rendererTest`](examples/rendererTest) | A manual test harness used while developing the renderer itself |

Scaffold a new example (manifest, icons/splash, `package.json`, a minimal `MainRoom`) with:

```
npm run create-example -- <name> ["Display Title"]
```

## Cloning and Running Examples

Expand Down Expand Up @@ -80,3 +169,12 @@ ropm install bge@npm:brighterscript-game-engine
## Documentation

Documentation can be found [here](https://markwpearce.github.io/brighterscript-game-engine)

## Acknowledgements

This project was originally forked from [Roku-gameEngine](https://github.com/Romans-I-XVI/Roku-gameEngine) by Austin Sojka, and converted into BrighterScript. This work owes a lot to this original project!

Thanks also to:

- [RokuCommunity](https://github.com/rokucommunity) for [BrighterScript](https://github.com/rokucommunity/brighterscript), [bslint](https://github.com/rokucommunity/bslint), [roku-deploy](https://github.com/rokucommunity/roku-deploy), and the rest of the tooling that makes this project possible.
- [Marcelo Lv Cabral](https://github.com/lvcabral) for his work on the Roku/BrightScript community and tooling, including the [BrightScript Simulator](https://github.com/lvcabral/brs-desktop) this engine supports developing against.
Binary file added assets/screenshots/3d.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/screenshots/asteroids.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/screenshots/snake.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
32 changes: 32 additions & 0 deletions examples/quickstart/.vscode/launch.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
{
"version": "0.2.0",
"configurations": [
{
"type": "brightscript",
"request": "launch",
"name": "Example Game - Quickstart Debug: Launch",
"stopOnEntry": false,
"host": "${promptForHost}",
"password": "${promptForPassword}",
"rootDir": "${workspaceFolder}/dist/",
"preLaunchTask": "build",
"enableDebuggerAutoRecovery": true,
"stopDebuggerOnAppExit": true,
"injectRaleTrackerTask": true
},
{
"type": "brightscript",
"request": "launch",
"name": "Example Game - Quickstart Debug: Launch From ENV",
"stopOnEntry": false,
"envFile": "${workspaceFolder}/../../.env",
"host": "${env:ROKU_HOST}",
"password": "${env:ROKU_PASSWORD}",
"rootDir": "${workspaceFolder}/dist/",
"preLaunchTask": "build",
"enableDebuggerAutoRecovery": true,
"stopDebuggerOnAppExit": true,
"injectRaleTrackerTask": true
}
]
}
7 changes: 7 additions & 0 deletions examples/quickstart/.vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"files.exclude": {
"node_modules": true,
"out": true,
"roku_modules": true
}
}
25 changes: 25 additions & 0 deletions examples/quickstart/.vscode/tasks.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
{
"version": "2.0.0",
"tasks": [
{
"label": "ropm",
"command": "ropm",
"type": "shell",
"group": {
"kind": "build",
"isDefault": true
},
"args": ["install"]
},
{
"label": "build",
"command": "npm",
"type": "shell",
"group": {
"kind": "build",
"isDefault": true
},
"args": ["run", "build"]
}
]
}
18 changes: 18 additions & 0 deletions examples/quickstart/bsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"extends": "../../bsconfig.json",
"rootDir": "src",
"outDir": "build",
"files": [
"**/*",
{
"src": "../../../src/**/*",
"dest": "source/roku_modules"
}
],
"emitDefinitions": false,
"diagnosticFilters": [
{
"files": "../../../src/source/roku_modules/**/*"
}
]
}
7 changes: 7 additions & 0 deletions examples/quickstart/bslint.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"rules": {
"named-function-style": "off",
"inline-if-style": "never",
"type-annotations": "all"
}
}
Loading
Loading