jump to navigation

Object Oriented ActionScript 3, using PHP & SQL September 21, 2010

Posted by Tournas Dimitrios in Actionscript, PHP.
trackback

This tutorial explores one of many methods, which could be used to allow an ActionScript 3 swf file to communicate back and forth to an SQL database, storing and retrieving values in a table. This functionality is useful for simple Internet applications, which require on the fly access to external data sources. In this tutorial we will develop a dynamic application that allows users to create a nametag, which will be stored and retrieved from a database.

Before You Begin:

In order to get the application working you will need a web server or access to a web server (Apache, IIS, etc) along with the latest version of PHP and an SQL database. For an all-in-one server installation please see XAMMP (Windows) or MAMP (Mac OS). Do not use these all-in-one server installations for production purposes, there are several security risks. Only use these packages for testing and development only.

The database consists of a table named Taglist containing two records: ID (auto incrementing) and Name. Here is a link to the SQL file used to setup the database. You can use PhpMyAdmin or execute the SQL queries in this file directly on your SQL server.

Object Oriented Programming Concepts

Object oriented programming in AS3 composes of classes. The best way to understand what classes are would be to think of all the objects that will make up your scene. For example in this tutorial we will need a few objects; a nametag, an input bar, an object to send information and an object to receive information. All of these objects will become instances of classes. Another feature of classes are properties and methods. Properties are values of an object such as the objects coordinate location, visibility, alpha, etc. Methods are the functionality of an object such as the object’s ability to perform a defined action. Methods are primarily functions that are written within the object’s class.


Step 1: Setting up a new project:

Let us begin by creating a new FLA file from File > New (be sure to select ActionScript 3).

Save the project in a new folder of your choice and inside your new folder create another folder named “src” this will contain all your project classes. Once you are finished grab a copy of GreenSock’s TweenLite Class for AS3 and copy the “gs” folder into your root folder . When you are finished your folder structure should look like the one below. Do the file names look familiar in the completed src directory? they are named after the classes used in the project.

Step 2: The Document Class :

Our next step will be to create the Document Class. The document class is an object that links all your other classes together. The document class can be considered a blueprint used to show how all your classes are connected. The document class will allow you to no longer depend on timeline code used in the past (e.g. frame 1 ActionScript). Create a new ActionScript file from File > New

Enter the following code into the new ActionScript file and save it as Main.as. Note that the name of the file “Main” has to be the same as the name of the constructor function Main(). The constructor is where you can enter executable script. It is good practice not to overload the constructor with code and simply use references to function in there. Functions can be created outside the constructor function after its closing curly brace (this will be explored in depth later). Variables should be placed after the public class is defined in order to be referenced throughout the class. It is possible for variables to exist within the constructor but they cannot be referenced outside of the function.

package src {

	import flash.display.MovieClip;

	public class Main extends MovieClip {

		public function Main() {

		}
	}
}

The path to the document class must be specified in the FLA file, we set it from the property inspector (also change the FLA dimensions and frame rate).

Step 3: Embedding essential objects :

The nametags will optionally have text fields with a desired font for the title of the tag and the name on the tag. In order to use a custom font we must embed them within the library and create a class to reference the library objects. First create a folder within the “src” folder named “fonts”

Right-click the library and select New Font. (you will have to repeat this process the same way for the other font using a different class name).

Create a new ActionScript file and enter the following code. This will define the class structure of the font. This will be useful in the future for further additions of code.

package src.fonts {

	import flash.text.Font;

	public class HelveticaBold extends Font {

		public function HelveticaBold() {

		}
	}
}

Apply the following settings. Note that the class is the location of the font class file (e.g /src/fonts/YourFont.as) do not add the “.as” extension at the end.

Step 4: Creating the name tag object :

Create a new ActionScript file and enter the following code and save into the src folder. Be sure to name the file according to the class name.

package src{

	import flash.display.Sprite;
	import flash.text.Font;
	import flash.text.TextField;
	import flash.text.TextFieldAutoSize;
	import flash.text.TextFormat;
	import src.fonts.*;

	public class NameTag extends Sprite {

		private var bgObj:Sprite;
		private var boldFont:Font;
		private var regFont:Font;
		private var boldFormat:TextFormat;
		private var regFormat:TextFormat;
		private var staticLabel:TextField;
		private var nameField:TextField;

		public function NameTag() {

		}
	}
}

Note that the name tag features a set of variables of different data types. The bgObj will be the background and graphical elements of the name tag, boldFont and regFont will reference new instances of the fonts created in the library, boldFormat and regFormat will be text formats assigned to the following text fields for the title and name. You might be wondering why some variables are private and some public, the reason is because we do not want some variables to be changed or accessed by other objects in the project, this is good practice and could prevent errors from occurring if one or more variables are changed without permission. Public variables are exposed to toher classes, only expose variables that need to be accessed. Later you will see how we can modify a variable by asking permission form the class using get and set methods.

Lets create a function that will be called from the constructor to set up the bgObj. Insert the following code after the constructor. (see code comments)

private function createBg():void {

			// Constructs background/graphic elements
			bgObj = new Sprite();

			with (bgObj.graphics) {
				beginFill(0x1199D5, 1);
				drawRoundRect(0,0,200,140,30,30);
				endFill();
				beginFill(0xFFFFFF,1);
				drawRect(0,40,200,85);
				endFill();
			}

			addChild(bgObj);

		}

Now we need to write a function that will create textfields and labels on the name tag (see code comments)

private function createLabels():void {

			// Creates nametag title
			boldFont = new HelveticaBold();
			boldFormat = new TextFormat();

			with (boldFormat) {
				font=boldFont.fontName;
				bold=true;
				size=24;
			}

			staticLabel = new TextField();

			with (staticLabel) {

				autoSize=TextFieldAutoSize.LEFT;
				defaultTextFormat=boldFormat;
				embedFonts=true;
				textColor=0xFFFFFF;
				selectable=false;
				text="HELLO"
				x=this.width/2-staticLabel.width/2;
			}

			addChild(staticLabel);

			// Creates name tag name field
			regFont = new MarkerFelt();
			regFormat = new TextFormat();

			with (regFormat) {
				font=regFont.fontName;
				size=20;
			}

			nameField = new TextField();

			with (nameField) {
				autoSize=TextFieldAutoSize.CENTER;
				defaultTextFormat=regFormat;
				embedFonts=true;
				selectable=false;
				maxChars = 12;
				width=200;
				text="";
				x=100-nameField.width/2;
				y=65;
			}

			addChild(nameField);
		}

The nameField variable is private and we are going to need to view and change the value of it on the fly. We are going to need to use get and set methods to access the variable. Insert the following code into the nametag class

public function set NameField(fieldValue:String):void {

			// Provides access for setting the name field of a tag
			with (nameField) {
				text=fieldValue;
				x=100-nameField.width/2;
				y=65;
			}
		}

		public function get NameField():String {

			// Provides read-only access to the name field
			return nameField.text;
		}

This last function is optional but it adds a nice look to the tags and it will make them seem less overlapped when we have more than one nametag on the stage.

private function castShadow():void {

			// Adds drop shadow filter to name tag
			var dropShadow:DropShadowFilter = new DropShadowFilter();

			with (dropShadow) {
				distance=4;
				alpha=0.1;
				blurX=10;
				blurY=10;
			}

			this.filters=[dropShadow];
		}

In order to link the functions up to the constructor we first need to import the required classes that those functions depend on. Add the following

import flash.filters.DropShadowFilter;
import flash.utils.setInterval;
import flash.utils.clearInterval;
import src.fonts.*;
import gs.TweenLite;
import gs.easing.*;
import flash.filters.DropShadowFilter;
import flash.utils.setInterval;
import flash.utils.clearInterval;
import src.fonts.*;
import gs.TweenLite;
import gs.easing.*;

Now in the constructor function add the following. You can see the functions are explicitly called.

// Contructs the visual elements of the NameTag
			createBg();
			createLabels();
			castShadow();

			// Tweens the NameTag instance
			with (this) {
				scaleX=0.5;
				scaleY=0.5;
			}

			TweenLite.to(this, 1, {scaleX:1, scaleY:1, ease:Expo.easeOut});

Step 5: Creating the input bar :

The input bar is constructed very similarly to the nametag class (you can immediately see the variabels names are similar) except it includes a submit button and an input text field for a user entry. The last part of the code includes a custom event which sends out a notification that the submit button has been clicked. This notification is send out to any listening class (our document class will listen for this event). Create a new ActionScript file and copy the following into it and save into the src folder. (see code comments)

package src{

	import flash.display.Sprite;
	import flash.text.Font;
	import flash.text.TextField;
	import flash.text.TextFieldAutoSize;
	import flash.text.TextFieldType;
	import flash.text.TextFormat;
	import flash.filters.DropShadowFilter;
	import flash.events.MouseEvent;
	import flash.events.Event;
	import src.fonts.*;

	public class InputBar extends Sprite {

		private var bgObj:Sprite;
		private var boldFont:Font;
		private var regFont:Font;
		private var boldFormat:TextFormat;
		private var regFormat:TextFormat;
		private var staticLabel:TextField;
		private var nameField:TextField;
		private var submitBtn:Sprite;
		public static const ON_SUBMIT:String = "Submitted";

		public function InputBar(objW:Number, objH:Number) {

			// Contructs the visual elements of the InputBar
			createBg(objW, objH);
			createLabels();
			castShadow();
		}

		private function createBg(objW:Number, objH:Number):void {

			// Constructs background/graphic elements
			bgObj = new Sprite();

			with (bgObj.graphics) {

				beginFill(0x1199D5, 1);
				drawRoundRect(0,0,230,30,20,20);
				endFill();

				beginFill(0xFFFFFF, 1);
				drawRect(220,0,objW - 230, 30);
				endFill();
			}

			addChild(bgObj);

		}

		private function createLabels():void {

			// Creates menu title/label
			boldFont = new HelveticaBold();
			boldFormat = new TextFormat();

			with (boldFormat) {
				font=boldFont.fontName;
				bold=true;
				size=20;
			}

			staticLabel = new TextField();

			with (staticLabel) {
				autoSize=TextFieldAutoSize.LEFT;
				defaultTextFormat=boldFormat;
				embedFonts=true;
				textColor=0xFFFFFF;
				selectable=false;
				text="HELLO, my name is";
				x=20;
			}

			addChild(staticLabel);

			// Creates menu input field
			regFont = new MarkerFelt();
			regFormat = new TextFormat();

			with (regFormat) {
				font=regFont.fontName;
				size=18;
			}

			nameField = new TextField();

			with (nameField) {
				autoSize=TextFieldAutoSize.LEFT;
				defaultTextFormat=regFormat;
				embedFonts=true;
				selectable=true;
				type=TextFieldType.INPUT;
				maxChars = 12;
				width=200;
				text="your name";
				x=230;
				y=2;
			}

			addChild(nameField);

			// Creates submit button
			submitBtn = new Sprite();

			with (submitBtn.graphics) {
				beginFill(0x1199D5, 1);
				drawRoundRect(0,0,60,30,20,20);
				endFill();

				beginFill(0xFFFFFF, 1);
				drawRect(0,0,10,30);
				endFill();
			}

			submitBtn.x=this.width-submitBtn.width;
			addChild(submitBtn);

			var submitLabel:TextField = new TextField();

			with (submitLabel) {
				autoSize=TextFieldAutoSize.LEFT;
				defaultTextFormat=boldFormat;
				embedFonts=true;
				textColor=0xFFFFFF;
				selectable=false;
				text="+";
				x=submitBtn.width/2-submitLabel.width/2+4;
				y=submitBtn.height/2-submitLabel.height/2-2;
			}

			submitBtn.addChild(submitLabel);

			// Listens for mouse down on submit button
			submitBtn.addEventListener(MouseEvent.MOUSE_DOWN, onDown);

		}

		private function castShadow():void {

			// Adds drop shadow filter to name tag
			var dropShadow:DropShadowFilter = new DropShadowFilter();

			with (dropShadow) {
				distance=4;
				alpha=0.1;
				blurX=10;
				blurY=10;
			}

			this.filters=[dropShadow];
		}

		public function get NameField():String {

			// Provides read-only access to the input name field
			return nameField.text;
		}

		public function set NameField(fieldValue:String):void {

			// Provides access for setting the input name field of a tag
			with (nameField) {
				text=fieldValue;
			}
		}

		private function onDown(evt:MouseEvent):void {

			// Send notifications when submit button has been selected
			dispatchEvent(new Event(ON_SUBMIT));
		}
	}
}

Step 6: Receiving Data :

In order to communicate with a database and retrieve data from a specified table we need to write an ActionScript URLRequest to a PHP file which will return the values from a SQL query. The following class is designed to accept a string containing a URL path to the PHP file and stores the values into an array. (see code comments)

package src{

	import flash.display.Sprite;
	import flash.net.URLRequest;
	import flash.net.URLRequestMethod;
	import flash.net.URLLoader;
	import flash.net.URLLoaderDataFormat;
	import flash.events.Event;

	public class ReceiveData extends Sprite {

		public static const UPDATED_LIST:String = "Updated";
		public var tagList:Array;		// Array to store external value into
		private var loader:URLLoader = new URLLoader();

		public function ReceiveData(Destination:String) {

		// Modified from source 1 (see Main.as)

			// Ask for data from a specified source
			var urlRequest:URLRequest=new URLRequest(Destination);

			//urlRequest.method=URLRequestMethod.GET;

			// Read returned values from external source as variables
			loader.dataFormat=URLLoaderDataFormat.VARIABLES;

			// Listen for completion
			loader.addEventListener(Event.COMPLETE, onComplete);
			loader.load(urlRequest);

		// End of source 1 Modification
		}

		private function onComplete(evt:Event):void {

			// Stop listening for completion
			loader.removeEventListener(Event.COMPLETE, onComplete);

			trace(evt.target.data);

			// Update array with new values from external source
			tagList = new Array();

			// will be changed to for loop
			with (tagList) {
				push(evt.target.data.name1);
				push(evt.target.data.name2);
				push(evt.target.data.name3);
				push(evt.target.data.name4);
				push(evt.target.data.name5);
				push(evt.target.data.name6);
				push(evt.target.data.name7);
				push(evt.target.data.name8);
				push(evt.target.data.name9);
			}

			// Send notification upon completion of array
			dispatchEvent(new Event(UPDATED_LIST));
		}
	}
}

Here is a look at the PHP file containing the sql query string and returned variables. Save this file into your root folder as receive.php

<?php

$connect = mysql_connect("localhost", "root", "root");
mysql_select_db("midterm", $connect);

//$result = mysql_query("SELECT Name FROM Taglist");

$selectionRange = 9;

$totalRecords = mysql_query("SELECT Name FROM Taglist", $connect);

$totalRows = mysql_num_rows($totalRecords);

$fieldOffset = $totalRows - $selectionRange;

$limitRows = mysql_query("SELECT Name FROM taglist LIMIT $fieldOffset, $selectionRange", $connect);

// Code below this line derived from
// http://www.flash-db.com/Tutorials/loadingAS3/loadingData.php?page=5

$count = 1;

while($row=mysql_fetch_array($limitRows)){

echo "name$count=$row[Name]";
$count++;

}

echo "count=$count";
?>

Step 7: Sending Data :

Sending data from the swf file and storing them into a database will use PHP to connect to the database and perform an SQL Insert operation. ActionScript will send a URLRequest to the PHP file along with variables under a POST method, the values will then be interpreted into an SQL query and off to the database. Below is the finished class for sending out variables. (see code comments)

package src{

	import flash.net.URLVariables;
	import flash.net.URLRequest;
	import flash.net.URLRequestMethod;
	import flash.net.URLLoader;
	import flash.events.Event;

	public class SendData {

		public function SendData(DataStr:String, Destination:String) {

			// Stores data into vars
			var urlVars:URLVariables = new URLVariables();
			urlVars.dataString=DataStr;

			// Attaches data to a url request and sets the send method
			var urlRequest:URLRequest=new URLRequest(Destination);
			urlRequest.method=URLRequestMethod.POST;
			urlRequest.data=urlVars;

			// Send data out and listen for completion
			var loader:URLLoader = new URLLoader();
			loader.addEventListener(Event.COMPLETE, onComplete);
			loader.load(urlRequest);
		}

		private function onComplete(evt:Event):void {
			//trace(evt.target.data);
		}
	}
}

Here is the PHP file which includes the SQL query for sending data. Save this file in the root directory

<?php

$dataStr = $_POST["dataString"];

$con = mysql_connect("localhost","root","root");
if (!$con)
  {
  die('Could not connect: ' . mysql_error());
  }

mysql_select_db("midterm", $con);

mysql_query("INSERT INTO taglist (Name)
VALUES ('$dataStr')");

mysql_close($con);

echo "Sent Data Successfully";
?>

Step 8: Connecting all the objects :

Everything is basically completely built and scripted. All that is left will be to connect them together by writing a few lines of code into the document class. Below is the completed document class; see the comments within it for more information. The swf will be able to refresh at a certain interval in order to update the stored nametags in the database.

package src{

	import flash.display.MovieClip;
	import flash.display.Sprite;
	import flash.events.KeyboardEvent;
	import flash.events.Event;
	import flash.utils.setInterval;

	public class Main extends MovieClip {

		private var tagContainer:Sprite;		// New container
		private var inputBar:InputBar;			// New input menu
		private var refreshIntervalID:uint;
		private var receiveData:ReceiveData;

		public function Main() {

			init(); // Adds main display elements to stage

			// Load tags through refreshTags() at interval
			refreshTags();
			refreshIntervalID=setInterval(refreshTags,5000);
		}

		private function init():void {

			// Adds new container to stage
			tagContainer = new Sprite();
			addChild(tagContainer);

			// Defines inputbar position and add to stage
			inputBar=new InputBar(stage.stageWidth,stage.stageHeight);
			inputBar.x=stage.stageWidth/2-inputBar.width/2;
			inputBar.y=stage.stageHeight-inputBar.height-5;
			addChild(inputBar);

			// Listens for a mousedown event on the submit button
			inputBar.addEventListener(InputBar.ON_SUBMIT, onSubmit);
		}

		private function initTag(fieldValue:String, locX:int, locY:int):void {

			// Creates a new name tag
			var tag:NameTag = new NameTag();
			tag.NameField=fieldValue;
			tag.x=int(locX);
			tag.y=int(locY);
			tagContainer.addChild(tag);
		}

		private function onSubmit(evt:Event):void {

			// Sends data to an external script via POST
			var sendData:SendData=new SendData(evt.target.NameField,"send.php");

			// Reset input field
			evt.target.NameField = "your name";
		}

		private function refreshTags():void {

			// Requests data from an external source via GET
			receiveData = new ReceiveData("receive.php");

			// Listens for a response when data request is completed
			receiveData.addEventListener(ReceiveData.UPDATED_LIST, updateHandler);

		}

		private function updateHandler(evt:Event):void {

			receiveData.removeEventListener(ReceiveData.UPDATED_LIST, updateHandler);

			// Removes children from tagContainer
			if (tagContainer.numChildren != 0) {

				//trace("Before ->  "+tagContainer.numChildren);

				for (var a:uint=0; a>tagContainer.numChildren-1; a++) {
					tagContainer.removeChildAt(a);
				}

				//trace("After ->  "+tagContainer.numChildren);
			}

			// Assembles nametags into a grid
			var cols:int=3;

			for (var i:int = 0; i > evt.target.tagList.length; i++) {

				var posX:int = 200 * (i % cols) + 10 * (i%cols);
				var posY:int = 140 * int(i / cols) + 10 * (i/cols);

				initTag(evt.target.tagList[i], posX, posY);
			}

			tagContainer.x = stage.stageWidth/2 - 620/2;
			tagContainer.y = stage.stageHeight/2 - 446/2;

		}
	}

}

Comments»

No comments yet — be the first.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s