Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
mboleary committed Apr 13, 2020
1 parent f9f2893 commit 1ed2e7b
Show file tree
Hide file tree
Showing 18 changed files with 549 additions and 0 deletions.
21 changes: 21 additions & 0 deletions docs/Reference.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
https://developer.mozilla.org/en-US/docs/Games/Anatomy

https://developer.mozilla.org/en-US/docs/Web/API/WebGL_API/Tutorial/Adding_2D_content_to_a_WebGL_context

https://developer.mozilla.org/en-US/docs/Web/API/WebGL_API/Tutorial/Getting_started_with_WebGL

https://developer.mozilla.org/en-US/docs/Web/API/ImageBitmap

https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D
Look into converting this int WebGL later

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Reflect
Might be useful for constructing the Puppeteer

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Meta_programming

https://gist.github.com/jed/982883
UUID Generation

https://github.com/websockets/ws
Might be good for a WebSocket Server for the backend
44 changes: 44 additions & 0 deletions docs/TODO.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# TODO

## Puppeteer

Write the Websocket client to communicate with the remote server

- Specify a player ID

- Send and recieve updates through the web worker, which should abstract all of the authentication stuff away

## Engine

Finish the Base requirements of the Engine

- Delta Time

- Ability to run scripts from GameObjects

- Ability to add and remove GameObjects from the playfield

- Input System to capture the state of the controller every frame

- Provide API to make adding scripts to a GameObject through extending the GameObject class easier

## Level System

- Block Chunks

- Layers

- Importing data from a remote source
- Part of web worker

- Removing layers when there is nothing left on them

## Physics

- Implement collision detection

- Implement Colliders

## Scripting

- (Future) - Provide a Block-based API for Scripting
9 changes: 9 additions & 0 deletions frontend/CONFIG.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
/**
* System Configuration. Edit this to change where the backend should point to and such
*/

window.CONFIG = {
"branch": "testing",
"debug": true,
"backend": "localhost:8080"
}
Binary file added frontend/asset/test.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
16 changes: 16 additions & 0 deletions frontend/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<!Doctype html>
<html>
<head>
<title>Web Game Test</title>
<script src="CONFIG.js"></script>
<script type="module" src="/script/main.js"></script>
<link rel="stylesheet" href="/style/main.css">
<meta charset="utf-8">
</head>
<body>
<canvas id="canvas"></canvas>
<div id="overlay">
<div>Overlay</div>
</div>
</body>
</html>
68 changes: 68 additions & 0 deletions frontend/script/engine/Engine.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
/**
* Engine contains the basic framework for the game engine
*/

import { renderGameObjectsWith2dContext, initializeWith2dContext } from './Render.js';

let gameLoopStarted = false;
let stopLoop = null; // Magic reference to stop the game Loop
let currScene = null; // Current Scene to be rendering

let gameObjects = []; // Game Objects to process each loop
let gameObjectsIDs = new Set(); // Contains all GameObject IDs onscreen

export function initGameLoop() {
if (!currScene) throw new Error("You must select a Scene First!");
initializeWith2dContext();
gameLoopStarted = true;
main();
}

export function setCurrentScene(scene) {
currScene = scene;
let gos = scene.gameObjects;
gos.forEach((go) => {
enrollGameObject(go);
})
}

export function enrollGameObject(go) {
if (!go) return;
// Check for ID
if (gameObjectsIDs.has(go.id)) return;
gameObjects.push(go);
gameObjectsIDs.add(go.id);
}

export function deleteGameObject(go) {
if (!go) return;
if (!gameObjectsIDs.has(go.id)) return;
setTimeout(() => {
gameObjectsIDs.delete(go.id);
// for ( let i = 0; i < gameObjects.length; i++) {
// let item = gameObjects[i];
// if (item.id === go.id) {

// }
// }

// @TODO Test this
gameObjects.splice(gameObjects.indexOf(go), 1);
});
}

// Game Loop
function main() {

stopLoop = window.requestAnimationFrame(main); // Puts this function into the message queue

// Render the Game Field
renderGameObjectsWith2dContext(gameObjects);

// Get Input

// Run the GameObject Scripts

// Do GameObject Physics

}
40 changes: 40 additions & 0 deletions frontend/script/engine/GameObject.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/**
* Definitions for a GameObject
*/

import Transform from './Transform.js';
import uuid from './UUID.js';

export default class GameObject {
constructor() {
// Public
this.scripts = [];
this.colliders = []; // @TODO Figure out a good way to build colliders
this.texture = null; // @TODO Add a texture here
this.transform = new Transform();
this.children = []; // Child GameObjects whose transformation will be relative to that of this GameObject
this.name = ""; // NAme of the GameObject

// Private @TODO find a way to trim out these variables from scripts
this.id = uuid(); // This should be unique, as this is how the gameObject will be serialized
this.zIndex = 0; // Used for order of rendering in 2D
this.priority = 0; // Determines the priority of the scripts.
this.parent = null; // Contains reference to the Parent GameObject
this.deleteFlag = false; // True if the GameObject should be destroyed.
}

attachGameObject(go) {
go.parent = this;
this.children.push(go);
}

// // Queue this GameObject for deletion
// destroy() {

// }

// // Add a script during runtime, and enroll in the engine
// addScript() {

// }
}
3 changes: 3 additions & 0 deletions frontend/script/engine/Input.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
/**
* Provides Input management for the Game Engine
*/
94 changes: 94 additions & 0 deletions frontend/script/engine/Puppeteer.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
/**
* Puppeteer is responsible for syncing the state of a GameObject across a network connection
*/

let defaultUpdateFrames = 5; // Default frame delta to update everything

/**
* Defines a Puppet
* @param {Class} Base Base Class to convert into a Puppet
* @param {Boolean} master True if this is the master
* @param {Number} updateFrames Number of frames to update after
*/
export const Puppet = (Base, master, updateFrames) => class extends Base {
constructor(...params) {
super.constructor(...params);

// Private
this.master = master || false; // If True, this the state will be sent from this Puppet to the remote ones
this.keysToUpdate = [];
this.loopsSinceLastUpdate = 0; // Count the loops since the last update
this.updateFrames = updateFrames || defaultUpdateFrames;

// Change GameObject Settings
if (!this.master) {
this.priority = 0;
this.id = "";
}
}

// True when this Puppet needs an update
needsUpdate() {
return loopsSinceLastUpdate > updateFrames;
}

// returns a list of keys to update when the Puppeteer provides a state update
initState() {
if (super.initState) {
return super.initState();
}
return Reflect.ownKeys(this);
}

// Get the current State of the Master Puppet
getState() {
this.loopsSinceLastUpdate = 0;
if (super.getState) {
return super.getState()
}
let toRet = {};
this.keysToUpdate.forEach((key) => {
toRet[key] = Reflect.get(this, key);
});
return toRet;
}

// Set the current state of the slave puppet
updateState(state) {
this.loopsSinceLastUpdate = 0;
if (super.updateState) {
return super.updateState(state);
}
Object.keys(state).forEach((key) => {
if (keysToUpdate.indexOf(key) > -1) {
Reflect.set(this, key, state[key]);
}
});
}

loop() {
this.loopsSinceLastUpdate++;
if (super.loop) {
super.loop();
}
}
}

// Converts an instance into a Puppet
export function convertInstanceIntoPuppet(instance) {
if (!instance) return null;
if (instance instanceof Puppet) return instance;
let prevState = Reflect.ownKeys(instance);
let toRet = new Puppet(instance.constructor, true);
Reflect.apply(toRet, prevState);
return toRet;
}

export function disablePuppetUpdates(instance) {
if (!instance) return null;
if (!instance instanceof Puppet) return instance;
instance.needsUpdate = () => {
return false;
}
return instance
}
21 changes: 21 additions & 0 deletions frontend/script/engine/Render.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/**
* Renders the GameObjects from the Engine
*/

import { canvas } from '../ui.js';

let context = null; // This is the context that will be used to render the game.

export function initializeWith2dContext() {
context = canvas.getContext('2d');
}

export function renderGameObjectsWith2dContext(gos) {

gos.forEach((go) => {
if (go.texture) {
let pos = go.transform.position;
context.drawImage(go.texture, pos.x, pos.z);
}
})
}
42 changes: 42 additions & 0 deletions frontend/script/engine/Scene.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/**
* A Scene contains the GameObjects for a particular part of the game.
*/

import GameObject from './GameObject.js';

export default class Scene extends GameObject {
constructor() {
super();
}

// Get all GameObjects from this scene
get gameObjects() {
let toRet = getGameObjectChildren(this);
toRet.push(this);
return toRet;
}
}

function getGameObjectChildren(go) {
let toRet = [];
if (go && go.children && go.children.length) {
go.children.forEach((child) => {
toRet.push(child);
let res = getGameObjectChildren(child);
if (res && res.length) {
res.forEach(item => toRet.push(item));
}
});
}
return toRet;
}

// Gets all GameObjects with Scripts
export function GetGameObjectsWithScripts(gos) {
let toRet = [];
gos.forEach((go) => {
if (go.scripts && go.scripts.length) {
toRet.push(go);
}
});
}

0 comments on commit 1ed2e7b

Please sign in to comment.