commit 5123fb654887c2accb04428d4285232427f96ba3 Author: Benjamin Kraft Date: Fri Mar 24 12:40:56 2023 +0100 Init diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..485dee6 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +.idea diff --git a/project.json b/project.json new file mode 100644 index 0000000..0bae730 --- /dev/null +++ b/project.json @@ -0,0 +1,6 @@ +{ + "display_name": "Jump and run", + "info_text": "Birthday present for Selina ♥", + "visible": true, + "tags": ["Game"] +} \ No newline at end of file diff --git a/public/data/audio/music/background0.mp3 b/public/data/audio/music/background0.mp3 new file mode 100644 index 0000000..df63a51 Binary files /dev/null and b/public/data/audio/music/background0.mp3 differ diff --git a/public/data/audio/music/background1.mp3 b/public/data/audio/music/background1.mp3 new file mode 100644 index 0000000..0e37bbb Binary files /dev/null and b/public/data/audio/music/background1.mp3 differ diff --git a/public/data/audio/music/background2.mp3 b/public/data/audio/music/background2.mp3 new file mode 100644 index 0000000..01a4124 Binary files /dev/null and b/public/data/audio/music/background2.mp3 differ diff --git a/public/data/audio/music/background3.mp3 b/public/data/audio/music/background3.mp3 new file mode 100644 index 0000000..6a2764f Binary files /dev/null and b/public/data/audio/music/background3.mp3 differ diff --git a/public/data/audio/music/background4.mp3 b/public/data/audio/music/background4.mp3 new file mode 100644 index 0000000..140fede Binary files /dev/null and b/public/data/audio/music/background4.mp3 differ diff --git a/public/data/audio/music/background5.mp3 b/public/data/audio/music/background5.mp3 new file mode 100644 index 0000000..7b49444 Binary files /dev/null and b/public/data/audio/music/background5.mp3 differ diff --git a/public/data/audio/music/background6.mp3 b/public/data/audio/music/background6.mp3 new file mode 100644 index 0000000..4441c02 Binary files /dev/null and b/public/data/audio/music/background6.mp3 differ diff --git a/public/data/audio/music/background7.mp3 b/public/data/audio/music/background7.mp3 new file mode 100644 index 0000000..3e10fc6 Binary files /dev/null and b/public/data/audio/music/background7.mp3 differ diff --git a/public/data/audio/music/background8.mp3 b/public/data/audio/music/background8.mp3 new file mode 100644 index 0000000..454105c Binary files /dev/null and b/public/data/audio/music/background8.mp3 differ diff --git a/public/data/audio/sound/aww0.wav b/public/data/audio/sound/aww0.wav new file mode 100644 index 0000000..81b19bc Binary files /dev/null and b/public/data/audio/sound/aww0.wav differ diff --git a/public/data/audio/sound/aww1.wav b/public/data/audio/sound/aww1.wav new file mode 100644 index 0000000..b8dee87 Binary files /dev/null and b/public/data/audio/sound/aww1.wav differ diff --git a/public/data/audio/sound/boo0.wav b/public/data/audio/sound/boo0.wav new file mode 100644 index 0000000..8eda32c Binary files /dev/null and b/public/data/audio/sound/boo0.wav differ diff --git a/public/data/audio/sound/cheer0.mp3 b/public/data/audio/sound/cheer0.mp3 new file mode 100644 index 0000000..5524f30 Binary files /dev/null and b/public/data/audio/sound/cheer0.mp3 differ diff --git a/public/data/audio/sound/cheer1.wav b/public/data/audio/sound/cheer1.wav new file mode 100644 index 0000000..f393203 Binary files /dev/null and b/public/data/audio/sound/cheer1.wav differ diff --git a/public/data/audio/sound/cheer2.wav b/public/data/audio/sound/cheer2.wav new file mode 100644 index 0000000..0b79288 Binary files /dev/null and b/public/data/audio/sound/cheer2.wav differ diff --git a/public/data/audio/sound/cheer3.wav b/public/data/audio/sound/cheer3.wav new file mode 100644 index 0000000..dde5810 Binary files /dev/null and b/public/data/audio/sound/cheer3.wav differ diff --git a/public/data/audio/sound/electrical_sweep.mp3 b/public/data/audio/sound/electrical_sweep.mp3 new file mode 100644 index 0000000..f9bf4f8 Binary files /dev/null and b/public/data/audio/sound/electrical_sweep.mp3 differ diff --git a/public/data/audio/sound/jump.mp3 b/public/data/audio/sound/jump.mp3 new file mode 100644 index 0000000..4627846 Binary files /dev/null and b/public/data/audio/sound/jump.mp3 differ diff --git a/public/data/images/favicon.ico b/public/data/images/favicon.ico new file mode 100644 index 0000000..3172667 Binary files /dev/null and b/public/data/images/favicon.ico differ diff --git a/public/data/scripts/Background.js b/public/data/scripts/Background.js new file mode 100644 index 0000000..30fa480 --- /dev/null +++ b/public/data/scripts/Background.js @@ -0,0 +1,54 @@ +"use strict" + +class Background{ + + constructor(world){ + this.yScale = height * 0.4; + this.backScale = int(values.backgroundMoveScale); + } + + update(){ + this.viewPort(); + } + + display(){ + this.show(); + } + + viewPort(){ + this.mountainPoints = []; + this.groundPoints = []; + this.yOff = height / 2 - (viewPort.y / game.world.dim.y - 0.5) * height / 2; + for (let x = 0; x < width; x++){ + let y = noise(x / 100 + viewPort.x / this.backScale) - 0.5; + this.mountainPoints.push({x: x, y: y * this.yScale + this.yOff}); + this.groundPoints.push({x: x, y: y * this.yScale * 0.1 + this.yOff + this.yScale / 2}); + } + } + + show(){ + + //Sky + background(colors.background.sky); + + //Mountains + strokeWeight(2); + stroke(colors.background.mountains.stroke); + fill(colors.background.mountains.fill) + beginShape(); + for (let p of this.mountainPoints) vertex(p.x, p.y); + vertex(width, height); + vertex(0, height); + vertex(0, this.mountainPoints[0].y); + endShape(); + + //Ground + fill(colors.background.ground); + beginShape(); + for (let p of this.groundPoints) vertex(p.x, p.y); + vertex(width, height); + vertex(0, height); + vertex(0, this.groundPoints[0].y); + endShape(); + } +} \ No newline at end of file diff --git a/public/data/scripts/Brick.js b/public/data/scripts/Brick.js new file mode 100644 index 0000000..f3549dc --- /dev/null +++ b/public/data/scripts/Brick.js @@ -0,0 +1,104 @@ +"use strict" + +class Brick{ + + constructor(x, y, w, h, v){ + this.pos = createVector(x, y); + this.vel = createVector(v.x, v.y); + this.dim = createVector(w, h); + this.prepareNoise(); + } + + createTrees(){ + this.trees = []; + for (let i = 0; i < int(random(3)); i++) this.trees.push(new Tree(this)); + } + + createPlants(){ + this.grasses = []; + for (let i = 0; i < int(random(4)); i++) this.grasses.push(new Grass(this, random(this.dim.x))); + } + + createCoins(){ + let rarity = int(values.coinRarity); + this.coin = ranBool(rarity) ? new Coin(this) : null; + } + + update(world){ + if (!game.paused) { + this.borders(world); + this.move(); + } + } + + display(){ + let thrashHold = 300; + if (this.pos.x < viewPort.x + width + thrashHold && this.pos.x + this.dim.x + thrashHold > viewPort.x && + this.pos.y < viewPort.y + height + thrashHold && this.pos.y + this.dim.y > viewPort.y - thrashHold){ + this.show(); + } + } + + move(){ + this.pos.add(this.vel); + } + + borders(world){ + if (this.pos.x > world.pos.x + world.dim.x - this.dim.x + || this.pos.x < world.pos.x){ + this.vel.x *= -1; + } + if (this.pos.y > world.pos.y + world.dim.y - this.dim.y + || this.pos.y < world.pos.y){ + this.vel.y *= -1; + } + } + + show(){ + noStroke(); + + //Brown earth + fill(colors.brick.earth); + rect(this.pos.x, this.pos.y + this.dim.y * 0.3, this.dim.x, this.dim.y * 0.7, this.dim.y / 4); + + //Green grass ground + fill(colors.brick.ground); + beginShape(); + for (let x = 0; x < this.dim.x; x += 5){ + let y = this.pos.y - this.noiseValues[x] * 3; + vertex(this.pos.x + x, y); + if (!(x + 5 < this.dim.x)){ + vertex(this.pos.x + this.dim.x, y); + break; + } + } + vertex(this.pos.x + this.dim.x, this.pos.y + this.dim.y / 2); + vertex(this.pos.x, this.pos.y + this.dim.y / 2); + endShape(); + + //Trees and grasses with flowers + for (let t of this.trees) t.show(); + for (let g of this.grasses) g.show(); + + //Coin + if (this.coin) this.coin.update(); + } + + getHitbox(){ + let hitbox = { + pos: {x: this.pos.x, y: this.pos.y}, + dim: {x: this.dim.x, y: 0}, + vel: {x: this.vel.x, y: this.vel.y} + }; + return hitbox; + } + + //For better performance + prepareNoise(){ + this.noiseValues = []; + let trashHold = 100; + for (let x = random(trashHold); x <= int(values.maxBrickWidth) + trashHold; x++){ + this.noiseValues.push(noise(x)); + } + } +} \ No newline at end of file diff --git a/public/data/scripts/Coin.js b/public/data/scripts/Coin.js new file mode 100644 index 0000000..b661ec1 --- /dev/null +++ b/public/data/scripts/Coin.js @@ -0,0 +1,90 @@ +"use strict" + +class Coin{ + + constructor(brick){ + this.pos = brick.pos; + this.dispoX = random(brick.dim.x); + this.brick = brick; + this.dir = ranBool() ? 1 : -1; + this.colorSetup(); + } + + update(){ + this.blink(); + this.show(); + this.collision(); + } + + blink(){ + this.hue += this.dir * sin(frameCount / 10) * 5; + this.hue = this.hue < 0 ? this.hue + 360 : this.hue; + this.hue %= 360; + + colorMode(HSB); + let s = this.color.stroke; + s = color(this.hue, saturation(s), brightness(s)); + this.color.stroke = s; + colorMode(RGB); + } + + show(){ + fill(this.color.fill); + stroke(this.color.stroke); + strokeWeight(4); + strokeJoin(ROUND); + + let size = int(values.coinSize), + dispoY = int(values.coinDispoY); + + let p1 = {x: this.pos.x + this.dispoX, y: this.pos.y - dispoY}, + p2 = {x: this.pos.x + this.dispoX + size / 3, y: this.pos.y - (dispoY + size / 2)}, + p3 = {x: this.pos.x + this.dispoX, y: this.pos.y - (dispoY + size)}, + p4 = {x: this.pos.x + this.dispoX - size / 3, y: this.pos.y - (dispoY + size / 2)}; + + quad(p1.x, p1.y, p2.x, p2.y, p3.x, p3.y, p4.x, p4.y); + + if (debug){ + let hitbox = this.getHitbox(); + noFill(); + stroke(255, 0, 0); + rect(hitbox.pos.x, hitbox.pos.y, hitbox.dim.x, hitbox.dim.y); + } + } + + collision(){ + if (game.player.touches(this) && hue(game.player.color) != hue(this.color.fill)){ + game.player.setColor(this.color.fill); + new Sound(Sound.Coin()).play(); + this.brick.coin = null; + } + } + + colorSetup(){ + let s = color(colors.brick.coin.stroke), + f = color(colors.brick.coin.fill); + this.hue = int(random(360)); + this.hue = floor(this.hue / 60) * 60; + + colorMode(HSB); + let stroke = color(this.hue, saturation(s), brightness(s)), + fill = color(this.hue, saturation(f), brightness(f)); + + this.color = { + stroke: stroke, + fill: fill + }; + colorMode(RGB); + } + + getHitbox(){ + let size = int(values.coinSize), + dispoY = int(values.coinDispoY); + let hitbox = { + pos: {x: this.pos.x + this.dispoX - size / 3, y: this.pos.y - (dispoY + size)}, + dim: {x: size * 2 / 3, y: size} + }; + return hitbox; + } + +} \ No newline at end of file diff --git a/public/data/scripts/Game.js b/public/data/scripts/Game.js new file mode 100644 index 0000000..b8368ed --- /dev/null +++ b/public/data/scripts/Game.js @@ -0,0 +1,318 @@ +"use strict" + +class Game{ + + constructor(){} + + load(){ + let minSize = int(values.minWorldSize), + maxSize = int(values.maxWorldSize); + let world = {pos: createVector(0, 0), dim: createVector(random(minSize, maxSize), random(minSize, maxSize))}; + let bricks = []; + loader = new Loader(Loader.Bar(), "Loading The Game..."); + this.createBrick(world.pos.x + int(values.maxBrickWidth), bricks, world, 4); + } + + next(num, bricks, world, loadingParts, percentage, partIndex, info, func){ + setTimeout(function(){ + let progress = percentage / loadingParts + partIndex / loadingParts; + loader.updateProgress(progress, info); + game[func](num, bricks, world, loadingParts); + }); + } + + createBrick(x, bricks, world, loadingParts){ + let minBrickWidth = int(values.minBrickWidth), + maxBrickWidth = int(values.maxBrickWidth), + maxWorldSize = int(values.maxWorldSize); + + if (x < world.pos.x + world.dim.x - maxBrickWidth){ + let y = random(world.pos.y, world.pos.y + world.dim.y), + w = random(minBrickWidth, maxBrickWidth), + h = 30, + v = { + x: ranBool() ? random(-4, 4) : 0, + y: ranBool() ? random(-4, 4) : 0 + }; + bricks.push(new Brick(x, y, w, h, v)); + x += 400000 / world.dim.y; + let percentage = (x - maxBrickWidth) / (world.pos.x + world.dim.x - maxBrickWidth * 2); + this.next(x, bricks, world, loadingParts, percentage, 0, "Building Platforms...", "createBrick"); + } else { + this.createTrees(0, bricks, world, loadingParts); + } + } + + createTrees(index, bricks, world, loadingParts){ + bricks[index].createTrees(); + if (bricks[index + 1]){ + index++; + let percentage = index / bricks.length; + this.next(index, bricks, world, loadingParts, percentage, 1, "Planting Trees...", "createTrees"); + } else { + this.createPlants(0, bricks, world, loadingParts); + } + } + + createPlants(index, bricks, world, loadingParts){ + bricks[index].createPlants(); + if (bricks[index + 1]){ + index++; + let percentage = index / bricks.length; + this.next(index, bricks, world, loadingParts, percentage, 2, "Planting Flowers...", "createPlants"); + } else { + this.createCoins(0, bricks, world, loadingParts); + } + } + + createCoins(index, bricks, world, loadingParts){ + bricks[index].createCoins(); + if (bricks[index + 1]){ + index++; + let percentage = index / bricks.length; + this.next(index, bricks, world, loadingParts, percentage, 3, "Hiding Treasures...", "createCoins"); + } else { + this.tidyUp(bricks, world); + } + } + + tidyUp(bricks, world){ + let variables = this.createVariables(bricks, world); + this.applyVariables(variables); + this.safeStartingConditions(variables); + resetMusics(); + loader.updateProgress(1, "Cleaning up..."); + //setTimeout(function(){loadAudioFiles(audioFilesLoaded)}, 1000); crashes PC :D + setTimeout(function(){game.finishLoading();}, int(values.loadedWaitTime)); + } + + createVariables(bricks, world){ + let maxWorldSize = int(values.maxWorldSize), + maxMapSize = int(values.maxMapSize); + let iconMap = new Map(map(world.dim.x, 0, maxWorldSize, 0, maxMapSize), map(world.dim.y, 0, maxWorldSize, 0, maxMapSize)); + let player = new Player(random(world.pos.x + width, world.pos.x + world.dim.x - width), random(world.pos.y + height, world.pos.y - height + world.dim.y)); + let goal = new Goal(); + let background = new Background(world); + viewPort.x = player.pos.x - width / 2; + viewPort.y = player.pos.y - height / 2; + let showHint = true; + let showMap = true; + let isWon = false; + let level = 0; + let maxLevel = int(values.maxLevelCount); + + let variablesObject = { + world: world, + bricks: bricks, + player: player, + goal: goal, + iconMap: iconMap, + background: background, + showHint: showHint, + showMap: showMap, + isWon: isWon, + level: level, + maxLevel: maxLevel + }; + + return variablesObject; + } + + applyVariables(variables){ + for (let property in variables){ + this[property] = variables[property]; + } + } + + safeStartingConditions(v){ + let sc = {}; + for (let key in v){ + if (v[key] instanceof Array){ + sc[key] = v[key].clone(); + } else if (v[key] instanceof Player){ + sc[key] = new Player(v[key].pos.x, v[key].pos.y); + } else if (v[key] instanceof Goal){ + sc[key] = new Goal(); + } + } + sc.isWon = false; + sc.level = 0; + this.startingConditions = sc; + } + + finishLoading(){ + loader.destroy(); + $("#loaderWrapper").hide(); + if (!menuOpen) toggleMenu($("#menuOpener")); + this.nextLevel(); + this.ready = true; + this.start(); + updateMenu(); + } + + start(){ + this.playMusic(); + this.resume(); + } + + restart(){ + this.applyVariables(this.startingConditions); + this.safeStartingConditions(this.startingConditions); + this.nextLevel(); + this.resume(); + } + + update(){ + if (!this.ready || this.paused){ + return; + } + this.background.update(); + + for (let b of this.bricks){ + b.update(this.world); + } + this.goal.update(); + this.player.update(); + if (!this.paused){ + this.player.collision(this.bricks, this.world); + } + + if (this.goal.contains(this.player) + && this.goal.brick == this.player.brick + && !this.paused + && !this.isWon){ + this.goalReached(); + } + + if (this.levelText.isActive()){ + this.levelText.update(); + } + } + + display(){ + if (!this.ready){ + return; + } + checkViewPort(); + this.background.display(); + + translate(-viewPort.x, -viewPort.y); + + for (let b of this.bricks){ + b.display(this.world); + } + if (this.showHint){ + this.goal.hint(this.player, this.world); + } + this.goal.display(); + this.player.display(); + + translate(viewPort.x, viewPort.y); + + if (this.showMap){ + this.iconMap.display(this.player, this.goal, this.world); + } + + if (this.levelText.isActive()){ + this.levelText.display(); + } + } + + nextLevel(){ + this.level++; + this.goal.setBrick(random(this.bricks)); + this.player.maxVelocityX = int(values.maxVelocityX[this.level - 1]); + this.player.jumpVelocity = int(values.jumpVelocity[this.level - 1]); + this.levelText = new LevelText(this.level); + } + + goalReached(){ + if (this.level < this.maxLevel) this.nextLevel(); + else this.won(); + } + + won(){ + this.isWon = true; + this.pause(); + new Sound(Sound.Won()).play(); + new Message(Message.Won()).display(); + } + + lost(){ + this.pause(); + new Sound(Sound.Lost()).play(); + new Message(Message.Lost()).display(); + } + + pause(){ + this.paused = true; + this.pauseMusic(); + } + resume(){ + this.paused = false; + this.unpauseMusic(); + } + + toggleRun(){ + if (this.paused) this.resume(); + else this.pause(); + } + toggleMap(){ + this.showMap = !this.showMap; + } + toggleHint(){ + this.showHint = !this.showHint; + } + + getMusics(){ + return audio.music.game; + } + playMusic(){ + let musics = this.getMusics(); + this.songIndex = int(random(musics.length)); + musics[this.songIndex].play(); + updateVolume(); + let self = this; + setTimeout(function(){ + musics[self.songIndex].onended(function(){ + if (!musics[self.songIndex].isPaused()) self.playMusic(); + }); + }); + } + pauseMusic(){ + let musics = this.getMusics(); + if (musics[this.songIndex].isPaused()) return; + musics[this.songIndex].pause(); + } + unpauseMusic(){ + let musics = this.getMusics(); + if (musics[this.songIndex].isPlaying()) return; + musics[this.songIndex].play(); + updateVolume(); + } +} + +function checkViewPort(){ + + //Between 0.5 and 1 + let limit = 0.5; + + let player = game.player, + world = game.world; + + if (player.pos.x > width * limit + viewPort.x && viewPort.x + width < world.pos.x + world.dim.x) viewPort.x = player.pos.x - width * limit; + if (player.pos.x < width * (1 - limit) + viewPort.x && viewPort.x > world.pos.x) viewPort.x = player.pos.x - width * (1 - limit); + + if (player.pos.y > height * limit + viewPort.y && viewPort.y + height < world.pos.y + world.dim.y) viewPort.y = player.pos.y - height * limit; + if (player.pos.y < height * (1 - limit) + viewPort.y && viewPort.y > world.pos.y) viewPort.y = player.pos.y - height * (1 - limit); +} + +function loadNewGame(){ + game = new Game(); + game.load(); +} + +function requestNewGame(){ + game.pause(); + new Message(Message.New()).display(); +} \ No newline at end of file diff --git a/public/data/scripts/Goal.js b/public/data/scripts/Goal.js new file mode 100644 index 0000000..ef91d89 --- /dev/null +++ b/public/data/scripts/Goal.js @@ -0,0 +1,90 @@ +"use strict" + +class Goal{ + + constructor(){ + this.dim = createVector(200, 375); + } + + setBrick(b){ + this.pos = createVector(b.pos.x + b.dim.x / 2, b.pos.y); + this.vel = b.vel; + this.brick = b; + } + + update(){ + let b = this.brick; + this.pos = createVector(b.pos.x + b.dim.x / 2, b.pos.y); + } + + display(){ + this.show(); + } + + show(){ + fill(colors.goal.main); + noStroke(); + rect(this.pos.x - this.dim.x / 2, this.pos.y - this.dim.y * 0.76, this.dim.x, this.dim.y * 0.76); + triangle(this.pos.x - this.dim.x / 2, this.pos.y - this.dim.y * 0.75, this.pos.x, this.pos.y - this.dim.y, this.pos.x + this.dim.x / 2, this.pos.y - this.dim.y * 0.75); + stroke(colors.goal.roof); + strokeWeight(20); + line(this.pos.x - this.dim.x / 2 - this.dim.x * 0.1, this.pos.y - this.dim.y * 0.75 + this.dim.x * 0.1, this.pos.x, this.pos.y - this.dim.y); + line(this.pos.x + this.dim.x / 2 + this.dim.x * 0.1, this.pos.y - this.dim.y * 0.75 + this.dim.x * 0.1, this.pos.x, this.pos.y - this.dim.y); + fill(colors.goal.hole); + noStroke(); + rect(this.pos.x - this.dim.x / 3, this.pos.y - this.dim.y * 0.41, this.dim.x * 2 / 3, this.dim.y * 0.41); + arc(this.pos.x, this.pos.y - this.dim.y * 0.4, this.dim.x * 2 / 3, this.dim.x * 2 / 3, PI, TWO_PI); + } + + contains(p){ + if (p.pos.x + p.radius < this.pos.x + this.dim.x / 2 && p.pos.x - p.radius > this.pos.x - this.dim.x / 2 + && p.pos.y - p.radius > this.pos.y - this.dim.y && p.pos.y + p.radius <= this.pos.y){ + return true; + } + return false; + } + + hint(player, world){ + let pl = player.pos.copy(); + let gl = this.pos.copy(); + let v = p5.Vector.sub(gl, pl).normalize(); + let d = dist(pl.x, pl.y, gl.x, gl.y); + while (true){ + v.setMag(v.mag() + 1); + if (pl.x + v.x > viewPort.x + width - 20 + || pl.x + v.x < viewPort.x + 20 + || pl.y + v.y > viewPort.y + height - 20 + || pl.y + v.y < viewPort.y + 20){ + break; + } + } + if (v.mag() > d) return; + + let pos = p5.Vector.add(pl, v); + + //green starts at a distance of worldWidth / 3 + let r = d / (world.dim.x / 3) * 255; + + //Arrow + push(); + translate(pos.x, pos.y); + rotate(v.heading()); + strokeWeight(3); + stroke(0); + fill(r, 255 - r, 0); + + //Arrow + beginShape(); + vertex(0, 0); + vertex(-10, 10); + vertex(-10, 5); + vertex(-30, 5); + vertex(-30, -5); + vertex(-10, -5); + vertex(-10, -10); + vertex(0, 0); + endShape(); + pop(); + } + +} \ No newline at end of file diff --git a/public/data/scripts/Interface.js b/public/data/scripts/Interface.js new file mode 100644 index 0000000..5604af6 --- /dev/null +++ b/public/data/scripts/Interface.js @@ -0,0 +1,73 @@ +"use strict" + +function prepareInterface(){ + globalCursor = { + isActive: true, + standStillTime: 0, + + //seconds not moving cursor -> it disappears + timeLimit: int(values.cursorTimeLimit) / 1000 + } + $("#messageWrapper").hide(); + $("#menuOpener").click(function(){ + toggleMenu($(this)); + }); + $("button, input").click(function(){ + $(this).blur(); + updateMenu(); + }); +} + +function toggleMenu(opener){ + menuOpen = !menuOpen; + let menuAnimationTime = int(values.menuAnimationTime), + openerAnimationTime = int(values.openerAnimationTime); + let menuLeft; + if ($("#menu").css("left") == "0px") menuLeft = -$("#menu").outerWidth(); + else menuLeft = 0; + let menuBorder = abs(menuLeft); + opener.animate({"left": menuBorder - opener.outerWidth()}, openerAnimationTime, function(){ + opener.hide(); + $("#menu").show(); + $("#menu").animate({"left": menuLeft}, menuAnimationTime, function(){ + menuBorder = int($(this).css("left").substring(0, $(this).css("left").length - 2)) + $(this).outerWidth(); + opener.show(); + opener.css("left", menuBorder - opener.outerWidth()); + opener.animate({"left": menuBorder}, openerAnimationTime, function(){ + //Animation ended successfully + }); + }); + }); +} + +function toggleFullscreen(htmlElement){ + let fs = fullscreen(); + fullscreen(!fs); + $(htmlElement).html(fs ? "Fullscreen: Off" : "Fullscreen: On"); +} + +function checkCursor(){ + globalCursor.standStillTime += 1 / frameRate(); + if (globalCursor.isActive && globalCursor.standStillTime > globalCursor.timeLimit){ + globalCursor.isActive = false; + noCursor(); + } + if (!globalCursor.isActive && globalCursor.standStillTime < globalCursor.timeLimit){ + globalCursor.isActive = true; + cursor(ARROW); + } +} + +function updateMenu(){ + let val = [ + ["run", game.paused ? "Resume" : "Pause"], + ["restart", "Restart"], + ["new", "New Game"], + ["map", game.showMap ? "Map: On" : "Map: Off"], + ["hint", game.showHint ? "Hint: On" : "Hint: Off"], + ["sound", audioOptions.sound ? "Sound: On" : "Sound: Off"], + ["music", audioOptions.music ? "Music: On" : "Music: Off"] + ]; + + for (let v of val) $("#" + v[0]).html(v[1]); +} \ No newline at end of file diff --git a/public/data/scripts/LevelText.js b/public/data/scripts/LevelText.js new file mode 100644 index 0000000..201cc89 --- /dev/null +++ b/public/data/scripts/LevelText.js @@ -0,0 +1,39 @@ +class LevelText{ + + constructor(level){ + this.text = "Level " + level; + this.pos = createVector(width / 2, height - 50); + this.vel = createVector(0, -0.1); + this.acc = createVector(0, -5); + this.dim = createVector(textWidth(this.text), 50); + } + + isActive(){ + return this.pos.y > -this.dim.y; + } + + display(){ + push(); + textSize(this.dim.y); + fill(255, 0, 0); + stroke(0); + strokeWeight(5); + textAlign(CENTER); + translate(this.pos.x, this.pos.y); + scale(2, 2 - (this.vel.y / 50)); + text(this.text, 0, 0); + pop(); + } + + update(){ + this.vel.add(this.acc); + this.pos.add(this.vel); + if (this.pos.y < height / 2 && this.acc.y != 8 && this.acc.y != -0.25){ + this.acc.y = 8; + } + if (this.vel.y > 0){ + this.acc.y = -0.25; + } + } + +} \ No newline at end of file diff --git a/public/data/scripts/Loader.js b/public/data/scripts/Loader.js new file mode 100644 index 0000000..15ae345 --- /dev/null +++ b/public/data/scripts/Loader.js @@ -0,0 +1,179 @@ +"use strict" + +class Loader{ + + constructor(type, title, loadedCallback){ + this.type = type; + this.title = title; + this.loadedCallback = loadedCallback; + this.spinnerAngle = 0; + $("#menu, #menuOpener").hide(); + } + + static Bar(){ + return 0; + } + + static Circle(){ + return 1; + } + + updateProgress(progress, infoText){ + this.progress = progress > 1 ? 1 : progress; + this.radianAngle = progress * TWO_PI; + this.strokeWidth = progress * 8 + 2; + this.infoText = infoText; + } + + update(){ + this.display(this.getColors()); + this.spinnerAngle += PI / 16; + this.spinnerAngle %= TWO_PI; + if (this.progress === 1 && this.loadedCallback){ + this.loadedCallback(); + } + } + + display(c){ + background(c.background); + switch (this.type){ + case Loader.Bar(): + this.bar(c); + break; + case Loader.Circle(): + this.circle(c); + break; + } + } + + bar(c){ + let w = width * 0.6, + h = 30; + let x = (width - w) / 2, + y = (height - h) / 2; + + this.displayBar(x, y, w, h, c); + + this.displaySpinner(width / 2, height * 3 / 4, 30, c.spinner); + + fill(c.text.fill); + stroke(c.text.stroke); + strokeWeight(5); + textAlign(CENTER, CENTER); + + textSize(height / 32); + text(str(this.title), width / 2, height / 8); + + strokeWeight(2); + textSize(h / 2); + text(str(this.infoText), width / 2, y - h * 1.5); + + strokeWeight(5); + stroke(c.progress); + textSize(height / 16); + text(int(this.progress * 100) + "%", width / 2, height * 5 / 8); + } + + circle(c){ + let size = min(width, height) / 2; + size = size < 100 ? 100 : size; + let posX = width / 2; + let posY = height / 2; + + this.displayCircle(posX, posY, size, c); + + this.displaySpinner(posX, height * 7 / 8, 30, c.spinner); + + fill(c.text.fill); + stroke(c.text.stroke); + strokeWeight(5); + + textSize(height / 32); + text(this.title, posX, height / 8); + + strokeWeight(2); + textSize(15); + text(str(this.infoText), width / 2, posY + size / 2 + 30); + + stroke(c.progress); + strokeWeight(5); + textSize(height / 16); + text(str(int(this.progress * 100)) + "%", posX, posY); + } + + displayBar(x, y, w, h, c){ + noFill(); + stroke(0); + strokeWeight(5); + rect(x, y, w, h, h / 4); + + w -= (1 - this.progress) * w; + + noStroke(); + fill(c.progress); + rect(x + 1, y + 1, w - 2 < 0 ? w : w - 2, h - 2, h / 4); + } + + displayCircle(posX, posY, size, c){ + noFill(); + for (let i = 0; i < 3; i++){ + stroke(i == 1 ? c.progress: 0); + strokeWeight(i == 1 ? 5 : 2); + if (this.radianAngle < TWO_PI && i == 1){ + arc(posX, posY, size, size, -HALF_PI, this.radianAngle - HALF_PI); + } else { + ellipse(posX, posY, size + (i - 1) * 10); + } + } + } + + displaySpinner(x, y, r, c){ + let c2 = c; + colorMode(HSB); + let c1 = color(hue(c2), saturation(c2), brightness(c2) / 5); + colorMode(RGB); + let length = PI + HALF_PI; + for (let i = this.spinnerAngle; i < this.spinnerAngle + length; i += PI / 16){ + strokeWeight((i - this.spinnerAngle) / length * 10); + //stroke(lerpColor(c1, c2, (i - this.spinnerAngle) / length)); + stroke(c2); + let x1 = sin(i) * r + x, + y1 = cos(i) * r + y, + x2 = sin(i + PI / 16) * r + x, + y2 = cos(i + PI / 16) * r + y; + line(x1, y1, x2, y2); + } + } + + getColors(){ + return { + background: color(colors.loader.background), + progress: color(colors.loader.finished), + spinner: color(colors.loader.spinner), + text: { + fill: color(colors.loader.text.fill), + stroke: color(colors.loader.text.stroke) + }, + }; + } + + destroy(){ + $("#loader").html(""); + $("#menu, #menuOpener").show(); + loader = null; + } + +} + +function drawGradient(x, y, w, h, c1, c2, r){ + strokeWeight(1); + for (let i = x; i <= x + w; i++){ + let inter = map(i, x, x + w, 0, 1); + let c = lerpColor(c1, c2, inter); + let b = r - pow(r * r - (i - x - r) * (i - x - r), 0.5); + b = (i - x > r && i < x + w - r) ? 0 : b; + b = i > x + w - r ? r - pow(r * r - (i - x - w + r) * (i - x - w + r), 0.5) : b; + stroke(c); + line(i, y + b + 1, i, y + h - b - 2); + } +} \ No newline at end of file diff --git a/public/data/scripts/Map.js b/public/data/scripts/Map.js new file mode 100644 index 0000000..d3070fc --- /dev/null +++ b/public/data/scripts/Map.js @@ -0,0 +1,46 @@ +"use strict" + +class Map{ + + constructor(w, h){ + let x = width - w - 20; + let y = height - h - 20; + this.pos = createVector(x, y); + this.dim = createVector(w, h); + this.bricks = []; + } + + display(player, goal, world){ + this.show(player, goal, world); + } + + show(player, goal, world){ + let x = width - this.dim.x - 20; + let y = height - this.dim.y - 20; + this.pos = createVector(x, y); + + fill(colors.map.background.fill); + stroke(colors.map.background.stroke); + strokeWeight(10); + rect(this.pos.x, this.pos.y, this.dim.x, this.dim.y, this.dim.x * 0.05); + + let goalX = map(goal.pos.x, 0, world.dim.x, this.pos.x + 10, this.pos.x + this.dim.x - 10), + goalY = map(goal.pos.y, 0, world.dim.y, this.pos.y + 10, this.pos.y + this.dim.y - 10); + stroke(colors.goal.main); + point(goalX, goalY); + + let playerX = map(player.pos.x, 0, world.dim.x, this.pos.x + 10, this.pos.x + this.dim.x - 10), + playerY = map(player.pos.y, 0, world.dim.y, this.pos.y + 10, this.pos.y + this.dim.y - 10); + stroke(player.color); + point(playerX, playerY); + + let flagH = 30, + flagW = 15; + stroke(0); + strokeWeight(2); + line(goalX, goalY, goalX, goalY - flagH); + fill(255, 0, 0); + rect(goalX, goalY - flagH + 2, flagW, flagH * 0.3); + } + +} \ No newline at end of file diff --git a/public/data/scripts/Message.js b/public/data/scripts/Message.js new file mode 100644 index 0000000..d4c451b --- /dev/null +++ b/public/data/scripts/Message.js @@ -0,0 +1,83 @@ +"use strict" + +class Message{ + + constructor(type){ + let set = settings.messages[type]; + this.getFullHTML(set); + } + + static Won(){return "won";} + + static Lost(){return "lost";} + + static New(){return "newGame";} + + static Credits(){return "credits";} + + getFullHTML(set){ + let self = this; + this.html = set.html; + this.styles = set.styles; + this.buttons = []; + for (let b of set.buttons){ + let htmlButton = $(""); + htmlButton.text(b.text); + htmlButton.css(b.styles); + htmlButton.click(function(){self.buttonClicked(b);}); + this.buttons.push(htmlButton); + } + } + + buttonClicked(setButton){ + eval(setButton.onclick); + this.destroy(this); + } + + display(){ + let pane = $("
"); + pane.css(this.styles); + pane.append(this.html); + for (let b of this.buttons) pane.append(b); + pane.attr("id", "message"); + $("#messageWrapper").append(pane); + $("#messageWrapper").show(); + } + + destroy(obj){ + $("#messageWrapper").hide(); + $("#messageWrapper").html(""); + obj = null; + } +} + +function prepareCredits(){ + credits = credits.credits; + + let htmlCredits = $("
"); + htmlCredits.attr("id", "creditsTableWrapper"); + + let table = ""; + table += ""; + for (let prop in credits[0]){ + table += ""; + } + table += ""; + + for (let c of credits){ + let section = ""; + for (let prop in c){ + let link = {open: "", close: ""}; + if (prop === "link"){ + link.open = ""; + link.close = ""; + } + section += ""; + } + section += ""; + table += section; + } + table += "
" + prop.capitalize() + "
" + link.open + c[prop] + link.close + "
"; + htmlCredits.append($(table)); + settings.messages.credits.html = htmlCredits; +} \ No newline at end of file diff --git a/public/data/scripts/Plant.js b/public/data/scripts/Plant.js new file mode 100644 index 0000000..79d1ac1 --- /dev/null +++ b/public/data/scripts/Plant.js @@ -0,0 +1,122 @@ +"use strict" + +class Tree{ + + constructor(brick){ + this.pos = brick.pos; + this.dim = createVector(random(10, 30), random(100, 200)); + this.current = createVector(0, 0); + this.dispoX = random(brick.dim.x - 40) + 20; + this.colorSetup(); + } + + show(){ + //Wood + fill(this.color.wood); + rect(this.pos.x + this.dispoX, this.pos.y - this.dim.y, this.dim.x, this.dim.y); + + //Leaf + fill(this.color.leaf); + for (let i = 0; i <= TWO_PI; i += PI / 4){ + let x = this.dispoX + this.pos.x + this.dim.x / 2 + this.dim.x * 2 * sin(i); + let y = this.pos.y - this.dim.y + this.dim.x * 2 * cos(i); + ellipse(x, y, this.dim.x * 3); + } + ellipse(this.dispoX + this.pos.x + this.dim.x / 2, this.pos.y - this.dim.y, this.dim.x * 3); + } + + colorSetup(){ + let l = color(colors.brick.tree.leaf), + w = color(colors.brick.tree.wood); + colorMode(HSB); + let leaf = color(hue(l), saturation(l), brightness(l) + random(-10, 10)), + wood = color(hue(w), saturation(w), brightness(w) + random(-10, 10)); + colorMode(RGB); + this.color = { + leaf: leaf, + wood: wood + }; + } + +} + +class Grass{ + + constructor(parent, dispoX){ + this.pos = parent.pos; + this.dispoX = dispoX; + this.positions = []; + this.flower = ranBool() ? new Flower(this) : null; + for (let i = HALF_PI + 0.25; i < HALF_PI + PI - 0.25; i += random(PI / 8, PI / 16)) this.positions.push(createVector(sin(i) * 15, cos(i) * 25)); + } + + show(){ + if (this.flower){ + this.flower.show(); + } + fill(colors.brick.grass); + for (let p of this.positions){ + let x1 = this.pos.x + this.dispoX + p.x; + let x2 = this.pos.x + this.dispoX + p.x * 0.5; + let y = this.pos.y + p.y; + triangle(x1, y, this.pos.x + this.dispoX, this.pos.y, x2, y); + } + } + +} + +class Flower{ + + constructor(grass){ + this.pos = grass.pos; + this.dim = createVector(3, random(25, 50)); + this.dispoX = grass.dispoX; + this.colorSetup(); + let cr = random(2, 5); + this.radius = { + center: cr, + petal: cr + random(2, 4) + }; + this.petals = []; + for (let i = 0; i < TWO_PI; i += PI / 2){ + let x = this.dispoX + sin(i) * this.radius.center * 2; + let y = cos(i) * this.radius.center * 2; + this.petals.push(createVector(x, y)); + } + } + + show(){ + + //Haulm + strokeWeight(this.dim.x); + stroke(colors.brick.flower.haulm); + line(this.pos.x + this.dispoX, this.pos.y, this.pos.x + this.dispoX, this.pos.y - this.dim.y); + + //Center + noStroke(); + fill(this.color.center); + ellipse(this.pos.x + this.dispoX, this.pos.y - this.dim.y, this.radius.center * 2); + + //Petals + fill(this.color.petal); + for (let p of this.petals){ + ellipse(p.x + this.pos.x, p.y + this.pos.y - this.dim.y, this.radius.petal * 2); + } + + } + + colorSetup(){ + let c = color(colors.brick.flower.center), + p = color(colors.brick.flower.petal); + colorMode(HSB); + let center = color(int(random(360)), saturation(c), brightness(c)); + let petal = color(int(random(360)), saturation(p), brightness(p)); + colorMode(RGB); + this.color = { + center: center, + petal: petal + }; + } + +} + diff --git a/public/data/scripts/Player.js b/public/data/scripts/Player.js new file mode 100644 index 0000000..e334957 --- /dev/null +++ b/public/data/scripts/Player.js @@ -0,0 +1,153 @@ +"use strict" + +class Player{ + + constructor(x, y){ + this.pos = createVector(x, y); + this.vel = createVector(0, 0); + this.acc = createVector(0, 0.25); + this.radius = 50; + this.brick = null; + this.colorSetup(); + } + + update(){ + this.move(); + } + + display(){ + this.show(); + } + + move(){ + if (this.brick){ + this.vel.y = 0; + this.pos.add(this.brick.vel); + this.pos.y = this.brick.pos.y - this.radius; + } + + this.pos.add(this.vel); + this.vel.add(this.acc); + + this.vel.x *= 0.95; + + let limit = this.maxVelocityX; + if (this.vel.x < -limit) this.vel.x = -limit; + if (this.vel.x > limit) this.vel.x = limit; + } + + show(){ + stroke(red(this.color) * 0.5, green(this.color) * 0.5, blue(this.color) * 0.5); + strokeWeight(1); + + //Body + fill(this.color); + ellipse(this.pos.x, this.pos.y, this.radius * 2); + + //Eyes + let radius = this.radius * 0.3; + let dispoX = 1 / (1 + pow(0.7, this.vel.x)) - 0.5; + let dispoY = 1 / (1 + pow(0.7, this.vel.y)) - 0.5; + let outerDispoX = dispoX * this.radius / 2; + let outerDispoY = dispoY * this.radius / 2; + let innerDispoX = outerDispoX + dispoX * radius / 2; + let innerDispoY = outerDispoY + dispoY * radius / 2; + + fill(colors.player.eyes.outer); + ellipse(this.pos.x + radius + outerDispoX, this.pos.y - radius + outerDispoY, radius, radius * 4/3); + ellipse(this.pos.x - radius + outerDispoX, this.pos.y - radius + outerDispoY, radius, radius * 4/3); + + fill(colors.player.eyes.inner); + ellipse(this.pos.x + radius + innerDispoX, this.pos.y - radius + innerDispoY, radius / 2, radius * 2/3); + ellipse(this.pos.x - radius + innerDispoX, this.pos.y - radius + innerDispoY, radius / 2, radius * 2/3); + + //Mouth + let rotation = dispoX / 2; + + fill(red(this.color) / 3, green(this.color) / 3, blue(this.color) / 3); + arc(this.pos.x, this.pos.y + this.radius * 0.2 + dispoY * this.radius / 2, this.radius, this.radius * 0.8, PI / 16 + rotation, PI - PI / 16 + rotation, CHORD); + } + + collision(bricks, world){ + + //Bricks + if (!this.touches(this.brick)){ + let brick = null; + for (let b of bricks){ + if (this.touches(b)){ + brick = b; + break; + } else brick = null; + } + this.brick = brick; + } + + let trashHold = 10; + //World borders + if (this.pos.x - this.radius < world.pos.x) this.pos.x = world.pos.x + this.radius; + if (this.pos.x + this.radius > world.pos.x + world.dim.x) this.pos.x = world.pos.x + world.dim.x - this.radius; + if (this.pos.y - this.radius < world.pos.y){ + this.pos.y = world.pos.y + this.radius; + this.vel.y *= -1; + } + if (this.pos.y - this.radius > world.pos.y + world.dim.y) game.lost(); + } + + touches(object){ + if (!object) return false; + + let hitbox = object.getHitbox(); + + if (object instanceof Brick){ + if (this.pos.x + this.radius / 2 > hitbox.pos.x && this.pos.x - this.radius / 2 < hitbox.pos.x + hitbox.dim.x && + (this.pos.y + this.radius <= hitbox.pos.y && (this.pos.y + this.radius + this.vel.y >= hitbox.pos.y + hitbox.vel.y + || this.pos.y + this.radius + this.vel.y >= hitbox.pos.y))){ + return true; + } + } + if (object instanceof Coin){ + let distX = abs(this.pos.x - (hitbox.pos.x + hitbox.dim.x / 2)); + let distY = abs(this.pos.y - (hitbox.pos.y + hitbox.dim.y / 2)); + if ((distX <= (hitbox.dim.x / 2) || distY <= (hitbox.dim.y / 2)) + && distX < (hitbox.dim.x / 2 + this.radius) + && distY < (hitbox.dim.y / 2 + this.radius)) return true; + let dx = distX - hitbox.dim.x / 2; + let dy = distY - hitbox.dim.y / 2; + if (dx * dx + dy * dy <= this.radius * this.radius) return true; + } + return false; + } + + walk(d){ + this.acc.x = d; + } + + break(){ + this.acc.x = 0; + } + + jump(){ + if (!this.brick) return; + this.vel.y = -abs(this.vel.x * 0.3) - this.jumpVelocity + this.brick.vel.y; + this.brick = null; + new Sound(Sound.Jump()).play(); + } + + fall(d){ + this.acc.y += d * 0.5; + } + + setColor(color){ + this.color = color; + } + + colorSetup(){ + let h = int(random(360)); + h = floor(h / 60) * 60; + let c = color(colors.player.body); + colorMode(HSB); + this.color = color(h, saturation(c), brightness(c)); + colorMode(RGB); + } + +} \ No newline at end of file diff --git a/public/data/scripts/Sound.js b/public/data/scripts/Sound.js new file mode 100644 index 0000000..1b52295 --- /dev/null +++ b/public/data/scripts/Sound.js @@ -0,0 +1,110 @@ +"use strict" + +let audioOptions = { + sound: true, + music: true +}; + +class Sound{ + + constructor(type){ + this.sound = random(audio.sound[type]); + } + + static Won(){return "won";} + + static Lost(){return "lost";} + + static Coin(){return "coin";} + + static Jump(){return "jump";} + + play(){ + this.sound.play(); + updateVolume(); + } +} + +function toggleSounds(){ + audioOptions.sound = !audioOptions.sound; + $("#soundVolume").prop("disabled", !audioOptions.sound); + updateVolume(); +} + +function toggleMusic(){ + audioOptions.music = !audioOptions.music; + $("#musicVolume").prop("disabled", !audioOptions.music); + updateVolume(); +} + +function updateVolume(){ + let soundVolume = $("#soundVolume").val() / 100, + musicVolume = $("#musicVolume").val() / 100; + soundVolume = !audioOptions.sound ? 0 : soundVolume; + musicVolume = !audioOptions.music ? 0 : musicVolume; + setVolume("sound", soundVolume); + setVolume("music", musicVolume); +} + +function getVolume(type){ + let val = $("#" + type + "Volume").val(); + return val / 100; +} + +function setVolume(key, volume){ + for (let prop in audio){ + if (prop === key){ + for (let type in audio[prop]){ + let audios = audio[prop][type]; + for (let audio of audios){ + audio.setVolume(volume); + } + } + } + } +} + +function resetMusics(){ + for (let type in audio.music){ + let audios = audio.music[type]; + for (let audio of audios){ + audio.jump(); + audio.pause(); + } + } +} + +function loadAudioFiles(loadedCallback){ + soundFormats("mp3", "wav"); + audio = JSON.parse(JSON.stringify(settings.audio)); + loader = new Loader(Loader.Circle(), "Loading Assets...", loadedCallback); + let count = 0, index = 0; + for (let prop in audio){ + let type = audio[prop]; + for (let key in type){ + let files = type[key]; + for (let file of files){ + count++; + } + } + } + for (let prop in audio){ + let type = audio[prop]; + for (let key in type){ + let files = type[key]; + for (let file of files){ + loadSound(file, updateProgress); + function updateProgress(song){ + files[files.indexOf(file)] = song; + index++; + loader.updateProgress(index / count, song.file); + } + } + } + } +} + +function audioFilesLoaded(){ + updateVolume(); + loadNewGame(); +} \ No newline at end of file diff --git a/public/data/scripts/events.js b/public/data/scripts/events.js new file mode 100644 index 0000000..b592547 --- /dev/null +++ b/public/data/scripts/events.js @@ -0,0 +1,79 @@ +"use strict" + +function keyPressed(){ + if (!game) return false; + if (!game.ready) return false; + switch(keyCode){ + case LEFT_ARROW: + game.player.walk(-1); + break; + case RIGHT_ARROW: + game.player.walk(1); + break; + case UP_ARROW: + game.player.jump(); + break; + case DOWN_ARROW: + game.player.fall(1); + break; + case 68: //D + debug = !debug; + break; + case 78: //N + loadNewGame(); + break; + case 76: //L + game.lost(); + break; + case 27: //ESC + case 9: //TAB + toggleMenu($("#menuOpener")); + break; + case 32: //Spacebar + game.toggleRun(); + break; + } + return false; +} + +function keyReleased(){ + if (!game) return false; + if (!game.ready) return true; + switch(keyCode){ + case LEFT_ARROW: + if (!keyIsDown(RIGHT_ARROW)) game.player.break(); + break; + case RIGHT_ARROW: + if (!keyIsDown(LEFT_ARROW)) game.player.break(); + break; + case DOWN_ARROW: + game.player.fall(-1); + break; + } +} + +function mouseMoved(){ + globalCursor ? globalCursor.standStillTime = 0 : null; +} + +function mouseDragged(){ + +} + +function mousePressed(){ + +} + +function mouseReleased(){ + +} + +window.onresize = function(){ + let i = 0; + function resize(){ + resizeCanvas($("#canvasHolder").outerWidth(), $("#canvasHolder").outerHeight(), true); + i++; + if (i < 5) window.setTimeout(resize, 0); + } + resize(); +} \ No newline at end of file diff --git a/public/data/scripts/lib/benjo_library.js b/public/data/scripts/lib/benjo_library.js new file mode 100644 index 0000000..a145901 --- /dev/null +++ b/public/data/scripts/lib/benjo_library.js @@ -0,0 +1,678 @@ +let TOP = 1, + RIGHT = 2, + BOTTOM = 3, + LEFT = 4, + TOP_RIGHT = 5, + BOTTOM_RIGHT = 6, + BOTTOM_LEFT = 7, + TOP_LEFT = 8; + +function collisionDetection(obj0, obj1){ + + let sp = strokePadding; + if (sp == null) sp = 0; + + if (obj0.isEllipse && obj1.isRectangle){ + + //Ball + let b = obj0; + + //Rectangle + let r = obj1; + + for (let i = 0; i < TWO_PI; i += PI / 32){ + + /* Check every borderpoint of the ball beginning + at the top in clock direction up to top again */ + + // Ball Center X + let bcx = b.x; + + // Ball Center Y + let bcy = b.y; + + // Ball Border X + let bbx = b.x + sin(i) * b.r; + + // Ball Border Y inverted because Y = 0 is the TOP of the screen + let bby = b.y - cos(i) * b.r; + + // Rectangle Width + let rW = r.width + 2 * sp; + + // Rectangle Height + let rH = r.height + 2 * sp; + + // Rectangle Border X + let rX = r.x - sp; + + // Rectangle Border Y + let rY = r.y - sp; + + // Objects touch + if (bbx > rX && bbx < rX + rW + && bby > rY && bby < rY + rH){ + + // STRAIGHT FACES // + + //Top/Bottom touch + if (bcx > rX && bcx < rX + rW){ + + //Top touch + if (b.v.y > 0) return {isTouching: true, location: TOP}; + + //Bottom touch + if (b.v.y < 0) return {isTouching: true, location: BOTTOM}; + } + + //Left/Right touch + if (bcy > rY && bcy < rY + rH){ + + //Left touch + if (b.v.x > 0) return {isTouching: true, location: LEFT}; + + //Right touch + if (b.v.x < 0) return {isTouching: true, location: RIGHT}; + + } + + // CORNERS // + + // BOTTOM Left/Right + if (i > 0 && i <= PI / 2) return {isTouching: true, location: BOTTOM_LEFT}; + + //LEFT Bottom/Top + if (i > PI / 2 && i <= PI) return {isTouching: true, location: TOP_LEFT}; + + //TOP Left/Right + if (i > PI && i <= PI + PI / 2) return {isTouching: true, location: TOP_RIGHT}; + + //RIGHT Bottom/Top + if (i > PI + PI / 2 && i <= TWO_PI) return {isTouching: true, location: BOTTOM_RIGHT}; + } + } + + } + + if (obj0.isEllipse && obj1.isEllipse){ + + //Ball 1 + let b1 = obj0; + + //Ball 2 + let b2 = obj1; + + //Balls are close to each other + if (b1.x + b1.r > b2.x - b2.r + && b1.x - b1.r < b2.x + b2.r + && b1.y + b1.r > b2.y - b2.r + && b1.y - b1.r < b2.y + b2.r){ + + let distance = sqrt(pow(b1.x - b2.x, 2) + pow(b1.y - b2.y, 2)); + + if (distance < b1.r + b2.r) return {isTouching: true}; + } + } + return {isTouching: false, location: 0}; +} + +function performCollision(obj0, obj1, collision){ + if (obj0.isEllipse){ + + let ball = obj0; + + //Ball collides with frameborder + if (obj1.isFrameborder){ + switch (collision.location){ + case BOTTOM: + ball.v.y *= -1; + break; + case LEFT: + case RIGHT: + ball.v.x *= -1; + break; + } + if (testMode && collision.location == TOP) ball.v.y *= -1; + ball.move(); + } + + //Ball collides with any brick + if (obj1.isBrick){ + let cornerX, cornerY; + switch (collision.location){ + case TOP: + case BOTTOM: + ball.v.y *= -1; + ball.move(); + return; + case LEFT: + case RIGHT: + ball.v.x *= -1; + ball.move(); + return; + case TOP_LEFT: + cornerX = obj1.x; + cornerY = obj1.y; + break; + case TOP_RIGHT: + cornerX = obj1.x + obj1.width; + cornerY = obj1.y; + break; + case BOTTOM_LEFT: + cornerX = obj1.x; + cornerY = obj1.y + obj1.height; + break; + case BOTTOM_RIGHT: + cornerX = obj1.x + obj1.width; + cornerY = obj1.y + obj1.height; + break; + } + + let nx = ball.x - cornerX; + let ny = ball.y - cornerY; + let length = sqrt(nx * nx + ny * ny); + nx /= length; + ny /= length; + + let projection = ball.v.x * nx + ball.v.y * ny; + ball.v.x = ball.v.x - 2 * projection * nx; + ball.v.y = ball.v.y - 2 * projection * ny; + + ball.move(); + + } + + //Ball collides with paddleboard + if (obj1.isPaddle){ + let cornerX, cornerY; + switch (collision.location){ + case TOP: + case TOP_LEFT: + case TOP_RIGHT: + ball.v.x = ball.calcVelocityX(obj1, ball.v.x); + ball.v.y = -ball.calcVelocityY(); + ball.move(); + return; + case LEFT: + case RIGHT: + ball.v.x *= -1; + ball.move(); + return; + case BOTTOM_LEFT: + cornerX = obj1.x; + cornerY = obj1.y + obj1.height; + break; + case BOTTOM_RIGHT: + cornerX = obj1.x + obj1.width; + cornerY = obj1.y + obj1.height; + break; + } + let nx = ball.x - cornerX; + let ny = ball.y - cornerY; + let length = sqrt(nx * nx + ny * ny); + nx /= length; + ny /= length; + + let projection = ball.v.x * nx + ball.v.y * ny; + ball.v.x = ball.v.x - 2 * projection * nx; + ball.v.y = ball.v.y - 2 * projection * ny; + + ball.move(); + } + + //Ball collides with other ball + if (obj1.isEllipse){ + + //Ball 1 + let b1 = obj0; + + //Ball 2 + let b2 = obj1; + + //Set mass equal to radius of each ball + b1.mass = b1.r; + b2.mass = b2.r; + + //Colliding angle of ball 1 to ball 2 using arc tan of both x and y differences + let collisionAngle = atan2((b2.y - b1.y), (b2.x - b1.x)); + + //Converting directions of velocity vector of balls into angles + let d1 = atan2(b1.v.y, b1.v.x); + let d2 = atan2(b2.v.y, b2.v.x); + + //Ignoring mass effects new velocites are simply magnitude multiplied with value of angle differences + let newXspeed1 = b1.v.mag * cos(d1 - collisionAngle); + let newYspeed1 = b1.v.mag * sin(d1 - collisionAngle); + let newXspeed2 = b2.v.mag * cos(d2 - collisionAngle); + let newYspeed2 = b2.v.mag * sin(d2 - collisionAngle); + + //According to the principle of linear momentum, kinetic energy stays the same after collision, so velocities are now related to masses + let finalXspeed1 = ((b1.mass - b2.mass) * newXspeed1 + b2.mass * 2 * newXspeed2) / (b1.mass + b2.mass); + let finalYspeed1 = newYspeed1; + let finalXspeed2 = (b1.mass * 2 * newXspeed1 + (b2.mass - b1.mass) * newXspeed2) / (b1.mass + b2.mass); + let finalYspeed2 = newYspeed2; + + //Values of collisionAngle + let cosAngle = cos(collisionAngle); + let sinAngle = sin(collisionAngle); + + //To also keep velocites relative to pure collisionAngle, subtract sin*x from cos*x and add sin*y to cos*y because coordSystem has y = 0 on the top + let u1x = cosAngle * finalXspeed1 - sinAngle * finalYspeed1; + let u1y = sinAngle * finalXspeed1 + cosAngle * finalYspeed1; + let u2x = cosAngle * finalXspeed2 - sinAngle * finalYspeed2; + let u2y = sinAngle * finalXspeed2 + cosAngle * finalYspeed2; + + //Set new velocities to both balls + b1.v.x = u1x; + b1.v.y = u1y; + b2.v.x = u2x; + b2.v.y = u2y; + + //Update magnitude + b1.v.mag = sqrt(pow(b1.v.x, 2) + pow(b1.v.y, 2)); + b2.v.mag = sqrt(pow(b2.v.x, 2) + pow(b2.v.y, 2)); + + + //Move balls one vx/vy forward to avoid double inverting collision detection + b1.x += b1.v.x; + b1.y += b1.v.y; + b2.x += b2.v.x; + b2.y += b2.v.y; + } + } +} + + + +function toTimeString(time, hoursWanted){ + + time = floor(time / 10); + + let hs = String(floor(time % 100)); + let fs = String(floor((time / 100) % 60)); + + if (hoursWanted){ + let min = String(floor(((time / 100) / 60) % 60)); + let hr = String(floor(((time / 100) / 60) / 60)); + + if (hs.length < 2) hs = "0" + hs; + if (fs.length < 2) fs = "0" + fs; + if (min.length < 2) min = "0" + min; + if (hr.length < 2) hr = "0" + hr; + + let timeString = hr + ":" + min + ":" + fs + ":" + hs; + } else { + let min = String(floor(((time / 100) / 60) % 60)); + + if (hs.length < 2) hs = "0" + hs; + if (fs.length < 2) fs = "0" + fs; + if (min.length < 2) min = "0" + min; + + let timeString = min + ":" + fs + ":" + hs; + } + + + + return timeString; +} + + +function setCookie(name, value, years){ + let expires = ""; + if (years){ + let date = new Date(); + date.setTime(date.getTime() + (years * 365 * 24 * 60 * 60 * 1000)); + expires = "; expires=" + date.toUTCString(); + } + document.cookie = name + "=" + value + expires + "; path=/"; +} + +function getCookie(name){ + let nameEQ = name + "="; + let ca = document.cookie.split(';'); + for (let i = 0; i < ca.length; i++){ + let c = ca[i]; + while (c.charAt(0) == ' ') c = c.substring(1, c.length); + if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length, c.length); + } + return null; +} + +function deleteCookies(){ + for (let i = 0; i < arguments.length; i++) setCookie(arguments[i], "", -1); +} + +function deleteAllCookies(){ + let cookies = document.cookie.split(";"); + for (let i = 0; i < cookies.length; i++) deleteCookies(cookies[i].split("=")[0]); +} + +Array.prototype.shuffle = function(){ + let currentIndex = this.length, temporaryValue, randomIndex; + while (0 != currentIndex){ + randomIndex = floor(random() * currentIndex); + currentIndex -= 1; + temporaryValue = this[currentIndex]; + this[currentIndex] = this[randomIndex]; + this[randomIndex] = temporaryValue; + } +} + +Array.prototype.clone = function(){ + return this.slice(0); +}; + +//Divides big Array into big multidimensional Array +Array.prototype.partitiate = function(dimensions){ + if (dimensions == 0) return this; + let parts = []; + while(this.length) parts.push(this.splice(0, round(pow(this.length, 1 / (1 + 1 / dimensions)))).partitiate(dimensions - 1)); + return parts; +} + +String.prototype.isValidHEX = function(){ + return /(^#[0-9A-Fa-f]{6}$)|(^#[0-9A-Fa-f]{3}$)/i.test(this); +} + +String.prototype.capitalize = function(){ + return this.charAt(0).toUpperCase() + this.slice(1); +} + +function debugInformation(){ + let x = 0, + y = 0; + textSize(12); + textStyle(NORMAL); + stroke(255); + strokeWeight(1); + fill(255); + text("FPS : " + round(frameRate()), 10 + x, 10 + textAscent("FPS : ") + y); + text("MouseX : " + round(mouseX + x), 10 + x, 10 + textAscent("FPS : ") + 10 + textAscent("MouseX : ") + y); + text("MouseY : " + round(-mouseY - y), 10 + x, 10 + textAscent("FPS : ") + 10 + textAscent("MouseX : ") + 10 + textAscent("MouseY : ") + y); +} + + + +function ColorPicker(editor) { + this.movingObject = ""; + + this.updateFromGraphical = function(){ + this.h = (1 - $("#hue_picker").position().top / $("#hue").height()) * 360; + this.s = ($("#sb_picker").position().left + 8) / $("#saturation").width() * 100; + this.v = (1 - ($("#sb_picker").position().top + 8) / $("#value").height()) * 100; + + this.r = HSVtoRGB(this.h, this.s, this.v).r; + this.g = HSVtoRGB(this.h, this.s, this.v).g; + this.b = HSVtoRGB(this.h, this.s, this.v).b; + + this.hex = RGBtoHEX(this.r, this.g, this.b); + + this.updateInterface(); + } + + this.updateFromHSV = function(){ + this.h = $($("#color_picker_hsv input")[0]).val(); + this.s = $($("#color_picker_hsv input")[1]).val(); + this.v = $($("#color_picker_hsv input")[2]).val(); + + this.r = HSVtoRGB(this.h, this.s, this.v).r; + this.g = HSVtoRGB(this.h, this.s, this.v).g; + this.b = HSVtoRGB(this.h, this.s, this.v).b; + + this.hex = RGBtoHEX(this.r, this.g, this.b); + + this.updateFromHEX(null, true); + + this.updateInterface(); + } + + this.updateFromRGB = function(){ + this.r = $($("#color_picker_rgb input")[0]).val(); + this.g = $($("#color_picker_rgb input")[1]).val(); + this.b = $($("#color_picker_rgb input")[2]).val(); + + this.h = RGBtoHSV(this.r, this.g, this.b).h; + this.s = RGBtoHSV(this.r, this.g, this.b).s; + this.v = RGBtoHSV(this.r, this.g, this.b).v; + + this.hex = RGBtoHEX(this.r, this.g, this.b); + + this.updateFromHEX(null, true); + + this.updateInterface(); + } + + this.updateFromHEX = function(input, otf){ + if (!otf){ //Not on the fly + if ($(input).val().isValidHEX()) this.hex = $(input).val(); + else { + alert("Error!"); + return; + } + } + + this.r = HEXtoRGB(this.hex).r; + this.g = HEXtoRGB(this.hex).g; + this.b = HEXtoRGB(this.hex).b; + + this.h = RGBtoHSV(this.r, this.g, this.b).h; + this.s = RGBtoHSV(this.r, this.g, this.b).s; + this.v = RGBtoHSV(this.r, this.g, this.b).v; + + this.updateInterface(); + } + + this.updateInterface = function(){ + + let r = $($("#color_picker_rgb input")[0]), + g = $($("#color_picker_rgb input")[1]), + b = $($("#color_picker_rgb input")[2]), + h = $($("#color_picker_hsv input")[0]), + s = $($("#color_picker_hsv input")[1]), + v = $($("#color_picker_hsv input")[2]), + hex = $("#color_picker_hex"), + bgColor; + + r.val(round(this.r)); + g.val(round(this.g)); + b.val(round(this.b)); + h.val(round(this.h)); + s.val(round(this.s)); + v.val(round(this.v)); + bgColor = color(this.r, 0, 0); + r.css({ + "background-color": bgColor.toString(), + "color": fontColor(bgColor) + }); + bgColor = color(0, this.g, 0); + g.css({ + "background-color": bgColor.toString(), + "color": fontColor(bgColor) + }); + bgColor = color(0, 0, this.b); + b.css({ + "background-color": bgColor.toString(), + "color": fontColor(bgColor) + }); + colorMode(HSL); + bgColor = color(this.h, 100, 50); + h.css({ + "background-color": bgColor.toString(), + "color": fontColor(bgColor) + }); + bgColor = color(this.h, this.s, 100 - this.s / 2); + s.css({ + "background-color": bgColor.toString(), + "color": fontColor(bgColor) + }); + bgColor = color(this.h, 100, this.v / 2); + v.css({ + "background-color": bgColor.toString(), + "color": fontColor(bgColor) + }); + colorMode(RGB); + hex.val(this.hex); + hex.css({ + "background-color": this.hex, + "color": fontColor(color(this.hex)) + }); + + + let sRGB = HSVtoRGB(this.h, 100, 100); + let saturationBackground = "linear-gradient(to right, #FFF 0%, rgb(" + + sRGB.r + "," + + sRGB.g + "," + + sRGB.b + ") 100%)"; + $("#hue_picker").css("top", (1 - this.h / 360) * $("#hue").height()); + $("#sb_picker").css({ + "left": this.s / 100 * $("#saturation").width() - 8, + "top": (1 - this.v / 100) * $("#value").height() - 8 + }); + $("#saturation").css("background", saturationBackground); + + } + + this.mousePressed = function(){ + let x = winMouseX - $("#saturation").offset().left; + let y = winMouseY - $("#value").offset().top; + if (x > 0 && x < $("#saturation").width() && y > 0 && y < $("#value").height()){ + this.movingObject = "sb"; + } + if (x > $("#saturation").width() + 6 && x < $("#saturation").width() + 6 + $("#hue").width() && y > 0 && y < $("#hue").height()){ + this.movingObject = "hue"; + } + this.mouseDragged(); + } + + this.mouseDragged = function(){ + if (this.movingObject == "hue"){ + let objH = $("#hue"); + let picker = $("#hue_picker"); + let h = winMouseY - objH.offset().top; + if (h > 0 && h < objH.height()){ + picker.css("top", h - 1); + } else if (h > objH.height()){ + picker.css("top", objH.height() - 1); + } else if (h < 0){ + picker.css("top", -1); + } + } + + if (this.movingObject == "sb"){ + let objS = $("#saturation"); + let objV = $("#value"); + let picker = $("#sb_picker"); + let s = winMouseX - objS.offset().left; + let v = winMouseY - objV.offset().top; + if (s > 0 && s < objS.width()){ + picker.css("left", s - 8); + } else if (s < 0){ + picker.css("left", -8); + } else if (s < objS.width()){ + picker.css("left", objS.width() - 8); + } + if (v > 0 && v < objV.height()){ + picker.css("top", v - 8); + } else if (v < 0){ + picker.css("top", -8); + } else if (v > objV.height()){ + picker.css("top", objV.height() - 8); + } + } + + this.updateFromGraphical(); + } + + this.mouseReleased = function(){ + this.movingObject = ""; + } + + this.getColor = function(){ + return this.hex; + } +} + +function fontColor(color){ + //https://www.nbdtech.com/Blog/archive/2008/04/27/Calculating-the-Perceived-Brightness-of-a-Color.aspx + let o = (red(color) * 299 + green(color) * 587 + blue(color) * 114) / 1000; + return (o > 125) ? "#000" : "#CCC"; +} + +//www.stackoverflow.com --> +function RGBtoHEX(r, g, b) { + let rgb = b | (g << 8) | (r << 16); + return '#' + (0x1000000 + rgb).toString(16).slice(1); +} + +function HEXtoRGB(hex) { + let shorthandRegex = /^#?([a-fA-F\d])([a-fA-F\d])([a-fA-F\d])$/i; + hex = hex.replace(shorthandRegex, function(m, r, g, b) { + return r + r + g + g + b + b; + }); + let result = /^#?([a-fA-F\d]{2})([a-fA-F\d]{2})([a-fA-F\d]{2})$/i.exec(hex); + return result ? { + r: parseInt(result[1], 16), + g: parseInt(result[2], 16), + b: parseInt(result[3], 16) + } : null; +} + +function HSVtoRGB(h, s, v) { + let r, g, b, i, f, p, q, t; + if (arguments.length === 1) { + s = h.s, v = h.v, h = h.h; + } + h /= 360; + s /= 100; + v /= 100; + i = Math.floor(h * 6); + f = h * 6 - i; + p = v * (1 - s); + q = v * (1 - f * s); + t = v * (1 - (1 - f) * s); + switch (i % 6) { + case 0: r = v, g = t, b = p; break; + case 1: r = q, g = v, b = p; break; + case 2: r = p, g = v, b = t; break; + case 3: r = p, g = q, b = v; break; + case 4: r = t, g = p, b = v; break; + case 5: r = v, g = p, b = q; break; + } + return { + r: r * 255, + g: g * 255, + b: b * 255 + }; +} + +function RGBtoHSV(r, g, b) { + if (arguments.length === 1) { + g = r.g, b = r.b, r = r.r; + } + let max = Math.max(r, g, b), min = Math.min(r, g, b), + d = max - min, + h, + s = (max === 0 ? 0 : d / max), + v = max / 255; + + switch (max) { + case min: h = 0; break; + case r: h = (g - b) + d * (g < b ? 6: 0); h /= 6 * d; break; + case g: h = (b - r) + d * 2; h /= 6 * d; break; + case b: h = (r - g) + d * 4; h /= 6 * d; break; + } + + return { + h: h * 360, + s: s * 100, + v: v * 100 + }; +} + + + + +function ranBool(chance){ + if (!chance) chance = 2; + return Math.floor(Math.random() * chance + 1) == chance ? true : false; +} \ No newline at end of file diff --git a/public/data/scripts/lib/benjo_library.min.js b/public/data/scripts/lib/benjo_library.min.js new file mode 100644 index 0000000..ade6468 --- /dev/null +++ b/public/data/scripts/lib/benjo_library.min.js @@ -0,0 +1 @@ +let TOP=1,RIGHT=2,BOTTOM=3,LEFT=4,TOP_RIGHT=5,BOTTOM_RIGHT=6,BOTTOM_LEFT=7,TOP_LEFT=8;function collisionDetection(a,e){let j=strokePadding;if(null==j&&(j=0),a.isEllipse&&e.isRectangle){let k=a,l=e;for(let n=0;nD&&zE&&AD&&uk.v.y)return{isTouching:!0,location:BOTTOM}}if(w>E&&wk.v.x)return{isTouching:!0,location:RIGHT}}if(0PI/2&&n<=PI)return{isTouching:!0,location:TOP_LEFT};if(n>PI&&n<=PI+PI/2)return{isTouching:!0,location:TOP_RIGHT};if(n>PI+PI/2&&n<=TWO_PI)return{isTouching:!0,location:BOTTOM_RIGHT}}}}if(a.isEllipse&&e.isEllipse){let k=a,l=e;if(k.x+k.r>l.x-l.r&&k.x-k.rl.y-l.r&&k.y-k.rj.length&&(j="0"+j),2>k.length&&(k="0"+k),2>l.length&&(l="0"+l),2>n.length&&(n="0"+n)}else{let l=floor(a/100/60%60)+"";2>j.length&&(j="0"+j),2>k.length&&(k="0"+k),2>l.length&&(l="0"+l)}return timeString}function setCookie(a,e,j){let k="";if(j){let l=new Date;l.setTime(l.getTime()+1e3*(60*(60*(24*(365*j))))),k="; expires="+l.toUTCString()}document.cookie=a+"="+e+k+"; path=/"}function getCookie(a){let e=a+"=",j=document.cookie.split(";");for(let l,k=0;k$("#saturation").width()+6&&e<$("#saturation").width()+6+$("#hue").width()&&0e.height()?j.css("top",e.height()-1):0>k&&j.css("top",-1)}if("sb"==this.movingObject){let e=$("#saturation"),j=$("#value"),k=$("#sb_picker"),l=winMouseX-e.offset().left,n=winMouseY-j.offset().top;0l?k.css("left",-8):ln?k.css("top",-8):n>j.height()&&k.css("top",j.height()-8)}this.updateFromGraphical()},this.mouseReleased=function(){this.movingObject=""},this.getColor=function(){return this.hex}}function fontColor(a){let e=Math.round((299*red(a)+587*green(a)+114*blue(a))/1e3);return 125You won the game! :D Wanna start another?

", + "styles": { + "border-color": "rgb(30, 120, 30)", + "height": "auto" + }, + "buttons": [ + { + "text": "Restart", + "styles": { + "background-color": "rgb(60, 160, 60)" + }, + "onclick": "game.restart();" + }, + { + "text": "New Game", + "styles": { + "background-color": "rgb(60, 160, 60)" + }, + "onclick": "loadNewGame();" + }, + { + "text": "Continue", + "styles": { + "background-color": "rgb(60, 160, 60)" + }, + "onclick": "game.resume()" + } + ] + }, + "lost": { + "html": "

Oh no, you fell out of the world!

", + "styles": { + "border-color": "rgb(160, 30, 30)", + "height": "auto" + }, + "buttons": [ + { + "text": "Restart", + "styles": { + "background-color": "rgb(160, 60, 60)" + }, + "onclick": "game.restart();" + } + ] + + }, + "newGame": { + "html": "

Are you sure you wanna start a new one?

", + "styles": { + "border-color": "rgb(70, 70, 20)", + "height": "auto" + }, + "buttons": [ + { + "text": "New Game", + "styles": { + "background-color": "rgb(60, 160, 60)" + }, + "onclick": "loadNewGame();" + }, + { + "text": "Cancel", + "styles": { + "background-color": "rgb(160, 60, 60)" + }, + "onclick": "game.resume();" + } + ] + }, + "credits": { + "html": "", + "styles": { + "border-color": "rgb(0, 37, 160)", + "background-color": "rgb(83, 61, 255)", + "height": "auto" + }, + "buttons": [ + { + "text": "Continue", + "styles": { + "background-color": "rgb(60, 160, 60)" + }, + "onclick": "game.resume()" + } + ] + } + }, + + "audio": { + "sound": { + "won": [ + "data/audio/sound/cheer0.mp3", + "data/audio/sound/cheer1.wav", + "data/audio/sound/cheer2.wav", + "data/audio/sound/cheer3.wav" + ], + "lost": [ + "data/audio/sound/boo0.wav", + "data/audio/sound/aww0.wav", + "data/audio/sound/aww1.wav" + ], + "jump": [ + "data/audio/sound/jump.mp3" + ], + "coin": [ + "data/audio/sound/electrical_sweep.mp3" + ] + }, + "music":{ + "game": [ + "data/audio/music/background0.mp3", + "data/audio/music/background1.mp3", + "data/audio/music/background2.mp3", + "data/audio/music/background3.mp3", + "data/audio/music/background4.mp3", + "data/audio/music/background5.mp3", + "data/audio/music/background6.mp3", + "data/audio/music/background7.mp3", + "data/audio/music/background8.mp3" + ] + } + }, + + "values": { + "minBrickWidth": "200", + "maxBrickWidth": "800", + "backgroundMoveScale": "500", + "minWorldSize": "5000", + "maxWorldSize": "10000", + "maxMapSize": "300", + "coinSize": "50", + "coinRarity": "20", + "coinDispoY": "10", + "loadedWaitTime": "1000", + "cursorTimeLimit": "1000", + "menuAnimationTime": "200", + "openerAnimationTime": "200", + "maxLevelCount": "5", + "maxVelocityX": [ + "15", + "12", + "10", + "9", + "8" + ], + "jumpVelocity": [ + "15", + "12", + "10", + "8", + "6" + ] + } +} + diff --git a/public/data/styles/color_picker.css b/public/data/styles/color_picker.css new file mode 100644 index 0000000..a5b510e --- /dev/null +++ b/public/data/styles/color_picker.css @@ -0,0 +1,88 @@ +#color_picker{ + width: 300px; + height: 25%; + margin: 20px; + margin-top: 50px; + border: 5px solid #000; + background-color: #000; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + position: relative; +} +#color_picker_numeric{ + width: 80%; + padding: 5%; + margin: 5%; + background-color: #888; + border-radius: 10px; + overflow: hidden; +} +.color_picker_rgb{ + float: left; + width: 22%; + height: 35px; + font-size: 25px; + color: #000; +} +.color_picker_rgb:nth-child(1){ + margin-right: 10%; + margin-left: 3%; + background-color: #F00; + +} +.color_picker_rgb:nth-child(2){ + background-color: #0F0; +} +.color_picker_rgb:nth-child(3){ + margin-left: 10%; + background-color: #00F; + color: #FFF; +} +#color_picker_hex{ + width: 50%; + height: 30px; + font-size: 25px; + margin: 10% 25% 0 25%; +} +#saturation{ + position: relative; + width: calc(100% - 33px); + height: 100%; + background: linear-gradient(to right, #FFF 0%, #F00 100%); + float: left; + margin-right: 6px; +} +#value { + width: 100%; + height: 100%; + background: linear-gradient(to top, #000 0%, rgba(255,255,255,0) 100%); +} +#sb_picker{ + border: 2px solid; + border-color: #FFF; + position: absolute; + width: 14px; + height: 14px; + border-radius: 10px; + bottom: 50px; + left: 50px; + box-sizing: border-box; + z-index: 10; +} +#hue { + width: 27px; + height: 100%; + position: relative; + float: left; + background: linear-gradient(to bottom, #F00 0%, #F0F 17%, #00F 34%, #0FF 50%, #0F0 67%, #FF0 84%, #F00 100%); +} +#hue_picker { + position: absolute; + background: #000; + border-bottom: 1px solid #000; + top: 0; + width: 27px; + height: 2px; +} \ No newline at end of file diff --git a/public/data/styles/font.ttf b/public/data/styles/font.ttf new file mode 100644 index 0000000..199cf40 Binary files /dev/null and b/public/data/styles/font.ttf differ diff --git a/public/data/styles/range_input.css b/public/data/styles/range_input.css new file mode 100644 index 0000000..1d7369c --- /dev/null +++ b/public/data/styles/range_input.css @@ -0,0 +1,88 @@ +input[type=range] { + -webkit-appearance: none; + margin: 18px 0; + width: 100%; +} +input[type=range]:focus { + outline: none; +} +input[type=range]::-webkit-slider-runnable-track { + width: 100%; + height: 8.4px; + cursor: pointer; + animate: 0.2s; + box-shadow: 1px 1px 1px #000000, 0px 0px 1px #0d0d0d; + background: #3071a9; + border-radius: 1.3px; + border: 0.2px solid #010101; +} +input[type=range]::-webkit-slider-thumb { + box-shadow: 1px 1px 1px #000000, 0px 0px 1px #0d0d0d; + border: 1px solid #000000; + height: 36px; + width: 16px; + border-radius: 3px; + background: #ffffff; + cursor: pointer; + -webkit-appearance: none; + margin-top: -14px; +} +input[type=range]:focus::-webkit-slider-runnable-track { + background: #367ebd; +} +input[type=range]::-moz-range-track { + width: 100%; + height: 8.4px; + cursor: pointer; + animate: 0.2s; + box-shadow: 1px 1px 1px #000000, 0px 0px 1px #0d0d0d; + background: #3071a9; + border-radius: 1.3px; + border: 0.2px solid #010101; +} +input[type=range]::-moz-range-thumb { + box-shadow: 1px 1px 1px #000000, 0px 0px 1px #0d0d0d; + border: 1px solid #000000; + height: 36px; + width: 16px; + border-radius: 3px; + background: #ffffff; + cursor: pointer; +} +input[type=range]::-ms-track { + width: 100%; + height: 8.4px; + cursor: pointer; + animate: 0.2s; + background: transparent; + border-color: transparent; + border-width: 16px 0; + color: transparent; +} +input[type=range]::-ms-fill-lower { + background: #2a6495; + border: 0.2px solid #010101; + border-radius: 2.6px; + box-shadow: 1px 1px 1px #000000, 0px 0px 1px #0d0d0d; +} +input[type=range]::-ms-fill-upper { + background: #3071a9; + border: 0.2px solid #010101; + border-radius: 2.6px; + box-shadow: 1px 1px 1px #000000, 0px 0px 1px #0d0d0d; +} +input[type=range]::-ms-thumb { + box-shadow: 1px 1px 1px #000000, 0px 0px 1px #0d0d0d; + border: 1px solid #000000; + height: 36px; + width: 16px; + border-radius: 3px; + background: #ffffff; + cursor: pointer; +} +input[type=range]:focus::-ms-fill-lower { + background: #3071a9; +} +input[type=range]:focus::-ms-fill-upper { + background: #367ebd; +} \ No newline at end of file diff --git a/public/index.html b/public/index.html new file mode 100644 index 0000000..ceeaa27 --- /dev/null +++ b/public/index.html @@ -0,0 +1,50 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Jump and Run + + +
+
+ + + + + \ No newline at end of file diff --git a/public/styles.css b/public/styles.css new file mode 100644 index 0000000..556452e --- /dev/null +++ b/public/styles.css @@ -0,0 +1,125 @@ +a:link, a:hover, a:active, a:visited{color: #000;} + +html, body{margin: 0; padding: 0; height: 100%; width: 100%;} + +canvas{margin: 0; padding: 0; border: none; display: block;} + +button:hover{cursor: pointer;} + +@font-face{ + font-family: "Rametto"; + src: url("data/styles/font.ttf"); +} + +*{ + font-family: "Rametto"; +} + +#canvasHolder{ + position: absolute; + width: 100%; + height: 100%; +} + +#messageWrapper{ + position: absolute; + width: 100%; + height: 100%; + background-color: rgba(0, 0, 0, 0.8); + z-index: 1; +} + +#message{ + position: absolute; + top: 50%; + transform: translateY(-50%); + width: 700px; + left: 0; + right: 0; + margin: auto; + background-color: rgb(130, 130, 130); + border: 10px solid; + border-radius: 50px; + text-align: center; + align-content: center; +} + +#message p{ + margin: 100px; + font-size: 35px; +} + +#message button{ + margin: 20px; + margin-bottom: 50px; + font-size: 35px; + border: 5px solid #000; + border-radius: 10px; +} + +#menuOpener{ + position: absolute; + left: 0; + top: 0; + bottom: 0; + margin: auto; + height: 100px; + width: 20px; + background-color: rgb(70, 70, 70); + border-radius: 0 20px 20px 0; + border: 3px solid #000; + border-left: none; +} +#menuOpener:hover{ + background-color: rgb(50, 50, 50); + cursor: pointer; +} + +#menu{ + position: absolute; + top: 50%; + transform: translateY(-50%); + left: -450px; + width: 400px; + background-color: rgb(90, 90, 90); + border-radius: 0 20px 20px 0; + border: 10px solid #000; + border-left: none; + padding: 20px; + text-align: center; +} +#menu button{ + margin-bottom: 20px; + width: 100%; + background-color: rgb(160, 200, 100); + border: 2px solid #000; + border-radius: 5px; + font-size: 30px; +} +#menu button:last-child{ + margin-bottom: 0px; +} +#menu button:hover{ + background-color: rgb(80, 190, 40); +} + +#creditsTableWrapper{ + margin: 20px; + height: 500px; + overflow-x: auto; + overflow-y: auto; +} +#creditsTable{ + border-collapse: collapse; + margin: 0px auto; +} +#creditsTable, #creditsTable th, #creditsTable td{ + border: 2px solid #0091a3; + padding: 5px; + font-size: 20px; + border-left: none; + border-right: none; +} +#creditsTable th{ + font-size: 25px; +} \ No newline at end of file diff --git a/public/thumbnail.png b/public/thumbnail.png new file mode 100644 index 0000000..c7adb11 Binary files /dev/null and b/public/thumbnail.png differ