我是一名 javascript 初学者,我正在努力提高我的技能。 我目前正在通过网站制作画布和动画。
我想做的是“模拟”城市汽车交通。我知道它毫无用处,但它让我致力于编码的不同方面。
目前,我的代码正在按我想要的方式工作,但动画很慢并且有点滞后。有时,代码需要时间来计算汽车的位置。
以下是完整 HTML 页面的代码:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<style>
*{
margin: 0;
position: absolute;
}
#background{
z-index: 1;
}
#cars{
z-index: 2;
}
</style>
</head>
<body>
<p id='debug'></p>
<canvas id="background"></canvas>
<canvas id="cars"></canvas>
<script type="text/javascript">
// BACKGROUND CANVAS -------------------------------------------
var background = document.getElementById("background");
background.height=window.innerHeight;
background.width=window.innerWidth;
var bkg=background.getContext("2d");
//--------------------------------------------------------------
// ANIMATED CANVAS ------------------------------------------------
var anim = document.getElementById("cars");
anim.height=window.innerHeight;
anim.width=window.innerWidth;
var anm=anim.getContext("2d");
// -------------------------------------------------------------
// VARIABLES ------------------------------------------
var width = anim.width;
var height = anim.height;
var numCars = 10;
var numRoads = 7;
if(width/numRoads/2<height/numRoads/2){
var roadWidth = ~~(width/numRoads/2);
} else {
var roadWidth = ~~(height/numRoads/2);
}
var klaxon = new Audio('res/sounds/klaxon.wav');
//------------------------------------------------------------------
// CROSSROAD LIST -----------------------------------
var roads = [];
for(i=0;i<numRoads+2;i++){
for(j=0;j<numRoads+2;j++){
var create = getRandomInt(3);
if(create>0){
roads.push([~~(width/(numRoads+1)*j),~~(height/(numRoads+1)*i),1])
} else {
roads.push([~~(width/(numRoads+1)*j),~~(height/(numRoads+1)*i),0])
}
}
}
// ------------------------------------------------------------
// TURN LIST -----------------------------------------
var turns = [];
var roadLength = roads.length;
for(i=0;i<roadLength;i++){
var road = roads[i];
if(road[2]==1){
if(i>numRoads+1 && (i+1)%(numRoads+2)!=0 && (i)%(numRoads+2)!=0 && i<roadLength-(numRoads+2)){
var rightbot = [~~(road[0]+roadWidth/4),~~(road[1]+roadWidth/4),0,0,0,0];
var righttop = [~~(road[0]+roadWidth/4),~~(road[1]-roadWidth/4),0,0,0,0];
var leftbot = [~~(road[0]-roadWidth/4),~~(road[1]+roadWidth/4),0,0,0,0];
var lefttop = [~~(road[0]-roadWidth/4),~~(road[1]-roadWidth/4),0,0,0,0];
if(roads[i+1][2]==1){
var right = true;
rightbot[3] = 1;
leftbot[3] = 1;
lefttop[4] = 1;
leftbot[3] = 1;
rightbot[2] = 1;
righttop[5] = 1;
}
if(roads[i-1][2]==1){
var left = true;
righttop[5] = 1;
lefttop[5] = 1;
lefttop[4] = 1;
leftbot[3] = 1;
rightbot[2] = 1;
righttop[5] = 1;
}
if(roads[i+(numRoads+2)][2]==1){
var bot = true;
lefttop[4] = 1;
leftbot[4] = 1;
lefttop[4] = 1;
leftbot[3] = 1;
rightbot[2] = 1;
righttop[5] = 1;
}
if(roads[i-(numRoads+2)][2]==1){
var top = true;
rightbot[2] = 1;
righttop[2] = 1;
lefttop[4] = 1;
leftbot[3] = 1;
rightbot[2] = 1;
righttop[5] = 1;
}
turns.push(rightbot,righttop,leftbot,lefttop);
}
}
}
//----------------------------------------------------------------------------------
// SPAWNPOINT LIST --------------------------------------------------
var spawnPoints = [];
for(i=1;i<roadLength;i++){
if(i!=(numRoads+1) && i!=(roadLength) && i!=(roadLength-1) && i!=(roadLength-(numRoads+2))){
var road = roads[i];
if(road[2]==1){
if(i<numRoads+1 && roads[i+numRoads+2][2]==1){
var spawnPoint = [~~(road[0]-roadWidth/4),~~(road[1]),"bot"];
spawnPoints.push(spawnPoint);
} else if(((i+1)%(numRoads+2))==0 && roads[i-1][2]==1){
var spawnPoint = [~~(road[0]),~~(road[1]-roadWidth/4),"left"];
spawnPoints.push(spawnPoint);
} else if(i>=(numRoads+2)){
if(i>roadLength-(numRoads+2) && roads[i-(numRoads+2)][2]==1){
var spawnPoint = [~~(road[0]+roadWidth/4),~~(road[1]),"top"];
spawnPoints.push(spawnPoint);
} else if(i<roadLength){
if((i)%(numRoads+2)==0 && roads[i+1][2]==1){
var spawnPoint = [~~(road[0]),~~(road[1]+roadWidth/4),"right"];
spawnPoints.push(spawnPoint);
}
}
}
}
}
}
//---------------------------------------------------------------------------
// BACKGROUND GEN ------------------------------------------------------
bkg.beginPath();
bkg.fillStyle = 'green';
bkg.rect(0,0,width,height);
bkg.fill();
for(i=0;i<roadLength;i++){
var road = roads[i];
if(road[2]==1){
if(i>numRoads+1 && (i+1)%(numRoads+2)!=0 && i<roadLength-(numRoads+2)){
if(roads[i+1][2]==1){
bkg.beginPath();
bkg.fillStyle = 'grey';
bkg.rect(road[0]-roadWidth/2,road[1]-roadWidth/2,roads[i+1][0]-road[0]+roadWidth,roadWidth);
bkg.fill();
}
}
if((i+1)%(numRoads+2)!=0 && i<roadLength-(numRoads+2) && (i)%(numRoads+2)!=0){
if(roads[i+numRoads+2][2]==1){
bkg.beginPath();
bkg.fillStyle = 'grey';
bkg.rect(road[0]-roadWidth/2,road[1]-roadWidth/2,roadWidth,roads[i+numRoads+2][1]-road[1]+roadWidth);
bkg.fill();
}
}
}
}
for(i=0;i<roadLength;i++){
var road = roads[i];
if(road[2]==1){
if(i>numRoads+1 && (i+1)%(numRoads+2)!=0 && i<roadLength-(numRoads+2)){
if(roads[i+1][2]==1){
bkg.beginPath();
bkg.setLineDash([5, 3]);
bkg.strokeStyle = 'white';
bkg.moveTo(road[0],road[1]);
bkg.lineTo(roads[i+1][0],roads[i+1][1]);
bkg.stroke();
bkg.fill();
}
}
if((i+1)%(numRoads+2)!=0 && i<roadLength-(numRoads+2) && (i)%(numRoads+2)!=0){
if(roads[i+numRoads+2][2]==1){
bkg.beginPath();
bkg.setLineDash([5, 3]);
bkg.strokeStyle = 'white';
bkg.moveTo(road[0],road[1]);
bkg.lineTo(roads[i+numRoads+2][0],roads[i+numRoads+2][1]);
bkg.stroke();
bkg.fill();
}
}
}
}
//-----------------------------------------------------------------------------------------
// CAR CLASS ---------------------------------------------------------------------------
function Car(){
this.size = ~~(roadWidth/4);
var rand = getRandomInt(spawnPoints.length);
try {
var initDir = spawnPoints[rand][2];
} catch {
location.reload();
}
this.x = spawnPoints[rand][0];
this.y = spawnPoints[rand][1];
switch(initDir){
case "right":
this.dir = 0;
break;
case "bot":
this.dir = (Math.PI)/2;
break;
case "top":
this.dir = -(Math.PI)/2;
break;
case "left":
this.dir = (Math.PI);
break;
}
this.timer = 0;
this.speedRand = 2+Math.random();
this.dx = Math.cos(this.dir)*(2+this.speedRand);
this.dy = Math.sin(this.dir)*(2+this.speedRand);
this.col = "red";
//this.col = '#'+(~~(Math.random()*16777215).toString(16);
}
// -----------------------------------------------------------------------------------------
// CAR LIST INIT ---------------------------------------------------------------
var cars = [];
for(i = 0 ; i < numCars ; i++){
var car = new Car();
cars.push(car);
}
//-----------------------------------------------------------------------------------------
var backRect = document.getElementById("background");
var intervalTurns = roadWidth/15;
var turnsLength = turns.length;
// DRAW UPDATE ----------------------------------------------------------------------------
function draw(){
// if(getRandomInt(50)==1){
// var car = new Car();
// cars.push(car);
// }
anm.globalAlpha = 0.1;
anm.drawImage(backRect,0,0);
anm.globalAlpha = 1;
var carsLength = cars.length;
for(i = 0; i < cars.length ; i++){
var car = cars[i];
anm.fillStyle=car.col;
anm.beginPath();
car.x = ~~(car.x+car.dx);
car.y = ~~(car.y+car.dy);
anm.rect(~~(car.x-car.size/2), ~~(car.y-car.size/2), car.size, car.size);
anm.fill();
if(car.timer==0){
for(j=0;j<turnsLength;j++){
var turn = turns[j];
if(car.x<turn[0]+intervalTurns && car.x>turn[0]-intervalTurns && car.y<turn[1]+intervalTurns && car.y>turn[1]-intervalTurns){
var possibleTurn = [];
for(i=2;i<turnsLength;i++){
if(turn[i]==1){
possibleTurn.push(i);
}
}
var change = getRandomInt(possibleTurn.length);
var newDir = possibleTurn[change];
switch(newDir){
case 2:
car.dir = -(Math.PI)/2;
car.dx = Math.cos(car.dir)*(2+car.speedRand);
car.dy = Math.sin(car.dir)*(2+car.speedRand);
break;
case 5:
car.dir = Math.PI;
car.dx = Math.cos(car.dir)*(2+car.speedRand);
car.dy = Math.sin(car.dir)*(2+car.speedRand);
break;
case 4:
car.dir = (Math.PI)/2;
car.dx = Math.cos(car.dir)*(2+car.speedRand);
car.dy = Math.sin(car.dir)*(2+car.speedRand);
break;
case 3:
car.dir = 0;
car.dx = Math.cos(car.dir)*(2+car.speedRand);
car.dy = Math.sin(car.dir)*(2+car.speedRand);
break;
}
car.timer = 3;
break;
}
}
} else if(car.timer > 0){
car.timer-=1;
}
if(car.x<0 || car.x>width || car.y<0 || car.y>height){
var rand = getRandomInt(spawnPoints.length);
try {
var initDir = spawnPoints[rand][2];
} catch {
location.reload();
}
car.x = spawnPoints[rand][0];
car.y = spawnPoints[rand][1];
//cars.splice(i,1);
switch(initDir){
case "right":
car.dir = 0;
car.dx = Math.cos(car.dir)*(2+car.speedRand);
car.dy = Math.sin(car.dir)*(2+car.speedRand);
break;
case "bot":
car.dir = (Math.PI)/2;
car.dx = Math.cos(car.dir)*(2+car.speedRand);
car.dy = Math.sin(car.dir)*(2+car.speedRand);
break;
case "top":
car.dir = -(Math.PI)/2;
car.dx = Math.cos(car.dir)*(2+car.speedRand);
car.dy = Math.sin(car.dir)*(2+car.speedRand);
break;
case "left":
car.dir = (Math.PI);
car.dx = Math.cos(car.dir)*(2+car.speedRand);
car.dy = Math.sin(car.dir)*(2+car.speedRand);
break;
}
}
}
}
//---------------------------------------------------------------------------------------
setInterval(draw, 30);
// KEYBINDS ------------------------------------------------------------------------
document.body.onkeyup = function(e){
if(e.keyCode == 32){
klaxon.play();
}
}
//-------------------------------------------------------------------------------
function getRandomInt(max) {
return ~~(Math.random() * max);
}
</script>
</body>
</html>
我很确定滞后来自于绘制函数中对转弯的不断检查(因为有很多),但我想确保这是问题所在。
另外,我尝试使用
~~
而不是 Math.floor()
、列表长度变量和中断来减少延迟,但我不确定这会产生很大的差异,不是吗?
您可以使用任何主要现代浏览器中的开发人员工具查看代码将时间花在哪里。从菜单中选择开发工具,或按 Ctrl+Shift+I 或 F12(或在 Mac OS 上按 Cmd+Shift+I)。可能有一个“性能”或“分析”选项卡(例如,在 Chrome 中,它是“性能”)。您可以使用其中的功能来运行您的代码,并查看它在哪些功能上花费最多时间等。您的浏览器的开发工具可能会有相当详细的文档记录。有一篇关于使用 Chrome 性能选项卡的文章这里。