Статьи

Создайте управляемый световой меч Wiimote с помощью WiiFlash и Papervision3D

Сегодня мы собираемся создать световой меч, управляемый wiimote, используя WiiFlash и Papervision3D. Цель этого руководства — узнать, как использовать wiimote во флэш-памяти и как его сочетать с papervision3D. После этого, конечно, вы можете использовать это приложение для подготовки к мастерству джедая.


Первый шаг также самый простой; скачайте нужные нам пакеты. Перейдите на blog.papervision3d.org и wiiflash.bytearray.org, чтобы загрузить последнюю версию обоих пакетов. Разархивируйте оба пакета и поместите библиотеки (каталог с именем org) в ваш рабочий каталог.

Поскольку этот проект будет полностью написан на ActionScript 3.0, первое, что нам нужно сделать, это создать новый документ Flash и сделать ссылку на наш основной класс: LightSaber. Сохраните его как «lightsaber.fla» в вашем рабочем каталоге.

Затем создайте пустой класс с именем «LightSaber». Это будет основной класс, где все инициализируется. Сохраните его как «LightSaber.as» в рабочем каталоге.

1
2
3
4
5
6
7
8
9
package
{
    public class LightSaber
    {
        public function LightSaber()
        {
        }
    }
}

Следующий класс, который мы собираемся создать, называется LightSaber3D, и он будет содержать всю трехмерную логику. Сохраните его как «LightSaber3D.as» в вашем рабочем каталоге.

1
2
3
4
5
6
7
8
9
package
{
    public class LightSaber3D
    {
        public function LightSaber3D()
        {
        }
    }
}

Теперь, когда все классы и библиотеки готовы, мы можем начать их заполнять. Начнем с настройки связи wiimote. Следующий код является полным кодом для класса LightSaber; в следующих шагах мы обсудим это более подробно.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
package
{
    import flash.display.*;
    import flash.events.*;
 
    import org.wiiflash.Wiimote;
    import org.wiiflash.events.*;
     
    import LightSaber3D;
 
    public class LightSaber extends Sprite
    {
        private var wiimote:Wiimote;
        private var lightSaber3D:LightSaber3D;
                 
        public function LightSaber():void
        {
            stage.align = StageAlign.TOP_LEFT;
            stage.scaleMode = StageScaleMode.NO_SCALE;
 
            wiimote = new Wiimote();
            wiimote.addEventListener( Event.CONNECT, onWiimoteConnect );
             
            wiimote.connect();
        }
         
        private function onWiimoteConnect( pEvent:Event ):void
        {
            lightSaber3D = new LightSaber3D();
            addChild(lightSaber3D)
             
            lightSaber3D.buildLightSaber();
            lightSaber3D.turnOffLightSaber();
             
            wiimote.addEventListener(WiimoteEvent.UPDATE, updateWiimote);
            wiimote.addEventListener(ButtonEvent.B_PRESS, buttonPressed);
            wiimote.addEventListener(ButtonEvent.B_RELEASE, buttonReleased);
        }
         
        private function updateWiimote( pEvent:WiimoteEvent ):void
        {
            lightSaber3D.updateLightSaber3D(wiimote.pitch);
        }
         
        private function buttonPressed( pEvent:ButtonEvent ):void
        {
            lightSaber3D.turnOnLightSaber();
        }
         
        private function buttonReleased( pEvent:ButtonEvent ):void
        {
            lightSaber3D.turnOffLightSaber();
        }
    }
}
1
2
3
4
5
6
7
import flash.display.*;
import flash.events.*;
 
import org.wiiflash.Wiimote;
import org.wiiflash.events.*;
 
import LightSaber3D;

Прежде чем мы сможем что-либо сделать с wiimote во Flash, нам нужно включить библиотеки wiiflash в наш класс. Для этого конкретного проекта нам понадобится основной класс WiiMote и события wiimote. Мы также включили наш класс LightSaber3D, но об этом мы поговорим позже.

Прежде чем обсуждать, что на самом деле делает код и зачем он нам нужен, очень важно знать «общую концепцию» этого приложения. Мы создаем трехмерный световой меч, который можно вращать с помощью wiimote, а в качестве дополнительной функции мы сможем включать и выключать его с помощью кнопки «B» на задней панели wiimote.

Как нам достичь всего этого? Ну, я решил разбить его на два класса; тот, который обрабатывает wiimote, и тот, который контролирует все аспекты 3D. Класс wiimote получает данные из wiimote и передает их в 3D-класс. Это делается с помощью обработчиков событий из класса wiimote.

01
02
03
04
05
06
07
08
09
10
public function LightSaber():void
{
    stage.align = StageAlign.TOP_LEFT;
    stage.scaleMode = StageScaleMode.NO_SCALE;
 
    wiimote = new Wiimote();
    wiimote.addEventListener( Event.CONNECT, onWiimoteConnect );
     
    wiimote.connect();
}

Сначала мы создаем новый экземпляр класса wiimote и добавляем прослушиватель событий с именем «Event.CONNECT» к этому объекту. Это сделано потому, что мы хотим, чтобы приложение запускалось только при наличии соединения с wiimote. Далее мы пытаемся подключиться к серверу wiimote. Если это работает, событие «CONNECT» будет отправлено, и приложение запустится.

Работа сервера wiimote будет объяснена в конце этого руководства.

01
02
03
04
05
06
07
08
09
10
11
12
private function onWiimoteConnect( pEvent:Event ):void
{
    lightSaber3D = new LightSaber3D();
    addChild(lightSaber3D)
     
    lightSaber3D.buildLightSaber();
    lightSaber3D.turnOffLightSaber();
     
    wiimote.addEventListener(WiimoteEvent.UPDATE, updateWiimote);
    wiimote.addEventListener(ButtonEvent.B_PRESS, buttonPressed);
    wiimote.addEventListener(ButtonEvent.B_RELEASE, buttonReleased);
}

Если мы подключены к серверу wiimote и найден wiimote, эта функция будет выполнена. Он создаст новый экземпляр класса lightsaber3D и добавит его на сцену. Далее будет вызвана пара внутренних функций, которые создадут трехмерный световой меч и включат его. Следующие 3 строки более важны для нас прямо сейчас. Они добавляют 3 прослушивателя событий к объекту wiimote, и эти прослушиватели передают необходимые данные классу lightsaber3D.

Для получения дополнительной информации о доступных событиях wiimote, взгляните на API wiiflash, он включен в пакет, который вы скачали ранее.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
private function updateWiimote( pEvent:WiimoteEvent ):void
{
    lightSaber3D.updateLightSaber3D(wiimote.pitch);
}
 
private function buttonPressed( pEvent:ButtonEvent ):void
{
    lightSaber3D.turnOnLightSaber();
}
 
private function buttonReleased( pEvent:ButtonEvent ):void
{
    lightSaber3D.turnOffLightSaber();
}

Эти 3 функции будут вызывать 3 открытые функции внутри класса lightsaber3D. Это довольно просто: до тех пор, пока вы нажимаете кнопку «B», зажигалка включена, а если вы перемещаете wiimote, значение датчика высоты звука передается в функцию, которая управляет движением светового меча.

Разбивая эти классы и используя прослушиватели событий, будет очень легко повторно использовать оба класса в других проектах. Они не зависят друг от друга, поэтому вы можете заменить wiimote обычной клавиатурой или мышью, не настраивая код lightsaber3D. Следовательно, сила объектно-ориентированного программирования 🙂

Поскольку все коммуникации wiimote настроены, пришло время заняться 3D-программированием. Для этого мы используем Papervision3D. Мы будем использовать один класс для настройки 3D-среды и создания в ней нашего светового меча. Обычно вы бы разбили его на несколько классов, но поскольку у нас есть только один световой меч, делать это здесь не обязательно. Скажем так, это довольно значительный кусок кода, поэтому, чтобы предотвратить падение вашего браузера, вы можете загрузить файл LightSaber3D.as для просмотра .

Во-первых, нам понадобятся необходимые классы из библиотеки papervsion3D для построения 3D-среды. Он будет состоять из области просмотра, сцены, камеры и движка рендеринга. Для получения более подробной информации о концепции 3D-программирования, посетите веб-сайт papervision3D .

Так как наш световой меч будет состоять из 2 цилиндров с прикрепленным к нему небольшим светящимся фильтром, нам понадобятся только 3 вышеупомянутых класса. Фильтр свечения, который мы используем, является частью стандартной флеш-библиотеки.

1
2
3
4
5
6
7
8
9
public function LightSaber3D():void
{
    viewport = new Viewport3D(600, 450, true);
    addChild(viewport);
     
    renderer = new BasicRenderEngine();
    scene = new Scene3D();
    camera = new Camera3D();
}

Теперь, когда у нас есть все доступные классы, пришло время создать световой меч, но прежде чем мы сможем это сделать, нам нужна трехмерная среда. Мы создадим область просмотра, своего рода окно, через которое мы смотрим, сцену, в которой мы размещаем наши объекты, камеру, которая действует как «глаз» и, наконец, механизм рендеринга, который рендерит все это.

Для этого мы используем конструктор, так как это самое логичное место. Как вы, вероятно, помните из шага 5, мы вызываем этот конструктор, когда есть соединение с сервером wiimote, как раз в то время, когда они нам нужны.

01
02
03
04
05
06
07
08
09
10
public function buildLightSaber():void
{
    lsHolder = new DisplayObject3D();
     
    var handleColor = new ColorMaterial(0xCCCCCC);
    var bladeColor = new ColorMaterial(0x99FF33, 0.6);
 
    // give the lightsaber some color
    handle = new Cylinder(handleColor, 16, 150, 8, 3, 16);
    blade = new Cylinder(bladeColor, 12, 500, 8, 3, 8);

Функция buildLightSaber — это та, которая фактически добавляет все 3D-объекты на сцену. Световой меч состоит из клинка и ручки, которые помещены в контейнер. Клинок и ручка — простые цилиндры с цветным материалом на поверхности. Обратите внимание, что лезвие сделано слегка прозрачным, добавив дополнительный параметр в конструктор цветного материала.

1
2
blade.useOwnContainer = true;
           blade.filters = [new GlowFilter(0x66FF33)];

К лезвию прикреплен очень простой светофильтр, поэтому вокруг него будет светиться настоящий световой меч. На этом этапе вы можете заменить цветной материал растровым материалом, чтобы добавить некоторые текстуры, но здесь мы просто будем использовать простой цвет.

01
02
03
04
05
06
07
08
09
10
11
// position the blade & handle
           handle.y = 0;
           blade.y = 325;
            
           lsHolder.addChild(handle);
           lsHolder.addChild(blade);
            
           // place the holder somewhat in the center of the screen
           lsHolder.y = -200;
            
           scene.addChild(lsHolder);

Теперь мы добавляем оба объекта в контейнер с именем «lsHolder». Мы делаем это потому, что нам нужен один объект, которым мы можем манипулировать. Наконец, мы добавляем контейнер на сцену, чтобы он был виден, когда мы все визуализируем.

1
2
3
4
// now move the camera somewhat to the right for a good angle on the lightsaber
           camera.x = -200;
           // …but it still needs to look at the lightsaber
           camera.lookAt(lsHolder);

В качестве последнего шага мы переместим камеру на 200 пикселей влево, чтобы у нас был небольшой угол на световом мече. Это сделано исключительно для того, чтобы сделать то, что мы делаем, более заметным. Конечно, нам также нужно указать камере, где искать, вот что мы делаем в последней строке.

1
2
// now render the scene so we can actually see the lightsaber
           renderer.renderScene(scene, camera, viewport);

Последняя строка функции buildLightSaber очень важна и требует некоторого внимания. Все, что вы программируете в 3D, будет невидимым до тех пор, пока вы его не отобразите, поэтому мы здесь и делаем

Ранее мы решили, что мы хотим, чтобы световой меч был активен только тогда, когда нажата кнопка «B» на задней панели wiimote. Поэтому мы добавили двух прослушивателей событий, один из которых отправляется при нажатии кнопки «B», а другой — при отпускании кнопки «B». Следующие две функции будут вызываться для этих событий.

1
2
3
4
5
6
7
8
9
public function turnOnLightSaber():void
       {
           blade.visible = true;
       }
        
       public function turnOffLightSaber():void
       {
           blade.visible = false;
       }

Чтобы создать эффект включения / выключения для нашего светового меча, мы просто делаем клинок видимым или невидимым. С некоторыми дополнительными усилиями вы можете добавить подпрограмму, которая заставляет лезвие расти и сжиматься, но это не обязательно для этого урока.

01
02
03
04
05
06
07
08
09
10
11
public function updateLightSaber3D(pitch:Number)
       {
           // calcaulte the difference in degrees of the pitch
           var newPitch:Number = 90 + Math.round(pitch * (180/Math.PI) — lsHolder.rotationX);
            
           // apply it
           lsHolder.pitch(newPitch);
            
           // and render it.
           renderer.renderScene(scene, camera, viewport);
       }

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

1
2
     
var newPitch:Number = 90 + Math.round(pitch * (180/Math.PI) — lsHolder.rotationX);

Значение шага wiimote будет дано в радианах, но функция высоты тона papervision3D рассчитывает градусы, поэтому нам нужно сделать некоторые вычисления. Поскольку функция шага использует относительный угол, нам необходимо вычесть текущий угол из значения датчика шага. В противном случае световой меч вышел бы из-под контроля.

1
2
3
4
5
// apply it
           lsHolder.pitch(newPitch);
            
           // and render it.
           renderer.renderScene(scene, camera, viewport);

После перевода контейнера в его новое значение нам нужно снова визуализировать сцену.

И мы сделали! Имея всего 151 строку кода, мы создали собственную программу обучения световому мечу джедая! Хотя не раньше, чем мы экспортируем это, конечно. Чтобы добиться максимальной производительности, мы должны использовать его как автономный проектор. Перейдите к настройкам публикации, коснитесь коробок проектора и используйте настройки, перечисленные ниже.

Теперь опубликуйте это, и все готово.

Не совсем … Прежде чем мы сможем запустить это приложение, нам нужно запустить сервер wiiflash и подключить к нему wiimote. Это должно быть очень просто. Запустите сервер (вы найдете его в пакете, который вы скачали на шаге 1) и нажмите кнопки 1 + 2 на вашем wiimote.

Краткое примечание по созданию приложений и игр, использующих wiimote. Данные датчика, которые вы получаете от wiimote, не очень точны. Вы заметите, что в приложении, которое мы только что создали. Вот почему большинство игр, которые вы найдете на Wii, основаны на распознавании движения. Это означает, что система (в данном случае Wii) распознает определенное движение, выполненное с помощью wiimote, и прикрепляет к нему определенное (визуальное) действие. Например, если вы делаете движение, которое напоминает подачу теннисного мяча, Wii вычислит вашу скорость и направление на основе данных датчика и переведет их в плавную трехмерную анимацию. Расчеты, связанные с этими процедурами, очень сложны и поэтому не включены в этот учебник.

Да пребудет с тобой сила..