diff --git a/README b/README new file mode 100644 index 0000000..8fe48b5 --- /dev/null +++ b/README @@ -0,0 +1,37 @@ +WEEE Open Game - Developed by WEEE Open student team, 2024 + +-- How does this works? +The root of the project is the index.html file, which loads each js module. +The modules loaded are, in order: +1. Utils (utils.js) +2. Assets (assets.js) +3. Scenes (scene_xxx.js) +4. (transition.js) +5. Main (main.js) +6. Inputs (inputs.js) +Let's see these modules more in details. + +-- 1. Utils +Contains general global functions that can be useful while coding and that do not require any declared constant/variable. +Usually Utils contains math functions and other frequent operations. + +-- 2. Assets +-- 2.1. Global variables and functions +-- 2.2. Resources +-- 2.3. Rendering properties and functions + +-- 3. Scenes +List of scenes in the format scene_xxx. Each scene must implement four methods: +-- 3.1. xxxSceneInit(): +-- 3.2. xxxSceneKeyPress(key): +-- 3.3. xxxSceneKeyRelease(key): +-- 3.4. xxxSceneLoop(): + +-- 4. Transition +It's a "special scene" that overlaps others while changing a scene. +It does not have methods about inputs (key press, key release) + +-- 5. Main +It's the "global scene" that executes the code in each one of the four methods regardless of which scene is active + +-- 6. Inputs diff --git a/index.html b/index.html new file mode 100644 index 0000000..14cee83 --- /dev/null +++ b/index.html @@ -0,0 +1,13 @@ + + +WOG + + + + + + + + \ No newline at end of file diff --git a/res/amp.pdn b/res/amp.pdn new file mode 100644 index 0000000..e20d93a Binary files /dev/null and b/res/amp.pdn differ diff --git a/res/amp.png b/res/amp.png new file mode 100644 index 0000000..3422c02 Binary files /dev/null and b/res/amp.png differ diff --git a/res/background.pdn b/res/background.pdn new file mode 100644 index 0000000..eeb8300 Binary files /dev/null and b/res/background.pdn differ diff --git a/res/background.png b/res/background.png new file mode 100644 index 0000000..002eef6 Binary files /dev/null and b/res/background.png differ diff --git a/res/character.pdn b/res/character.pdn new file mode 100644 index 0000000..c04f554 Binary files /dev/null and b/res/character.pdn differ diff --git a/res/character.png b/res/character.png new file mode 100644 index 0000000..2dba21a Binary files /dev/null and b/res/character.png differ diff --git a/res/clouds.png b/res/clouds.png new file mode 100644 index 0000000..fc828fb Binary files /dev/null and b/res/clouds.png differ diff --git a/res/coin.wav b/res/coin.wav new file mode 100644 index 0000000..1d5fe63 Binary files /dev/null and b/res/coin.wav differ diff --git a/res/comic_bakery_noise_maker.mp3 b/res/comic_bakery_noise_maker.mp3 new file mode 100644 index 0000000..72b2e59 Binary files /dev/null and b/res/comic_bakery_noise_maker.mp3 differ diff --git a/res/death.wav b/res/death.wav new file mode 100644 index 0000000..cea7839 Binary files /dev/null and b/res/death.wav differ diff --git a/res/emulogic.ttf b/res/emulogic.ttf new file mode 100644 index 0000000..99b620c Binary files /dev/null and b/res/emulogic.ttf differ diff --git a/res/jetpack.wav b/res/jetpack.wav new file mode 100644 index 0000000..5cbbe48 Binary files /dev/null and b/res/jetpack.wav differ diff --git a/res/old/amp_old_1.pdn b/res/old/amp_old_1.pdn new file mode 100644 index 0000000..a139c2a Binary files /dev/null and b/res/old/amp_old_1.pdn differ diff --git a/res/old/amp_old_2.pdn b/res/old/amp_old_2.pdn new file mode 100644 index 0000000..ca26021 Binary files /dev/null and b/res/old/amp_old_2.pdn differ diff --git a/res/old/amp_old_3.pdn b/res/old/amp_old_3.pdn new file mode 100644 index 0000000..57b6dc4 Binary files /dev/null and b/res/old/amp_old_3.pdn differ diff --git a/res/old/amp_old_4.png b/res/old/amp_old_4.png new file mode 100644 index 0000000..b11c478 Binary files /dev/null and b/res/old/amp_old_4.png differ diff --git a/res/old/background_old_1.png b/res/old/background_old_1.png new file mode 100644 index 0000000..4c50c0c Binary files /dev/null and b/res/old/background_old_1.png differ diff --git a/res/old/background_old_2.png b/res/old/background_old_2.png new file mode 100644 index 0000000..773d809 Binary files /dev/null and b/res/old/background_old_2.png differ diff --git a/res/old/eli.jpg b/res/old/eli.jpg new file mode 100644 index 0000000..5db08c6 Binary files /dev/null and b/res/old/eli.jpg differ diff --git a/res/old/eli.pdn b/res/old/eli.pdn new file mode 100644 index 0000000..d6cfbcf Binary files /dev/null and b/res/old/eli.pdn differ diff --git a/res/old/grid.png b/res/old/grid.png new file mode 100644 index 0000000..46cdd93 Binary files /dev/null and b/res/old/grid.png differ diff --git a/res/old/jetpack_old_1.wav b/res/old/jetpack_old_1.wav new file mode 100644 index 0000000..87e312b Binary files /dev/null and b/res/old/jetpack_old_1.wav differ diff --git a/res/old/jetpack_old_2.wav b/res/old/jetpack_old_2.wav new file mode 100644 index 0000000..4c2e1d3 Binary files /dev/null and b/res/old/jetpack_old_2.wav differ diff --git a/res/screw.pdn b/res/screw.pdn new file mode 100644 index 0000000..53e91a4 Binary files /dev/null and b/res/screw.pdn differ diff --git a/res/screw.png b/res/screw.png new file mode 100644 index 0000000..b35a6eb Binary files /dev/null and b/res/screw.png differ diff --git a/res/sound_of_infinity_f777.mp3 b/res/sound_of_infinity_f777.mp3 new file mode 100644 index 0000000..ebfc999 Binary files /dev/null and b/res/sound_of_infinity_f777.mp3 differ diff --git a/res/template.pdn b/res/template.pdn new file mode 100644 index 0000000..fe2d4d4 Binary files /dev/null and b/res/template.pdn differ diff --git a/res/time_machine_waterflame.mp3 b/res/time_machine_waterflame.mp3 new file mode 100644 index 0000000..d0619f4 Binary files /dev/null and b/res/time_machine_waterflame.mp3 differ diff --git a/res/unreal_super_hero_3.mp3 b/res/unreal_super_hero_3.mp3 new file mode 100644 index 0000000..a3adf6c Binary files /dev/null and b/res/unreal_super_hero_3.mp3 differ diff --git a/res/world_of_vikings_maniac.mp3 b/res/world_of_vikings_maniac.mp3 new file mode 100644 index 0000000..43999bb Binary files /dev/null and b/res/world_of_vikings_maniac.mp3 differ diff --git a/src/assets.js b/src/assets.js new file mode 100644 index 0000000..165bc85 --- /dev/null +++ b/src/assets.js @@ -0,0 +1,142 @@ +/* Global variables and functions */ +const [W,H] = [1024,576]//[960,540] +const VERSION = 0.1 +const keys = { + Enter:{pressed:false}, + ' ':{pressed:false}, + ArrowUp:{pressed:false}, + ArrowDown:{pressed:false}, + ArrowLeft:{pressed:false}, + ArrowRight:{pressed:false}, + w:{pressed:false}, + a:{pressed:false}, + s:{pressed:false}, + d:{pressed:false}, + r:{pressed:false}, + l:{pressed:false}, + m:{pressed:false}, +} +const display = { + scene:'', + transition:false, +} +function sceneChange(scene_new,{type='fade',sleep=1000}={}) { + if(arguments.length>1) { + if(!display.transition) { + display.transition = true + transitionInit(scene_new,type,sleep) + } + } else { + window[scene_new+'SceneInit']() + display.scene = scene_new + } +} + +/* Resources */ +const fonts = [ + new FontFace('Emulogic','url(res/emulogic.ttf)'), +] +const sprites = { + character:{img:null,frames:4,slowness:8}, + screw:{img:null,frames:4,slowness:8}, + amp:{img:null,frames:4,slowness:8}, + background:{img:null,dw:W*6,dh:H,sw:768,sh:72}, + clouds:{img:null,dw:W,dh:H,sw:64,sh:36}, +} +const music = { + theme1:{audio:new Audio('res/comic_bakery_noise_maker.mp3'),volume:0.5}, + theme2:{audio:new Audio('res/world_of_vikings_maniac.mp3'),volume:0.4,verse:14.5}, + theme3:{audio:new Audio('res/unreal_super_hero_3.mp3'),volume:0.8,verse:14.2}, + theme4:{audio:new Audio('res/time_machine_waterflame.mp3'),volume:0.5}, + theme5:{audio:new Audio('res/sound_of_infinity_f777.mp3'),volume:0.4}, +} +const sounds = { + screw:{audio:new Audio('res/coin.wav'),volume:0.8}, + death:{audio:new Audio('res/death.wav'),volume:0.6}, + jetpack:{audio:new Audio('res/jetpack.wav'),loop:true,volume:0.4} +} +function loadResources() { + fonts.forEach(f => document.fonts.add(f)) + Object.keys(sprites).forEach(s => { + sprites[s].img = new Image() + sprites[s].img.src = 'res/'+s+'.png' + }) + Object.keys(music).forEach(m => { + music[m].audio.loop = true + if(music[m].volume) music[m].audio.volume = music[m].volume + }) + Object.keys(sounds).forEach(s => { + if(sounds[s].loop) sounds[s].audio.loop = sounds[s].loop + if(sounds[s].volume) sounds[s].audio.volume = sounds[s].volume + }) +} +function musicStop() { + Object.keys(music).forEach(m => { + music[m].audio.pause() + if(music[m].verse) music[m].audio.currentTime = music[m].verse + else music[m].audio.currentTime = 0 + }) +} +function musicPlay() { + musicStop() + const themes = Object.keys(music) + const track = randomInt(themes.length) + music[themes[track]].audio.play() +} +function soundStop(sound) { + sounds[sound].audio.pause() + sounds[sound].audio.currentTime = 0 +} +function soundPlay(sound) { + if(sounds[sound].loop) { + sounds[sound].audio.play() + } else { + const clone = sounds[sound].audio.cloneNode() + clone.volume = sounds[sound].audio.volume + clone.play() + } +} + +/* Rendering properties and functions */ +const canvas = document.getElementById('game') +canvas.width = W +canvas.height = H +const ctx = canvas.getContext('2d') +ctx.imageSmoothingEnabled = false + +function renderClear(x=0,y=0,w=W,h=H) { + ctx.clearRect(x,y,w,h) +} + +function renderRect(x,y,w,h,color) { + ctx.fillStyle = color + ctx.fillRect(x,y,w,h) +} + +function renderCircle(x,y,r,color) { + ctx.beginPath() + ctx.arc(x,y,r,0,2*Math.PI) + ctx.fillStyle = color + ctx.fill() +} + +function renderText(text,x,y,color='black',{size=1,font='sans-serif',centered=false,maxw=undefined}={}) { + ctx.font = W/32*size+'px '+font + ctx.textAlign = centered ? 'center' : 'left' + ctx.fillStyle = color + ctx.fillText(text,x,y+size,maxw) +} + +function renderLine(ax,ay,bx,by,color) { + ctx.strokeStyle = color + ctx.beginPath() + ctx.moveTo(ax,ay) + ctx.lineTo(bx,by) + ctx.closePath() + ctx.stroke() +} + +function toggleFullscreen() { + if(document.fullscreenElement) document.exitFullscreen() + else canvas.requestFullscreen() +} \ No newline at end of file diff --git a/src/inputs.js b/src/inputs.js new file mode 100644 index 0000000..1487d71 --- /dev/null +++ b/src/inputs.js @@ -0,0 +1,22 @@ +/* Before page loaded */ +loadResources() + +/* After page loaded */ +addEventListener('load',() => { + mainInit() + mainLoop() + + addEventListener('keydown',({key}) => { + if(Object.keys(keys).includes(key) && !keys[key].pressed) { + keys[key].pressed = true + mainKeyPress(key) + } + }) + + addEventListener('keyup',({key}) => { + if(Object.keys(keys).includes(key)) { + keys[key].pressed = false + mainKeyRelease(key) + } + }) +}) \ No newline at end of file diff --git a/src/main.js b/src/main.js new file mode 100644 index 0000000..3f5ee8d --- /dev/null +++ b/src/main.js @@ -0,0 +1,20 @@ +function mainInit() { + display.scene = 'menu' + display.transition = false +} + +function mainKeyPress(key) { + window[display.scene+'SceneKeyPress'](key) + if(key=='Enter') toggleFullscreen() +} + +function mainKeyRelease(key) { + window[display.scene+'SceneKeyRelease'](key) +} + +function mainLoop() { + renderClear() + window[display.scene+'SceneLoop']() + if(display.transition) transitionLoop() + requestAnimationFrame(mainLoop) +} \ No newline at end of file diff --git a/src/scene_game.js b/src/scene_game.js new file mode 100644 index 0000000..514a13f --- /dev/null +++ b/src/scene_game.js @@ -0,0 +1,357 @@ +const GAME_COLOR_BG = 'lightblue' +const GAME_COLOR_CEILING = '#335' +const GAME_COLOR_FLOOR = '#335' +const GAME_CELL_SIZE = 32 +const GAME_PADDING = 2 +const GAME_FLOOR = H-GAME_CELL_SIZE*GAME_PADDING +const GAME_CEILING = GAME_CELL_SIZE*GAME_PADDING +const GAME_LEFT_LIMIT = GAME_CELL_SIZE*GAME_PADDING +const GAME_RIGHT_LIMIT = W/2 +const GAME_SPEED_H = 8 +const GAME_SPEED_BG = GAME_SPEED_H*6/8 +const GAME_PLAYER_W = GAME_CELL_SIZE +const GAME_PLAYER_H = GAME_CELL_SIZE*2 +const GAME_PLAYER_SPEED_V = 0.5 +const GAME_PLAYER_SPEED_H = 6 +const GAME_LOSESCREEN_SIZE = 0.6 +const GAME_MAXTICK_FRAME = 1024 +const GAME_MAXTICK_BG = sprites.background.dw/GAME_SPEED_BG +const GAME_MAXTICK_OBJ = W*2/GAME_SPEED_H + +const game = { + state:'', + ticks:{ + frame:0, + bg:0, + npc:0, + }, + patterns:{ + screw:[ + [ + [0,0,1,1,1,1,1,1,0,0], + [0,1,1,1,1,1,1,1,1,0], + [1,1,1,1,1,1,1,1,1,1], + [0,1,1,1,1,1,1,1,1,0], + [0,0,1,1,1,1,1,1,0,0], + ], + [ + [0,0,1,1,1,1,1,1,0,0], + [0,1,1,1,1,1,1,1,1,0], + [1,1,1,1,1,1,1,1,1,1], + [1,1,0,0,0,0,0,0,1,1], + [1,0,0,0,0,0,0,0,0,1], + ], + [ + [1,0,0,0,0,0,0,0,0,1], + [1,1,0,0,0,0,0,0,1,1], + [1,1,1,1,1,1,1,1,1,1], + [0,1,1,1,1,1,1,1,1,0], + [0,0,1,1,1,1,1,1,0,0], + ], + [ + [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1], + [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1], + [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1], + ], + [ + [1,0,1,0,1,0,1,0,1,0,1], + [0,1,0,1,0,1,0,1,0,1,0], + [1,0,1,0,1,0,1,0,1,0,1], + [0,1,0,1,0,1,0,1,0,1,0], + [1,0,1,0,1,0,1,0,1,0,1], + ], + ], + amp:[ + [ + [1], + [1], + [1], + [1], + [1], + [1], + [1], + ], + [ + [1,1,1,1,1,1,1,1,1,1,1,1], + ], + [ + [1,0,1,0,1,0,1,0,1], + [0,0,0,0,0,0,0,0,0], + [1,0,1,0,1,0,1,0,1], + [0,0,0,0,0,0,0,0,0], + [1,0,1,0,1,0,1,0,1], + ], + [ + [1,0,0,0,0,0,0], + [0,1,0,0,0,0,0], + [0,0,1,0,0,0,0], + [0,0,0,1,0,0,0], + [0,0,0,0,1,0,0], + [0,0,0,0,0,1,0], + [0,0,0,0,0,0,1], + ], + [ + [0,0,0,0,0,0,1], + [0,0,0,0,0,1,0], + [0,0,0,0,1,0,0], + [0,0,0,1,0,0,0], + [0,0,1,0,0,0,0], + [0,1,0,0,0,0,0], + [1,0,0,0,0,0,0], + ], + ], + }, + score:0, + npc:{ + type:'', + pattern:[], + offset:{ + x:0, + y:0, + }, + }, + npc_odd:{ + type:'', + pattern:[], + offset:{ + x:0, + y:0, + }, + }, +} + +class Player { + constructor(x,y) { + this.x = x + this.y = y + this.w = GAME_PLAYER_W + this.h = GAME_PLAYER_H + this.vel_y = 0 + this.acc_y = 0 + } + render() { + // renderRect(this.x,this.y,this.w,this.h,'red') + // if(this.acc_y<0) + // renderRect(this.x,this.y+this.h,this.w,10,'yellow') + const frame = Math.floor(game.ticks.frame/sprites[game.npc.type].slowness) + ctx.drawImage(sprites.character.img, + GAME_CELL_SIZE*(frame%sprites[game.npc.type].frames), + this.acc_y<0 ? GAME_CELL_SIZE : 0, + GAME_CELL_SIZE, + GAME_CELL_SIZE, + this.x-GAME_CELL_SIZE, + this.y, + GAME_CELL_SIZE*2, + GAME_CELL_SIZE*2 + ) + } + update() { + /* Vertical axis */ + if(keys.ArrowUp.pressed || keys.w.pressed || keys[' '].pressed) + this.acc_y = -GAME_PLAYER_SPEED_V + else + this.acc_y = GAME_PLAYER_SPEED_V + this.vel_y += this.acc_y + if(this.y+this.vel_y<=GAME_CEILING) + this.stop(GAME_CEILING) + if(this.y+this.h+this.vel_y>=GAME_FLOOR) + this.stop(GAME_FLOOR-this.h) + this.y += this.vel_y + /* Horizontal axis */ + if(keys.ArrowLeft.pressed || keys.a.pressed) + if(this.x>GAME_LEFT_LIMIT) + this.x -= GAME_PLAYER_SPEED_H + if(keys.ArrowRight.pressed || keys.d.pressed) + if(this.x+this.w game.ticks[t] = 0) + musicStop() + musicPlay() + player = new Player(GAME_CELL_SIZE*2,GAME_FLOOR-GAME_PLAYER_H) +} + +function gameSceneKeyPress(key) { + if(game.state=='running') { + if(key=='l') gameChangeState('lose') + if(key=='m') musicPlay() + if(key=='ArrowUp' || key=='w' || key==' ') soundPlay('jetpack') + } + if(game.state=='lose') { + if(key=='r') sceneChange('game',{type:'bars',sleep:500}) + if(key=='m') sceneChange('menu',{type:'circle',sleep:500}) + } +} + +function gameSceneKeyRelease(key) { + if(game.state=='running') { + if(key=='ArrowUp' || key=='w' || key==' ') soundStop('jetpack') + } +} + +function gameSceneLoop() { + function render() { + function renderBG() { + renderRect(0,0,W,H,GAME_COLOR_BG) + ctx.drawImage( + sprites.clouds.img, + W/2-game.ticks.bg%(GAME_MAXTICK_BG/3)*GAME_SPEED_BG/2, + 0, + sprites.clouds.dw, + sprites.clouds.dh + ) + ctx.drawImage( + sprites.clouds.img, + W/2+sprites.clouds.dw-game.ticks.bg%(GAME_MAXTICK_BG/3)*GAME_SPEED_BG/2, + 0, + sprites.clouds.dw, + sprites.clouds.dh + ) + ctx.drawImage( + sprites.background.img, + 0-game.ticks.bg*GAME_SPEED_BG, + 0, + sprites.background.dw, + sprites.background.dh + ) + ctx.drawImage( + sprites.background.img, + sprites.background.dw-game.ticks.bg*GAME_SPEED_BG, + 0, + sprites.background.dw, + sprites.background.dh + ) + renderRect(0,0,W,H,'rgba(255,255,255,0.2)') + renderRect(0,0,W,GAME_CEILING,GAME_COLOR_CEILING) + renderRect(0,GAME_FLOOR,W,H-GAME_FLOOR,GAME_COLOR_FLOOR) + renderText('v '+VERSION,10,H-10,'green',{font:'Emulogic',size:0.4}) + } + function renderNPC() { + if(game.ticks.npc==0) { + game.npc.type = ['screw','amp'][randomInt(2)] + game.npc.pattern = structuredClone(game.patterns[game.npc.type][randomInt(game.patterns[game.npc.type].length)]) + game.npc.offset.x = randomInt(W/GAME_CELL_SIZE-game.npc.pattern[0].length) + game.npc.offset.y = randomInt(GAME_PADDING,H/GAME_CELL_SIZE-GAME_PADDING-game.npc.pattern.length) + } + const frame = Math.floor(game.ticks.frame/sprites[game.npc.type].slowness) + game.npc.pattern.forEach((row,i) => row.forEach((cell,j) => { + if(cell) { + let npc_x = W-game.ticks.npc*GAME_SPEED_H+(game.npc.offset.x+j)*GAME_CELL_SIZE + let npc_y = (game.npc.offset.y+i)*GAME_CELL_SIZE + if(game.npc.type=='amp') { + ctx.drawImage( + sprites.amp.img, + GAME_CELL_SIZE*((frame)%sprites.amp.frames),0,GAME_CELL_SIZE,GAME_CELL_SIZE, + npc_x,npc_y,GAME_CELL_SIZE,GAME_CELL_SIZE + ) + } else { + ctx.drawImage( + sprites[game.npc.type].img, + GAME_CELL_SIZE*(frame%sprites[game.npc.type].frames),0,GAME_CELL_SIZE,GAME_CELL_SIZE, + npc_x,npc_y,GAME_CELL_SIZE,GAME_CELL_SIZE + ) + } + if(checkIntersection2D( + player.x,player.y,player.w,player.h, + npc_x,npc_y,GAME_CELL_SIZE,GAME_CELL_SIZE + )) { + if(game.npc.type=='screw') { + game.score++ + game.npc.pattern[i][j] = 0 + soundPlay('screw') + } + if(game.npc.type=='amp') + if(game.state=='running') + gameChangeState('lose') + } + } + })) + } + function renderNPCOdd() { + if(game.ticks.npc==0) { + game.npc_odd.type = ['screw','amp'][randomInt(2)] + game.npc_odd.pattern = structuredClone(game.patterns[game.npc_odd.type][randomInt(game.patterns[game.npc_odd.type].length)]) + game.npc_odd.offset.x = randomInt(W/GAME_CELL_SIZE-game.npc_odd.pattern[0].length) + game.npc_odd.offset.y = randomInt(GAME_PADDING,H/GAME_CELL_SIZE-GAME_PADDING-game.npc_odd.pattern.length) + } + const frame = Math.floor(game.ticks.frame/sprites[game.npc_odd.type].slowness) + game.npc_odd.pattern.forEach((row,i) => row.forEach((cell,j) => { + if(cell) { + let npc_x = W*2-game.ticks.npc*GAME_SPEED_H+(game.npc_odd.offset.x+j)*GAME_CELL_SIZE + let npc_y = (game.npc_odd.offset.y+i)*GAME_CELL_SIZE + ctx.drawImage( + sprites[game.npc_odd.type].img, + GAME_CELL_SIZE*(frame%sprites[game.npc_odd.type].frames),0,GAME_CELL_SIZE,GAME_CELL_SIZE, + npc_x,npc_y,GAME_CELL_SIZE,GAME_CELL_SIZE + ) + if(checkIntersection2D( + player.x,player.y,player.w,player.h, + npc_x,npc_y,GAME_CELL_SIZE,GAME_CELL_SIZE + )) { + if(game.npc_odd.type=='screw') { + game.score++ + game.npc_odd.pattern[i][j] = 0 + soundPlay('screw') + } + if(game.npc_odd.type=='amp') + if(game.state=='running') + gameChangeState('lose') + } + } + })) + } + function renderLoseScreen() { + renderRect( + W/2*(1-GAME_LOSESCREEN_SIZE), + H/2*(1-GAME_LOSESCREEN_SIZE), + W*GAME_LOSESCREEN_SIZE, + H*GAME_LOSESCREEN_SIZE, + 'rgba(0,0,0,0.8)' + ) + renderText('GAME OVER',W/2,H*2/5,'white',{centered:true,font:'emulogic'}) + renderText('Your score is '+game.score,W/2,H*3/5,'white',{centered:true,font:'emulogic',size:0.6}) + renderText('Press to retry',W/2,H*2/3,'white',{centered:true,font:'emulogic',size:0.5}) + } + function renderScore() { + renderText('Score: '+game.score,16,GAME_CEILING*3/4,'green',{font:'emulogic'}) + } + /* Render pipeline */ + /* 0 */ renderBG() + /* 1 */ renderNPC() + // renderNPCOdd() + /* 2 */ player.render() + /* 3 */ if(game.state=='lose') renderLoseScreen() + /* 4 */ if(game.state=='running') renderScore() + } + function update() { + if(game.state=='running') { + player.update() + game.ticks.frame++ + game.ticks.frame %= GAME_MAXTICK_FRAME + game.ticks.bg++ + game.ticks.bg %= GAME_MAXTICK_BG + game.ticks.npc++ + game.ticks.npc %= GAME_MAXTICK_OBJ + } + } + render() + update() +} \ No newline at end of file diff --git a/src/scene_menu.js b/src/scene_menu.js new file mode 100644 index 0000000..9ce153b --- /dev/null +++ b/src/scene_menu.js @@ -0,0 +1,45 @@ +const MENU_COLOR_BG = '#444' +const MENU_COLOR_TITLE = 'green' +const MENU_COLOR_SUBTITLE = '#bbb' +const MENU_SQUARE_SIZE = W/8 +const MENU_MAXTICK_SQUARES = 50 + +const menu = { + ticks:{ + squares:0, + } +} + +function menuSceneInit() { + return +} + +function menuSceneKeyPress(key) { + if(key==' ') sceneChange('game',{type:'bars',sleep:500}) +} + +function menuSceneKeyRelease(key) { + return +} + +function menuSceneLoop() { + function render() { + renderRect(0,0,W,H,MENU_COLOR_BG) + ctx.rotate(-Math.PI/24) + ctx.translate(-100,40) + ctx.scale(1.1,1.1) + for(i=0;i { + transition.state = 'out' + sceneChange(transition.scene_new) + },transition.sleep) + } + } +} \ No newline at end of file diff --git a/src/utils.js b/src/utils.js new file mode 100644 index 0000000..f82cea3 --- /dev/null +++ b/src/utils.js @@ -0,0 +1,28 @@ +function randomInt(a,b) { + let min,max + if(arguments.length==1) { + min = 0 + max = a + } + if(arguments.length==2) { + min = a + max = b + } + return Math.floor(Math.random()*(max-min))+min +} + +function distance(ax,ay,bx,by) { + return Math.sqrt((ax-bx)**2+(ay-by)**2) +} + +function checkIntersection1D(ax1,ax2,bx1,bx2) { + if(ax2>bx1&&ax1