-
Notifications
You must be signed in to change notification settings - Fork 49
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
14 changed files
with
1,420 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,3 +3,4 @@ scripts/__pycache__/convert_notebooks.cpython-311.pyc | |
_posts/*_IPYNB_2_.md | ||
nohup.out | ||
Gemfile.lock | ||
node_modules |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,192 @@ | ||
--- | ||
layout: base | ||
title: Socket.io Multiplayer Game | ||
description: Using socket.io for multiplayer game | ||
type: ccc | ||
courses: { csse: {week: 20} } | ||
image: /images/platformer/backgrounds/hills.png | ||
--- | ||
|
||
<style> | ||
#gameBegin, #controls, #gameOver { | ||
position: relative; | ||
z-index: 2; /*Ensure the controls are on top*/ | ||
} | ||
</style> | ||
|
||
<!-- Prepare DOM elements --> | ||
<!-- Wrap both the canvas and controls in a container div --> | ||
<div id="canvasContainer"> | ||
<div id="gameBegin" hidden> | ||
<button id="startGame">Start Game</button> | ||
</div> | ||
<div id="controls"> <!-- Controls --> | ||
<!-- Background controls --> | ||
<button id="toggleCanvasEffect">Invert</button> | ||
</div> | ||
<div id="gameOver" hidden> | ||
<button id="restartGame">Restart</button> | ||
</div> | ||
</div> | ||
|
||
|
||
<script type="module"> | ||
// Imports | ||
import GameEnv from '{{site.baseurl}}/assets/js/multiplayer/GameEnv.js'; | ||
import GameLevel from '{{site.baseurl}}/assets/js/multiplayer/GameLevel.js'; | ||
import GameControl from '{{site.baseurl}}/assets/js/multiplayer/GameControl.js'; | ||
|
||
|
||
/* ========================================== | ||
* ======= Data Definitions ================= | ||
* ========================================== | ||
*/ | ||
|
||
// Define assets for the game | ||
var assets = { | ||
obstacles: { | ||
tube: { src: "/images/platformer/obstacles/tube.png" }, | ||
}, | ||
platforms: { | ||
grass: { src: "/images/platformer/platforms/grass.png" }, | ||
alien: { src: "/images/platformer/platforms/alien.png" } | ||
}, | ||
backgrounds: { | ||
start: { src: "/images/platformer/backgrounds/home.png" }, | ||
hills: { src: "/images/platformer/backgrounds/hills.png" }, | ||
planet: { src: "/images/platformer/backgrounds/planet.jpg" }, | ||
castles: { src: "/images/platformer/backgrounds/castles.png" }, | ||
end: { src: "/images/platformer/backgrounds/game_over.png" } | ||
}, | ||
players: { | ||
mario: { | ||
src: "/images/platformer/sprites/mario.png", | ||
width: 256, | ||
height: 256, | ||
w: { row: 10, frames: 15 }, | ||
wa: { row: 11, frames: 15 }, | ||
wd: { row: 10, frames: 15 }, | ||
a: { row: 3, frames: 7, idleFrame: { column: 7, frames: 0 } }, | ||
s: { }, | ||
d: { row: 2, frames: 7, idleFrame: { column: 7, frames: 0 } } | ||
}, | ||
monkey: { | ||
src: "/images/platformer/sprites/monkey.png", | ||
width: 40, | ||
height: 40, | ||
w: { row: 9, frames: 15 }, | ||
wa: { row: 9, frames: 15 }, | ||
wd: { row: 9, frames: 15 }, | ||
a: { row: 1, frames: 15, idleFrame: { column: 7, frames: 0 } }, | ||
s: { row: 12, frames: 15 }, | ||
d: { row: 0, frames: 15, idleFrame: { column: 7, frames: 0 } } | ||
} | ||
} | ||
}; | ||
|
||
// add File to assets, ensure valid site.baseurl | ||
Object.keys(assets).forEach(category => { | ||
Object.keys(assets[category]).forEach(assetName => { | ||
assets[category][assetName]['file'] = "{{site.baseurl}}" + assets[category][assetName].src; | ||
}); | ||
}); | ||
|
||
/* ========================================== | ||
* ===== Game Level Call Backs ============== | ||
* ========================================== | ||
*/ | ||
|
||
// Level completion tester | ||
function testerCallBack() { | ||
// console.log(GameEnv.player?.x) | ||
if (GameEnv.player?.x > GameEnv.innerWidth) { | ||
return true; | ||
} else { | ||
return false; | ||
} | ||
} | ||
|
||
// Helper function for button click | ||
function waitForButton(buttonName) { | ||
// resolve the button click | ||
return new Promise((resolve) => { | ||
const waitButton = document.getElementById(buttonName); | ||
const waitButtonListener = () => { | ||
resolve(true); | ||
}; | ||
waitButton.addEventListener('click', waitButtonListener); | ||
}); | ||
} | ||
|
||
// Start button callback | ||
async function startGameCallback() { | ||
const id = document.getElementById("gameBegin"); | ||
id.hidden = false; | ||
|
||
// Use waitForRestart to wait for the restart button click | ||
await waitForButton('startGame'); | ||
id.hidden = true; | ||
|
||
return true; | ||
} | ||
|
||
// Home screen exits on Game Begin button | ||
function homeScreenCallback() { | ||
// gameBegin hidden means game has started | ||
const id = document.getElementById("gameBegin"); | ||
return id.hidden; | ||
} | ||
|
||
// Game Over callback | ||
async function gameOverCallBack() { | ||
const id = document.getElementById("gameOver"); | ||
id.hidden = false; | ||
|
||
// Use waitForRestart to wait for the restart button click | ||
await waitForButton('restartGame'); | ||
id.hidden = true; | ||
|
||
// Change currentLevel to start/restart value of null | ||
GameEnv.currentLevel = null; | ||
|
||
return true; | ||
} | ||
|
||
/* ========================================== | ||
* ========== Game Level setup ============== | ||
* ========================================== | ||
* Start/Homme sequence | ||
* a.) the start level awaits for button selection | ||
* b.) the start level automatically cycles to home level | ||
* c.) the home advances to 1st game level when button selection is made | ||
*/ | ||
// Start/Home screens | ||
new GameLevel( {tag: "start", callback: startGameCallback } ); | ||
new GameLevel( {tag: "home", background: assets.backgrounds.start, callback: homeScreenCallback } ); | ||
// Game screens | ||
new GameLevel( {tag: "hills", background: assets.backgrounds.hills, platform: assets.platforms.grass, player: assets.players.mario, tube: assets.obstacles.tube, callback: testerCallBack } ); | ||
new GameLevel( {tag: "alien", background: assets.backgrounds.planet, platform: assets.platforms.alien, player: assets.players.monkey, callback: testerCallBack } ); | ||
// Game Over screen | ||
new GameLevel( {tag: "end", background: assets.backgrounds.end, callback: gameOverCallBack } ); | ||
|
||
/* ========================================== | ||
* ========== Game Control ================== | ||
* ========================================== | ||
*/ | ||
|
||
// create listeners | ||
toggleCanvasEffect.addEventListener('click', GameEnv.toggleInvert); | ||
window.addEventListener('resize', GameEnv.resize); | ||
|
||
// more listeners | ||
GameEnv.socket.on("stateUpdate", (data) => { | ||
console.log("update", data) | ||
for (var gameObj of GameEnv.gameObjects) { | ||
gameObj.updateInfo(data) | ||
} | ||
}) | ||
|
||
// start game | ||
GameControl.gameLoop(); | ||
|
||
</script> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
import GameEnv from './GameEnv.js'; | ||
import GameObject from './GameObject.js'; | ||
|
||
export class Background extends GameObject { | ||
constructor(canvas, image, speedRatio) { | ||
super(canvas, image, speedRatio); | ||
} | ||
|
||
/* Update uses modulo math to cycle to start at width extent | ||
* x is position in cycle | ||
* speed can be used to scroll faster | ||
* width is extent of background image | ||
*/ | ||
update() { | ||
this.x = (this.x - this.speed) % this.width; | ||
} | ||
|
||
/* To draws are used to capture primary frame and wrap around ot next frame | ||
* x to y is primary draw | ||
* x + width to y is wrap around draw | ||
*/ | ||
draw() { | ||
this.ctx.drawImage(this.image, this.x, this.y); | ||
this.ctx.drawImage(this.image, this.x + this.width, this.y); | ||
} | ||
|
||
/* Background camvas is set to screen | ||
* the ADJUST contant elements portions of image that don't wrap well | ||
* the GameEnv.top is a getter used to set canvas under Menu | ||
* the GameEnv.bottom is setter used to establish game bottom at offsetHeight of canvas | ||
*/ | ||
size() { | ||
// Update canvas size | ||
const ADJUST = 1 // visual layer adjust; alien_planet.jpg: 1.42, try 1 for others | ||
|
||
const canvasWidth = GameEnv.innerWidth; | ||
const canvasHeight = canvasWidth / this.aspect_ratio; | ||
GameEnv.backgroundHeight = canvasHeight; | ||
const canvasLeft = 0; | ||
|
||
this.canvas.width = this.width; | ||
this.canvas.height = this.height; | ||
this.canvas.style.width = `${canvasWidth}px`; | ||
this.canvas.style.height = `${GameEnv.backgroundHeight}px`; | ||
this.canvas.style.position = 'absolute'; | ||
this.canvas.style.left = `${canvasLeft}px`; | ||
this.canvas.style.top = `${GameEnv.top}px`; | ||
|
||
// set bottom of game to new background height | ||
GameEnv.setBottom(); | ||
} | ||
} | ||
|
||
export default Background; |
Oops, something went wrong.