iPhone SDK: обнаружение столкновений, это должен быть прямоугольник? - PullRequest
2 голосов
/ 31 августа 2009

Я делаю базовую платформенную игру для iPhone, и у меня возникла проблема с обнаружением столкновений.

if (CGRectIntersectsRect(player.frame, platform.frame))
    pos2 = CGPointMake(0.0, +0.0);
else
    pos2 = CGPointMake(0.0, +10.0);

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

1 Ответ

3 голосов
/ 31 августа 2009

Вам придется запрограммировать это самостоятельно, и остерегайтесь, что попиксельное столкновение, вероятно, слишком дорого для iPhone. Я рекомендую написать протокол Collidable (называемый интерфейсом на любом другом языке программирования), назначить ему функцию collidedWith: (Collidable *) c, а затем просто реализовать ее для любого объекта, для которого вы хотите разрешить столкновение. Затем вы можете написать логику столкновения в каждом конкретном случае. Точно так же вы можете создать большой суперкласс, который будет иметь всю информацию, необходимую для коллизий (в вашем случае это X, Y, ширина и высота, или X, Y и массив данных пикселей) и метод collidesWith. , В любом случае вы можете написать кучу разных методов коллизий - если вы делаете пиксельную коллизию только для нескольких вещей, это не сильно скажется на производительности. Как правило, однако, лучше делать столкновение с ограничивающим прямоугольником или другое столкновение, основанное на геометрии, поскольку оно значительно быстрее.

Сотрудники Metanetsoftware сделали несколько отличных уроков по технике столкновений, среди которых столкновение с разделением осей и столкновение на основе сетки , последнее из которых звучит так, как если бы оно было более жизнеспособным для ваша игра. Однако, если вы хотите использовать обнаружение столкновений методом грубой силы (сверяя каждый объект со всеми другими объектами), тогда создание ограничивающего прямоугольника, который просто на меньше , чем изображение, обычно является правильным способом. Это то, что сделали многие успешные платформеры, включая Super Mario Brothers. Вы могли бы также рассмотреть взвешенные ограничивающие рамки - то есть у вас есть один ограничивающий прямоугольник для одного типа объекта и другой размер для других. Например, в Марио у вас есть коробка большего размера, чтобы поражать монеты, чем враги.

Теперь, хотя я и предупредил вас поступить иначе, я обязую вас и объясню, как делать пиксельные столкновения. Вы захотите получить доступ к пиксельным данным вашего CGImage, а затем выполнить итерацию по всем пикселям, чтобы увидеть, имеет ли это изображение местоположение с любым другим изображением. Вот код для этого.

for (int i = 0; i < [objects count]; i++)
{
    MyObject *obj1 = [objects objectAtIndex:i];

    //Compare every object against every other object.
    for (int j = i+1; j < [objects count]; j++)
    {
        MyObject *obj2 = [objects objectAtIndex:j];

        //Store whether or not we've collided.
        BOOL collided = NO;

        //First, do bounding box collision. We don't want to bother checking
        //Pixels unless we are within each others' bounds.
        if (obj1.x + obj1.imageWidth >= obj2.x &&
            obj2.x + obj2.imageWidth >= obj1.x &&
            obj1.y + obj1.imageHeight >= obj2.y &&
            obj2.y + obj2.imageGeight >= obj1.y)
        {
            //We want to iterate only along the object with the smallest image.
            //This way, the collision checking will take the least time possible.
            MyObject *check = (obj1.imageWidth * obj1.imageHeight < obj2.imageWidth * obj2.imageHeight) ? obj1 : obj2;

            //Go through the pixel data of the two objects.
            for (int x = check.x; x < check.x + check.imageWidth && !collided; x++)
            {
                for (int y = check.y; y < check.y + check.imageHeight && !collided; y++)
                {
                    if ([obj1 pixelIsOpaqueAtX:x andY:y] && [obj2 pixelIsOpaqueAtX:x andY:y])
                    {
                        collided = YES;
                    }
                }
            }
        }
    }
}

Я сделал так, что pixelIsOpaque принимает глобальную координату, а не локальную координату, поэтому, когда вы программируете эту часть, вы должны быть осторожны, чтобы снова вычесть x и y из этого, иначе вы будете выходить за границы вашего изображения.

...