Статьи

Создайте онлайн Photobooth и потрясающий 3D Photowall

В этом уроке Premium мы создадим онлайн-фотобудку и 3D-фотостену. Это приложение позволит вам сделать фотографию с помощью веб-камеры, после чего она будет отправлена ​​на сервер, где она будет храниться в базе данных. Наконец, ваша фотография будет доступна для просмотра в 3D-карусели. Мы рассмотрим широкий спектр методов, таких как флэш-удаленное взаимодействие, AMFPHP, базы данных mySQL, PHP и движок Away3D lite.


Цель этого урока — дать вам несколько примеров конкретных техник и, что более важно, как их объединить для достижения наилучшего эффекта.


Поскольку это клиент-серверное приложение, нам понадобится сервер. Этот сервер должен запускать сервер http, сервер базы данных mysql и должен быть оснащен PHP (по крайней мере, версия 5). Это звучит как много, но большинство основных пакетов веб-хостинга предоставят вам это. Если у вас нет сервера, вы можете превратить свой собственный компьютер в один, используя пакеты программного обеспечения, такие как xampp. Я не буду вдаваться в детали настройки такой среды, так как это не то, о чем этот урок. Есть много хороших уроков и статей по настройке такого сервера.

Я предполагаю, что у вас есть некоторые базовые знания о всей концепции клиентского сервера, FTP и веб-хостинга.


Далее нам понадобятся инструменты для разработки. Хорошие старые времена разработки всего в блокноте прошли … Итак, нам нужно:

  • Flash IDE (CS4)
  • Редактор php / html (Aptana)
  • FTP-клиент (Cyberduck)
  • Приличный веб-браузер (Firefox)
  • Удаленный сниффер для отладки (Чарльз)

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


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

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

В zip-файле, прилагаемом к этому руководству, вы найдете 4 папки в корневом каталоге: doc, bin, lib и src. В двух наиболее важных из них, src & bin, вы найдете все файлы, над которыми мы будем работать. Папки lib & doc содержат файлы, которые нам понадобятся, но работать не нужно. Более подробная информация о роли этих папок будет предоставлена ​​позже.


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

Сначала нам понадобится AMFPHP. Хотя разработка AMFPHP в последнее время была немного медленной, она все еще очень полезна, если вы хотите использовать Flash Remoting с PHP. Вы найдете это на amfphp.org . После загрузки вы должны распаковать его и скопировать в каталог lib.


В какой-то момент нам потребуется сохранить изображение, снятое веб-камерой, в базе данных. Поскольку мы не хотим хранить необработанные растровые изображения, нам понадобится кодер JPEG. Мы могли бы сделать это, используя скрипт PHP, но у этого есть 2 недостатка. Во-первых, это создаст большой сетевой трафик, а во-вторых, это будет дополнительной нагрузкой на сервер, если ему придется выполнять все эти вычисления. Итак, мы делаем кодировку JPEG на стороне клиента.

Поскольку AS3 не имеет стандартных функций кодирования JPEG, мы будем использовать внешнюю библиотеку AS3CoreLib. Вы можете найти это здесь . После загрузки вы должны скопировать его в каталог lib.


Наконец, нам понадобятся две другие библиотеки для приложений flash, а именно библиотека Away3d lite и библиотека TweenMax. Вы найдете их здесь и здесь . Загрузив их, разархивируйте их и скопируйте в каталог lib.

Мы будем использовать Away3dLite здесь, потому что он поддерживает новую 3D-функциональность Flash Player 10, что приводит к гораздо лучшей производительности, чем Papervision3D.


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

Обо всем по порядку; в zip-файле вы найдете файл tables.sql.txt в папке / src / sql. Этот файл содержит SQL-код, необходимый для настройки базы данных для этого проекта. Мы обсудим файл sql на следующем шаге.

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


SQL часть этого проекта, вероятно, самая простая часть. Нам нужна только 1 таблица, состоящая из 3 полей. Мы назовем эту таблицу «фотографиями», а поля в ней будут называться «id», потому что нам нужен уникальный ключ «data», который содержит фактические двоичные данные фотографии и «ip», чтобы регистрировать IP-адрес компьютер, на котором была сделана фотография. Последнее поле несколько произвольно, но по соображениям безопасности оно может быть полезным.

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

Большинство современных клиентов SQL предоставляют способ «импорта» файлов sql в базу данных, поэтому просто импортируйте файл tables.sql.txt в базу данных, и все готово!


Теперь, когда часть базы данных запущена и работает, пришло время подготовить оставшуюся часть сервера. Здесь не так много работы, в основном, создание папки на вашем веб-сервере подойдет. Я все равно упомяну об этом, потому что этот каталог будет онлайн-эквивалентом папки bin в корне нашего проекта.

Папка bin содержит фактический результат нашей сборки, и, поскольку это веб-сайт, эта папка окажется в сети. Возможно, вы захотите связать эту папку в вашем FTP-клиенте, так как мы собираемся использовать его часто. Если вы используете настройку, аналогичную XAMPP, вы захотите добавить эту папку в свой webroot.


Первый шаг, который нам нужно сделать, это разархивировать загруженный пакет и поместить его в папку bin. Затем скопируйте папку «services» из папки «AMFPHP» в папку «bin». Эта папка будет содержать фактические PHP-скрипты, которые мы собираемся написать.


Так как мы изменили некоторые вещи в AMFPHP, нам нужно обновить файл конфигурации AMFPHP. Поэтому откройте «bin / amfphp / gateway.php» и перейдите к строке 123. Здесь вы найдете параметр, указывающий на папку services, измените его на «../services». Теперь перейдите к строке 123 и убедитесь, что рабочий сервер установлен на false. В противном случае вы можете получить пресловутую ошибку «Bad Gateway» во Flash IDE при попытке доступа к этому веб-сервису.

Сделайте быстрый тест, чтобы увидеть, все ли работает правильно; загрузите папку bin на свой сервер и откройте http: // yourserver / amfphp / browser /. Если вы видите только пустой гибкий фон, щелкните правой кнопкой мыши, снимите флажок «повторить», щелкните правой кнопкой мыши еще раз и нажмите кнопку воспроизведения. Это должно делать свое дело.


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

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

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


Первый класс, который мы создадим, это класс базы данных. Он находится в «bin / services / nl / gerbster / utils». Почему? Ну, поскольку я использую этот класс очень часто, я поместил его в специальную папку утилит. Таким образом, я могу использовать его во многих различных проектах, не меняя его каждый раз, когда я его использую. Так что откройте его и давайте посмотрим.

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
<?php
  
class Db
{
    var $connection = NULL;
    var $link = NULL;
    var $host, $username, $password, $database;
  
    function Db($host, $username, $password, $database)
    {
        $this->username = $username;
        $this->password = $password;
        $this->host = $host;
        $this->database = $database;
    }
      
    function getDbConnection()
    {
        if(!$this->connection = mysql_connect($this->host, $this->username, $this->password))
        {
            return false;
        }
          
        if(!$this->link = mysql_select_db($this->database))
        {
            return false;
        }
          
        mysql_query(«SET NAMES \’utf8\'»);//WOW!
          
        return $this->link;
    }
}
  
?>

Идея этого класса очень проста; установить соединение с базой данных MySQL, выполнить аутентификацию и, если все пойдет хорошо, вернуть ссылку, в противном случае вернуть false.


Базовым классом нашего бэкэнда будет класс PhotoBooth (.php). Другой класс, Photo (.php), расширит этот класс и будет содержать две функции, которые мы будем вызывать позже из приложений flash.

1
<?php // default includes include_once(dirname(__FILE__).’/../../../db.inc.php’);

Этот класс включает в себя ‘db.inc.php’, который содержит некоторые предварительно определенные переменные, и ранее обсуждавшийся файл ‘Db.php’. Функции класса «PhotoBooth» — это не что иное, как обертка, которая содержит ссылку на объект базы данных, поэтому мы можем делать вызовы в базу данных.

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


Этот класс является классом, где происходит все действие. Он содержит две функции, которые мы будем вызывать из двух приложений flash: getPhotos и storePhoto. Конструктор делает то, что в основном делают все конструкторы, устанавливает переменные и инициализирует вещи. В этом случае он устанавливает формат кодирования AMFPHP на «amf3». Мы сделаем это на стороне флеш-памяти позже. Причиной этого является то, что версия 3 протокола AMF поддерживает байтовые массивы, что мы будем активно использовать.

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
56
57
58
59
60
61
62
63
64
65
66
67
<?php
  
// default includes
include_once(dirname(__FILE__).\’/PhotoBooth.php\’);
  
class Photo extends PhotoBooth
{
    public function __construct()
    {
        $GLOBALS[\’amfphp\’][\’encoding\’] = \’amf3\’;
          
        // we need a DB connection
        $this->getDbConnection();
    }
      
    public function getPhotos()
    {
        $sql = «SELECT
                    data, id
                FROM
                    photos
                ORDER BY id DESC
                LIMIT 0, 24″;
  
        if(!$recordSet = mysql_query($sql))
        {
            return false;
        }
          
        $data = array();
          
        while($record = mysql_fetch_assoc($recordSet))
        {
            $record[\’data\’] = new ByteArray( base64_decode( $record[\’data\’] ) );
              
            $data[] = $record;
        }
          
        return $data;
    }
      
    public function storePhoto($photoByteArray)
    {
        // store photo in DB
        $sql = «INSERT INTO photos
                (
                    data,
                    ip
                )
                VALUES
                (
                    \'» . base64_encode( $photoByteArray->data ) . «\’,
                    \'» . $_SERVER[\’REMOTE_ADDR\’] . «\’
                )»;
          
        if (!mysql_query($sql))
        {
            return mysql_error();
        }
        else
        {
            return true;
        }
    }
}
  
?>

Две функции в этом классе — очень простые функции set и get. Начнем с первого, getPhotos. Первое, что он делает, это извлекает данные из базы данных, используя очень простой SQL-запрос. Обратите внимание, что мы ограничиваем ответ из базы данных 24 записями сверху вниз, что означает, что мы получаем только 24 последних добавленных изображения. Следующим шагом является циклический просмотр записей, декодирование информации из базы данных, помещение ее в байтовый массив и укладка в массив. Наконец, массив отправляется клиенту.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public function storePhoto($photoByteArray)
{
    // store photo in DB
    $sql = «INSERT INTO photos
            (
                data,
                ip
            )
            VALUES
            (
                \'» . base64_encode( $photoByteArray->data ) . «\’,
                \'» . $_SERVER[\’REMOTE_ADDR\’] . «\’
            )»;
      
    if (!mysql_query($sql))
    {
        return mysql_error();
    }
    else
    {
        return true;
    }
}

Другая функция в этом классе, storePhoto, в основном является аннулированием предыдущей обсуждаемой функции. Он принимает байтовый массив, кодирует его и сохраняет в базе данных. Если что-то идет не так, он возвращает сообщение об ошибке, в противном случае он просто возвращает true. Единственными действительно интересными частями этих функций являются части кодирования. Когда данные поступают, это фактические двоичные данные, однако MySQL не может хранить их таким образом, поэтому нам придется преобразовать их в форму, принятую MySQL. И вот тут и появляется base64. Base64 — это способ кодирования двоичных данных в знаки ASCII, поэтому они могут храниться в базе данных MySQL. Более подробную информацию о base64 можно найти в сети.


Теперь, когда мы завершили PHP-часть этого руководства, пришло время протестировать его. Это очень важно, потому что мы хотим убедиться, что все работает, прежде чем мы начнем с внешнего интерфейса. Итак, мы начнем с загрузки контента на наш сервер и снова откроем инспектор сервиса: http: // yourserver / amfphp / browser / Если все в порядке, вы видите что-то вроде этого:


Если вы сделали опечатку или что-то пошло не так, вы, вероятно, получите здесь сообщение об ошибке. Обратите внимание, что этот тест показывает только правильность вашего кода PHP. Это, конечно, не означает, что ваш PHP-код делает именно то, что вы хотите! Однако пока этого достаточно, когда у нас есть готовый интерфейс и мы можем выполнить более детальное тестирование.


Веб-интерфейс этого приложения состоит из трех частей. Сначала есть приложение PhotoBoth, которое позволяет сделать снимок и отправить его на сервер. Далее у нас будет фотостена, которая извлекает данные с сервера и показывает их в трехмерной карусели. И, наконец, третья часть состоит из HTML-файлов, в которых все хранится вместе. Мы разберемся с этими частями в том же порядке, как описано выше.


Сначала мы создадим новый флэш-файл для фотобудки и назовем его photobooth.fla. Прежде чем мы начнем писать код ActionScript, чтобы все это работало, нам нужно будет настроить некоторые параметры и добавить экземпляр «кнопки записи». Итак, сначала откройте настройки профиля.


Теперь нажмите на «Actionscript Settings»


Мы определим наш класс документа здесь. Он находится в папке с именем «com / photobooth /», а файл называется PhotoBooth.as, поэтому класс документа будет «com.photobooth.PhotoBooth». Далее нам нужно определить путь к классам библиотеки и SWC. Мы разместим их в другом каталоге, называемом «lib», поэтому наши файлы проекта будут отделены от файлов нашей библиотеки. Добавьте каталог с помощью диалогового окна и перейдите в каталог «lib».


Теперь перейдите на вкладку «Путь к библиотеке» и сделайте то же самое. После настройки переменных пора добавить «кнопку записи» в библиотеку. Добавьте изображение кнопки записи в библиотеку. Теперь создайте новый MovieClip, назовите его RecordBtn и сделайте его доступным для actioncript. Наконец, установите размер 300 х 375 пикселей.


Поскольку это приложение на самом деле не ракетостроение, приложение имеет только один класс. Он называется PhotoBooth и, как упоминалось ранее, он находится в каталоге / src / flash / com / photobooth. Скопируйте код внизу в этот файл и сохраните его. В следующих главах мы обсудим код более подробно.

1
package com.photobooth { import flash.display.*;

Начиная сверху, мы начнем с импорта. Поскольку это более продвинутый учебник, я предполагаю, что вы знаете кое-что о ActionScript, поэтому неудивительно, что мы импортируем первые 3 элемента. Следующие три, касающиеся «сетевой» функциональности, используются для удаленного взаимодействия. Три «текстовых» класса используются для счетчика, а два класса камер импортируются, поскольку мы собираемся использовать веб-камеру. Последними из встроенных классов Flash, которые мы импортируем, являются некоторые служебные классы, а именно классы «ByteArray» и «Timer», подробнее о них позже.

2 внешних библиотеки, которые мы собираемся импортировать, это класс кодировщика JPEG и классы TweenMax. Они нужны нам для преобразования фотографии с веб-камеры в изображение JPEG и для анимации некоторых элементов.

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
package com.photobooth
{
    import flash.display.*;
    import flash.events.*;
    import flash.geom.*;
      
    import flash.net.ObjectEncoding;
    import flash.net.NetConnection;
    import flash.net.Responder;
      
    import flash.text.TextField;
    import flash.text.TextFormat;
    import flash.text.TextFormatAlign;
          
    import flash.media.Camera;
    import flash.media.Video;
      
    import flash.utils.*;
      
    import com.adobe.images.JPGEncoder;
      
    import gs.TweenMax;
    import gs.easing.*;
      
    public class PhotoBooth extends MovieClip

Наконец, мы определим класс, он называется PhotoBooth и расширяет класс MovieClip. Ничего особенного там нет.


Большинство программ будет иметь некоторые переменные, как и эта. В основном, объявленные здесь переменные относятся к классам, импортированным выше. Есть некоторые переменные для удаленной части, веб-камеры и визуальных элементов.

1
2
3
private var gateway:String = «http://yourserver/amfphp/gateway.php»;
private var connection:NetConnection;
private var responder:Responder;

Первые три касаются удаленной части этой программы. Первый из них особенно важен, поскольку он содержит расположение нашего скрипта amfphp gateway. Настройте его так, чтобы он указывал на ваш сервер! Другие 2 рассматриваются позже.

1
2
private var myWebcam:Camera;
private var myVideo:Video;

Следующие две переменные используются для веб-камеры и видеообъекта, которые мы будем использовать позже.

1
2
3
4
5
6
private var buttonLayer:MovieClip = new MovieClip();
private var bgSprite:Sprite = new Sprite();
private var flashSprite:Sprite = new Sprite();
private var btnMC:RecordBtn = new RecordBtn();
private var myTextField:TextField = new TextField();
private var textFormat:TextFormat = new TextFormat();

Так как в этой программе есть некоторые визуальные элементы, нам также нужно определить их. Они не очень интересны и будут упомянуты позже. Обратите внимание на переменную ‘btnMC’, это ссылка на мувиклип, который мы создали ранее.

1
private var bmpd:BitmapData;

Наконец, мы объявим переменную ‘bmpd’. Это объект bitmapData, который мы будем использовать для хранения данных изображения веб-камеры при съемке.


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

01
02
03
04
05
06
07
08
09
10
function PhotoBooth():void
{
    myWebcam = Camera.getCamera();
 
    if(myWebcam != null)
    {
        initWebcam();
        initAssets();
    }
}

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

01
02
03
04
05
06
07
08
09
10
11
12
13
14
      
private function initWebcam():void
{
    myWebcam.setMode(300, 400, 30);
 
    myVideo = new Video(stage.stageWidth, stage.stageHeight);
    myVideo.smoothing = true;
      
    flipVideo(myVideo);
      
    myVideo.attachCamera(myWebcam);
 
    stage.addChild(myVideo);
}

Функция initWebcam инициализирует веб-камеру (без сюрпризов) и выводит изображение на экран. Шаг 1 — определить размер и частоту кадров камеры. Затем создается новый объект Video, изображение переворачивается для создания зеркального эффекта с помощью функции flipVideo, и объект веб-камеры присоединяется к объекту Video. В качестве последнего шага мы добавим его на сцену, чтобы все могли его увидеть.

FlipVideo — это простая матричная функция, которая «переворачивает» видеопоток. Больше информации о матричных вычислениях можно найти в сети, конечно.


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

01
02
03
04
05
06
07
08
09
10
11
private function initAssets():void
{
    flashSprite.graphics.beginFill(0xffffff);
    flashSprite.graphics.drawRect(0, 0, stage.stageWidth, stage.stageHeight);
    flashSprite.graphics.endFill();
    flashSprite.alpha = 0;
  
    bgSprite.graphics.beginFill(0xffffff);
    bgSprite.graphics.drawRect(0, 0, stage.stageWidth, 80);
    bgSprite.graphics.endFill();
    bgSprite.alpha = .5;

Далее мы добавим кнопку «запись». Как упоминалось ранее, этот объект связан с RecordBtn, который мы добавили в библиотеку файла .fla. Так как это все еще MovieClip, первое, что нужно сделать, это включить его buttonMode. Это заставит его вести себя как кнопка. Далее мы правильно разместим его на экране и, наконец, добавим к нему прослушиватель событий. Это событие вызывается при щелчке объекта, и он показывает таймер.

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
btnMC.buttonMode = true;
 
btnMC.x = bgSprite.width / 2 — btnMC.width / 2;
btnMC.y = bgSprite.height / 2 — btnMC.height / 2;
  
btnMC.addEventListener(MouseEvent.CLICK, showTimer);
  
textFormat.font = «Arial»;
textFormat.size = 48;
textFormat.bold = true;
textFormat.align = TextFormatAlign.CENTER;
textFormat.color = 0xFFFFFF;
  
myTextField.defaultTextFormat = textFormat;
myTextField.selectable = false;
myTextField.multiline = false;
myTextField.height = 48;
myTextField.width = 48;
  
  
myTextField.x = bgSprite.width / 2 — myTextField.width / 2;
myTextField.y = (bgSprite.height / 2 — myTextField.height / 2) — 5;
  
myTextField.visible = false;
  
buttonLayer.addChild(bgSprite);
buttonLayer.addChild(btnMC);
buttonLayer.addChild(myTextField);
  
buttonLayer.y = stage.stageHeight — 80;

Третий сегмент этой функции добавит текстовое поле на экран. Это текстовое поле используется для отображения обратного отсчета после нажатия кнопки записи.

1
2
3
    stage.addChild(flashSprite);
    stage.addChild(buttonLayer);
}

Последним шагом этой функции будет добавление всего на сцену. Помните, во флэш-памяти ничего не будет видно, если он не добавлен на сцену. Сначала мы добавляем фон, кнопку и текстовое поле в «контейнер» с именем «buttonLayer», а затем добавляем его на stage. Мы делаем это, потому что позже будет проще спрятать все это вместе.

В качестве последнего шага мы добавим «buttonLayer» и flashSprite на сцену.


Подача фото механизма очень проста. После того, как пользователи нажимают кнопку «запись», отображается таймер, а кнопка записи становится невидимой. Когда обратный отсчет достигает нуля, кадр из потока веб-камеры берется, изменяется и кодируется как изображение JPEG.

Чтобы добавить визуальную обратную связь с этим процессом, блок flashSprite анимирует за 0,5 секунды от альфа 1 до альфа 0, создавая ранее упомянутый эффект вспышки. Тем временем изображение JPEG отправляется на сервер с использованием удаленного объекта. После завершения этого процесса кнопка «запись» снова становится видимой.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
private function showTimer(e:MouseEvent):void
{
    btnMC.visible = false;
    myTextField.visible = true;
    myTextField.text = «3»;
      
    var myTimer:Timer = new Timer(1000, 3);
    myTimer.addEventListener(TimerEvent.TIMER, doCountDown);
    myTimer.addEventListener(TimerEvent.TIMER_COMPLETE, makeSnapShot);
    myTimer.start();
}
  
private function doCountDown(event:TimerEvent):void
{
    myTextField.text = String(Number(myTextField.text) — 1);
}

«ShowTimer» воплощает первый шаг процесса. Это делает кнопку «запись» невидимой, затем показывает и инициализирует таймер. Таймер установлен на 1 секунду, 1000 миллисекунд, и он должен повторяться 3 раза. Мы также добавили двух слушателей событий. Тот, который срабатывает, если готов цикл, для которого он будет уменьшать счет с помощью функции doCountDown. Другой срабатывает, когда таймер полностью завершен, и он вызывает функцию makeSnapShot.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
private function makeSnapShot(event:TimerEvent):void
{
    btnMC.visible = true;
    myTextField.visible = false;
      
    flashSprite.alpha = 1;
      
    var scaleMatrix:Matrix = new Matrix();
    scaleMatrix.scale(.5 ,.5);
    bmpd = new BitmapData(myVideo.width/2, myVideo.height/2);
    bmpd.draw(myVideo, scaleMatrix);
      
    var ba:ByteArray;
    var encoder:JPGEncoder = new JPGEncoder(65);
    ba = encoder.encode( bmpd );
 
    TweenMax.to(flashSprite, .5, {alpha: 0, ease:Quad.easeIn});
 
    sendByteArrayToServer(ba);
}

Функция makeSnapShot сделает кнопку «запись» снова видимой; сделайте текстовое поле обратного отсчета невидимым и покажите эффект «фото вспышки». Что еще более важно, он берет кадр из видеопотока веб-камеры, масштабирует его, кодирует его в изображение JPEG, после чего он передается функции ‘sendByteArrayToServer’.


Хотя это ключевая часть всего руководства, код, обрабатывающий вызов удаленного взаимодействия, состоит всего из 5 строк. Вызов выполняется функцией sendByteArrayToServer. Сначала создается объект «Ответчик». Этот объект обрабатывает ответ, который мы получаем после вызова нашего шлюза AMFPHP.

1
2
3
4
private function sendByteArrayToServer(byteArray:ByteArray):void
{
    // make net call..
    responder = new Responder(onResult, onFault);

Далее мы создадим объект NetConnection. Этот объект устанавливает фактическое соединение с нашим шлюзом AMFPHP. Мы определяем формат данных, которые мы отправляем, и, наконец, мы подключаемся к шлюзу с помощью переменной «gateway», которую мы объявили ранее.

1
2
3
4
5
6
    connection = new NetConnection;
    connection.objectEncoding = ObjectEncoding.AMF3;
    connection.connect(gateway);
      
    connection.call(«com.photobooth.Photo.storePhoto», responder, byteArray);
}

Теперь, когда мы подключены, пришло время сделать звонок. Мы вызовем функцию com.photobooth.Photo.storePhoto и отправим массив байтов, содержащий наше изображение. Второй аргумент функций вызова содержит ссылку на объект респондента, поэтому объект соединения знает, кого вызывать, когда ответ возвращается.

1
2
3
4
5
6
private function onResult(result:Object):void {
}
 
private function onFault(fault:Object):void {
}

Поскольку мы определили объект респондента, нам понадобятся две функции, называемые onResult и onFault. Эти функции будут вызваны, когда ответ вернется с сервера. Тем не менее, мы не используем их здесь. Если вы хотите, вы можете встроить некоторые функции, которые обеспечивают некоторую обратную связь с пользователем о статусе вызова.


Теперь, когда все готово, пришло время скомпилировать и протестировать эту часть приложения. Поскольку мы уже создали бэкэнд этого приложения, мы можем проверить, правильно ли сохранены фотографии. Так что нажмите комбинацию ввода-ввода и посмотрите, работает ли она. Если все в правильном порядке, вы увидите что-то вроде этого:



Начальные этапы строительства фотостены в основном такие же, как и для фотокабины. Мы кратко рассмотрим их. Сначала создайте новый файл .fla и назовите его «PhotoWall.fla». Затем добавьте пути к библиотекам и определите класс документа в com.photobooth.PhotoWall. Наконец, установите размер 800 X 600 пикселей.

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

Класс PhotoWall не делает ничего, кроме вызова шлюза AMFPHP, извлечения фотографий и передачи их классу Wall3d.

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
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
package com.photobooth
{
    import flash.display.*;
    import flash.events.*;
    import flash.geom.*;
  
    import flash.net.URLRequest;
    import flash.net.ObjectEncoding;
    import flash.net.NetConnection;
    import flash.net.Responder;
      
    import flash.utils.ByteArray;
  
    import com.photobooth.Wall3d;
  
    public class PhotoWall extends MovieClip
    {
        private var wall3d:Wall3d;
          
        private var gateway:String = «http://yourserver/flashtuts/photobooth/amfphp/gateway.php»;
        private var connection:NetConnection;
        private var responder:Responder;
          
        private var databaseResult:Object;
        private var photos:Array = new Array();
                  
        private var totalResults:int = 0;
          
        function PhotoWall():void
        {
            stage.align = StageAlign.TOP_LEFT;
            stage.scaleMode = StageScaleMode.NO_SCALE;
              
            getPhotosFromServer();
        }
          
        private function getPhotosFromServer():void
        {
            // make net call..
            responder = new Responder(onResult, onFault);
              
            connection = new NetConnection;
            connection.objectEncoding = ObjectEncoding.AMF3;
            connection.connect(gateway);
              
            connection.call(«com.photobooth.Photo.getPhotos», responder);
        }
          
        private function onResult(result:Object):void {
            totalResults = result.length;
              
            for(var i:int = 0; i < result.length; i++)
            {
                var ldr:Loader = new Loader();
                ldr.loadBytes(result[i].data);
                ldr.contentLoaderInfo.addEventListener(Event.COMPLETE, bytesComplete);
            }
        }
  
        private function bytesComplete(e:Event):void
        {
            photos.push(Bitmap(e.target.content).bitmapData);
          
            if(totalResults == photos.length)
            {
                // now every photo is the array, let show the carousel
                wall3d = new Wall3d(photos);
                this.addChild(wall3d);
            }
        }
  
        private function onFault(fault:Object):void {
            trace(fault);
        }
    }
}

Импорт этого класса примерно такой же, как импорт класса PhotoBooth. Однако нам нужен только импорт, связанный с сетью, байтовым массивом и классом wall3d, который мы собираемся построить позже.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
package com.photobooth
{
    import flash.display.*;
    import flash.events.*;
    import flash.geom.*;
  
    import flash.net.URLRequest;
    import flash.net.ObjectEncoding;
    import flash.net.NetConnection;
    import flash.net.Responder;
      
    import flash.utils.ByteArray;
  
    import com.photobooth.Wall3d;
  
    public class PhotoWall extends MovieClip
    {

Все переменные, используемые в этом классе, используются для вызова удаленного взаимодействия, за исключением wall3d, который используется для хранения экземпляра 3d-стены, которую мы собираемся построить.

01
02
03
04
05
06
07
08
09
10
private var wall3d:Wall3d;
  
private var gateway:String = «http://yourserver/flashtuts/photobooth/amfphp/gateway.php»;
private var connection:NetConnection;
private var responder:Responder;
  
private var databaseResult:Object;
private var photos:Array = new Array();
          
private var totalResults:int = 0;

Как упоминалось ранее, конструкторы в основном используются для установки переменных и инициализации содержимого. Ну, ничего нового здесь. После установки некоторых переменных, касающихся масштабирования и выравнивания, вызывается функция getPhotosFromServer. Эта функция отвечает за вызов шлюза AMFPHP и получение массива с фотографиями. Мы не будем обсуждать это более подробно, так как мы уже сделали это с классом PhotoBooth.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
function PhotoWall():void
{
    stage.align = StageAlign.TOP_LEFT;
    stage.scaleMode = StageScaleMode.NO_SCALE;
      
    getPhotosFromServer();
}
  
private function getPhotosFromServer():void
{
    // make net call..
    responder = new Responder(onResult, onFault);
      
    connection = new NetConnection;
    connection.objectEncoding = ObjectEncoding.AMF3;
    connection.connect(gateway);
      
    connection.call(«com.photobooth.Photo.getPhotos», responder);
}

Более интересная часть этого класса — часть обработки данных. Когда результат возвращается с сервера, он передается функции onResult. Первое, что делает эта функция — устанавливает для переменной totalResults общую длину массива с фотографиями. Затем он будет циклически проходить по массиву и преобразовывать каждый байтовый массив в объект растровых данных, используя класс Loader.

01
02
03
04
05
06
07
08
09
10
private function onResult(result:Object):void {
    totalResults = result.length;
      
    for(var i:int = 0; i < result.length; i++)
    {
        var ldr:Loader = new Loader();
        ldr.loadBytes(result[i].data);
        ldr.contentLoaderInfo.addEventListener(Event.COMPLETE, bytesComplete);
    }
}

Этот класс ‘Loader’ нуждается в прослушивателе событий, поэтому есть функция ‘bytesComplete’. Эта функция создает объект BitmapData и помещает его в массив ‘photos’. Если длина массива ‘photos’ равна значению переменной ‘totalResults’, создается новый экземпляр Wall3d, который добавляется на сцену.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
        private function bytesComplete(e:Event):void
        {
            photos.push(Bitmap(e.target.content).bitmapData);
          
            if(totalResults == photos.length)
            {
                // now every photo is the array, let show the carousel
                wall3d = new Wall3d(photos);
                this.addChild(wall3d);
            }
        }
  
        private function onFault(fault:Object):void {
            trace(fault);
        }
    }
}

Это будет последний класс ActionScript, который мы создаем для этого урока, и он несколько особенный. Как упоминалось ранее, этот класс покажет трехмерную карусель из всех изображений. Причина, по которой мы делаем это в 3d, состоит в том, чтобы показать, почему было бы неплохо отделить часть обработки данных приложения от части представления. Это также хороший пример для демонстрации библиотеки Away 3D Lite.

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


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

1
2
3
4
5
package com.photobooth
{
    import flash.display.*;
    import flash.events.*;
    import flash.geom.*;

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

1
2
3
4
5
6
7
8
9
import away3dlite.cameras.*;
import away3dlite.containers.*;
import away3dlite.core.base.*;
import away3dlite.events.*;
import away3dlite.materials.*;
import away3dlite.primitives.*;
  
public class Wall3d extends MovieClip
{

Все переменные, которые мы используем в этом классе, связаны с трехмерной средой, которую мы собираемся построить. Первые три являются базовыми объектами, которые нам нужны для построения трехмерной среды; а именно камера, сцена и окно просмотра.

1
2
3
4
//engine variables
private var scene:Scene3D;
private var camera:HoverCamera3D;
private var view:View3D;

Следующие 7 переменных связаны с движением и интерактивностью карусели. Мы обсудим их более подробно позже.

1
2
3
4
5
6
7
8
// movement variables
private var drag:Boolean = false;
private var lastPanAngle:Number;
private var lastTiltAngle:Number;
private var lastMouseX:Number;
private var lastMouseY:Number;
private var speed:Number = 1;
private var currentSpeed:Number = speed;

Прежде чем мы сможем анимировать или щелкнуть что-либо вообще, нам нужно построить карусель. Мы собираемся сделать это с использованием некоторой базовой математики, и по этой причине используются следующие 3 переменные.

1
2
3
4
// circle variables
private var angle:Number = 0;
private var diameter:int = 400;
private var angleOffset:Number = 30;

Последняя переменная является держателем для массива с фотографиями.

1
2
// photos
private var allPhotos:Array;

Ничего нового здесь, сначала мы сохраним массив фотографий в локальной переменной, после чего вызываются некоторые функции инициализации. Функции init делятся на одну для создания фона, одну для создания трехмерного движка и одну для добавления прослушивателей событий. Наконец, вызывается функция для создания фото-карусели.

01
02
03
04
05
06
07
08
09
10
function Wall3d(_allPhotos:Array):void
{
    allPhotos = _allPhotos;
      
    initBackground();
    initEngine();
    initListeners();
                  
    buildPhotoCarousel(allPhotos);
}

Мы обсудим все эти функции, за исключением фоновой функции, более подробно позже.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
private function initBackground():void
{
    var fillType:String = GradientType.LINEAR;
    var colors:Array = [0x3b3b3b, 0x010101];
    var alphas:Array = [1, 1];
    var ratios:Array = [0x00, 0xFF];
    var matr:Matrix = new Matrix();
    matr.createGradientBox(800, 600, (Math.PI/180)*90, 0, 0);
 
    var bgSprite:Sprite = new Sprite();
    bgSprite.graphics.beginGradientFill(fillType, colors, alphas, ratios, matr);
    bgSprite.graphics.endFill();
      
    this.addChild(bgSprite);
}

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


Настройка движка 3D Lite не сильно отличается от настройки других движков 3D. Три основных компонента, сцена, камера и область просмотра инициализируются и добавляются на сцену.

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
private function initEngine():void
{
    scene = new Scene3D();
      
    camera = new HoverCamera3D();
    camera.focus = 50;
    camera.distance = 1000;
    camera.minTiltAngle = 0;
    camera.maxTiltAngle = 90;
      
    camera.panAngle = 45;
    camera.tiltAngle = 20;
    camera.hover(true);
      
    view = new View3D();
    view.scene = scene;
    view.camera = camera;
      
    //hack to get framerate up in cs4
    var background:Sprite = new Sprite();
    background.graphics.lineStyle(1, 0)
    background.graphics.drawRect(-400, -300, 800, 600);
      
    view.addChild(background);
      
    view.x = 400;
    view.y = 300;
      
    this.addChild(view);
}

Для этой настройки мы будем использовать камеру при наведении, поскольку позже будем перемещать камеру. Также обратите внимание на небольшой взлом, чтобы улучшить частоту кадров. Обычно такие трюки должны быть включены в 3d-библиотеку, но так как это еще не сделано, мы оставим это здесь.


Карусель, которую мы собираемся построить, состоит из ряда двухсторонних самолетов. Плоскость — это трехмерный примитив в форме прямоугольника. Функция довольно проста: она циклически перебирает массив фотографий, создает плоскость для каждой фотографии и добавляет их в трехмерную сцену. Каждая плоскость расположена на 20 пикселей дальше, это необходимо для создания спирального эффекта. В противном случае фотографии будут перекрывать друг друга.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
private function buildPhotoCarousel(photos:Array):void
{
    for(var i:int=0; i<photos.length; i++)
    {
        var bitmapMaterial = new BitmapMaterial(photos[i]);
          
        var plane = new Plane();
        plane.z = i*20;
        plane.width = 150;
        plane.height = 200;
        plane.rotationY = 180;
        plane.sortType = MeshSortType.BACK;
        plane.segmentsW = 4;
        plane.segmentsH = 4;
        plane.bothsides = true;
        plane.material = bitmapMaterial;
          
        scene.addChild(plane);
    }
}

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

1
2
3
4
5
6
private function initListeners():void
{
    this.addEventListener(Event.ENTER_FRAME, onEnterFrame);
    this.addEventListener(MouseEvent.MOUSE_DOWN, onMouseDown);
    this.addEventListener(MouseEvent.MOUSE_UP, onMouseUp);
}

Итак, первое, что мы собираемся сделать, это добавить слушателей событий. Первым является старое доброе событие «onEnterFrame», которое вызывает функцию «onEnterFrame». Эта функция обрабатывает все движения и будет первой, которую мы обсудим.

1
2
3
4
5
6
private function onEnterFrame(event:Event):void
{
    if (drag) {
        camera.panAngle = 0.3*(stage.mouseX — lastMouseX) + lastPanAngle;
        camera.tiltAngle = 0.3*(stage.mouseY — lastMouseY) + lastTiltAngle;
    }

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

01
02
03
04
05
06
07
08
09
10
11
12
var i:int = 0;
  
for each (var mesh:Mesh in scene.children) {
    mesh.x = diameter * Math.sin((angle+(i*angleOffset)) * (Math.PI/180));
    mesh.y = diameter * Math.cos((angle+(i*angleOffset)) * (Math.PI/180));
  
    mesh.rotationZ = -(angle + (i*angleOffset));
      
    i++;
}
  
angle = (angle + currentSpeed) % 360;

Далее мы будем использовать теорему Пифагора, чтобы поместить все плоскости в спиральную форму. Для этого мы используем переменные «angle», «angleOffset» и «Diameter». Каждый раз, когда вызывается эта функция, угол увеличивается, поэтому при следующем позиционировании плоскостей они немного поворачиваются. Это создает круговое движение.

1
2
    camera.hover();
}

Наконец, мы скажем камере перемещаться, если необходимо, и окну просмотра для визуализации сцены.


Последнее, что осталось сейчас, это протестировать приложение. Если вы хотите, вы можете настроить переменные, такие как «angleOffset» и «Diameter», чтобы они изменяли внешний вид карусели, но в конечном итоге это должно выглядеть так:



Теперь, когда все готово, скомпилировано и протестировано, пришло время создавать файлы HTML, которые мы собираемся разместить на сервере. Мы собираемся создать 3 html-файла, один индексный файл, файл booth.html, в котором содержится приложение для фотобудки, и третий html-файл, в котором хранится фотостена, которая называется wall.html. Все файлы будут использовать CSS и JavaScript.


Мы используем утилиту javascript ‘swfobject’, чтобы встроить флэш-приложение в booth.html. Существуют различные сценарии и методы для вставки flash в html-файл, и здесь нет особой причины для использования «swfobject». Тем не менее, это хороший сценарий, который можно использовать в различных проектах.

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
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
<!DOCTYPE HTML PUBLIC «-//W3C//DTD HTML 4.01//EN» «http://www.w3.org/TR/html4/strict.dtd»>
<html>
    <head>
        <meta http-equiv=»Content-Type» content=»text/html; charset=iso-8859-1″ />
          
        <link rel=»shortcut icon» href=»./favicon.ico» />
          
        <title>FlashTuts+ PhotoBooth</title>
          
        <script type=»text/javascript» src=»javascript/swfobject.js»></script>
          
        <script type=»text/javascript»>
            params = {
                allowfullscreen: «true»,
                AllowScriptAccess: «always»
            };
              
            swfobject.embedSWF(«PhotoBooth.swf», «flash», «300», «375», «10.0.0», «expressInstall.swf», null, params);
        </script>
        <style type=»text/css»>
            html, body {
                margin: 20px;
                padding: 20px;
                background-color: #242A2D;
                color: #EDE3ED;
                font-family: Helvetica;
            }
              
            #intro
            {
                font-size: 12px;
                letter-spacing: 3px;
                font-weight: 100;
            }
              
            #border
            {
                border: 5px solid #EDE3ED;
                height: 375px;
                width: 300px;
                margin-top: 5px;
                margin-bottom: 10px;
            }
              
            #links
            {
                font-size: 36px;
                letter-spacing: -2px;
                font-weight: 900;
            }
              
            a:link {text-decoration: none;
            a:visited {text-decoration: none;
            a:active {text-decoration: none;
            a:hover {text-decoration: underline;
        </style>
    </head>
    <body>
        <div id=»intro»>
            Take a picture!
        </div>
        <div id=»border»>
            <div id=»flash»>
                <h1>You\’ll need flashplayer 10</h1>
                  
  
  
                    <a href=»http://www.adobe.com/go/getflashplayer»>
                        <img src=»http://www.adobe.com/images/shared/download_buttons/get_flash_player.gif» alt=»Get Adobe Flash player» />
                    </a>
                  
  
  
            </div>
        </div>
        <div id=»links»>
            <a href=»./index.html»>Back</a>
        </div>
    </body>
</html>

Поскольку этот урок посвящен флеш-памяти и PHP, мы не будем вдаваться в подробности. Однако, если вас интересует swfobject и комбинация flash / html, пожалуйста, проверьте Интернет.


Wall.html в основном совпадает с файлом booth.html. Он использует swfobject для встраивания flash-приложения в страницу.

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
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
<html>
    <head>
        <meta http-equiv=»Content-Type» content=»text/html; charset=iso-8859-1″ />
          
        <link rel=»shortcut icon» href=»./favicon.ico» />
          
        <title>FlashTuts+ PhotoWall</title>
          
        <script type=»text/javascript» src=»javascript/swfobject.js»></script>
          
        <script type=»text/javascript»>
            params = {
                allowfullscreen: «true»,
                AllowScriptAccess: «always»
            };
              
            swfobject.embedSWF(«PhotoWall.swf», «myContent», «800», «600», «10.0.0», «expressInstall.swf», null, params);
        </script>
        <style type=»text/css»>
            html, body {
                margin: 20px;
                padding: 20px;
                background-color: #242A2D;
                color: #EDE3ED;
                font-family: Helvetica;
            }
              
            #intro
            {
                font-size: 12px;
                letter-spacing: 3px;
                font-weight: 100;
            }
              
            #border
            {
                border: 5px solid #EDE3ED;
                height: 600px;
                width: 800px;
                margin-top: 5px;
                margin-bottom: 10px;
            }
              
            #links
            {
                font-size: 36px;
                letter-spacing: -2px;
                font-weight: 900;
            }
              
            a:link {text-decoration: none;
            a:visited {text-decoration: none;
            a:active {text-decoration: none;
            a:hover {text-decoration: underline;
        </style>
    </head>
    <body>
        <div id=»intro»>
            Look who\’s there!
        </div>
        <div id=»border»>
            <div id=»myContent»>
                <h1>You\’ll need flashplayer 10</h1>
                  
  
  
                    <a href=»http://www.adobe.com/go/getflashplayer»>
                        <img src=»http://www.adobe.com/images/shared/download_buttons/get_flash_player.gif» alt=»Get Adobe Flash player» />
                    </a>
                  
  
  
            </div>
        </div>
        <div id=»links»>
            <a href=»./index.html»>Back</a>
        </div>
    </body>
</html>

Последний шаг, который мы должны сделать, прежде чем мы сможем протестировать этот проект, — это загрузить все файлы на ваш сервер. Мы обсудили настройку папки нашего проекта на одном из первых шагов этого урока, и теперь вы поймете, почему этот каталог ‘bin’ полезен. Единственное, что вам нужно загрузить — это содержимое папки ‘bin’, не нужно искать файлы или исключать исходные файлы. Опять же, в проекте такого размера это может не быть абсолютно необходимым, но, поверьте мне, если ваши проекты становятся все больше и больше, вы оцените эту настройку.

Хотя это не ракетостроение, есть несколько вещей, которые вы должны иметь в виду. Прежде всего, убедитесь, что все html и php файлы доступны для чтения всем пользователям. Затем проверьте правильность всех путей, как в html, так и в приложениях flash.


Теперь, когда все сделано и на его месте пришло время для всех важных заключительных испытаний. Конечно, мы проделали некоторое тестирование, но простая ошибка в html или PHP все еще может нанести вред всему приложению. Поэтому убедитесь, что вы можете сделать снимок в фотокабине и чтобы он появился на фотостене. Очень полезное приложение для тестирования и отладки удаленных вызовов — «Чарльз». Это позволяет вам просматривать и отлаживать весь трафик между клиентом и сервером, чтобы выяснить, есть ли какие-либо «скрытые» проблемы.



Если все сделано правильно, это должно выглядеть так:



Спасибо за подписку!