conf.js | conf.js | ||||
node_modules |
canvas { | canvas { | ||||
position: absolute; | position: absolute; | ||||
} | } | ||||
#done-screen { | |||||
position: absolute; | |||||
background-color: rgba(255, 255, 255, 0.7); | |||||
border: 1px solid black; | |||||
border-radius: 20px; | |||||
text-align: center; | |||||
font-size: 2em; | |||||
left: 0px; | |||||
right: 0px; | |||||
top: 0px; | |||||
bottom: 0px; | |||||
margin: auto; | |||||
width: 300px; | |||||
height: 150px; | |||||
padding-top: 50px; | |||||
} | |||||
#done-screen.hidden { | |||||
display: none; | |||||
} |
<title>Flappy Dick</title> | <title>Flappy Dick</title> | ||||
<link rel="stylesheet" href="css/style.css"> | <link rel="stylesheet" href="css/style.css"> | ||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1.0, user-scalable=0"> | <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1.0, user-scalable=0"> | ||||
</head> | </head> | ||||
<body> | <body> | ||||
<canvas id="canvas"></canvas> | <canvas id="canvas"></canvas> | ||||
<div id="done-screen" class="hidden"> | |||||
Your score: <span id="score"></span> | |||||
<div> | |||||
<button id="restart">Restart</button> | |||||
</div> | |||||
</div> | |||||
<script src="conf.js"></script> | <script src="conf.js"></script> | ||||
<script src="js/util.js"></script> | <script src="js/util.js"></script> | ||||
<script src="js/vec2.js"></script> | <script src="js/vec2.js"></script> |
var assetsPath = "assets/"+conf.assets; | var assetsPath = "assets/"+conf.assets; | ||||
var commonPath = "assets/common"; | |||||
var assets = { | var assets = { | ||||
imgs: { | imgs: { | ||||
player: new ImageSource("player"), | |||||
player: new ImageSource("theme:player"), | |||||
player_flipped: new ImageSource("theme:player_flipped"), | |||||
background: new ImageSource("background", null, ".jpg"), | background: new ImageSource("background", null, ".jpg"), | ||||
wall: new ImageSource("wall") | |||||
wall: new ImageSource("wall"), | |||||
wall_overlap: new ImageSource("wall-overlap"), | |||||
}, | |||||
audio: { | |||||
hurt: new AudioSource("audio/hurt"), | |||||
loss: new AudioSource("audio/loss"), | |||||
flap: new AudioSource("audio/flap"), | |||||
chomp: new AudioSource("audio/chomp"), | |||||
}, | }, | ||||
soundtracks: { | soundtracks: { | ||||
soundtrack1: new AudioSource("soundtracks/track1"), | soundtrack1: new AudioSource("soundtracks/track1"), | ||||
soundtrack2: new AudioSource("soundtracks/track2"), | soundtrack2: new AudioSource("soundtracks/track2"), | ||||
soundtrack3: new AudioSource("soundtracks/track3") | |||||
} | |||||
soundtrack3: new AudioSource("soundtracks/track3"), | |||||
}, | |||||
}; | }; | ||||
/* | /* | ||||
makeEventListener(this); | makeEventListener(this); | ||||
var ext = ext || ".mp3"; | var ext = ext || ".mp3"; | ||||
this.audio = document.createElement("audio"); | |||||
this.elems = []; | |||||
for (var i = 0; i < 10; ++i) | |||||
this.elems[i] = new Audio(commonPath+"/"+src+ext); | |||||
this.ready = false; | this.ready = false; | ||||
this.index = 0; | |||||
this.audio.addEventListener("canplaythrough", function() { | |||||
this.elems[0].addEventListener("canplaythrough", function() { | |||||
if (this.ready) | if (this.ready) | ||||
return; | return; | ||||
this.emit("load"); | this.emit("load"); | ||||
}.bind(this)); | }.bind(this)); | ||||
this.audio.addEventListener("ended", function() { | |||||
this.elems[0].addEventListener("ended", function() { | |||||
this.emit("ended"); | this.emit("ended"); | ||||
}.bind(this)); | }.bind(this)); | ||||
this.audio.src = assetsPath+"/"+src+ext; | |||||
this.elems[0].onerror = function() { | |||||
console.error("Error with", src); | |||||
} | |||||
} | } | ||||
AudioSource.prototype.play = function() { | AudioSource.prototype.play = function() { | ||||
this.audio.currentTime = 0; | |||||
this.audio.play(); | |||||
this.elems[this.index++].play(); | |||||
this.index %= this.elems.length; | |||||
} | } | ||||
AudioSource.prototype.pause = function() { | AudioSource.prototype.pause = function() { | ||||
this.audio.pause(); | |||||
for (var i in this.elems) | |||||
this.elmes[i].pause(); | |||||
} | } | ||||
/* | /* | ||||
function ImageSource(src, frameh, ext) { | function ImageSource(src, frameh, ext) { | ||||
var ext = ext || ".png"; | var ext = ext || ".png"; | ||||
if (src.indexOf("theme:") == 0) { | |||||
src = assetsPath+"/images/"+src.split(":")[1]; | |||||
} else { | |||||
src = commonPath+"/images/"+src; | |||||
} | |||||
this.img = document.createElement("img"); | this.img = document.createElement("img"); | ||||
this.ready = false; | this.ready = false; | ||||
this.width = 0; | this.width = 0; | ||||
this.steps = 1; | this.steps = 1; | ||||
this.img.onload = function() { | this.img.onload = function() { | ||||
console.log(this); | |||||
this.ready = true; | this.ready = true; | ||||
this.width = this.img.width; | this.width = this.img.width; | ||||
this.height = this.img.height; | this.height = this.img.height; | ||||
} | } | ||||
}.bind(this); | }.bind(this); | ||||
this.img.src = assetsPath+"/images/"+src+ext; | |||||
this.img.src = src+ext | |||||
this.img.onerror = function() { | |||||
console.error("error with", src); | |||||
} | |||||
} | } | ||||
ImageSource.prototype.draw = function(ctx, step) { | ImageSource.prototype.draw = function(ctx, step) { | ||||
if (!step) step = 0; | if (!step) step = 0; |
if (this.img.ready && this.img2x === 0) | if (this.img.ready && this.img2x === 0) | ||||
this.img2x = this.img1x + this.img.width * 2; | this.img2x = this.img1x + this.img.width * 2; | ||||
if (this.game.started) | |||||
this.force.add({ x: 0.09, y: 0 }); | |||||
this.vel.set({ x: this.game.ids.player.vel.x * 0.9, y: 0 }); | |||||
if (this.img1x + this.img.width * 2 + this.pos.x < this.game.camera.x) { | if (this.img1x + this.img.width * 2 + this.pos.x < this.game.camera.x) { | ||||
this.img1x = this.img2x; | this.img1x = this.img2x; | ||||
*/ | */ | ||||
function Player(game) { | function Player(game) { | ||||
makeEnt(this, game, 100); | |||||
makeEnt(this, game, 100, "player"); | |||||
this.img = assets.imgs.player; | this.img = assets.imgs.player; | ||||
this.img_flipped = assets.imgs.player_flipped; | |||||
this.hurt = assets.audio.hurt; | |||||
this.loss = assets.audio.loss; | |||||
this.flap = assets.audio.flap; | |||||
this.chomp = assets.audio.chomp; | |||||
this.hurtLoop = null; | |||||
game.started = false; | game.started = false; | ||||
this.moves = true; | this.moves = true; | ||||
this.layer = 1; | this.layer = 1; | ||||
this.invincible = false; | this.invincible = false; | ||||
this.visible = true; | |||||
this.invincibleTimeout = null; | this.invincibleTimeout = null; | ||||
this.started = false; | this.started = false; | ||||
this.rotation = 0; | this.rotation = 0; | ||||
} | } | ||||
Player.prototype.rise = function() { | Player.prototype.rise = function() { | ||||
this.erectLevel += 1; | this.erectLevel += 1; | ||||
this.setInvincible(200); | |||||
this.setInvincible(200, false); | |||||
this.setBox(); | this.setBox(); | ||||
} | } | ||||
Player.prototype.lower = function() { | Player.prototype.lower = function() { | ||||
return; | return; | ||||
this.erectLevel -= 1; | this.erectLevel -= 1; | ||||
if (this.erectLevel === 0) | |||||
if (this.erectLevel === 0) { | |||||
this.lose(); | this.lose(); | ||||
else | |||||
this.setInvincible(500); | |||||
} else { | |||||
this.hurt.play(); | |||||
this.setInvincible(2000, true); | |||||
} | |||||
this.setBox(); | this.setBox(); | ||||
} | } | ||||
Player.prototype.setInvincible = function(time) { | |||||
Player.prototype.setInvincible = function(time, hurt) { | |||||
clearTimeout(this.invincibleTimeout); | clearTimeout(this.invincibleTimeout); | ||||
if (hurt) { | |||||
clearInterval(this.hurtLoop); | |||||
this.hurtLoop = setInterval(function() { | |||||
this.visible = !this.visible; | |||||
}.bind(this), 60); | |||||
} | |||||
this.invincible = true; | this.invincible = true; | ||||
this.invincibleTimeout = setTimeout(function() { | this.invincibleTimeout = setTimeout(function() { | ||||
this.invincible = false; | this.invincible = false; | ||||
this.visible = true; | |||||
clearInterval(this.hurtLoop); | |||||
this.hurtLoop = null; | |||||
}.bind(this), time); | }.bind(this), time); | ||||
} | } | ||||
Player.prototype.onInput = function(name, down) { | Player.prototype.onInput = function(name, down) { | ||||
// Jump | // Jump | ||||
if (name === "jump" && down) { | if (name === "jump" && down) { | ||||
this.flap.play(); | |||||
this.game.started = true; | this.game.started = true; | ||||
this.vel.y = -1.3; | this.vel.y = -1.3; | ||||
} | } | ||||
if (ent instanceof Obstacle && this.shape.collidesWith(ent.shape)) { | if (ent instanceof Obstacle && this.shape.collidesWith(ent.shape)) { | ||||
this.lower(); | this.lower(); | ||||
return; | |||||
this.vel.x = -1; | |||||
} else if (ent instanceof PowerUp && this.bigShape.collidesWith(ent.shape)) { | } else if (ent instanceof PowerUp && this.bigShape.collidesWith(ent.shape)) { | ||||
this.rise(); | this.rise(); | ||||
this.chomp.play(); | |||||
ent.dead = true; | ent.dead = true; | ||||
} | } | ||||
} | } | ||||
this.rotation = this.vel.angle(); | this.rotation = this.vel.angle(); | ||||
} | } | ||||
Player.prototype.lose = function() { | Player.prototype.lose = function() { | ||||
this.game.stop(this.pos.x / 10); | |||||
this.loss.play(); | |||||
this.game.stop(this.pos.x / 100); | |||||
} | } | ||||
Player.prototype.draw = function(ctx) { | Player.prototype.draw = function(ctx) { | ||||
if (!this.visible) | |||||
return; | |||||
ctx.rotate(this.rotation); | ctx.rotate(this.rotation); | ||||
var scale = 0.4 + this.erectLevel / 8; | var scale = 0.4 + this.erectLevel / 8; | ||||
ctx.scale(scale, scale); | ctx.scale(scale, scale); | ||||
ctx.translate(70, -50); | ctx.translate(70, -50); | ||||
ctx.rotate(Math.PI / 2); | ctx.rotate(Math.PI / 2); | ||||
this.img.draw(ctx); | |||||
if (this.vel.y < 0) | |||||
this.img.draw(ctx); | |||||
else | |||||
this.img_flipped.draw(ctx); | |||||
} | } | ||||
/* | /* | ||||
function Obstacle(game, x, y) { | function Obstacle(game, x, y) { | ||||
makeEnt(this, game, 100); | makeEnt(this, game, 100); | ||||
this.img = assets.imgs.wall; | this.img = assets.imgs.wall; | ||||
this.overlap = assets.imgs.wall_overlap; | |||||
this.collude = false; | this.collude = false; | ||||
ctx.scale(0.9, 1.1); | ctx.scale(0.9, 1.1); | ||||
this.img.draw(ctx); | this.img.draw(ctx); | ||||
} | } | ||||
Obstacle.prototype.drawOverlay =function(ctx) { | |||||
ctx.translate(-100, this.game.canvas.height / 2 - 340); | |||||
ctx.scale(0.9, 1.1); | |||||
this.overlap.draw(ctx); | |||||
} | |||||
Obstacle.prototype.update = function() { | Obstacle.prototype.update = function() { | ||||
if (this.game.camera.x > this.pos.x + 800) | if (this.game.camera.x > this.pos.x + 800) | ||||
this.dead = true; | this.dead = true; |
} | } | ||||
// Make entity from object | // Make entity from object | ||||
function makeEnt(obj, game, mass) { | |||||
function makeEnt(obj, game, mass, id) { | |||||
obj.pos = new Vec2(); | obj.pos = new Vec2(); | ||||
obj.vel = new Vec2(); | obj.vel = new Vec2(); | ||||
obj.force = new Vec2(); | obj.force = new Vec2(); | ||||
obj.mass = mass || 0; | obj.mass = mass || 0; | ||||
obj.forceScalar = 1 / obj.mass; | obj.forceScalar = 1 / obj.mass; | ||||
if (id) { | |||||
game.ids[id] = obj; | |||||
} | |||||
} | } | ||||
/* | /* | ||||
this.worldgen = null; | this.worldgen = null; | ||||
this.entities = []; | this.entities = []; | ||||
this.ids = {}; | |||||
this.layers = []; | this.layers = []; | ||||
this.inputListeners = []; | this.inputListeners = []; | ||||
} | } | ||||
} | } | ||||
ent.drawn = false; | |||||
if (ent.collude && ent.pos.x + ent.shape.width() < this.camera.x) | if (ent.collude && ent.pos.x + ent.shape.width() < this.camera.x) | ||||
continue; | continue; | ||||
if (ent.collude && ent.pos.x > this.camera.x + this.canvas.width) | if (ent.collude && ent.pos.x > this.camera.x + this.canvas.width) | ||||
continue; | continue; | ||||
ent.drawn = true; | |||||
this.ctx.save(); | this.ctx.save(); | ||||
this.ctx.translate( | this.ctx.translate( | ||||
ent.pos.x - this.camera.x, | ent.pos.x - this.camera.x, | ||||
} | } | ||||
} | } | ||||
// Go through and draw overlap | |||||
for (var i = 0; i < this.layers.length; ++i) { | |||||
var layer = this.layers[i]; | |||||
for (var j = 0; j < layer.length; ++j) { | |||||
var ent = layer[j]; | |||||
if (!ent.drawn) | |||||
continue; | |||||
if (!ent.drawOverlay) | |||||
continue; | |||||
this.ctx.save(); | |||||
this.ctx.translate( | |||||
ent.pos.x - this.camera.x, | |||||
ent.pos.y - this.camera.y); | |||||
ent.drawOverlay(this.ctx); | |||||
this.ctx.restore(); | |||||
} | |||||
} | |||||
// Clear presses | // Clear presses | ||||
for (var i in this.presses) { | for (var i in this.presses) { | ||||
this.presses[i] = false; | this.presses[i] = false; |
} | } | ||||
playSoundtrack(assets.soundtracks); | playSoundtrack(assets.soundtracks); | ||||
document.querySelector("#restart").addEventListener("click", function() { | |||||
document.querySelector("#done-screen").className = "hidden"; | |||||
run(); | |||||
}); | |||||
function run() { | function run() { | ||||
var game = new Game(document.getElementById("canvas")); | var game = new Game(document.getElementById("canvas")); | ||||
game.canvas.width = window.innerWidth; | game.canvas.width = window.innerWidth; | ||||
game.start(worldgen); | game.start(worldgen); | ||||
game.onstop = function(score) { | game.onstop = function(score) { | ||||
alert("You lost! Score: "+score); | |||||
run(); | |||||
document.querySelector("#score").innerText = score; | |||||
document.querySelector("#done-screen").className = ""; | |||||
} | } | ||||
} | } | ||||
this.powerupCounter = randInt(WorldGen.range[0], WorldGen.range[1]); | this.powerupCounter = randInt(WorldGen.range[0], WorldGen.range[1]); | ||||
// Spawn player and background | // Spawn player and background | ||||
game.spawn(new Background(game)); | |||||
game.spawn(new Player(game)); | game.spawn(new Player(game)); | ||||
game.spawn(new Background(game)); | |||||
} | } | ||||
WorldGen.range = [5, 12]; | WorldGen.range = [5, 12]; | ||||
{ | |||||
"name": "flappydick", | |||||
"version": "1.0.0", | |||||
"description": "", | |||||
"main": "conf.js", | |||||
"scripts": { | |||||
"test": "echo \"Error: no test specified\" && exit 1" | |||||
}, | |||||
"repository": { | |||||
"type": "git", | |||||
"url": "gogs@git.mort.coffee:mort/flappydick.git" | |||||
}, | |||||
"author": "Martin Dørum <martid0311@gmail.com> (http://mort.coffee)", | |||||
"license": "ISC" | |||||
} |