我正在研究自己的游戏技能(主要是使用数组)来生成敌人,现在使用子弹将其击落。我能够在测试时设置项目符号,但是只有当我按下一个键(比如说空格键)并且在它们之间没有间隔时,它才可见,因此浏览器无法一次完成那么多任务。
有没有一种简单的方法可以使飞船发射子弹,并且它们之间有一定间隔(不会给浏览器加载太多时间),也许是在去敌人[i] .x / y位置以删除敌人时,子弹可以消失了吗?
这里是我目前拥有的尽可能多的已清理代码(HTML和JS文件。也有一些图像,并会提供游戏的URL以便在需要时进行检查-http://sarahkerrigan.biz/spaceship
<!DOCTYPE html>
<html>
<head>
<title>Space Ship</title>
</head>
<body>
<h3>Space Ship</h3>
<canvas id="canvas" width="1000" height="600"></canvas>
<script src="spaceship.js"></script>
</body>
</html>
这是spaceship.js文件:
var cvs = document.getElementById("canvas");
var ctx = cvs.getContext("2d");
//-------------------------------
// load images
var player = new Image();
var enemy = new Image();
var bullet = new Image();
player.src = "images/player.png";
enemy.src = "images/enemy.png";
bullet.src = "images/fire.png";
//-------------------------------
// vars
var score = 0;
var pause = 0;
var playerY = 300;
var playerX = 100;
var upPressed = false;
var downPressed = false;
var leftPressed = false;
var rightPressed = false;
// audio
var fire = new Audio();
var hit = new Audio();
fire.src = "sounds/fire.mp3";
hit.src = "sounds/hit.mp3";
//-------------------------------
// on key down
document.addEventListener("keydown", keyDownHandler);
function keyDownHandler(e) {
if (e.keyCode == 87) {
upPressed = true;
}
if (e.keyCode == 83) {
downPressed = true;
}
if (e.keyCode == 65) {
leftPressed = true;
}
if (e.keyCode == 68) {
rightPressed = true;
}
}
// on key up
document.addEventListener("keyup", keyUpHandler);
function keyUpHandler(e) {
if (e.keyCode == 87) {
upPressed = false;
}
if (e.keyCode == 83) {
downPressed = false;
}
if (e.keyCode == 65) {
leftPressed = false;
}
if (e.keyCode == 68) {
rightPressed = false;
}
}
//-------------------------------
function moveUp() {
if (playerY <= canvas.height - canvas.height){
}
else{
playerY -= 6;
}
}
function moveDown() {
if (playerY >= canvas.height - player.height){
}
else{
playerY += 6;
}
}
function moveLeft() {
if (playerX <= canvas.width - canvas.width){
}
else{
playerX -= 6;
}
}
function moveRight() {
if (playerX >= canvas.width - player.width){
}
else{
playerX += 6;
}
}
//-------------------------------
// Enemy coordinates
var enemies = [];
enemies[0] = {
x: cvs.width,
y: 0
};
//-------------------------------
// reload page
function reLoad() {
location.reload(); // reload the page
}
//-------------------------------
// draw images
function draw() {
ctx.fillStyle = "black";
ctx.fillRect(0, 0, canvas.width, canvas.height);
if (upPressed === true) {
moveUp();
}
if (downPressed === true) {
moveDown();
}
if (leftPressed === true) {
moveLeft();
}
if (rightPressed === true) {
moveRight();
}
//-------------------------------
for (var i = 0; i < enemies.length; i++) {
//draw the enemy
ctx.drawImage(enemy, enemies[i].x, enemies[i].y);
// enemy movement speed
enemies[i].x -= 3;
if (enemies[i].x == 880) {
enemies.push({
x: cvs.width,
y: Math.floor(Math.random() * enemy.height) * 10 - enemy.height
});
}
// detect collision
// if enemy hits player
if (playerX + player.width >= enemies[i].x && playerX <= enemies[i].x + enemy.width && (playerY <= enemies[i].y + enemy.height && playerY + player.height >= enemies[i].y)) {
pause = 1;
}
}
//-------------------------------
//draw the player
ctx.drawImage(player, playerX, playerY);
//draw score
ctx.fillStyle = "#fff";
ctx.font = "20px Verdana";
ctx.fillText("Destroyed ships : " + score + "$", 10, cvs.height - 20);
function onPause() {
if (pause >= 1) {
hit.play();
ctx.fillStyle = "#df8a62";
ctx.fillRect(150, 150, 280, 100);
ctx.fillStyle = "#000";
ctx.font = "20px Verdana";
ctx.fillText("You died:", 165, 170);
document.addEventListener("keydown", reLoad);
} else if (pause <= 0) {
requestAnimationFrame(draw);
}
}
onPause();
}
draw();
答案 0 :(得分:2)
您要使用时间间隔而不是侦听器。
var myVar = setInterval(timeCycle, 50);
function timeCycle() {
//all the stuff you currently have listeners for.
}
这样,当时间间隔发生时,它将只执行一次按键。然后,如果您想更改射速,请添加以下内容:
setInterval(timeCycle, 50);
rateOfFire = 5;
shootCoolDown = 0;
function timeCycle() {
if (shootPressed === true) {
if(shootCoolDown === 0){
shootCoolDown = rateOfFire;
shoot();
}
}
if (shootCoolDown > 0){
shootCoolDown --;
}
}
这样,它将每5个游戏周期射击一次(在这种情况下,每秒射击4个回合)。
您可以做更多花哨的事情来创建一个增量时间系统,以根据执行时间周期的时间来更改模拟率,从而抵消时滞,但这往往更加复杂且容易弄乱。 ,所以我不建议初学者钻进那个兔子洞。
[编辑] 因此,我最近看到了有关deltaTime的几个问题,但是看不到任何有关如何实现它的好例子。因此,这是我一起提出的一个基本示例。要实现它,只需用游戏周期中发生的事情的实际代码替换GAME STUFF部分,然后通过delta()函数运行所有基于时间的值,它将把您的值从每秒转换为单位。每个currentFrame的单位。
My game us under a load of <input type="text" id="lag" value="100000000"> operations per frame.<br>
My speed is = <input type="text" id="speed" value="500"> px per second<br>
I moved <span id="adjusted"></span>px this frame.<br>
FPS: <span id="fps"></span>
<script>
function wrapDelta(lastTime){
var d = new Date();
var n = d.getSeconds()*1000 + d.getMilliseconds();
if (lastTime >= n) {
lastTime -= 60000;
}
return n - lastTime;
}
function delta(input){
return input * deltaCoeff / 1000;
}
var d = new Date();
var ed = new Date();
var endTime = d.getSeconds()*1000 + d.getMilliseconds();
var startTime = d.getSeconds()*1000 + d.getMilliseconds();
var deltaCoeffMin = 25;
var deltaCoeff = deltaCoeffMin;
setInterval(function () {
d = new Date();
startTime = d.getSeconds()*1000 + d.getMilliseconds();
// START GAME STUFF
var lag = Math.round(Math.sqrt(document.getElementById('lag').value)); //because comparing large numbers caused a wierd lag spike at from 9999999 to 10000000
var speed = document.getElementById('speed').value;
document.getElementById('adjusted').innerHTML = delta(speed);
document.getElementById('fps').innerHTML = (1000/deltaCoeff).toFixed(2);
var i; var j; var k; for (i=0; i<lag; i++){ for (j=0; j<lag; j++){ k = 1234567*1.1;}} //This is just a random math loop to simulate the lag cause by actual game stuff
// END GAME STUFF
ed = new Date();
endTime = ed.getSeconds()*1000 + ed.getMilliseconds();
deltaCoeff = endTime - startTime;
if (deltaCoeff < deltaCoeffMin){deltaCoeff = deltaCoeffMin;}
} , deltaCoeffMin);
</script>
答案 1 :(得分:1)
仅当计算机足够快时,对requestAnimationFrame
的调用才会以显示器支持的速率运行绘图功能。如果代码运行缓慢,它将不时自动跳过对绘图函数的调用。因此,draw函数应该只包含渲染代码,而不能包含逻辑。
您应该首先将任何更新游戏状态的代码放入另一个称为update的函数中。将使用setInterval
以一致的速率调用此函数:
function update() {
// read inputs
// move objects
// detect collisions
// etc.
// render a new frame only if the browser is done drawing the previous one
requestAnimationFrame(draw);
}
// run the update function 60 times per second
var updateInterval = setInterval(update, 1000 / 60);
存储updateInterval
总是很好,这样我们就可以停止游戏在clearInterval(updateInterval)
下完全运行,但是您可能永远不需要使用它。
现在您的游戏速度有些一致,您可以像这样设置射击的冷却时间:
if (fireCooldown > 0) {
fireCooldown -= 1;
}
if (/* holding the fire key */ && fireCooldown === 0) {
// create a projectile in front of the player ship
fireCooldown = 30;
}
您需要先在某个地方声明该变量,然后在某个地方声明var fireCooldown = 0;
,但这应该可以帮助您入门。
正如杰克·霍尔辛格(Jake Holzinger)在评论中所提到的,setInterval
并非100%准确,因此更新功能的调用时间可能比预期的晚几毫秒。如果您想对时间进行完美计时,则必须使用Date对象或其他方式检查两次通话之间的时间,但是我怀疑这对于简单的射击游戏是必要的。