Игровая логика и игровые циклы в ActionScript 3 - PullRequest
1 голос
/ 23 октября 2011

Я делаю игру-стрелялку на flash ActionScript 3 и у меня есть несколько вопросов о логике и о том, как разумно использовать концепции ООП.

В основном есть 3 класса:

  1. Основной класс: Инициализирует объекты на экране.
  2. Класс врага: Для перемещения врагов на экране.
  3. Класс пули: Для стрельбы.

Что я хочу сделать, так это выяснить, попал ли враг из-за пули, и сделать то, что должно быть сделано в результате ...

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

Это правильная техника?или есть лучшие решения?

Ответы [ 2 ]

4 голосов
/ 23 октября 2011

Попытайтесь думать больше ООП, за что отвечает каждый объект ?

У нас есть враги, которых мы можем поразить:

class Enemy : extends NPC implements IHittable {
    . . .

    function update(delta) {
        // move, shoot, etc.
    }

    function handleHit(bullet) {
        // die
    }
}

Хитабильный объект:

interface IHittable {
    function handleHit(bullet);
}

Пуля должна двигаться и бить:

class Bullet : {
    function update(delta) {
        // update position
    }

    function checkHits(world:World) {
        for each(var hittable:IHittable in world.objects) { // might want to cluster objects by location if you're handling lots of objects / bullets)
            if (isColidingWith(hittable))
                o.handleHit(bullet);
        }
    }
}

И тогда у нас есть мир со всем внутри:

class World {
    var npcs: Array ...
    var bullets: Array ...
    var hittables: Array ...

    function update(delta) {
        foreach(var c:NPC in npcs)
            c.update(delta);

        foreach(var b:Bullet in bullets) {
            b.update(delta);
            b.checkCollisions(world);
        }
    }
}

А ваш основной цикл просто прост:

var lastTime:int;

function onEnterFrame(...) {
    var now:int = getTimer(); // FlashPlayer utility function to get the time since start (in ms)

    world.update(now - lastTime);
    lastTime = now;
}

Несколько других заметок:

  • попытайтесь выполнить все вычисления, основанные на delta времени, в противном случае скорость игры будет зависеть от частоты кадров.

  • что происходит, когда персонаж умирает? пуля исчезнет? Ну, вы можете сделать это несколькими способами:

    • запустить событие, например EnemyDied и удалить его из мира
    • реализует интерфейс CanDie, который имеет (get dead():Boolean свойство) и использует его для очистки мира при каждом обновлении.
    • но не пишите код для удаления врага в классе Enemy, потому что тогда вы будете загрязнять класс кодом, который должен обрабатываться World, и это будет сложно поддерживать позже.

Извините за длинный ответ, но я не мог с собой поделать:)

0 голосов
/ 23 октября 2011

Было ли засорение Главного класса проблемой или выяснение того, какая пуля попала в противника? Если это была пуля, вам нужно описать поведение пули - может ли она поразить нескольких врагов, как быстро она движется (возможно ли, что при тестировании с использованием «enterFrame» пуля сначала появится перед врагом, и, на второй кадр, он появится за врагом?). Может ли враг быть упрощен до некоторой базовой геометрической формы, такой как круг или прямоугольник, или вам нужна точность с точностью до пикселя? Наконец, сколько пуль и сколько врагов вы планируете иметь одновременно? Это может быть слишком дорого иметь экранный объект для каждой пули, если у вас их будет сотни, и тогда было бы более разумно нарисовать их в одной форме / растровых данных.

Если проблема в том, что класс Main слишком длинный, здесь есть несколько возможностей.

  1. Ответ нобрейнера на эту проблему - используйте наследование, чтобы просто поместить части кода в отдельные файлы. Не лучшим образом, но многие люди делают это.
  2. Если бы вы сделали первое, то поняли бы, что есть определенные группы функций, которые вы помещаете в суперкласс и подклассы - это поможет вам разделить «забитый» класс на несколько более мелких независимых частей, имеющих более конкретную специализацию.
  3. После того, как вы сделали второе, вы можете обнаружить, что существует определенная зависимость между тем, как вы разделяете большой класс на более мелкие классы, поэтому вы можете попытаться сгенерировать эти меньшие классы по определенному шаблону.
  4. А затем вы пишете засоренный код, обобщающий те части, которые вам только что удалось разделить.

Выше представлен цикл от более конкретного кода к более общему. В процессе усовершенствования последнего шага вы снова напишите какой-то конкретный код. И это переместит вас к шагу 1. Мыть, полоскать, повторять :) На самом деле, вы не хотите писать ОО-код, или код процедуры, или что-нибудь, что вам скажет мода дня. Вы хотите написать хороший код :) И вы делаете это, переходя от более общего к более конкретному и обратно к более общему, пока не станет совершенным: P

Возможно, не самый лучший ответ, но вы должны признать, что вы не дали много информации, чтобы дать вам более точный ответ.

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