Compare commits

..

No commits in common. "ee84ecaad01e50cf6ccfd81a3a56fb1618768440" and "460d5ef60d6e341ef31f93434feece660eb54a45" have entirely different histories.

View File

@ -81,10 +81,20 @@
<div id="viewport"> <div id="viewport">
<div id="flash" style="z-index:11; <div id="flash" style="z-index:11;
background-color: white; background-color: white;
width: 100vw; width: 800px;
height: 100vh; height: 480px;
opacity: 0%;"></div> opacity: 0%;"></div>
<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=" <div id="background" style="
left:0px; left:0px;
top:0px; top:0px;
@ -95,53 +105,37 @@
z-index: -2; z-index: -2;
"> ">
</div> </div>
<div id="background2" style="
left:800px;
top:0px;
background-image:url(sheet.png);
background-position: -0px -355px;
width: 800px;
height: 480px;
z-index: -2;
">
</div>
<div id="plane" style=" <div id="plane" style="
z-index: 0; z-index: 0;
"> ">
</div> </div>
</div>
<div id="game_over" style=" <div id="game_over" style="
left: calc(50vw - 206px); left:200px;
top: 40vh; top:200px;
background-image:url(sheet.png); background-image:url(sheet.png);
background-position: -0px -835px; background-position: -0px -835px;
width: 412px; width: 412px;
height: 78px; height: 78px;
z-index: 10; z-index: 10;
"> ">
</div> </div>
<div id="score" style=" <div id="get_ready" style="
left:50px; left:200px;
top: 50px; top:200px;
z-index: 10;
">Score</div>
<div id="get_ready" style="
left: calc(50vw - 200px);
top: 40vh;
background-image:url(sheet.png); background-image:url(sheet.png);
background-position: -0px -913px; background-position: -0px -913px;
width: 400px; width: 400px;
height: 73px; height: 73px;
z-index: 10; z-index: 10;
"> ">
</div>
</div> </div>
<script> <script>
// // Setup // Setup
// Scale viewport to fit device width // Scale viewport to fit device width
function apply_scale() { function apply_scale() {
@ -151,6 +145,7 @@
} }
window.onresize = apply_scale; window.onresize = apply_scale;
apply_scale(); apply_scale();
// Game Loop // Game Loop
@ -168,6 +163,12 @@
STARTSCREEN: 1 STARTSCREEN: 1
}; };
var current_gamestate = GameState.STARTSCREEN;
var has_died = false;
var just_died = false;
var frame_passed = false;
function frame() { function frame() {
now = timestamp(); now = timestamp();
dt = dt + Math.min(1, (now - last) / 1000); dt = dt + Math.min(1, (now - last) / 1000);
@ -183,31 +184,15 @@
requestAnimationFrame(frame); requestAnimationFrame(frame);
} }
// // Game // Game
const GRAVITY = 200 const GRAVITY = 200
const JUMP_VEL = 200 const JUMP_VEL = 200
const SPIKE_DISTANCE = 250 const SPIKE_DISTANCE = 250
const GROUND_DISTANCE = 800;
const INITIAL_SPIKE_DISTANCE = 2000;
const FIRST_SPIKE_POSITION = 350;
// Should be considered a const too, but can't be because it needs to react to viewport resizing
var camera_x = window.innerWidth / 10.0; var camera_x = window.innerWidth / 10.0;
// Score
var score = 0; var score = 0;
var under_spikes_in_previous_frame = false; var under_spikes_in_previous_frame = false;
// Level placement utilities
var next_spike_location;
var current_gamestate = GameState.STARTSCREEN;
var has_died = false; // true if the player has ever died during this session
var just_died = false; // true from player death to one frame after play death
var frame_passed_after_death = false; // true in the frame after the player has died
// Classes
class Bird { class Bird {
constructor() { constructor() {
this.position_x = 100; this.position_x = 100;
@ -285,103 +270,39 @@
} }
} }
class Ground {
constructor(x) {
this.position_x = x;
this.position_y = 12345;
this.id = Math.floor(Math.random() * 1000000);
this.element1 = document.createElement("div");
this.element1.id = this.id;
document.getElementById("viewport").appendChild(this.element1);
$("#" + this.id).css({
"left": (this.position_x) + "px",
"top": "409px",
"background-image": "url(sheet.png)",
"background-position": "-0px -142px",
"width": "800px",
"height": "71px",
"z-index": "2"
});
}
set_camera_position(x) {
$("#" + this.id).css({
"left": (this.position_x + x) + "px"
})
}
remove() {
document.getElementById(this.id).remove();
}
}
// Objects
let player = new Bird() let player = new Bird()
var spikes = [] var spikes = []
var grounds = []
// Utility functions function spawn_spikes(x, y) {
spikes.push(new Spikes(x, y));
}
function randomInt(min, max) { function randomInt(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min; return Math.floor(Math.random() * (max - min + 1)) + min;
} }
function spawn_spikes() { const INITIAL_SPIKE_DISTANCE = 2000;
spikes.push(new Spikes(next_spike_location, randomInt(-100, 100)));
next_spike_location += SPIKE_DISTANCE;
}
function spawn_ground(x) {
grounds.push(new Ground(x));
}
// Setup the game world by removing old objects and spawning new ones
function setupGame() { function setupGame() {
next_spike_location = FIRST_SPIKE_POSITION;
spikes.forEach(function (spike) { spikes.forEach(function (spike) {
spike.remove(); spike.remove();
}) })
grounds.forEach(function (ground) {
ground.remove();
})
spikes.length = 0; spikes.length = 0;
grounds.length = 0;
player.position_x = 100; player.position_x = 100;
player.position_y = 150; player.position_y = 150;
player.velocity_y = 0; player.velocity_y = 0;
for (let i = next_spike_location; i < INITIAL_SPIKE_DISTANCE; i += SPIKE_DISTANCE) { for (let i = 350; i < INITIAL_SPIKE_DISTANCE; i += SPIKE_DISTANCE) {
spawn_spikes(); spawn_spikes(i, randomInt(-100, 100));
}
for (let i = -GROUND_DISTANCE; i < INITIAL_SPIKE_DISTANCE; i += GROUND_DISTANCE) {
spawn_ground(i);
} }
} }
// Fixed time loop // Fixed time loop
function update(dt) { function update(dt) {
if (current_gamestate == GameState.PLAYING) { if (current_gamestate == GameState.PLAYING) {
// Remove old spikes and spawn new ones
var first_spike = spikes[0];
if (first_spike.position_x < player.position_x - camera_x - first_spike.width) {
// This spike has just left the view -> remove it
first_spike.remove()
spikes.shift();
// Spawn new spikes in front of the player
spawn_spikes();
}
// Move the player
player.position_y += player.velocity_y * dt; player.position_y += player.velocity_y * dt;
player.position_x += 100 * dt; player.position_x += 100 * dt;
@ -400,9 +321,9 @@
die(); die();
} }
// Player hits a spike
var under_spikes_this_frame = false; var under_spikes_this_frame = false;
// Player hits a spike
spikes.forEach(function (spike) { spikes.forEach(function (spike) {
if (player.get_center_x() > spike.position_x + spike.collision_begin_x if (player.get_center_x() > spike.position_x + spike.collision_begin_x
&& player.get_center_x() < spike.position_x + spike.collision_end_x) { && player.get_center_x() < spike.position_x + spike.collision_end_x) {
@ -420,13 +341,14 @@
if (under_spikes_in_previous_frame && !under_spikes_this_frame) { if (under_spikes_in_previous_frame && !under_spikes_this_frame) {
score += 1; score += 1;
} }
under_spikes_in_previous_frame = under_spikes_this_frame; under_spikes_in_previous_frame = under_spikes_this_frame;
// TODO: Display as UI // TODO: Display as UI
console.log(score); console.log(score);
} else if (current_gamestate == GameState.STARTSCREEN) { } else if (current_gamestate == GameState.STARTSCREEN) {
// Drop the player to the ground if they're not there yet (after hitting a spike) // Drop the player to the ground if they're not there yet (after hitting a spike)
if (player.position_y < 400 && has_died) { if (player.position_y < 400) {
player.velocity_y += GRAVITY * dt; player.velocity_y += GRAVITY * dt;
player.position_y += player.velocity_y * dt; player.position_y += player.velocity_y * dt;
} }
@ -435,21 +357,21 @@
// Variable time render loop // Variable time render loop
function render(dt) { function render(dt) {
// Place the player
$("#plane").css({ $("#plane").css({
top: player.position_y + "px", top: player.position_y + "px",
left: camera_x + "px" left: camera_x + "px"
}); });
// Move the camera by moving everything in the level by the inverse of the player position // 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) { spikes.forEach(function (spike) {
spike.set_camera_position(-player.position_x + camera_x); spike.set_camera_position(-player.position_x + camera_x);
}) })
grounds.forEach(function (ground) {
ground.set_camera_position(-player.position_x + camera_x);
})
// Visibility of start / game over texts
if (current_gamestate == GameState.STARTSCREEN) { if (current_gamestate == GameState.STARTSCREEN) {
if (has_died == false) { if (has_died == false) {
$("#get_ready").css({ visibility: "visible" }); $("#get_ready").css({ visibility: "visible" });
@ -464,46 +386,36 @@
} }
if (just_died) { if (just_died) {
// We need to wait for one frame in order to make sure that the flash has been set to full opacity by die(). if (frame_passed == true) {
// After waiting for this frame to pass, we can enable the smooth transition to 0% opacity.
if (frame_passed_after_death == true) {
$("#flash").addClass("opacity-transition"); $("#flash").addClass("opacity-transition");
$("#flash").css({ $("#flash").css({
"opacity": "0%", "opacity": "0%",
}); });
frame_passed = false;
frame_passed_after_death = false;
just_died = false; just_died = false;
} else { } else {
frame_passed_after_death = true; frame_passed = true;
} }
} }
} }
// Lose state
function die() { function die() {
current_gamestate = GameState.STARTSCREEN; current_gamestate = GameState.STARTSCREEN;
has_died = true; has_died = true;
just_died = true; just_died = true;
// Remove the flash from the opacity-transition class to set it to white immediately
$("#flash").removeClass("opacity-transition") $("#flash").removeClass("opacity-transition")
$("#flash").css({ $("#flash").css({
"opacity": "100%", "opacity": "100%",
}); });
// Drop the player down with some speed
player.velocity_y = 100;
} }
// Sets up and starts a new game
function restart() { function restart() {
setupGame(); setupGame();
current_gamestate = GameState.PLAYING; current_gamestate = GameState.PLAYING;
} }
// Input
document.onmousedown = function (evt) { document.onmousedown = function (evt) {
if (current_gamestate == GameState.PLAYING) { if (current_gamestate == GameState.PLAYING) {
// Jump // Jump
@ -513,7 +425,6 @@
} }
}; };
// Start the game loop
requestAnimationFrame(frame); requestAnimationFrame(frame);
</script> </script>