我正在尝试使用HTML 5 canvas和JavaScript进行游戏编码。我的游戏还没有完成,但我已经遇到了一些突出的滞后问题。游戏可以在这里找到:http://survival.sthost.net/gunsvsships.html 此外,任何其他有关改进功能的建议都会有所帮助。这是js:
$(document).ready(function(){
var canvas = $("#canvas")[0];
var ctx = canvas.getContext("2d");
var w = $("#canvas").width();
var h = $("#canvas").height();
var cw = 10;
var title = new Image();
var startButton = new Image();
var startButtonSelected1 = new Image();
var startButtonSelected2 = new Image();
var startButtonSelected3 = new Image();
var background = new Image();
var ship = new Image();
var dead_ship = new Image();
var retical = new Image();
var bullet = new Image();
var slug = new Image();
var gunLabel1 = new Image();
var gunLabel2 = new Image();
var gunLabel3 = new Image();
var gunLabel4 = new Image();
var gunLabel5 = new Image();
var gunLabel1Trans = new Image();
var gunLabel2Trans = new Image();
var gunLabel3Trans = new Image();
var currentStartButton = startButton;
var startButtonIncrementor = 0;
var startButtonTimeNow = new Date().getTime();
var startButtonTimeThen = new Date().getTime();
var drawStart = true;
var gun = "Sniper"
var credits = 0;
var dead = 0;
var dead2 = 0;
var dead3 = 0;
var newSpeed = 5;
var bulletSpeed = 8;
var shipX = 0;
var ship2X = 1000;
var ship3X = 0;
var shipY = 250;
var ship2Y = 300;
var ship3Y = 250;
var bulletX = 500;
var bulletY = 550;
var slugAX = 500;
var slugBX = 500;
var slugCX = 500;
var slugAY = 550;
var slugBY = 550;
var slugCY = 550;
var gunType = -1;
var reticalX = 0;
var reticalY = 0;
var reticalX2 = -1;
var reticalY2 = -1;
var drawShipA = true;
var drawShipB = true;
var drawShipC = true;
var drawBullet = false;
var drawSlugs = false;
var now, then = new Date().getTime(), delta;
var sniperSound = new Audio("sniper.wav");
var shotgunSound = new Audio("shotgun.wav");
title.src = "images/title1.png";
startButton.src = "images/start_button.png";
startButtonSelected1.src = "images/start_button_selected1.png";
startButtonSelected2.src = "images/start_button_selected2.png";
startButtonSelected3.src = "images/start_button_selected3.png";
background.src = "images/background.png";
ship.src = "images/ship.png";
dead_ship.src = "images/crashed_ship.png";
retical.src = "images/retical.png";
bullet.src = "images/bullet.png";
slug.src = "images/slug.png";
gunLabel1.src = "images/1.png";
gunLabel2.src = "images/2.png";
gunLabel3.src = "images/3.png";
gunLabel4.src = "images/4.png";
gunLabel5.src = "images/5.png";
gunLabel1Trans.src = "images/1_trans.png";
gunLabel2Trans.src = "images/2_trans.png";
gunLabel3Trans.src = "images/3_trans.png";
sniperSound.volume = 0.1;
function getRandomInt(min, max) {
return Math.floor(Math.random() * (max - min + 1) + min);
}
function findPos(obj) {
var curleft = 0, curtop = 0;
if (obj.offsetParent) {
do {
curleft += obj.offsetLeft;
curtop += obj.offsetTop;
} while (obj = obj.offsetParent);
return { x: curleft, y: curtop };
}
return undefined;
}
$('#canvas').mousemove(function(e) {
var pos = findPos(this);
reticalX = e.pageX - pos.x;
reticalY = e.pageY - pos.y;
});
$('#canvas').click(function(e) {
var pos = findPos(this);
reticalX2 = e.pageX - pos.x - 40;
reticalY2 = e.pageY - pos.y - 40;
if (gunType == 0){
if ((Math.abs(reticalX2 - (shipX - 35)) <= 50) && (Math.abs(reticalY2 - (shipY + 35)) <= 50)){
dead = 1;
credits += 100}
if ((Math.abs(reticalX2 - (ship2X - 10)) <= 50) && (Math.abs(reticalY2 - (ship2Y + 10)) <= 50)){
dead2 = 1;
credits += 100}
if ((Math.abs(reticalX2 - (ship3X - 10)) <= 50) && (Math.abs(reticalY2 - (ship3Y + 10)) <= 50)){
dead3 = 1;
credits += 100}}
else if (gunType == 1 && drawBullet == false){
drawBullet = true;
bulletX = reticalX2;
sniperSound.play();}
else if (gunType == 2 && drawSlugs == false){
drawSlugs = true;
slugAX = reticalX2;
slugBX = reticalX2;
slugCX = reticalX2;
shotgunSound.play();}
else if (gunType == -1)
if ((reticalX >= 370 && reticalY >= 220) && (reticalX < 520 && reticalY < 300)) {
drawStart = false;
gunType = 0;}
});
$(document).keydown(function(e) {
if (drawStart == false) {
if (drawBullet == false && drawSlugs == false) {
switch(e.keyCode) {
case 49:
gunType = 0;
gun = "Sniper";
break;
case 50:
gunType = 1;
gun = "Revolver";
break;
case 51:
gunType = 2;
gun = "Shotgun";
break;}
}}
});
function update() {
if ((reticalX >= 370 && reticalY >= 220) && (reticalX < 520 && reticalY < 280)) {
if ((startButtonTimeNow - startButtonTimeThen) < 500) {
currentStartButton = startButtonSelected1;
startButtonTimeNow = new Date().getTime()}
else if ((startButtonTimeNow - startButtonTimeThen) < 1000) {
currentStartButton = startButtonSelected2;
startButtonTimeNow = new Date().getTime();}
else if ((startButtonTimeNow - startButtonTimeThen) < 1500) {
currentStartButton = startButtonSelected3;
startButtonTimeNow = new Date().getTime();}
else if ((startButtonTimeNow - startButtonTimeThen) < 2000) {
startButtonTimeNow, startButtonTimeThen = new Date().getTime(), new Date().getTime();}
else {startButtonTimeNow, startButtonTimeThen = new Date().getTime(), new Date().getTime();}
}
else {currentStartButton = startButton;}
if (shipY >= -70 && dead == 0){
drawShipA = true;
shipY -= newSpeed;
shipX += newSpeed;
}
else if (dead == 1 && shipY < 600){
shipY += newSpeed;
drawShipA = false;
}
else {
shipY = getRandomInt(400, 425);
shipX = getRandomInt(100, 900);
dead = 0;
drawShipA = true;
}
if (ship2Y >= -70 && dead2 == 0){
drawShipB = true;
ship2Y -= newSpeed;
ship2X -= newSpeed;
}
else if (dead2 == 1 && ship2Y < 600){
ship2Y += newSpeed;
drawShipB = false;
}
else {
ship2Y = getRandomInt(400, 425);
ship2X = getRandomInt(100, 900);
dead2 = 0;
drawShipB = true;;
}
if (ship3Y >= -70 && dead3 == 0){
drawShipC = true;
ship3Y -= newSpeed;
ship3X -= newSpeed;
}
else if (dead3 == 1 && ship3Y < 600){
ship3Y += newSpeed;
drawShipC = false;
}
else {
ship3Y = getRandomInt(400, 425);
ship3X = getRandomInt(100, 900);
dead3 = 0;
drawShipC = true;
}
if ((dead + dead2 + dead3 >= 2) && (((Math.abs(shipX - ship2X) + Math.abs(shipY - ship2Y)) + (Math.abs(shipX - ship3X) + Math.abs(shipY - ship3Y)) + (Math.abs(ship3X - ship2X) + Math.abs(ship3Y - ship2Y))) < 1500)) {credits += 50}
if (drawBullet == true){
bulletY -= bulletSpeed;
if ((Math.abs(bulletX - (shipX + 20)) <= 40) && (Math.abs(bulletY - (shipY + 10)) <= 50)){
dead = 1;
credits += 100}
if ((Math.abs(bulletX - (ship2X + 20)) <= 40) && (Math.abs(bulletY - (ship2Y + 10)) <= 50)){
dead2 = 1;
credits += 100}
if ((Math.abs(bulletX - (ship3X + 20)) <= 40) && (Math.abs(bulletY - (ship3Y + 10)) <= 50)){
dead3 = 1;
credits += 100}
if (bulletY <= -130){
drawBullet = false;
bulletY = 550;
} }
if (drawSlugs == true){
slugAY -= bulletSpeed;
bulletSpeed = bulletSpeed * 2;
bulletSpeed = (bulletSpeed - (bulletSpeed % 3))/3
slugBX -= bulletSpeed;
slugBY -= bulletSpeed * 2;
slugCX += bulletSpeed;
slugCY -= bulletSpeed * 2;
if ((Math.abs(slugAX - (shipX + 10)) <= 40) && (Math.abs(slugAY - (shipY + 10)) <= 50)){
dead = 1;
credits += 100}
if ((Math.abs(slugAX - (ship2X + 10)) <= 40) && (Math.abs(slugAY - (ship2Y + 10)) <= 50)){
dead2 = 1;
credits += 100}
if ((Math.abs(slugAX - (ship3X + 10)) <= 40) && (Math.abs(slugAY - (ship3Y + 10)) <= 50)){
dead3 = 1;
credits += 100}
if ((Math.abs(slugBX - (shipX + 10)) <= 40) && (Math.abs(slugBY - (shipY + 10)) <= 50)){
dead = 1;
credits += 100}
if ((Math.abs(slugBX - (ship2X + 10)) <= 40) && (Math.abs(slugBY - (ship2Y + 10)) <= 50)){
dead2 = 1;
credits += 100}
if ((Math.abs(slugBX - (ship3X + 10)) <= 40) && (Math.abs(slugBY - (ship3Y + 10)) <= 50)){
dead3 = 1;
credits += 100}
if ((Math.abs(slugCX - (shipX + 10)) <= 40) && (Math.abs(slugCY - (shipY + 10)) <= 50)){
dead = 1;
credits += 100}
if ((Math.abs(slugCX - (ship2X + 10)) <= 40) && (Math.abs(slugCY - (ship2Y + 10)) <= 50)){
dead2 = 1;
credits += 100}
if ((Math.abs(slugCX - (ship3X + 10)) <= 40) && (Math.abs(slugCY - (ship3Y + 10)) <= 50)){
dead3 = 1;
credits += 100}
if (slugAY <= -150){
drawSlugs = false;
slugAY = 550;
slugBY = 550;
slugCY = 550;}}
}
function paint()
{
now = new Date().getTime();
delta = now - then;
ctx.drawImage(background,0,0);
if (drawShipA == true){ctx.drawImage(ship, shipX, shipY, 70, 70);}
else {ctx.drawImage(dead_ship, shipX, shipY, 70, 70);}
if (drawShipB == true){ctx.drawImage(ship, ship2X, ship2Y, 70, 70);}
else {ctx.drawImage(dead_ship, ship2X, ship2Y, 70, 70);}
if (drawShipC == true){ctx.drawImage(ship, ship3X, ship3Y, 70, 70);}
else {ctx.drawImage(dead_ship, ship3X, ship3Y, 70, 70);}
if (drawBullet == true){
ctx.drawImage(bullet, bulletX + 30, bulletY, 10,10);}
if (drawSlugs == true){
ctx.drawImage(slug, slugAX + 20, slugAY, 30, 30);
ctx.drawImage(slug, slugBX + 20, slugBY, 30, 30);
ctx.drawImage(slug, slugCX + 20, slugCY, 30, 30);
}
bulletSpeed = calcSpeed(delta, 6);
newSpeed = calcSpeed(delta, 3);
then = now;
ctx.drawImage(retical, reticalX - 40, reticalY - 40, 80, 80);
ctx.font = "30px sans-serif";
ctx.strokeStyle = "rgba(255, 165, 0, 1)"
ctx.strokeText("$" + credits, 15, 30);
ctx.strokeStyle = "rgba(255, 165, 0, .8)"
ctx.strokeText(gun, 450, 500);
ctx.drawImage(gunLabel1, 445, 510, 35, 35);
ctx.drawImage(gunLabel2, 470, 510, 35, 35);
ctx.drawImage(gunLabel3, 495, 510, 35, 35);
switch(gunType) {
case 0:
ctx.drawImage(gunLabel1Trans, 445, 510, 35, 35);
break;
case 1:
ctx.drawImage(gunLabel2Trans, 470, 510, 35, 35);
break;
case 2:
ctx.drawImage(gunLabel3Trans, 495, 510, 35, 35);
break;
}
if (drawStart == true) {
ctx.drawImage(background, 0, 0);
ctx.drawImage(title, 270, 90, 400, 100);
ctx.drawImage(currentStartButton, 370, 220, 150, 60);
ctx.drawImage(retical, reticalX - 40, reticalY - 40, 80, 80);}
ctx.strokeRect(0,0,w,background.height);
}
var init = function()
{
requestAnimationFrame(init);
update();
paint();
}
var calcSpeed = function(del, speed) {
return (speed * 60 * del) / 1000;
}
init();})
答案 0 :(得分:3)
问题是你的游戏速度与你的帧速率有关:
var init = function()
{
requestAnimationFrame(init);
update();
paint();
}
当每秒的帧数下降时,每秒的更新次数也会减少。结果,当帧速率下降时游戏减慢,当帧速率上升时游戏速度加快。要解决此问题,请按固定间隔执行update-loop:
window.setInterval(update, 10);
这样,游戏逻辑将始终每秒更新100次,无论渲染现在多快或多慢。
执行此操作时,您可能会注意到一个问题:绘图发生时无法控制。在调用paint
期间,对update
的调用可能会发生。结果它将绘制一个游戏状态,即半逻辑帧n和半逻辑帧n + 1。这可能会导致一些奇怪的图形故障。我通常像这样构建我的游戏循环(伪代码):
calculated_time_in_ms = getCurrentTimeInMs();
while(game_is_running) {
paint();
while(calculated_time_in_ms < getCurrentTimeInMs()) {
update();
calculated_time_in_ms += 10;
}
}
这样维护游戏逻辑帧率始终优先于渲染,但是当图形引擎足够快时,它能够比游戏逻辑更新更频繁地绘制。