Reputation: 35
Recently I've been trying to make JS canvas project and a few days ago I started coding it. I created enemies that generate random point on the canvas and move to it. I'm creating enemies by running createEnemy() function. It creates an object with enemy's data and stores it in "enemies" array. Everything works fine except of my FPS :( After some time they drop really hard. What's happening and why? Here's my code:
var c = document.getElementById("canv");
var context = c.getContext("2d");
var mouseX, mouseY;
const fpsTime = [];
var fps;
var enemies = []
var speed = 2
c.width = window.innerWidth;
c.height = window.innerHeight;
document.addEventListener("mousemove", e => { mouseX = e.pageX; mouseY = e.pageY;});
function getEnemies() {
return enemies;
}
function drawCharacter(x, y) {
context.clearRect(0, 0, c.width, c.height);
context.fillStyle = 'red';
context.fillRect(x, y,50,60);
context.save();
context.font = "30px Arial";
}
function getCurrentMouse() {
return {"x": mouseX, "y": mouseY}
}
function drawPoint(x, y) {
context.fillStyle = 'red';
context.fillRect(x, y,10,10);
context.save();
}
function createEnemy(name) {
var enemy = {
name: name,
didCompletePoint: true,
targetX: 0,
targetY: 0,
currentX: Math.floor(Math.random() * (+window.innerWidth + 1 - +0)) + +0,
currentY: Math.floor(Math.random() * (+window.innerHeight + 1 - +0)) + +0,
generatePoint: function() {
this.targetX = Math.floor(Math.random() * (+ window.innerWidth + 1 - +0)) + +0
this.targetY = Math.floor(Math.random() * (+ window.innerHeight + 1 - +0)) + +0
return [this.targetX, this.targetY];
},
draw: function() {
context.fillStyle = 'black';
context.fillRect(this.currentX, this.currentY,60,60);
context.save();
drawPoint(this.targetX, this.targetY)
context.font = "30px Arial";
}
};
enemies.push(enemy)
return enemy
}
var enemy = createEnemy("tak")
var enemy1 = createEnemy("tak")
var enemy2 = createEnemy("tak")
var enemy3 = createEnemy("tak")
var enemy5 = createEnemy("tak")
function drawFrame() {
document.getElementById("fps").innerHTML = "FPS: " + fps;
drawCharacter(getCurrentMouse().x, getCurrentMouse().y)
getEnemies().forEach((en, index) => {
if(en.didCompletePoint) {
en.didCompletePoint = false;
en.generatePoint()
}else {
if((en.targetX === en.currentX) && (en.targetY === en.currentY)) {
en.didCompletePoint = true;
}
else {
//vertical movement
if (en.targetY > en.currentY){
en.currentY++
}
else if (en.targetY < en.currentY) {
en.currentY--
}
//side movement
// going right
if (en.targetX > en.currentX) {
en.currentX++
}
// going left
else if (en.targetX < en.currentX) {
en.currentX--
}
}
}
en.draw()
})
}
function startLoop() {
window.requestAnimationFrame(() => {
const p = performance.now();
while (fpsTime.length > 0 && fpsTime[0] <= p - 1000) {
fpsTime.shift();
}
fpsTime.push(p);
fps = fpsTime.length;
drawFrame()
startLoop();
});
}
startLoop();
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
html, body {
width: 100%;
height: 100%;
margin: 0 !important;
padding: 0 !important;
}
</style>
</head>
<body>
<p id="fps" style="font-size: 30px; font-family: 'Calibri Light', serif; position: absolute; right: 2%; top: 0%;"></p>
<canvas id="canv" style="margin: 0;"></canvas>
</body>
<script src="script.js"></script>
</html>
Upvotes: 2
Views: 690
Reputation: 4244
First i need to say you are on good way. Using tradicional ecma is good to make fill good/comform in canvas oriented scripts.
You make mistake in context.save() calling . Constant calling save() without calling restore() make hard pain for program and causes memory leaks.
canvas 2d context must be used on smart way.
Usage for save restore
// we have some complex setup initial already
// but we need to change something
ctx.save()
ctx.fillStyle = "red";
ctx.fillText ('use it' , 1, 1, 111, 111)
ctx.restore()
// Now back me to the old setup
Almost to forgot one more bigger mistake: i removed startLoop() i put it like last call in drawFrame function. In that way we got fluid work.
Explanation: You call drawFrame() and than in same time call startLoop func how calls Again drawFrame....
My english is bad but i am glad if i help...
drawFrame()
startLoop();
var c = document.getElementById("canv");
var context = c.getContext("2d");
var mouseX, mouseY;
const fpsTime = [];
var fps;
var enemies = []
var speed = 2
c.width = window.innerWidth;
c.height = window.innerHeight;
document.addEventListener("mousemove", e => { mouseX = e.pageX; mouseY = e.pageY;});
function getEnemies() {
return enemies;
}
function drawCharacter(x, y) {
context.clearRect(0, 0, c.width, c.height);
context.fillStyle = 'red';
context.fillRect(x, y,50,60);
// context.font = "30px Arial";
}
function getCurrentMouse() {
return {"x": mouseX, "y": mouseY}
}
function drawPoint(x, y) {
context.fillStyle = 'red';
context.fillRect(x, y,10,10);
}
function createEnemy(name) {
var enemy = {
name: name,
didCompletePoint: true,
targetX: 0,
targetY: 0,
currentX: Math.floor(Math.random() * (+window.innerWidth + 1 - +0)) + +0,
currentY: Math.floor(Math.random() * (+window.innerHeight + 1 - +0)) + +0,
generatePoint: function() {
this.targetX = Math.floor(Math.random() * (+ window.innerWidth + 1 - +0)) + +0
this.targetY = Math.floor(Math.random() * (+ window.innerHeight + 1 - +0)) + +0
return [this.targetX, this.targetY];
},
draw: function() {
context.fillStyle = 'black';
context.fillRect(this.currentX, this.currentY,60,60);
drawPoint(this.targetX, this.targetY)
context.font = "30px Arial";
}
};
enemies.push(enemy)
return enemy
}
var enemy = createEnemy("tak")
var enemy1 = createEnemy("tak")
var enemy2 = createEnemy("tak")
var enemy3 = createEnemy("tak")
var enemy5 = createEnemy("tak")
function drawFrame() {
document.getElementById("fps").innerHTML = "FPS: " + fps;
drawCharacter(getCurrentMouse().x, getCurrentMouse().y)
getEnemies().forEach((en, index) => {
if(en.didCompletePoint) {
en.didCompletePoint = false;
en.generatePoint()
}else {
if((en.targetX === en.currentX) && (en.targetY === en.currentY)) {
en.didCompletePoint = true;
}
else {
//vertical movement
if (en.targetY > en.currentY){
en.currentY++;
}
else if (en.targetY < en.currentY) {
en.currentY--;
}
//side movement
// going right
if (en.targetX > en.currentX) {
en.currentX++;
}
// going left
else if (en.targetX < en.currentX) {
en.currentX--;
}
}
}
en.draw();
})
startLoop();
}
function startLoop() {
window.requestAnimationFrame(() => {
const p = performance.now();
while (fpsTime.length > 0 && fpsTime[0] <= p - 1000) {
fpsTime.shift();
}
fpsTime.push(p);
fps = fpsTime.length;
drawFrame();
});
}
startLoop();
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
html, body {
width: 100%;
height: 100%;
margin: 0 !important;
padding: 0 !important;
}
</style>
</head>
<body>
<p id="fps" style="font-size: 30px; font-family: 'Calibri Light', serif; position: absolute; right: 2%; top: 0%;"></p>
<canvas id="canv" style="margin: 0;"></canvas>
</body>
<script src="script.js"></script>
</html>
Upvotes: 3