Collision Script в javascript нужна помощь - PullRequest
0 голосов
/ 02 ноября 2011

Хорошо, поэтому я просто попытался сократить количество строк кода, изменив ручную запись всего в массив .. Моя проблема в том, что он теперь телепортируется, а гравитация не работает ... во-первых, у меня есть сетка ячеистых объектовкоторые в основном являются сеткой 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 раз для каждой ячейки, и проблема в том, что теперь, когда у меня есть одна итерация циклического перебора их в виде массива, он запутывается и телепортирует меня на дно, и если я пытаюсь прыгнуть, даже когда не нижеили в блоке он телепортирует меня обратно ко дну.

// edit
Я думаю, что все переменные должны объяснять свое назначение по имени, но если у вас есть какие-либо вопросы, пожалуйста, задавайте.

// edit
Все переменные применяют объект, для которого вы проверяете коллизию, например, collisioncheck (player). Это ссылка на работающую демонстрацию кода ... В ней есть код Зака ​​Блума, и он прекрасно работает применительно к неопубликованной горизонтали.сценарии столкновений, но по вертикали, они не будут сбрасываться и подтверждать ваше положение в блоке, т.е. ongroud = true; Демонстрационная ссылка

// edit
Хорошо, теперь, когда Зак указал на сброс значений 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 ]

3 голосов
/ 02 ноября 2011

Иначе, если / 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 голос
/ 02 ноября 2011

Некоторые комментарии к вашему коду:

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.Можете ли вы разбить его на более простые, логичные шаги?

Ах, Зак тоже опубликовал ответ, поэтому я оставлю его здесь.

...