Обнаружение столкновений карты тайлов - PullRequest
0 голосов
/ 05 апреля 2010

Есть много подобных тем, но ни одна с конкретными ответами. Я рисую карту тайла традиционным способом (два для циклов) и держу своего игрока в центре, за исключением случаев, когда края карты достигнуты. Как бы я создал обнаружение столкновений? Мне нужно знать, как перевести расположение плитки в массиве в координаты экрана, я думаю.

Ответы [ 2 ]

2 голосов
/ 28 октября 2011

Я дам вам код, который я написал для обнаружения коллизий точек / плиток. Код предполагает, что у вас есть точка в (xfrom, yfrom), и вы хотите переместить ее в (xto, yto) и хотите увидеть, есть ли столкновение с блоком на карте тайловой карты [Y] [X]. Я предполагаю, что метод isSolid (tileId), который будет возвращать true, если плитка сплошная.

 /**
 * This method returns true if there is a collision between a point and a 2D tilemap map[Y][X]. 
 * The isSolid method must be implemented to indicate if a tile is solid or not 
 * Assumes the tilemap starts at (0,0) and TILEWIDTH and TILEHEIGHT hold the size of a tile (in pixels) 
 * @param xfrom the original x-coordinate of the point
 * @param yfrom the original y-coordinate of the point   
 * @param xto the destination x-coordinate of the point 
 * @param yto the destination y-coordinate of the point 
 * @param outCollisionPoint output the location where the collision occurs
 * @return true if a collision is found
 */
public boolean collisionDetection(int xfrom, int yfrom, int xto, int yto, Point outCollisionPoint){
    //Ref: A fast voxel traversal algorithm J.Amanatides, A. Woo
    float tMaxX, tMaxY, tDeltaX, tDeltaY, collisionLength;
    int X, Y, stepX, stepY, endX, endY, blkX, blkY;

    //Calculate direction vector
    float dirX = (xto - xfrom);
    float dirY = (yto - yfrom);

    float length = (float) Math.sqrt(dirX * dirX + dirY * dirY);

    //Normalize direction vector
    dirX /= length;
    dirY /= length;

    //tDeltaX: distance in terms of vector(dirX,dirY) between two consecutive vertical lines
    tDeltaX = TILEWIDTH / Math.abs(dirX);
    tDeltaY = TILEHEIGHT / Math.abs(dirY);

    //Determine cell where we originally are
    X = xfrom / TILEWIDTH;
    Y = yfrom / TILEHEIGHT;

    endX = xto / TILEWIDTH;
    endY = yto / TILEHEIGHT;

    //stepX: Determine in what way do we move between cells
    //tMaxX: the distance in terms of vector(dirX,dirY) to the next vertical line
    if (xto > xfrom){
        blkX = 0;
        stepX = 1;
        tMaxX = ((X+1) * TILEWIDTH - xfrom) / dirX;
    }else{
        blkX = 1;
        stepX = -1;
        tMaxX = (X * TILEWIDTH - xfrom) / dirX;
    }
    if (yto > yfrom){
        blkY = 0;
        stepY = 1;
        tMaxY = ((Y+1) * TILEHEIGHT - yfrom) / dirY;
    }else{
        blkY = 1;
        stepY = -1;
        tMaxY = (Y * TILEHEIGHT - yfrom) / dirY;
    }

    if (isSolid(map[Y][X])) {
        //point already collides
        outCollisionPoint = new Point(xfrom, yfrom);
        return true;
    }
    //Scan the cells along the line between 'from' and 'to'
    while (X != endX || Y !=endY){
        if(tMaxX < tMaxY){
            tMaxX += tDeltaX;
            X += stepX;
            if (isSolid(map[Y][X])) {
                collisionLength = ((X + blkX) * TILEWIDTH - xfrom) / dirX;
                outCollisionPoint = new Point((int)(xfrom + dirX * collisionLength), (int)(yfrom + dirY * collisionLength));
                return true;
            }
        }else{
            tMaxY += tDeltaY;
            Y += stepY; 
            if (isSolid(map[Y][X])) {           
                collisionLength= ((Y  + blkY) * TILEHEIGHT - yfrom) / dirY;
                outCollisionPoint = new Point((int)(xfrom + dirX * collisionLength), (int)(yfrom + dirY * collisionLength));
                return true;
            }                   
        }
    }
    return false;
}
1 голос
/ 05 апреля 2010

Зависит от модели.

Если ваша модель (данные) является сеткой, то столкновение происходит просто тогда, когда два несовместимых объекта занимают одно и то же место. Самый простой способ справиться с таким типом столкновения - просто убедиться, что место, куда вы пытаетесь переместить игровой объект, «доступно». Если это так, столкновения нет, и обновите модель . Если это было не бесплатно, то произошло столкновение.

Экран просто отображает модель. За исключением чего-то вроде обнаружения столкновений на пиксель (представьте себе оригинальные лемминги или черви), не используйте его для обнаружения столкновений .

Экран / представление - это просто агент рендеринга. Хотя модель может быть жестко привязана к экрану (например, вам нужно обновить только те части экрана, на которых что-то изменилось, например, когда часть перемещена), экран не является и не должен, как правило, считаться частью модели. Однако при современной скорости вычислений вы можете просто перерисовать всю видимую модель в каждом кадре.

(Да, я знаю, что повторил. Это было специально.)

Теперь, чтобы ответить на второй вопрос, не упомянутый в заголовке:

Когда вы начинаете рендеринг, просто нарисуйте ячейки screen_width / cell_width / 2 слева и ячейки screen_width / cell_width / 2 справа от проигрывателя (предполагается, что игрок занимает 1x1). Сделайте то же самое для взлета и падения. Убедитесь, что вы не вызвали исключение Index-Out-Of-Bounds. Вы можете запускать циклы for со значениями, выходящими за границы, при условии, что перед их использованием вы зажимаете / фильтруете. Если вы хотите, чтобы персонаж «проталкивал» край, когда он приближается, также отслеживайте текущую ссылку модель-на-просмотр.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...