msp-flappy-bird/index.html
2021-10-16 18:25:30 +02:00

381 lines
10 KiB
HTML

<html>
<head>
<style type="text/css">
body {
margin: 0;
padding: 0;
border: 0;
background: black;
overflow: hidden;
}
div {
position: absolute;
margin: 0;
padding: 0;
border: 0;
outline: 0;
font-family: arial;
font-size: 12px;
color: white;
text-align: center;
}
#viewport {
width: 100%;
height: 100%;
overflow: hidden;
top: 0px;
left: 0px;
margin-left: 0px;
margin-top: 0px;
}
#plane {
width: 88px;
height: 73px;
background-image: url(sheet.png);
-webkit-animation: cycle_sprites 300ms steps(1) infinite;
animation: cycle_sprites 300ms steps(1) infinite;
}
@-webkit-keyframes cycle_sprites {
0% {
background-position: -330px -1371px;
}
33.33% {
background-position: -372px -1132px;
}
66.66% {
background-position: -222px -1562px;
}
}
@keyframes cycle_sprites {
0% {
background-position: -330px -1371px;
}
33.33% {
background-position: -372px -1132px;
}
66.66% {
background-position: -222px -1562px;
}
}
</style>
<meta name="viewport" content="width=device-width, height=device-height, initial-scale=1, maximum-scale=1">
<script src="jquery-3.6.0.min.js"></script>
</head>
<body>
<div id="viewport">
<div id="floor" class="level" style="
left:0px;
top:409px;
background-image:url(sheet.png);
background-position: -0px -142px;
width: 800px;
height: 71px;
z-index: 2;
">
</div>
<div id="background" style="
left:0px;
top:0px;
background-image:url(sheet.png);
background-position: -0px -355px;
width: 800px;
height: 480px;
z-index: -2;
">
</div>
<div id="plane" style="
z-index: 0;
">
</div>
<div id="game_over" style="
left:200px;
top:200px;
background-image:url(sheet.png);
background-position: -0px -835px;
width: 412px;
height: 78px;
z-index: 10;
">
</div>
<div id="get_ready" style="
left:200px;
top:200px;
background-image:url(sheet.png);
background-position: -0px -913px;
width: 400px;
height: 73px;
z-index: 10;
">
</div>
</div>
<script>
// Setup
// Scale viewport to fit device width
function apply_scale() {
var scale = window.innerHeight / 480.0;
$("#viewport").css({ "transform": "scale(" + scale + ")", "transform-origin": "0 0" });
camera_x = window.innerWidth / 10.0;
}
window.onresize = apply_scale;
apply_scale();
// Game Loop
function timestamp() {
return window.performance && window.performance.now ? window.performance.now() : new Date().getTime();
}
var now,
dt = 0,
last = timestamp(),
step = 1 / 60;
const GameState = {
PLAYING: 0,
STARTSCREEN: 1
};
var current_gamestate = GameState.STARTSCREEN;
var has_died = false;
function frame() {
now = timestamp();
dt = dt + Math.min(1, (now - last) / 1000);
while (dt > step) {
dt = dt - step;
update(step);
}
render(dt);
last = now;
requestAnimationFrame(frame);
}
// Game
const GRAVITY = 200
const JUMP_VEL = 200
const SPIKE_DISTANCE = 250
var camera_x = window.innerWidth / 10.0;
class Bird {
constructor() {
this.position_x = 100;
this.position_y = 150;
this.width = 88;
this.height = 73;
this.velocity_y = 0;
}
get_center_x() {
return this.position_x + this.width / 2.0;
}
get_center_y() {
return this.position_y + this.height / 2.0;
}
}
class Spikes {
constructor(x, y) {
this.position_x = x;
this.position_y = y;
this.collision_begin_x = 25;
this.collision_end_x = 75;
this.collision_begin_y = 170;
this.collision_end_y = 280;
this.id = Math.floor(Math.random() * 1000000);
this.element1 = document.createElement("div");
this.element1.id = this.id;
this.element2 = document.createElement("div");
this.element2.id = this.id + 1;
document.getElementById("viewport").appendChild(this.element1);
document.getElementById("viewport").appendChild(this.element2);
$("#" + this.id).css({
"top": (y + 300) + "px",
"background-image": "url(sheet.png)",
"background-position": "-0px -1757px",
"width": "108px",
"height": "239px",
"z-index": "1"
})
$("#" + (this.id + 1)).css({
"top": (y - 100) + "px",
"background-image": "url(sheet.png)",
"background-position": "-264px -986px",
"width": "108px",
"height": "239px",
"z-index": "1"
})
}
set_camera_position(x) {
$("#" + this.id).css({
"left": (this.position_x + x) + "px"
})
$("#" + (this.id + 1)).css({
"left": (this.position_x + x) + "px"
})
}
remove() {
document.getElementById(this.id).remove();
document.getElementById(this.id + 1).remove();
}
}
let player = new Bird()
var spikes = []
function spawn_spikes(x, y) {
spikes.push(new Spikes(x, y));
}
function randomInt(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
const INITIAL_SPIKE_DISTANCE = 2000;
function setupGame() {
spikes.forEach(function (spike) {
spike.remove();
})
spikes.length = 0;
player.position_x = 100;
player.position_y = 150;
player.velocity_y = 0;
for (let i = 350; i < INITIAL_SPIKE_DISTANCE; i += SPIKE_DISTANCE) {
spawn_spikes(i, randomInt(-100, 100));
}
}
// Fixed time loop
function update(dt) {
if (current_gamestate == GameState.PLAYING) {
player.position_y += player.velocity_y * dt;
player.position_x += 100 * dt;
// Clamp at top
if (player.position_y < 0) {
player.position_y = 0;
player.velocity_y = 0;
}
// Gravity
player.velocity_y += GRAVITY * dt;
// // Lose conditions
// Player hits the ground
if (player.position_y > 400) {
die();
}
// Player hits a spike
spikes.forEach(function (spike) {
if (player.get_center_x() > spike.position_x + spike.collision_begin_x
&& player.get_center_x() < spike.position_x + spike.collision_end_x) {
// Player is inside the spikes - check the y axis
if (!(player.get_center_y() > spike.position_y + spike.collision_begin_y
&& player.get_center_y() < spike.position_y + spike.collision_end_y)) {
die();
}
}
})
} else if (current_gamestate == GameState.STARTSCREEN) {
// Do nothing
}
}
// Variable time render loop
function render(dt) {
$("#plane").css({
top: player.position_y + "px",
left: camera_x + "px"
});
// Move camera by moving everything in the level to the inverse of the player position
// TODO: offset by the object's actual position
$(".level").css({
left: (-player.position_x + camera_x) + "px"
})
spikes.forEach(function (spike) {
spike.set_camera_position(-player.position_x + camera_x);
})
if (current_gamestate == GameState.STARTSCREEN) {
if (has_died == false) {
$("#get_ready").css({ visibility: "visible" });
$("#game_over").css({ visibility: "hidden" });
} else {
$("#get_ready").css({ visibility: "hidden" });
$("#game_over").css({ visibility: "visible" });
}
} else {
$("#get_ready").css({ visibility: "hidden" });
$("#game_over").css({ visibility: "hidden" });
}
}
function die() {
current_gamestate = GameState.STARTSCREEN;
has_died = true;
}
function restart() {
setupGame();
current_gamestate = GameState.PLAYING;
}
document.onmousedown = function (evt) {
if (current_gamestate == GameState.PLAYING) {
// Jump
player.velocity_y = -JUMP_VEL;
} else if (current_gamestate == GameState.STARTSCREEN) {
restart();
}
};
requestAnimationFrame(frame);
</script>
</body>
</html>