You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
280 lines
6.6 KiB
JavaScript
280 lines
6.6 KiB
JavaScript
// https://stackoverflow.com/questions/25612452/html5-canvas-game-loop-delta-time-calculations
|
|
// TODO: Need to fully figure out a 60FPS and also display FPS on top right
|
|
let game = {
|
|
fps : 60 // ??
|
|
,time : 0.0
|
|
,start : Date.now()
|
|
,frameDuration : 1000 / 60 // Target FPS 60?
|
|
,lagOffset : 0
|
|
,player : false
|
|
}
|
|
|
|
startGame();
|
|
|
|
function startGame(){
|
|
|
|
// Create player
|
|
createPlayerEntity(canvas.width/2, canvas.height/2);
|
|
|
|
// Start game loop
|
|
gameLoop();
|
|
|
|
}
|
|
|
|
function gameLoop(){
|
|
|
|
// Check player exists (not dead/undefined by OOB)
|
|
if(entities[game.player] === undefined || game.player === false){
|
|
console.log('gome');
|
|
return false;
|
|
}
|
|
|
|
setTimeout(() => {
|
|
requestAnimationFrame(gameLoop, canvas);
|
|
}, game.frameDuration);
|
|
|
|
// Calcuate the time that has elapsed since the last frame
|
|
let current = Date.now();
|
|
let elapsed = current - game.start;
|
|
game.start = current;
|
|
game.lagOffset += elapsed;
|
|
|
|
// Update the frame if the lag counter is greater than or
|
|
// equal to the frame duration
|
|
while (game.lagOffset >= game.frameDuration){
|
|
|
|
gameUpdate();
|
|
game.lagOffset -= game.frameDuration;
|
|
|
|
}
|
|
|
|
// Calculate the lag offset and use it to render the sprites
|
|
// var lagOffset = Math.round(game.lagOffset / game.frameDuration);
|
|
// drawEntities(); // May need to pass lagOffset here to attempt to correct positions, etc.
|
|
drawGame();
|
|
|
|
// Print the game version above everything
|
|
printText(GAME_VERSION,
|
|
20,
|
|
canvas.height - 20,
|
|
'left', 'alphabetic', 'normal', 'bold', '10', 'Arial', '#00000050'
|
|
);
|
|
|
|
printText(elapsed,
|
|
canvas.width - 20 - (ctx.measureText(elapsed).width),
|
|
20 + 10, // + 10 is pt font-size to get in right pos
|
|
'left', 'alphabetic', 'normal', 'bold', '10', 'Arial', '#00000090'
|
|
);
|
|
|
|
}
|
|
|
|
// All the game update logic
|
|
function gameUpdate(){
|
|
|
|
calculatePlayerMovement();
|
|
calculateDirectionToPlayer();
|
|
|
|
updateMovement();
|
|
updateOOB();
|
|
|
|
if(MOUSE.down){
|
|
createBulkEntities(MOUSE.x, MOUSE.y);
|
|
}
|
|
|
|
|
|
}
|
|
|
|
function calculatePlayerMovement(){
|
|
|
|
let speedNow = speed[game.player];
|
|
if(KEYPRESS.shift){ speedNow = speedNow * 5; }
|
|
|
|
if(KEYPRESS.w){ position[game.player].y -= (1*speedNow); }
|
|
if(KEYPRESS.s){ position[game.player].y += (1*speedNow); }
|
|
|
|
if(KEYPRESS.a){ position[game.player].x -= (1*speedNow); }
|
|
if(KEYPRESS.d){ position[game.player].x += (1*speedNow); }
|
|
|
|
}
|
|
|
|
function updateMovement(){
|
|
// Use the direction currently, but likely 'velocity' in the future
|
|
for (const [entity] of Object.entries(direction)) {
|
|
if(position[entity] === undefined){ continue; }
|
|
|
|
if(direction[entity].x !== undefined){
|
|
if(direction[entity].x == 1){
|
|
position[entity].x += (1 * speed[entity]);
|
|
}
|
|
else if(direction[entity].x == -1){
|
|
position[entity].x -= (1 * speed[entity]);
|
|
}
|
|
}
|
|
|
|
if(direction[entity].y !== undefined){
|
|
if(direction[entity].y == 1){
|
|
position[entity].y += (1 * speed[entity]);
|
|
}
|
|
else if(direction[entity].y == -1){
|
|
position[entity].y -= (1 * speed[entity]);
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
function calculateDirectionToPlayer(){
|
|
|
|
// Enemies will W key towards the player as a hoard
|
|
for (const [entity] of Object.entries(position)) {
|
|
|
|
if(entity == game.player){ continue; }
|
|
|
|
if(position[game.player].x > position[entity].x){ direction[entity].x = 1; }
|
|
else{ direction[entity].x = -1; }
|
|
|
|
if(position[game.player].y > position[entity].y){ direction[entity].y = 1; }
|
|
else{ direction[entity].y = -1; }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
function updateOOB(){
|
|
for (const [entity] of Object.entries(position)) {
|
|
// Remove the entity if it goes out of bounds
|
|
if(
|
|
position[entity].y >= canvas.height-50 || position[entity].y <= 50
|
|
||
|
|
position[entity].x >= canvas.width-50 || position[entity].x <= 50
|
|
){
|
|
deleteEntity(entity);
|
|
}
|
|
}
|
|
}
|
|
function deleteEntity(entity){
|
|
|
|
// Remove from each component
|
|
// Definitely the most inefficient and janky way, but it does it
|
|
if(position[entity] !== null){ delete position[entity]; }
|
|
if(size[entity] !== null){ delete size[entity]; }
|
|
if(team.good[entity] !== null){ delete team.good[entity]; }
|
|
if(team.bad[entity] !== null){ delete team.bad[entity]; }
|
|
if(team.allied[entity] !== null){ delete team.allied[entity]; }
|
|
if(direction[entity] !== null){ delete direction[entity]; }
|
|
|
|
// Finally remove the entity itself
|
|
delete entities[entity];
|
|
entityLive--; // To keep track of how many active entities there are (just a count)
|
|
|
|
}
|
|
|
|
|
|
function drawGame(){
|
|
|
|
// Reset/clear all prior draws
|
|
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
|
|
|
drawEntities();
|
|
|
|
// Draw 'temp' hitbox area (to visualise entity removal)
|
|
drawRectangle(50,50,canvas.width-100,canvas.height-100,null,'#FFF');
|
|
|
|
}
|
|
|
|
// Draw the game's entities
|
|
function drawEntities(){
|
|
|
|
// Draw all entities (with size/position)
|
|
for (const entity in size) {
|
|
|
|
// If there's no position (or size), skip
|
|
if(position[entity] === undefined){ continue; }
|
|
|
|
// TEMP z-index draw to ensure player, etc. are drawn atop enemies (for now)
|
|
// 0,1,2 TODO: WHY ISN'T IT WOKRIINNNGG
|
|
for(let i = 0; i < 2; i++){
|
|
|
|
// JANK IF. Change to defensive when I can be bothered
|
|
if((zindex[entity] === undefined && i === 0) || zindex[entity] === i){
|
|
|
|
// console.log(zindex[entity]);
|
|
|
|
if(team.bad[entity] !== undefined){
|
|
// Draw pixels from imageCanvas
|
|
drawEnemy(entity);
|
|
}
|
|
if(team.allied[entity] !== undefined){
|
|
// Draw pixels from imageCanvas
|
|
drawAlly(entity);
|
|
}
|
|
|
|
// Player, temp
|
|
if(team.good[entity] !== undefined){
|
|
// Draw pixels from imageCanvas
|
|
drawPlayer(entity);
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
function createTestEntity(x,y){
|
|
|
|
entityCount++;
|
|
entityLive++; // To keep track of how many active entities there are (just a count)
|
|
entities[entityCount] = entityCount;
|
|
|
|
position[entityCount] = {x: x, y: y};
|
|
size[entityCount] = {width: 16, height: 16};
|
|
|
|
if(MOUSE.button[0]){
|
|
team.bad[entityCount] = true;
|
|
}
|
|
else if(MOUSE.button[1]){
|
|
team.allied[entityCount] = true;
|
|
}
|
|
else if(MOUSE.button[2]){
|
|
//
|
|
}
|
|
|
|
direction[entityCount] = {x: 0, y: 0}; // 0,1 left,right/up,down
|
|
zindex[entityCount] = 0;
|
|
speed[entityCount] = .75;
|
|
|
|
}
|
|
function createBulkEntities(x,y){
|
|
let amount = 90;
|
|
for(let i = 0; i < amount; i++){
|
|
createTestEntity(
|
|
x+(Math.floor(Math.random() * 45)+1)
|
|
,y+Math.floor(Math.random() * 35)+1
|
|
);
|
|
}
|
|
}
|
|
|
|
|
|
function createPlayerEntity(x,y){
|
|
|
|
entityCount++;
|
|
game.player = entityCount; // Set game.player to the player entity. TEMP
|
|
|
|
entityLive++; // To keep track of how many active entities there are (just a count)
|
|
entities[entityCount] = entityCount;
|
|
|
|
position[entityCount] = {x: x, y: y};
|
|
size[entityCount] = {width: 16, height: 16};
|
|
|
|
team.good[entityCount] = true;
|
|
|
|
direction[entityCount] = {x: 0, y: 0}; // 0,1 left,right/up,down
|
|
|
|
zindex[entityCount] = 1;
|
|
speed[entityCount] = 1.6;
|
|
|
|
}
|