0

我有这个 jsfiddle:http: //jsfiddle.net/phjUL/11/

代码:

function createShipMissil(x, y,imgw,imgh) {

            missile = new Image();
            missile.onload = function () {
                ctx.drawImage(missile, x + 25, y, imgw,imgh);
                y--; 
            }
            missile.src = 'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcRwk5oUcssd2r4wzBQMBPr9c0BSEjjwpnl5MhoBSJaUV2Dwaxmvu31BMVk';
            setTimeout(function () { createShipMissil(x, y,imgw,imgh); }, 0.5);
        }

        function render() {
            ctx.clearRect(0, 0, cw, ch);

            if (startgame) {
                DrawStatistics();
               // createShipMissil(px, py,1,15);
            }
            ctx.drawImage(playerimage, px, py, pw, ph);

        }

正如您将在示例中看到的那样,当按下空格键时,我面临渲染导弹的问题

4

1 回答 1

0

您的核心问题是您没有任何中央游戏循环。这在任何使用“实时”事件和交互的游戏中都是必不可少的。不过别担心,这通常是新手游戏制作者犯的第一个错误。以下一些内容可能会引起您的兴趣:

问题的原因

您的问题是,当您发射导弹时,您正在为该导弹创建一个时间循环,这确实会继续不断地吸引您的导弹;然而,你也只是在用户按下一个键时才清除你的游戏显示——这意味着你的导弹画成一条线。你可以让这个系统为一枚导弹和一名玩家工作,但如果你开始添加更多的射弹和敌人,你会遇到越来越多的问题。当您的游戏有一个单一的更新“节拍”(即游戏循环)时,思考和编码要容易得多,而不是每个实体都有自己的更新“节拍”,然后您必须对其进行同步。

一个很好的类比是想想简单的旧现实。在现实生活中,时间并不仅仅在某事发生时才开始出现(除非你开始真正进入量子力学时空和大爆炸!)——相反,时间总是在流逝,新的实体/物体会随之出现期间互动。一旦这些对象已经消失,时间仍然会继续(除非您订阅任何基于随机观察者的理论)。

解决方案

你需要改变你对更新/重绘的看法。你需要考虑你的对象存在于一个世界中,它们每个都有一个节拍或滴答声来改变它们的位置或显示,在那个滴答声之后,整个游戏屏幕都会更新……而且——通常——你应该有每秒至少发生 24 个这样的滴答声(为了欺骗人眼,使屏幕上绘制的静态对象实际上在移动)。

因此,与其为每个子弹创建一个新的间隔,不如从一个控制整个游戏重绘的单一全局间隔开始。有几种方法可以做到这一点,最简单的方法是setInterval像在代码中那样使用,但是这种方法也有缺点——实现这一点的更现代的方法是使用window.requestAnimationFrame

然后,一旦你让这个循环每秒触发 24 次(或更多),你就可以处理添加到你的世界的所有实体。这通常意味着拥有某种集中的列表来跟踪每个实体。这完全取决于您,有些人只会保留一个列表,即实体数组;其他人会将该列表分解为更具描述性的术语,例如bullets, players, enemies... 等等。下面是一些伪代码来说明您的游戏循环的外观:

var display = {/* object that controls your canvas */};
var entities = [];
var entity = {/* object/constructor represents a game entity i.e. player */}

var gameloop = function(){
  display.clear();
  for( var i=0; i<entities.length; i++ ) {
    entities[i].update();
  }
};

显然,上面没有任何内容entities。这就是其他代码的来源,以准备entities包含您的播放器和世界上已经存在的一些其他项目;以及随着游戏的进行添加和删除实体的更多代码,即子弹,例如:

entities.push( new entity({
  type: 'player',
  image: 'ship.png'
}) );

您应该设计每个实体以支持名为 的方法update,因此无论您添加什么新实体,游戏循环都会自动支持它。这个update方法应该负责在世界各地移动该实体(无论它是什么),如果您愿意,可以在世界上绘制实体 - 但是通常最好将您的updatedraw调用分开,以便所有实体在重绘之前完成移动发生——这有助于计算碰撞:

var gameloop = function(){
  display.clear();
  for( var i=0; i<entities.length; i++ ) {
    entities[i].update();
  }
  for( var i=0; i<entities.length; i++ ) {
    entities[i].draw();
  }
};

如何处理键盘交互

这是另一个棘手的事情,人们通常认为在基于 HTML 的游戏中很容易,因为您已经有了要监听的关键事件。但是,您永远不应该将按键直接链接到更新代码......否则您会得到演示中发生的情况,其中“按键重复”触发会导致奇怪的动作。

你应该做的是听按键,就像你正在做的那样,但是controls用按键的当前状态更新一个对象(或类似的东西)。然后在您的实体update方法中,您侦听您的实体应响应并执行该操作的关键状态。这会使按键与动作错位,避免按键重复,并意味着事情保持在游戏的“节拍”内,它还允许您更具体地控制对该按键(或组合键)的反应。下面的代码又是一个说明:

var controls = {};

$(document).on(
  'keydown': function(e){
    controls[e.keyCode] = true;
  },
  'keyup': function(e){
    delete controls[e.keyCode];
  }
);

然后在您希望检查密钥状态时,您可以轻松使用:

if ( controls[32] ) {
  /// space has been pressed
}

结论

所以总的来说,我建议通读 HTML5 游戏教程,查看热门链接,然后将您的游戏重新设计为该设计。你会发现它更容易使用。

于 2013-07-29T12:09:13.867 回答