需要javascript帮助中的碰撞脚本

时间:2011-11-02 00:25:13

标签: javascript arrays html5 collision

好吧所以我只是试图通过手动将所有内容写入数组来减少代码行。我的问题是他现在传送并且重力不起作用...... 首先,我有一个单元格对象网格,基本上是32x32网格“640X480”。 这些对象都被传递到像这样的数组 -

var gridcellarray = [750];
gridcellarray[0] = cell0;
gridcellarray[1] = cell1;
gridcellarray[2] = cell2;
and so on for 750 32x32 cells...

现在关于碰撞脚本我有这个......

function collisioncheck(obj) {
    obj = obj;
    for(var i = 0; i < gridcellarray.length; i++){
    //really long if statement// sorry...
    if ((gridcellarray[i].solid == true) && ((obj.PosY >= gridcellarray[i].y - obj.maskImg.height) && !(obj.PosY >= gridcellarray[i].y ) && !((obj.PosX > gridcellarray[i].x + solidOriginX + solidImg.width/2-5) || (obj.PosX < gridcellarray[i].x - solidOriginX - solidImg.width/2)))){
         if(obj.onground == 0){
             obj.PosY = gridcellarray[i].y - obj.maskImg.height;
             obj.VelY = 0;
             obj.onground = 1;
             obj.jump = 0;
         }
      }
     else if (obj.PosY >= canvas.height - obj.maskImg.height){
        if(obj.onground == 0){
            obj.VelY = 0;
            obj.onground = 1;
            obj.jump = 0;
            obj.PosY = canvas.height - obj.maskImg.height;
        }
    }
    else {
        obj.VelY += 1;
        obj.onground = 0;
    }
  }
 }

现在这个代码工作得很好如果我为每个单元格手动复制了750次 问题是,现在我有一次迭代它循环通过它们作为一个数组它会混淆并传送我到底部如果我试图跳跃甚至不在下面或在块上它传送我回到底部。

//编辑
我认为所有变量都应该通过名称来解释它们的用途,但如果您有任何疑问,请询问。

//编辑
所有变量都应用您的检查碰撞对象,例如collisioncheck(播放器) 这里是一个代码运行演示的链接... Zack Bloom的代码在其中,它适用于未发布的水平碰撞脚本,但垂直方向,它不会重置并确认您在一个块上的站立,即ongroud = true; Demo link

//编辑
好了,现在Zack指出将y重置为x并且它帮助了很多但是他仍然无法跳跃,因为当检测到碰撞时onground变量不想重置...哦,传送是由于我的向上脚本 -

  //Upwards Collision//     
  if ((cell.solid == true) && ((obj.PosY >= cell.y - 32) && !(obj.PosY > cell.y+32) && !((obj.PosX > cell.x + solidOriginX + solidImg.width/2-5) || (obj.PosX < cell.x - solidOriginX - solidImg.width/2)))){
         if (obj.onground == 0){
             obj.VelY += 1;
             obj.onground = 0;
             obj.PosY = cell.y + obj.maskImg.height-13; 
         }
     }

关于如何修复混乱的任何想法?阻止他传送?它只是为了检查碰撞面罩的顶部(红色矩形)是否正在触碰该块,就像试图跳过它一样,但是它意味着阻止它发生,所以你会撞到你的头部然后倒下来。 在此先感谢!

2 个答案:

答案 0 :(得分:3)

否则if / else实际上根本不属于循环,他们不会评估循环的单元格,但每次调用collisioncheck时都会被触发多次。

function collisioncheck(obj) {
    for(var i = 0; i < gridcellarray.length; i++){
        var cell = gridcellarray[i];

        if (cell.solid && ((obj.PosY >= cell.y - obj.maskImg.height) && !(obj.PosY >= cell.y ) && !((obj.PosX > cell.x + solidOriginX + solidImg.width/2-5) || (obj.PosX < cell.x - solidOriginX - solidImg.width/2)))){
             if(!obj.onground){
                 obj.PosY = cell.x - obj.maskImg.height;
                 obj.VelY = 0;
                 obj.onground = 1;
                 obj.jump = 0;

                 break;
             }
         }
     }
     if (obj.PosY >= canvas.height - obj.maskImg.height){
        if(!obj.onground){
            obj.VelY = 0;
            obj.onground = 1;
            obj.jump = 0;
            obj.PosY = canvas.height - obj.maskImg.height;
        }
     } else {
        obj.VelY += 1;
        obj.onground = 0;
     }
}

但更好的方法是根据它的位置存储每个网格单元,这样你就必须在船的附近查找网格单元。

// You only have to do this once to build the structure, don't do it every time you
// need to check a collision.
var gridcells = {};
for (var i=0; i < gridcellarray.length; i++){
    var cell = gridcellarray[i];

    var row_num = Math.floor(cell.PosX / 32);
    var col_num = Math.floor(cell.PosY / 32);

    if (!gridcells[row_num])
        gridcells[row_num] = {};

    gridcells[row_num][col_num] = cell;
}

// Then to check a collision:
function collisioncheck(obj){
    // I'm not sure exactly what your variables mean, so confirm that this will equal
    // the width of the object:
    var obj_width = solidImg.width;
    var obj_height = obj.maskImg.height;

    var collided = false;

    var left_col = Math.floor(obj.PosX / 32),
        right_col = Math.floor((obj.PosX + obj_width) / 32),
        top_row = Math.floor(obj.PosY / 32),
        bottom_row = Math.floor((obj.PosY + obj_height) / 32);

    for (var row=top_row; row <= bottom_row; row++){ 
        for (var col=left_col; col <= right_col; col++){
            var cell = gridcells[row][col];

            if (cell.solid){
                collided = true;

                if (row == top_row){
                    // We collided into something above us

                    obj.VelY = 0;
                    obj.PosY = cell.PosY + 32;
                } else if (row == bottom_row && !obj.onground){
                    // We collided into the ground

                    obj.PosY = cell.x - obj_height;
                    obj.VelY = 0;
                    obj.onground = 1;
                    obj.jump = 0;
                }

                if (col == left_col){
                    // We collided left

                    obj.VelX = 0;
                    obj.PosX = cell.PosX + 32;
                } else if (col == right_col){
                    // We collided right

                    obj.VelX = 0;
                    obj.PosX = cell.PosX - obj_width;
                }
            }
        }
    }

    if (obj.PosY >= canvas.height - obj_height){
        if (!obj.onground){
            obj.VelY = 0;
            obj.onground = 1;
            obj.jump = 0;
            obj.PosY = canvas.height - obj_height;
        }
    }

    if (!collided){
        obj.VelY += 1;
        obj.onground = 0;
    }
}

我们只关注我们知道重叠的细胞,而不是每帧循环720个细胞。与所有位置计算相比,这更有效,更易于阅读。

答案 1 :(得分:1)

对您的代码的一些评论:

var gridcellarray = [750];

创建一个数组,其中包含一个值为750的单个成员。我认为你假设它等同于:

var gridcellarray = new Array(750);

创建一个长度为750的数组。不需要设置数组的大小,只需将其初始化为空数组并赋值。

var gridcellarray = [];
gridcellarray[0] = cell0;

这将使用 cell0 的值替换第一个成员的值。

function collisioncheck(obj) {
    obj = obj;

第二行中没有任何意义,它只是将obj的值赋给obj(所以它是多余的)。

  for(var i = 0; i < gridcellarray.length; i++){

在大多数浏览器中保存 gridcellarray.length 的值要高效得多,否则必须每次都查找它(编译器可能无法工作,无论它是否可以缓存它) ,所以:

  for (var i = 0, iLen = gridcellarray.length; i < iLen; i++) {

存储对 gridcellarray [i] 的引用更有效,而不是每次都查找它。此外,您可以使用短名称,因为它仅在循环中使用,因此很容易找到它的目的:

    var c = gridcellarray[i];

所以不仅代码运行得更快,而且if语句的字符更少(并且您可能更喜欢以不同的方式对其进行格式化):

if ((c.solid == true) &&
    ((obj.PosY >= c.y - obj.maskImg.height) && !(obj.PosY >= c.y ) &&
    !((obj.PosX > c.x + solidOriginX + solidImg.width/2-5) ||
      (obj.PosX < c.x - solidOriginX - solidImg.width/2)))) {
哇,这真是一些if声明。你能把它分解成更简单,合乎逻辑的步骤吗?

啊,Zack也发了一个答案,所以我会留在这里。