gpt4 book ai didi

javascript - forEach inside Ticker 使 Canvas 变慢

转载 作者:行者123 更新时间:2023-11-30 17:33:12 26 4
gpt4 key购买 nike

我正在创建一个使用碰撞检测的 HTML5 迷你游戏,我最近发现它存在速度问题:

我认为这个问题的原因是...

在 60fps 代码中有两个 forEach 循环,一个用于 rects 数组,另一个用于 lasers 数组。因此,当 Canvas 中有 5 个矩形和 5 个激光时,它将在第一个 forEach 中循环 5 次,在第二个每一帧 中循环五次,并且每个 forEach 函数中有很多 ifs,使游戏变慢。我如何才能将其更改为CPU 密集型

如果你知道这个小游戏中更大的速度问题,请随时帮助我解决它。


这是我的全部代码:

我强烈建议您查看 JSFiddle而不是下面的代码,因为有 400 多行。

<!DOCTYPE html>
<html>

<head>
<title>VelJS α</title>

<!-- This app was coded by Tiago Marinho -->
<!-- Do not leech it! -->

<link rel="shortcut icon" href="http://i.imgur.com/Jja8mvg.png">

<!-- EaselJS: -->
<script src="http://static.tumblr.com/uzcr0ts/uzIn1l1v2/easeljs-0.7.1.min.js"></script>

<script src="http://pastebin.com/raw.php?i=W4S2mtCp"></script>

<!-- jQuery: -->
<script src="http://code.jquery.com/jquery-1.11.0.min.js"></script>

<script>
(function () {

// Primary vars (stage, circle, rects):
var stage,
circle, // Hero!
rects = [], // Platforms
lasers = [];
// Velocity vars:
var xvel = 0, // X Velocity
yvel = 0, // Y Velocity
xvelpast = 0,
yvelpast = 0;
// Keyvars (up, left, right, down):
var up = false, // W or arrow up
left = false, // A or arrow left
right = false, // D or arrow right
down = false; // S or arrow down
// Other vars (maxvel, col, pause):
var maxvel = 256, // Maximum velocity
col = false, // Collision detection helper (returns true if collided side-to-side)
pause = false;
// Volatility vars (rmdir, pastrmdir):
var rmdir = 0,
pastrmdir = 0;

// Main part (aka creating stage, creating circle, etc):

function init() {
stage = new createjs.Stage("canvas");

// Creating circle:
var circle = new createjs.Shape();
circle.radius = 11;
circle.graphics.beginFill("#fff").beginStroke("white").drawCircle(circle.radius - 0.5, circle.radius - 0.5, circle.radius);
circle.width = circle.radius * 2;
circle.height = circle.radius * 2;
stage.addChild(circle);

setTimeout(function () {

// newobj(W, H, X, Y)
newobj("laser", 3, 244, stage.canvas.width / 2 - 125, stage.canvas.height / 4 * 3 - 247);
newobj("rect", 125, 3, stage.canvas.width / 2 - 125, stage.canvas.height / 4 * 3 - 250);
}, 250); // Wait until first tick finishes and stage is resized to 100%, then calculate the middle of canvas.

// User Input (Redirect input to Input Handler):

// Keydown:
document.addEventListener("keydown", function (evt) {
if (evt.keyCode == 87 || evt.keyCode == 38) { // up
up = true;
}
if (evt.keyCode == 65 || evt.keyCode == 37) { // left
left = true;
}
if (evt.keyCode == 68 || evt.keyCode == 39) { // right
right = true;
}
if (evt.keyCode == 83 || evt.keyCode == 40) { // down
down = true;
}
if (evt.keyCode == 8 || evt.keyCode == 80) { // del/p
if (pause == false) {
xvelpast = xvel;
yvelpast = yvel;
pause = true;

var fadestep = 0;
for (var i = 1; i > 0; i -= 0.1) {
i = parseFloat(i.toFixed(1));
fadestep++;
fadeFill("circle", i, fadestep);
rects.forEach(function (rect) {
fadeFill("rect", i, fadestep);
});
}
} else {
pause = false;
xvel = xvelpast;
yvel = yvelpast;
var fadestep = 0;
for (var i = 0; i <= 1; i += 0.1) {
i = parseFloat(i.toFixed(1));
fadestep++;
fadeFill("circle", i, fadestep);
rects.forEach(function (rect) {
fadeFill("rect", i, fadestep);
});
}
}
}
});
// Keyup:
document.addEventListener("keyup", function (evt) {
if (evt.keyCode == 87 || evt.keyCode == 38) { // up
up = false;
}
if (evt.keyCode == 65 || evt.keyCode == 37) { // left
left = false;
}
if (evt.keyCode == 68 || evt.keyCode == 39) { // right
right = false;
}
if (evt.keyCode == 83 || evt.keyCode == 40) { // down
down = false;
}
});

// Functions:

// Fade beginFill to a lower alpha:
function fadeFill(obj, i, t) {
setTimeout(function () {
if (obj == "circle") {
circle.graphics.clear().beginFill("rgba(255,255,255," + i + ")").beginStroke("white").drawCircle(circle.radius, circle.radius, circle.radius).endFill();
}
if (obj == "rect") {
for (var r = 0; r < rects.length; r++) {
rects[r].graphics.clear().beginFill("rgba(255,255,255," + i + ")").beginStroke("white").drawRect(0, 0, rects[r].width, rects[r].height).endFill();
}
}
}, t * 20);
};
// To create new rects:
function newobj(type, w, h, x, y) {
if (type == "rect") {
var rect = new createjs.Shape();
rect.graphics.beginFill("#fff").beginStroke("white").drawRect(0, 0, w, h);
rect.width = w + 1;
rect.height = h + 1;
rect.y = Math.round(y) + 0.5;
rect.x = Math.round(x) + 0.5;
stage.addChild(rect);
rects.push(rect);
}
if (type == "laser") {
var laser = new createjs.Shape();
if (w >= h) {
laser.graphics.beginFill("#c22").drawRect(0, 0, w, 1);
laser.width = w;
laser.height = 1;
} else {
laser.graphics.beginFill("#c22").drawRect(0, 0, 1, h);
laser.width = 1;
laser.height = h;
}
laser.shadow = new createjs.Shadow("#ff0000", 0, 0, 5);
laser.y = Math.round(y);
laser.x = Math.round(x);
stage.addChild(laser);
lasers.push(laser);
}
}
// Collision recoil:
function cls(clsdir) {
if (clsdir == "top") {
if (yvel <= 4) {
yvel = 0;
} else {
yvel = Math.round(yvel * -0.5);
}
}
if (clsdir == "left") {
if (xvel <= 4) {
xvel = 0;
} else {
xvel = Math.round(xvel * -0.5);
}
}
if (clsdir == "right") {
if (xvel >= -4) {
xvel = 0;
} else {
xvel = Math.round(xvel * -0.5);
}
}
if (clsdir == "bottom") {
if (yvel >= -4) {
yvel = 0;
} else {
yvel = Math.round(yvel * -0.5);
}
}
col = true;
}
// Die:
function die() {
circle.alpha = 1;
createjs.Tween.get(circle).to({
alpha: 0
}, 250).call(handleComplete);

function handleComplete() {
circle.x = stage.canvas.width / 2 - circle.radius;
circle.y = stage.canvas.height / 2 - circle.radius;
createjs.Tween.get(circle).to({
alpha: 1
}, 250);
yvel = 0;
xvel = 0;
yvelpast = 0;
xvelpast = 0;
}
yvel = yvel/2;
xvel = xvel/2;
}

// Set Intervals:

// Speed/Score:
setInterval(function () {
if (pause == false) {
speed = Math.abs(xvel) + Math.abs(yvel);
$(".speed").html("Speed: " + speed);
} else {
speed = Math.abs(xvelpast) + Math.abs(yvelpast);
$(".speed").html("Speed: " + speed + " (Paused)");
}
}, 175);

// Tick:

createjs.Ticker.on("tick", tick);
createjs.Ticker.setFPS(60);

function tick(event) {

// Input Handler:

if (up == true) {
yvel -= 2;
} else {
if (yvel < 0) {
yvel++;
}
}
if (left == true) {
xvel -= 2;
} else {
if (xvel < 0) {
xvel++;
}
}
if (right == true) {
xvel += 2;
} else {
if (xvel > 0) {
xvel--;
}
}
if (down == true) {
yvel += 2;
} else {
if (yvel > 0) {
yvel--;
}
}

// Volatility:

pastrmdir = rmdir;
rmdir = Math.floor((Math.random() * 20) + 1);
if (rmdir == 1 && pastrmdir != 4) {
yvel--;
}
if (rmdir == 2 && pastrmdir != 3) {
xvel--;
}
if (rmdir == 3 && pastrmdir != 2) {
xvel++;
}
if (rmdir == 4 && pastrmdir != 1) {
yvel++;
}

// Velocity limiter:

if (xvel > maxvel || xvel < maxvel * -1) {
(xvel > 0) ? xvel = maxvel : xvel = maxvel * -1;
}
if (yvel > maxvel || yvel < maxvel * -1) {
(yvel > 0) ? yvel = maxvel : yvel = maxvel * -1;
}

// Collision handler:
// xvel and yvel modifications must be before this!

rects.forEach(function (rect) { // Affect all rects

// Collision detection:
// (This MUST BE after every change in xvel/yvel)

// Next circle position calculation:
nextposx = circle.x + event.delta / 1000 * xvel * 30,
nextposy = circle.y + event.delta / 1000 * yvel * 30;
// Collision between objects (Rect and Circle):
if (nextposy + circle.height > rect.y && circle.y + circle.height < rect.y && circle.x + circle.width > rect.x && circle.x < rect.x + rect.width) {
cls("top");
}
if (nextposx + circle.width > rect.x && circle.x + circle.width < rect.x && circle.y + circle.height > rect.y && circle.y < rect.y + rect.height) {
cls("left");
}
if (nextposx < rect.x + rect.width && circle.x > rect.x + rect.width && circle.y + circle.height > rect.y && circle.y < rect.y + rect.height) {
cls("right");
}
if (nextposy < rect.y + rect.height && circle.y > rect.y + rect.height && circle.x + circle.width > rect.x && circle.x < rect.x + rect.width) {
cls("bottom");
}
rects.forEach(function (rect) {
// Check side-to-side collisions with other rects:
if (nextposy + circle.height > rect.y && circle.y + circle.height < rect.y && circle.x + circle.width > rect.x && circle.x < rect.x + rect.width) {
col = true;
}
if (nextposx + circle.width > rect.x && circle.x + circle.width < rect.x && circle.y + circle.height > rect.y && circle.y < rect.y + rect.height) {
col = true;
}
if (nextposx < rect.x + rect.width && circle.x > rect.x + rect.width && circle.y + circle.height > rect.y && circle.y < rect.y + rect.height) {
col = true;
}
if (nextposy < rect.y + rect.height && circle.y > rect.y + rect.height && circle.x + circle.width > rect.x && circle.x < rect.x + rect.width) {
col = true;
}
});

// Edge-to-edge collision between objects (Rect and Circle) - Note that this will not occur if a side-to-side collision occurred in the current frame!:
if (nextposy + circle.height > rect.y &&
nextposx + circle.width > rect.x &&
nextposx < rect.x + rect.width &&
nextposy < rect.y + rect.height &&
col == false) {
if (circle.y + circle.height < rect.y &&
circle.x + circle.width < rect.x) {
cls("top");
cls("left");
}
if (circle.y > rect.y + rect.height &&
circle.x + circle.width < rect.x) {
cls("bottom");
cls("left");
}
if (circle.y + circle.height < rect.y &&
circle.x > rect.x + rect.width) {
cls("top");
cls("right");
}
if (circle.y > rect.y + rect.height &&
circle.x > rect.x + rect.width) {
cls("bottom");
cls("right");
}
}
col = false;

// Stage collision:
if (nextposy < 0) { // Collided with TOP of stage. Trust me.
cls("bottom"); // Inverted clsdir is proposital!
}
if (nextposx < 0) {
cls("right");
}
if (nextposx + circle.width > stage.canvas.width) {
cls("left");
}
if (nextposy + circle.height > stage.canvas.height) {
cls("top");
}
});

// Laser collision handler:
lasers.forEach(function (laser) {
laser.alpha = Math.random() + 0.5;
nextposx = circle.x + event.delta / 1000 * xvel * 30,
nextposy = circle.y + event.delta / 1000 * yvel * 30;

if (nextposy + circle.height > laser.y && circle.y + circle.height < laser.y && circle.x + circle.width > laser.x && circle.x < laser.x + laser.width) {
circle.y = laser.y-circle.height;
die();
}
if (nextposx + circle.width > laser.x && circle.x + circle.width < laser.x && circle.y + circle.height > laser.y && circle.y < laser.y + laser.height) {
circle.x = laser.x-circle.width;
die();
}
if (nextposx < laser.x + laser.width && circle.x > laser.x + laser.width && circle.y + circle.height > laser.y && circle.y < laser.y + laser.height) {
circle.x = laser.x+laser.width;
die();
}
if (nextposy < laser.y + laser.height && circle.y > laser.y + laser.height && circle.x + circle.width > laser.x && circle.x < laser.x + laser.width) {
circle.y = laser.y+laser.height;
die();
}
});

// Velocity:
if (pause == true) {
xvel = 0;
yvel = 0;
}
circle.x += event.delta / 1000 * xvel * 20;
circle.y += event.delta / 1000 * yvel * 20;

// Stage.canvas 100% width and height:

stage.canvas.width = window.innerWidth;
stage.canvas.height = window.innerHeight;

// Update stage:

stage.update(event);
}
setTimeout(function () {
// Centre circle:
circle.x = stage.canvas.width / 2 - circle.radius;
circle.y = stage.canvas.height / 2 - circle.radius;

// Fade-in after loading:

$(".speed").css({
opacity: 1
});
$("canvas").css({
opacity: 1
});
}, 500);
}
$(function () {
init();
});
})();
</script>
<style>
* {
margin: 0;
}
html,
body {
-webkit-font-smoothing: antialiased;
font-family: "HelveticaNeue-Light", "Helvetica Neue Light", "Helvetica Neue", Helvetica, Arial, "Lucida Grande", sans-serif;
font-weight: 300;
color: #fff;
background-color: #181818
}
.build {
position: absolute;
bottom: 5px;
right: 5px;
color: rgba(255, 255, 255, 0.05)
}
canvas {
-ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)";
filter: alpha(opacity=0);
opacity: 0;
position: absolute;
top: 0;
left: 0;
-moz-transition: 5s ease;
-o-transition: 5s ease;
-webkit-transition: 5s ease;
transition: 5s ease
}
.speed {
-ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)";
filter: alpha(opacity=0);
opacity: 0;
position: absolute;
top: 5px;
left: 5px;
color: #fff;
font-size: 16px;
-moz-transition: 5s ease;
-o-transition: 5s ease;
-webkit-transition: 5s ease;
transition: 5s ease
}
h2 {
text-align: center;
font-size: 22px;
font-weight: 700
}
p {
font-size: 16px;
margin: 0
}
</style>
</head>

<body>
<p class="speed"></p>
<p class="build">α256</p>
<canvas id="canvas">
<h2>Your browser doesn't support Canvas.</h2>
<p>Switch to <b>Chrome 33</b>, <b>Firefox 27</b> or <b>Safari 7</b>.</p>
</canvas>
</body>

</html>

JSFiddle

最佳答案

游戏逻辑不是真正的问题,它慢的原因是你通过设置宽度和高度在每个刻度“创建”一个新的 Canvas :

stage.canvas.width = window.innerWidth;
stage.canvas.height = window.innerHeight;

因此,即使您将 Canvas 宽度和高度设置为相同的值,在引擎盖下也几乎构建了一个新 Canvas 。如果您从游戏循环中删除上面的行,它应该可以顺利运行。

只需设置一次 Canvas 宽度和高度,然后监听窗口调整大小并在浏览器窗口更改大小时设置它。

关于javascript - forEach inside Ticker 使 Canvas 变慢,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22566527/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com