JavaScript Canvas 游戏在一段时间后下降 FPS

标签 javascript performance canvas frame-rate

最近我一直在尝试制作 JS canvas 项目,几天前我开始编码它。我创建的敌人会在 Canvas 上生成随机点并移动到该点。我通过运行 createEnemy() 函数来创建敌人。它使用敌人的数据创建一个对象并将其存储在“敌人”数组中。除了我的 FPS 之外,一切都工作正常:( 一段时间后,它们下降得非常厉害。发生了什么以及为什么?这是我的代码:

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>

最佳答案

首先我需要说你进展顺利。使用传统的 ecma 可以很好地进行填充 面向 Canvas 的脚本良好/舒适。

您在 context.save() 调用中犯了错误。 不断调用 save() 而不调用 Restore() 会给程序带来痛苦 并导致内存泄漏。

canvas 2d 上下文必须以智能方式使用。

  • 切勿毫无目的地使用上下文。
  • 某些设置的成本更高,例如 .font 或阴影。

用于保存恢复

 // 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

差点忘记了一个更大的错误: 我删除了startLoop(),我把它放在drawFrame函数中的最后一个调用中。 通过这种方式,我们的工作变得流畅。

说明: 您调用drawFrame()并同时调用startLoop函数如何再次调用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>

关于JavaScript Canvas 游戏在一段时间后下降 FPS,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/67459706/

相关文章:

javascript - 将参数转换为对象?

linux - iozone 什么是记录大小/记录长度?

c# - 基数排序中的分组何时会带来优势?

python - Discord py - 如何提高代码速度?

javascript - 如何裁剪 Canvas 边?

javascript - 关闭模式对话框而不刷新父级

javascript - 将基本的Python游戏嵌入到网络中?

javascript - 是否可以从 JavaScript 中的 "inner"范围获取值?

swift - Buildtime Canvas Pod xCode 问题 |缺少 [super awakeFromNib] 调用 ||来自 CSAnimationView.m 文件

html - Canvas 教程/引用