From f3808251ff8a464062f6f75674b64e88d85d167b Mon Sep 17 00:00:00 2001 From: Marak Date: Mon, 6 Nov 2023 23:11:06 -0500 Subject: [PATCH] Adds Camera config option to new Game() Updates PhysX path, add additional ready guard Removes un-used debug GUI from CSSGraphics Switches default scriptRoot to yantra.gg CDN Updates ReadMe --- ReadMe.md | 9 ++- mantra-client/public/mantra.css | 38 ------------ mantra-game/Game.js | 14 +++-- .../plugins/graphics-css/CSSGraphics.js | 58 ++++++------------- .../plugins/physics-physx/PhysXPhysics.js | 20 ++++++- 5 files changed, 50 insertions(+), 89 deletions(-) diff --git a/ReadMe.md b/ReadMe.md index 5af52c5d..cff5dd6c 100644 --- a/ReadMe.md +++ b/ReadMe.md @@ -43,7 +43,7 @@ Mantra's default 3D graphics are rendered using WebGPU and Babylon.js. Mantra's ### Matter.js + Phaser 3 -For 2D, Mantra has built-in support for Phaser 3 and Matter.js. It's possible to mix and match configuration options and easily add new Graphics plugins. You can even render the same Game through [multiple graphics pipelines](https://yantra.gg/mantra/examples/solo/split-render/pong.html) at once if you need to. +For 2D, Mantra has built-in support for Phaser 3 and Matter.js. It's possible to mix and match configuration options and easily add new Graphics plugins. You can render Mantra games [entirely in CSS](https://codepen.io/Marak-Squires/pen/abXpEve). You can even render the same Game through [multiple graphics pipelines](https://yantra.gg/mantra/examples/solo/split-render/pong.html) at once if you need to. **How is this even possible?** @@ -57,9 +57,7 @@ Mantra is designed to start a full-featured local game instance immediately with ## Serverless Physics -Mantra is architectured from the ground up to work within Serverless environments like CloudFlare Workers or [Hathora](https://hathora.dev). - -This unique architecture places Mantra at the forefront of Serverless Physics game engines. +Mantra is architectured from the ground up to work within Serverless environments like [CloudFlare Workers](https://github.com/yantra-core/mantra/tree/master/mantra-edge) or [Hathora](https://hathora.dev). This unique architecture places Mantra at the forefront of Serverless Physics game engines. Are you still learning about [Serverless Physics](https://yantra.gg)? No worries! Mantra can also run on any standard hosting environment. @@ -80,6 +78,7 @@ Returns a new game instance. `options` defaults to: { physics: 'matter', // enum, 'physx', 'matter' graphics: ['babylon'], // array enum, 'babylon', 'phaser', 'css' + camera: 'center', // enum, 'follow', 'center' keyboard: true, // boolean or `Keyboard` config object mouse: true, // boolean or `Mouse` config object collisions: false, // boolean @@ -234,7 +233,7 @@ The following checklist outlines the planned features and their current status: ### Plugin System - [X] **Everything is a Plugin** -- [ ] **All Plugin methods are event emitters** +- [X] **All Plugin methods are event emitters** - [ ] **All Plugin events have hooks** ## Mod Support diff --git a/mantra-client/public/mantra.css b/mantra-client/public/mantra.css index c85df1bb..4361d6e7 100644 --- a/mantra-client/public/mantra.css +++ b/mantra-client/public/mantra.css @@ -3,44 +3,6 @@ body { padding: 0; } -#gameHolder { - display: flex; - flex-wrap: wrap; - justify-content: flex-start; - align-items: flex-start; - padding: 0; - margin: 0; -} - -/* Combined styles for both canvas and .render-div */ -#gameHolder>canvas, -#gameHolder>.render-div { - max-width: calc(50% - 20px); - /* Adjust this value to change the number of items per row */ - margin: 10px; - /* Spacing between items */ - background-color: #000; - /* Visualize the area for both canvases and divs */ - /* You might want to set a min-height or a padding-top to maintain aspect ratio */ - min-height: 150px; - /* Example fixed min-height */ -} - -/* If you have absolutely positioned content inside the canvas */ -#gameHolder>canvas>* { - position: absolute; - top: 0; - left: 0; - width: 100%; - height: 100%; -} - -/* Additional specific styles for .render-div if needed */ -#gameHolder>.render-div { - /* Additional styles specific to .render-div here */ -} - - /* InputLegend.js Plugin */ #controlsView { diff --git a/mantra-game/Game.js b/mantra-game/Game.js index 54d4ca86..925440b0 100644 --- a/mantra-game/Game.js +++ b/mantra-game/Game.js @@ -27,6 +27,7 @@ class Game { physics = 'matter', graphics = ['babylon'], collisions, + camera = 'follow', keyboard = true, mouse = true, isOfflineMode, @@ -42,17 +43,20 @@ class Game { physics, graphics, collisions, + camera, keyboard, mouse, isOfflineMode, options }; + this.config = config; // Define the scriptRoot variable for loading external scripts - // In most cases you will want to load from the local directory - this.scriptRoot = './'; + // To support demos and CDN based Serverless Games, we default scriptRoot to yantra.gg + this.scriptRoot = 'https://yantra.gg/mantra'; - // Could be CDN or other remote location, https://yantra.gg/mantra/vendor/ + // Could be another CDN or other remote location + // For local development, try this.scriptRoot = './'; if (options.scriptRoot) { this.scriptRoot = options.scriptRoot; } @@ -194,7 +198,9 @@ class Game { this.use(new plugins.BabylonGraphics()); } if (graphics.includes('css')) { - this.use(new plugins.CSSGraphics()); + this.use(new plugins.CSSGraphics({ + camera: this.config.camera + })); } if (graphics.includes('phaser')) { this.use(new plugins.PhaserGraphics()); diff --git a/mantra-game/plugins/graphics-css/CSSGraphics.js b/mantra-game/plugins/graphics-css/CSSGraphics.js index 5d2b3540..b6bc5052 100644 --- a/mantra-game/plugins/graphics-css/CSSGraphics.js +++ b/mantra-game/plugins/graphics-css/CSSGraphics.js @@ -1,13 +1,17 @@ +// CSSGraphics.js - Marak Squires 2023 import GraphicsInterface from '../../lib/GraphicsInterface.js'; class CSSGraphics extends GraphicsInterface { - constructor({ debug = true, onlineMode = true, followPlayer = false } = {}) { + constructor({ camera } = {}) { super(); - this.onlineMode = onlineMode; - this.entityStates = {}; - this.debug = debug; + + // config scope for convenience + let config = { + camera + }; + this.config = config; + this.name = 'graphics-css'; - this.followPlayer = followPlayer; this.cameraPosition = { x: 0, y: 0 }; } @@ -16,42 +20,17 @@ class CSSGraphics extends GraphicsInterface { game.graphics.push(this); this.game = game; - // Only initialize DebugGUI if debug flag is set to true - if (this.debug) {} - // leave always on ( for now ) - // this.initDebugUI(); this.game.systemsManager.addSystem('graphics-css', this); // let the graphics pipeline know the document is ready ( we could add document event listener here ) + // Remark: CSSGraphics current requires no async external loading scripts game.graphicsReady.push(self.name); // Initialize the CSS render div this.initCSSRenderDiv(); } - initDebugUI() { - // Create a debug UI container - this.debugUIContainer = document.createElement('div'); - this.debugUIContainer.id = 'debugUIContainer'; - this.debugUIContainer.style.top = '10px'; - this.debugUIContainer.style.right = '10px'; - this.debugUIContainer.style.width = '40vw'; - this.debugUIContainer.style.height = '50vw'; - this.debugUIContainer.style.background = 'rgba(0, 0, 0, 0.5)'; - this.debugUIContainer.style.padding = '10px'; - this.debugUIContainer.style.color = 'white'; - this.debugUIContainer.style.zIndex = '9999'; - this.debugUIContainer.style.position = 'absolute'; - - // Create a table within the debug UI container - this.debugTable = document.createElement('table'); - this.debugTable.id = 'debugTable'; - this.debugUIContainer.appendChild(this.debugTable); - - this.renderDiv.appendChild(this.debugUIContainer); - } - initCSSRenderDiv() { const gameHolder = document.getElementById('gameHolder'); if (!gameHolder) { @@ -101,7 +80,6 @@ class CSSGraphics extends GraphicsInterface { break; */ case 'BULLET': - // For PLAYER entities, create a triangle entityElement.style.width = '0px'; entityElement.style.height = '0px'; @@ -129,7 +107,6 @@ class CSSGraphics extends GraphicsInterface { return entityElement; } - updateGraphic(entityData) { const entityElement = document.getElementById(`entity-${entityData.id}`); if (entityElement) { @@ -165,7 +142,6 @@ class CSSGraphics extends GraphicsInterface { return entityElement; } - removeGraphic(entityId) { let entity = this.game.getEntity(entityId); @@ -180,7 +156,9 @@ class CSSGraphics extends GraphicsInterface { } } + updateEntityElementPosition(entityElement, {position, width, height, rotation = 0}) { + // Adjust the position based on the camera position const adjustedPosition = { x: position.x - this.cameraPosition.x + window.innerWidth / 2, @@ -200,15 +178,17 @@ class CSSGraphics extends GraphicsInterface { return entityElement; } - + update () { const currentPlayer = this.game.getEntity(window.currentPlayerId); - if (this.followPlayer && currentPlayer && currentPlayer.position) { - this.cameraPosition.x = currentPlayer.position.x; - this.cameraPosition.y = currentPlayer.position.y; + if (this.config.camera && this.config.camera === 'follow' && currentPlayer) { + if (currentPlayer.position) { + this.cameraPosition.x = currentPlayer.position.x; + this.cameraPosition.y = currentPlayer.position.y; + } } } - + render () {} } diff --git a/mantra-game/plugins/physics-physx/PhysXPhysics.js b/mantra-game/plugins/physics-physx/PhysXPhysics.js index cd1efc7f..fa466549 100644 --- a/mantra-game/plugins/physics-physx/PhysXPhysics.js +++ b/mantra-game/plugins/physics-physx/PhysXPhysics.js @@ -67,11 +67,25 @@ class PhysXPhysics extends PhysicsInterface { let self = this; game.loadScripts([ - 'physx-js-webidl.js' + '/physx-js-webidl.js' ], () => { - this.physXReady(); - }) + PhysXObjectAvailable(function(){ + self.physXReady(); + }) + }); + // PhysXObjectAvailable may not be necessary, the PhysX() should immediately be available + function PhysXObjectAvailable (callback) { + if (typeof PhysX !== 'undefined') { + callback(); + } + // try again in 10ms + else { + setTimeout(function () { + PhysXObjectAvailable(callback); + }, 10); + } + } } physXReady () {