Опубликован: 07.11.2006 | Уровень: специалист | Доступ: свободно
Лекция 12:

Изучение SphereCage

  1. Ниже приведены два последних метода для BallModel.
    BallModel.prototype.rotateDirection = function(axis, degree) { 
      var rad = degree*Math.PI/180; 
      var sin = Math.sin(rad); 
      var cos = Math.cos(rad); 
      if (axis == "y") {
        var x = cos*this.direction.x-sin*this.direction.z;
        this.direction.z = cos*this.direction.z+sin*this.direction.x;
        this.direction.x = x; 
      } else {
        var z = cos*this.direction.z-sin*this.direction.y;
        this.direction.y = cos*this.direction.y+sin*this.direction.z;
        this.direction.z = z; 
      }
    };
    BallModel.prototype.reset = function() { 
      this.clip[0]._visible = 1; 
      this.velocity = 1.5;
      this.vertexList [0] = {x:0, y:0, z:0, w:l}; 
      this.setDirection(Math.random()-1, Math.random()-.5, 
        Math. random()); 
      setTarget();
    };

    rotateDirection вызывается каждый раз, когда пользователь поворачивает весь трехмерный мир. При этом нам не только необходимо настраивать расположение каждого объекта в трехмерном пространстве, но также и вектор направления самого шарика. Это не сложно выполнить. ball.direction - единичный вектор, содержащий компоненты x, y и z (его направление определяется по отношению к центру пространства), и нам нужно повернуть координаты этого вектора около соответствующей оси. Код вам знаком, если вы проделывали тривиальные действия с любым типом трехмерного содержимого во Flash. Аналогичная функция использовалась в начале предыдущей лекции. Мы осуществляем поворот около осей x и y (мы не реализуем поворот вокруг оси z в этой игре) с помощью уже готовых формул.

    При начале проигрывания нового звука (каждый раз после того, как игрок теряет шарик) вызывается метод reset. Он отображает фильм innerball (хранимый в массиве clip ), устанавливает velocity обратно на 1.5, устанавливает случайное направление и устанавливает координаты шарика на центр пространства (обратите внимание на параметр w, который всегда равен 1). Наконец, он устанавливает цель в соответствующем месте. В этом легко разобраться, за исключением функции setTarget, которую мы сейчас обсудим.

    Вот мы и создали класс BallModel! Помните, что при создании шарика с помощью выражения

    ball = new BallModel();

    он будет содержать не только все методы класса BallModel, но и все параметры и методы класса Model.

  2. Создание BallModel завершено. Теперь нужно определить плоскости.
    PlaneModel = function() {
    };
    PlaneModel.prototype = new Model(); 
    PlaneModel.prototype.render = function() {
      super.applyTransform();
      this.clip.clear();
      this.clip.lineStyle(1, 0, 100);
      var verts2D = [];
      this.zDepth = 0;
      for (var i = 0; i<this.vertexList.length; i++) {
        var whichVert = this.vertexList[i]; 
        verts2D[i] = {};
        var scale = focalLength/(focalLength-whichVert.z); 
        verts2D[i].x = whichVert.x*scale; 
        verts2D[i].y = whichVert.y*scale; 
        this.zDepth += whichVert.z;
      }
      this.clip.moveTo(verts2D[0].x, verts2D[0].y);
      this.clip.beginFill(this.getSideColor(this.side[0]), 100);
      for (var j = 1; j<verts2D.length; j++) {
        this.clip.lineTo(verts2D[j].x, verts2D[j].y);
      }
      this.clip.lineTo(verts2D[0].x, verts2D[0].y); 
      this.clip.endFill(); 
    };

    Вы обрадуетесь, узнав, что этот блок кода полностью представляет собой определение класса PlaneModel. Для добавления ракеток (которые являются плоскостями) нам нужен только метод прорисовки.

    Минуточку! У нас уже метод render, определенный для класса Model! Да, это так, однако давайте вернемся к обсуждению цепочек наследования. При использовании paddle.render, Flash будет сначала искать метод с именем render в классе PlaneModel. Если он будет найден, поиск будет прекращен. Flash никогда не дойдет до класса Model для выяснения метода с таким же именем. Таким образом, мы предоставили отдельный метод render для наших плоскостей, однако разрешили использование оставшихся методов Model.

    Этот метод сначала вызывает метод applyTransform своего большого класса, в данном случае - Model. Так же, как this ссылается на его собственные методы, super будет обращаться к методам своего суперкласса, используя при этом ссылки на них в параметре prototype (посмотрите, в каком месте предыдущего кода мы установили его).

    После применения преобразования удаляем фильм с рисованием объектов, обрабатываем циклом вершины и рисуем плоскость. Этот процесс очень похож на то, что мы делали в предыдущей лекции, поэтому я не хочу вдаваться в более мелкие подробности, однако вы должны иметь в виду добавление параметра zDepth. Он содержит сумму координат z всех вершин и будет использоваться лишь для определения того, расположена ли плоскость спереди или сзади сферы. Поэтому дальнейшие вычисления z нам не нужны.

  3. Рассмотрим последний имеющийся у нас тип модели. Ранее, когда вы пробовали играть в игру, вы, наверняка, даже не подозревали о его присутствии в этой программе. Введите следующий код.
    PopUp = function (w, h) { 
      this.vertexList = [];
      this.vertexList.push({x:-w, y:-h, z:20, w:l});
      this.vertexList.push({x:-w, y:h, z:20, w:l});
      this.vertexList.push({x:w, y:h, z:20, w:l});
      this.vertexList.push({x.-w, y:-h, z:20, w:l});
      this.vertexList.push({x:-w-15, y:-h-15, z:0, w:l});
      this.vertexList.push({x:-w-15, y:h+15, z:0, w:l});
      this.vertexList.push({x:w+15, y:h+15, z:0, w:l});
      this.vertexList.push({x:w+15, y:-h-15, z:0, w:l});
      this.vertexList.push({x:-w+5, y:-h+5, z:15, w:l});
      this.vertexList.push({x:-w+5, y:h-5, z:15, w:l});
      this.vertexList.push({x:w-5, y:h-5, z:15, w:l});
      this.vertexList.push({x:w-5, y:-h+5, z:15, w:l});
      this.side = [];
      this.side.push({vertices:[0, 1, 2, 3], sideColor:"666666"});
      this.side.push({vertices:[0, 4, 5, 1], sideColor:"888888"});
      this.side.push({vertices:[0, 3, 7, 4], sideColor:"888888"});
      this.side.push({vertices:[7, 3, 2, 6], sideColor:"333333"});
      this.side.push({vertices:[1, 5, 6, 2], sideColor:"333333"});
      this.side.push({vertices:[8, 9, 10, 11], sideColor:"666666"});
      this.side.push({vertices:[0, 8, 9, 1], sideColor:"444444"});
      this.side.push({vertices:[3, 2, 10, 11], sideColor:"777777"});
      this.side.push({vertices:[9, 10, 2, 1], sideColor:"777777"}) ;
      this.side.push({vertices:[0, 3, 11, 8], sideColor:"444444"});
    };
    PopUp.prototype = new Model();
    Пример 11.8.

    Да, всплывающие окна также являются моделями. Здесь видно, что конструктору будут отправлены переменные ширины (w) и высоты (h) для изменения размера всплывающего окна, однако я оставил размер таким же. Почти весь этот блок кода вам знаком из работы с предыдущей лекцией. Обратите внимание на присутствие дополнительного параметра w для каждой вершины так, чтобы можно было использовать матрицы размером 4x4. Также видно, что я оптимизировал 3D-подсветку модели, добавив свои собственные настройки применительно к sideColor освещенных и затемненных сторон.

  4. Для модели PopUp есть только одна функция.
    PopUp. prototype.render = function() { 
      this.clip.clear(); 
      var verts2D = []; 
      for (var i = 0; i<this.vertexList.length; i++) {
        var whichVert = this.vertexList[i];
        verts2D[i] = {};
        var scale = focalLength/(focalLength-whichVert.z);
        verts2D[i].x = whichVert.x*scale;
        verts2D[i].y = whichVert.y*scale; 
    }
      for (var i = 0; i<this.side.length; i++) {
        this.clip.moveTo(verts2D[this.side[i].vertices[0]].x, 
        Кverts2D[this.side[i].vertices[0]].y);
        this.clip.beginFillthis.getSideColor(this.side[i]), 100); 
        for (var j = 1; j<this.side[i].vertices.length; j++) {
          this.clip.lineTo(verts2D[this.side[i].vertices[j]].x, 
          Кverts2D[this.side[i].vertices[j]].y);
        }
        this.clip.lineTo(verts2D[this.side[i].vertices[0]].x, 
        verts2D[this.side[i].vertices[0]].y); 
        this.clip.endFill(); 
      } 
    };

    Это еще один метод render. По идее нужно объединить этот метод с методом render PlaneModel и сделать PopUp подклассом Plane, однако это лишь несколько строк уже знакомого вам дополнительного кода.

    Последним фрагментом кода объекта будет расширение самого объекта Object.

    Object.prototype.duplicate = function() { 
      var temp = {}; 
      for (var i in this) { 
        temp[i] = this[i];
      }
      return temp;
    };

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

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

Игорь Хан
Игорь Хан
След не остается
Александр Коргапольцев
Александр Коргапольцев
Вопрос по содержанию лекции №2, курс Flash MX Studio
Анатолий Федоров
Анатолий Федоров
Россия, Москва
Ольга Ремез
Ольга Ремез
Латвия, Рига