у меня аналогичная ситуация. Однако, если взять пример из приложения (ball_motion_04_click for trial.fla) то след остается. при этом заметил, что в моем проекте в поле "One item in library" виден кружок, в то время как в приложенном примере такого кружка нет. Вопрос знатокам, что не так? |
Изучение SphereCage
- Ниже приведены два последних метода для 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.
- Создание 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 нам не нужны.
- Рассмотрим последний имеющийся у нас тип модели. Ранее, когда вы пробовали играть в игру, вы, наверняка, даже не подозревали о его присутствии в этой программе. Введите следующий код.
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 освещенных и затемненных сторон.
- Для модели 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-функций, перед запуском нашей игры. Если вы сейчас запустите фильм, вы не увидите абсолютно никакой разницы по сравнению с предыдущим запуском. Так что же мы делали все это время? Это была подготовка. Теперь все наши собственные классы определены и настроены на обработку их собственных действий, и остается создать лишь несколько служебных функций.