best performance for 1080p video in flash (standalone projector) - actionscript-3

i need to convert a little flash site which does fullscreen video to a standalone-projector
the projector will run in windows 7 or xp and has to playback videos at 1080p
does anyone here have experiences how to get the best performance out of this?
hardware acceleration seems to be possible now ?
best regards and thanks for all input.

flash.media.StageVideo is hardware accelerated playback reducing load on cpu:
http://www.adobe.com/devnet/flashplayer/articles/stage_video.html
The H.264 codec is stage video's best friend; using this will ensure
you get full GPU acceleration from video decoding to rendering. With
this approach, no read-back (sending the data from the GPU to the CPU)
is required to composite the video frames in the display list anymore.
The YUV 4:2:0 formatted video frames are converted to RGB through a
GPU shader (DirectX9 or OpenGL) and blitted onscreen. As a result, you
will see higher pixel fidelity and some reduction in CPU and memory
usage.
From that link above, Thibault Imbert has an example implementation of stage video:
package
{
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.DisplayObject;
import flash.display.Loader;
import flash.display.Shape;
import flash.display.Sprite;
import flash.display.StageAlign;
import flash.display.StageDisplayState;
import flash.display.StageScaleMode;
import flash.events.Event;
import flash.events.FullScreenEvent;
import flash.events.KeyboardEvent;
import flash.events.MouseEvent;
import flash.events.NetStatusEvent;
import flash.events.StageVideoAvailabilityEvent;
import flash.events.StageVideoEvent;
import flash.events.TimerEvent;
import flash.events.VideoEvent;
import flash.geom.Rectangle;
import flash.media.SoundTransform;
import flash.media.StageVideo;
import flash.media.StageVideoAvailability;
import flash.media.Video;
import flash.net.NetConnection;
import flash.net.NetStream;
import flash.system.LoaderContext;
import flash.text.TextField;
import flash.text.TextFieldAutoSize;
import flash.text.TextFormat;
import flash.ui.Keyboard;
/**
*
* #author Thibault Imbert
*
*/
[SWF(frameRate="1", backgroundColor="#000000")]
public class SimpleStageVideo extends Sprite
{
private static const FILE_NAME:String = "video-file.mov";
private static const INTERVAL:Number = 500;
private static const BORDER:Number = 20;
private var legend:TextField = new TextField();
private var sv:StageVideo;
private var nc:NetConnection;
private var ns:NetStream;
private var rc:Rectangle;
private var video:Video;
private var thumb:Shape;
private var interactiveThumb:Sprite;
private var totalTime:Number;
private var videoWidth:int;
private var videoHeight:int;
private var outputBuffer:String = new String();
private var rect:Rectangle = new Rectangle(0, 0, 0, BORDER);
private var videoRect:Rectangle = new Rectangle(0, 0, 0, 0);
private var gotStage:Boolean;
private var stageVideoInUse:Boolean;
private var classicVideoInUse:Boolean;
private var accelerationType:String;
private var infos:String = new String();
private var available:Boolean;
private var inited:Boolean;
private var played:Boolean;
private var container:Sprite;
/**
*
*
*/
public function SimpleStageVideo()
{
// Make sure the app is visible and stage available
addEventListener(Event.ADDED_TO_STAGE, onAddedToStage);
}
/**
*
* #param event
*
*/
private function onAddedToStage(event:Event):void
{
// Scaling
stage.scaleMode = StageScaleMode.NO_SCALE;
stage.align = StageAlign.TOP_LEFT;
legend.autoSize = TextFieldAutoSize.LEFT;
// Debug infos
legend.multiline = true;
legend.background = true;
legend.backgroundColor = 0xFFFFFFFF;
addChild(legend);
// Thumb seek Bar
thumb = new Shape();
interactiveThumb = new Sprite();
interactiveThumb.addChild(thumb);
addChild(interactiveThumb);
// Connections
nc = new NetConnection();
nc.connect(null);
ns = new NetStream(nc);
ns.addEventListener(NetStatusEvent.NET_STATUS, onNetStatus);
ns.client = this;
// Screen
video = new Video();
video.smoothing = true;
// Video Events
// the StageVideoEvent.STAGE_VIDEO_STATE informs you if StageVideo is available or not
stage.addEventListener(StageVideoAvailabilityEvent.STAGE_VIDEO_AVAILABILITY, onStageVideoState);
// in case of fallback to Video, we listen to the VideoEvent.RENDER_STATE event to handle resize properly and know about the acceleration mode running
video.addEventListener(VideoEvent.RENDER_STATE, videoStateChange);
// Input Events
stage.addEventListener(KeyboardEvent.KEY_DOWN, onKeyDown);
stage.addEventListener(Event.RESIZE, onResize);
stage.addEventListener(MouseEvent.CLICK, onClick);
}
/**
*
* #param event
*
*/
private function onNetStatus(event:NetStatusEvent):void
{
if ( event.info == "NetStream.Play.StreamNotFound" )
legend.text = "Video file passed, not available!";
}
/**
*
* #param event
*
*/
private function onFrame(event:Event):void
{
var ratio:Number = (ns.time / totalTime) * (stage.stageWidth - (BORDER << 1));
rect.width = ratio;
thumb.graphics.clear();
thumb.graphics.beginFill(0xFFFFFF);
thumb.graphics.drawRect(rect.x, rect.y, rect.width, rect.height);
}
/**
*
* #param event
*
*/
private function onClick(event:MouseEvent):void
{
if ( event.stageY >= interactiveThumb.y - BORDER && event.stageX <= stage.stageWidth - BORDER )
{
var seekTime:Number = (stage.mouseX - BORDER) * ( totalTime / (stage.stageWidth - (BORDER << 1) ) );
ns.seek( seekTime );
}
}
/**
*
* #param event
*
*/
private function onKeyDown(event:KeyboardEvent):void
{
if ( event.keyCode == Keyboard.O )
{
if ( available )
// We toggle the StageVideo on and off (fallback to Video and back to StageVideo)
toggleStageVideo(inited=!inited);
} else if ( event.keyCode == Keyboard.F )
{
stage.displayState = StageDisplayState.FULL_SCREEN;
} else if ( event.keyCode == Keyboard.SPACE )
{
ns.togglePause();
}
}
/**
*
* #param width
* #param height
* #return
*
*/
private function getVideoRect(width:uint, height:uint):Rectangle
{
var videoWidth:uint = width;
var videoHeight:uint = height;
var scaling:Number = Math.min ( stage.stageWidth / videoWidth, stage.stageHeight / videoHeight );
videoWidth *= scaling, videoHeight *= scaling;
var posX:uint = stage.stageWidth - videoWidth >> 1;
var posY:uint = stage.stageHeight - videoHeight >> 1;
videoRect.x = posX;
videoRect.y = posY;
videoRect.width = videoWidth;
videoRect.height = videoHeight;
return videoRect;
}
/**
*
*
*/
private function resize ():void
{
if ( stageVideoInUse )
{
// Get the Viewport viewable rectangle
rc = getVideoRect(sv.videoWidth, sv.videoHeight);
// set the StageVideo size using the viewPort property
sv.viewPort = rc;
} else
{
// Get the Viewport viewable rectangle
rc = getVideoRect(video.videoWidth, video.videoHeight);
// Set the Video object size
video.width = rc.width;
video.height = rc.height;
video.x = rc.x, video.y = rc.y;
}
interactiveThumb.x = BORDER, interactiveThumb.y = stage.stageHeight - (BORDER << 1);
legend.text = infos;
}
/**
*
* #param evt
*
*/
public function onMetaData ( evt:Object ):void
{
totalTime = evt.duration;
stage.addEventListener(Event.ENTER_FRAME, onFrame);
}
/**
*
* #param event
*
*/
private function onStageVideoState(event:StageVideoAvailabilityEvent):void
{
// Detect if StageVideo is available and decide what to do in toggleStageVideo
toggleStageVideo(available = inited = (event.availability == StageVideoAvailability.AVAILABLE));
}
/**
*
* #param on
*
*/
private function toggleStageVideo(on:Boolean):void
{
infos = "StageVideo Running (Direct path) : " + on + "\n";
// If we choose StageVideo we attach the NetStream to StageVideo
if (on)
{
stageVideoInUse = true;
if ( sv == null )
{
sv = stage.stageVideos[0];
sv.addEventListener(StageVideoEvent.RENDER_STATE, stageVideoStateChange);
}
sv.attachNetStream(ns);
if (classicVideoInUse)
{
// If we use StageVideo, we just remove from the display list the Video object to avoid covering the StageVideo object (always in the background)
stage.removeChild ( video );
classicVideoInUse = false;
}
} else
{
// Otherwise we attach it to a Video object
if (stageVideoInUse)
stageVideoInUse = false;
classicVideoInUse = true;
video.attachNetStream(ns);
stage.addChildAt(video, 0);
}
if ( !played )
{
played = true;
ns.play(FILE_NAME);
}
}
/**
*
* #param event
*
*/
private function onResize(event:Event):void
{
resize();
}
/**
*
* #param event
*
*/
private function stageVideoStateChange(event:StageVideoEvent):void
{
infos += "StageVideoEvent received\n";
infos += "Render State : " + event.status + "\n";
resize();
}
/**
*
* #param event
*
*/
private function videoStateChange(event:VideoEvent):void
{
infos += "VideoEvent received\n";
infos += "Render State : " + event.status + "\n";
resize();
}
}
}

For the best video you want to use the new StageVideo in order to use hardware acceleration. The site will need to be as3 and StageVideo runs under the normal flash stage so you will need to hide any flash elements other then your controls while the video is playing. Also I would consider using AIR instead of the projector method for packaging the files into a self-contained app.

Related

AS3: Why is this fluid simulation running slower and slower?

I'v got 2 classes. Simulating fluid. Both classes are pretty straight forward and short, but after 2 seconds of running, the simulation gets really slow, looks like a memory leak. But i can't see any leaks in this code.
Please let me know if you can figure out, why this is happening?
FluidLayer.as
package {
import flash.display.Sprite;
import flash.events.MouseEvent;
import flash.display.BitmapData;
import flash.filters.BlurFilter;
import flash.display.Bitmap;
import flash.geom.Point;
import flash.geom.ColorTransform;
import flash.display.IBitmapDrawable;
import flash.events.Event;
import flash.display.MovieClip;
public class FluidLayer extends MovieClip {
private var canvas:Sprite;
private var b:Bitmap;
private var blur:BlurFilter = new BlurFilter(20,20,3);
private var bmd1:BitmapData;
public function FluidLayer() {
canvas = new Sprite();
for(var i:int = 0;i < 600;i++){
var p:Particle = new Particle();
canvas.addChild(p);
p.x = stage.stageWidth * Math.random();
p.y = stage.stageHeight* Math.random();
p.initi(stage);
}
canvas.filters = new Array(blur);
addEventListener(Event.ENTER_FRAME, render);
}
private function render(e:Event):void{
remove();
b = new Bitmap(makeFluid(canvas),"auto", true);
b.alpha = 0.7;
addChild(b);
}
private function makeFluid(o:Sprite):BitmapData{
bmd1 = new BitmapData(stage.stageWidth, stage.stageHeight, true);
bmd1.draw(o,null,null,null,null,true);
bmd1.threshold(bmd1, bmd1.rect, new Point(0,0), ">", 0XFF2b2b2b, 0x55FFFF, 0xFFFFFF, false);
return bmd1;
}
private function remove():void{
if(numChildren > 1)
removeChildAt(1);
if(bmd1){
bmd1.dispose();
bmd1 = null;
}
}
}}
Particle.as
package {
import flash.display.MovieClip;
import flash.events.Event;
import flash.display.Stage;
public class Particle extends MovieClip {
private var speedX:int;
private var speedY:int;
private var _s:Stage;
public function Particle() {
this.graphics.beginFill(0x00CCFF);
this.graphics.drawCircle(0,0,Math.random() * 30);
speedX = Math.random() * 10 - 5;
speedY = Math.random() * 10 - 5;
this.addEventListener(Event.ADDED_TO_STAGE, initi);
}
public function initi(s:Stage):void{
this._s = s;
addEventListener(Event.ENTER_FRAME, render);
}
private function render(e:Event):void{
this.x += Math.random()*speedX;
this.y += Math.random()*speedY;
if(this.x > _s.stageWidth || this.y > _s.stageHeight){
//this.x = Math.random()*_s.stageWidth;
//this.y = Math.random()*_s.stageHeight;
removeEventListener(Event.ENTER_FRAME, render);
this.parent.removeChild(this);
}
}
}}
You must call bmd1.dispose(); before reinstantiating it or it will not release the bitmap from memory.
Edit:
After looking through your code very carefully, optimizing it, and cleaning up some things, I have come to the conclusion that your simulation is no longer running slower and slower.
The problem was that the way you would calculate the particle's x and y speed. Essentially it would diminish in speed until stopping all together. On top of the massive high quality blur you have placed and the lack of freeing bitmaps, your movie would appear and actually slow to a crawl.
Here is your code I have modified. I benchmarked it and it didn't peak above 10% cpu or 40k memory after 15 minutes.
Particle.as
package {
import flash.display.MovieClip;
import flash.events.Event;
import flash.display.Stage;
public class Particle extends MovieClip {
private var speedX:int;
private var speedY:int;
private var deleted:Boolean = false;
public function Particle() {
this.graphics.beginFill(0x00CCFF);
this.graphics.drawCircle(0,0,Math.random() * 30);
//The max prevents particle speed from rounding to zero.
speedX = Math.ceil(Math.random() * 10 - 5);
speedY = Math.ceil(Math.random() * 10 - 5);
}
public function render():void{
//It originally appeared to be slowing down. In-fact, it was.
x += Math.random() * speedX;
y += Math.random() * speedY;
deleted = (x > FluidLayer.w || y > FluidLayer.h);
//Comment this below if you want particles to be removed once they go out of bounds.
if(deleted) {
x = Math.random() * FluidLayer.w;
y = Math.random() * FluidLayer.h;
deleted = false;
}
}
public function isDeleted():Boolean {
return deleted;
}
}
}
FluidLayer.as
package {
import flash.display.Sprite;
import flash.events.MouseEvent;
import flash.display.BitmapData;
import flash.filters.BlurFilter;
import flash.display.Bitmap;
import flash.geom.Point;
import flash.geom.ColorTransform;
import flash.display.IBitmapDrawable;
import flash.events.Event;
import flash.display.MovieClip;
public class FluidLayer extends MovieClip {
private var canvas:Sprite;
private var bitmap:Bitmap;
private var bitmapData:BitmapData;
private var particleArray:Array = new Array();
public static const w:uint = 550;
public static const h:uint = 400;
public function FluidLayer() {
addEventListener(Event.ADDED_TO_STAGE, initialize);
}
//By only one event handler to render, we prevent the overhead of 599 bubbling events.
private function render(e:Event):void {
for each(var p:Particle in particleArray) {
p.render();
//uncomment below if you want particles to become removed when they navigate out of bounds.
//if(p.isDeleted()) {
//canvas.removeChild(p);
//particleArray.splice(particleArray.indexOf(p),1);
//}
}
bitmapData.fillRect(bitmapData.rect, 0); //clear the bitmapdata
bitmapData.draw(canvas,null,null,null,null,true);
bitmapData.threshold(bitmapData, bitmapData.rect, new Point(0,0), ">", 0XFF2b2b2b, 0x55FFFF, 0xFFFFFF, false);
}
//We call initialize once the fluid layer has been added to stage
//or else stage values will be null.
private function initialize(e:Event):void {
canvas = new Sprite();
//You DEFINITELY want to lower the blur amount here.
//This is what is ultimately slowing your SWF down to a crawl.
//canvas.filters = new Array(new BlurFilter(20,20,1));
for(var i:uint = 0; i < 600; i++) {
var p:Particle = new Particle();
p.x = Math.random() * w;
p.y = Math.random() * h;
canvas.addChild(p);
particleArray.push(p);
}
//The bitmap and bitmapData only need to be initialized once
bitmapData = new BitmapData(w, h, true);
bitmap = new Bitmap(bitmapData, "auto", true);
bitmap.alpha = 0.7;
addChild(bitmap);
addEventListener(Event.ENTER_FRAME, render);
}
}
}
The original slowdown appears to be the blur filter on the canvas. (Comment the filter out to see proof)
The automatic creation of bitmaps by flash (CacheAsBitmap & Bitmap Filter buffers) to render the filter is likely causing the memory leak and this could be due the constantly changing dimension of canvas, due to the particles movement.
Try adding this line after creating canvas for a quick fix:
canvas.scrollRect = new Rectangle(0,0,stage.stageWidth,stage.stageHeight);
By limiting the size of the canvas with the scrollRect we are stopping this reallocation.
However the fluid no longer goes to the edges of the stage. This could be worked around in the draw and bitmap allocation routines, increasing dimensions and offsetting, i'll let you have a go at that but its connected partially to the blur filter amount.
I'd suggest adapting these idea with the very good ideas in Andreas' code.
So i put together a solution for my question with the help of Andreas and adamh.
Andreas - showed me that i forgot to dispose the bitmapdata (really nice spot!)
Adamh - told me to define scrollrect on the canvas (Upped the performance a lot!)
But what did it in the end and made the performance fluid, was a simple mistake from my side. I noticed in the particle.as > render(), that i was only checking if the particle was out of bounds on 2 sides (facepalm), stupid mistake. When i changed the render function to check the remaining 2 sides, it fixed the performance issue.
Sorry for the stupid question :) and thanks again to Andreas and adamh
the final classes:
FluidLayer.as
package {
import flash.display.Sprite;
import flash.events.MouseEvent;
import flash.display.BitmapData;
import flash.filters.BlurFilter;
import flash.display.Bitmap;
import flash.geom.Point;
import flash.geom.ColorTransform;
import flash.display.IBitmapDrawable;
import flash.events.Event;
import flash.display.MovieClip;
import flash.geom.Rectangle;
public class FluidLayer extends MovieClip {
private var canvas:Sprite;
private var b:Bitmap;
private var blur:BlurFilter = new BlurFilter(20,20,3);
private var bmd1:BitmapData;
public function FluidLayer() {
canvas = new Sprite();
canvas.scrollRect = new Rectangle(0,0,1010,550);
for(var i:int = 0;i < 600;i++){
var p:Particle = new Particle();
canvas.addChild(p);
p.x = stage.stageWidth * Math.random();
p.y = stage.stageHeight* Math.random();
p.initi(stage);
}
canvas.filters = new Array(blur);
addEventListener(Event.ENTER_FRAME, render);
}
private function render(e:Event):void{
remove();
b = new Bitmap(makeFluid(canvas),"auto", true);
b.alpha = 0.7;
addChild(b);
}
private function makeFluid(o:Sprite):BitmapData{
bmd1 = new BitmapData(stage.stageWidth, stage.stageHeight, true);
bmd1.draw(o,null,null,null,null,true);
bmd1.threshold(bmd1, bmd1.rect, new Point(0,0), ">", 0XFF2b2b2b, 0x55FFFF, 0xFFFFFF, false);
return bmd1;
}
private function remove():void{
if(numChildren > 1)
removeChildAt(1);
if(bmd1){
bmd1.dispose();
bmd1 = null;
}
}}}
Particle.as
package {
import flash.display.MovieClip;
import flash.events.Event;
import flash.display.Stage;
public class Particle extends MovieClip {
private var speedX:int;
private var speedY:int;
private var _s:Stage;
public function Particle() {
this.graphics.beginFill(0x00CCFF);
this.graphics.drawCircle(0,0,Math.random() * 30);
speedX = Math.random() * 10 - 5;
speedY = Math.random() * 10 - 5;
this.addEventListener(Event.ADDED_TO_STAGE, initi);
}
public function initi(s:Stage):void{
this._s = s;
addEventListener(Event.ENTER_FRAME, render);
}
private function render(e:Event):void{
this.x += Math.random()*speedX;
this.y += Math.random()*speedY;
if(this.x > _s.stageWidth || this.y > _s.stageHeight || this.x < 0 && this.y < 0){
this.x = Math.random()*_s.stageWidth;
this.y = Math.random()*_s.stageHeight;
//removeEventListener(Event.ENTER_FRAME, render);
//this.parent.removeChild(this);
}
}
}}

Multitouch as3 problems

I have a little problem with multitouch in as3.
Recently started a project in connection with my student practice.
This is to be a small game for android.
Are used to control two virtual joysticks and that's the problem with them.
As long as I use one of them or the other separately all works very well. However, when I try to use two at the same time, one of them is blocked and the object which moves begin to move in a random way and I can not control it.
Here is my code:
joystick.as:
package com.controls {
import flash.events.TouchEvent;
import flash.ui.Multitouch;
import flash.ui.MultitouchInputMode;
import flash.display.Sprite;
import flash.events.Event;
import flash.display.MovieClip;
import flash.geom.Rectangle;
import com.controls.JoystickKnob;
import com.Hero;
import com.Fire;
import com.greensock.*;
import com.greensock.easing.*;
public class Joystick extends MovieClip {
Multitouch.inputMode = MultitouchInputMode.TOUCH_POINT;
private var my_x:Number;
private var my_y:Number;
private var knob:JoystickKnob;
private var hero:Hero;
private var fire:Fire;
private var knob_tween:TweenLite;
public function Joystick(margin_left, margin_bottom, hero_mc) {
var circle:Sprite = new Sprite();
circle.graphics.beginFill(0x696969);
circle.graphics.drawCircle(50, 50, 60);
circle.graphics.endFill();
addChild(circle);
my_x = margin_left;
my_y = margin_bottom;
hero = hero_mc;
if (stage) {
init();
} else {
addEventListener(Event.ADDED_TO_STAGE,init);
}
}
private function init(e:Event = null):void {
if (hasEventListener(Event.ADDED_TO_STAGE)) {
removeEventListener(Event.ADDED_TO_STAGE,init);
}
this.x = my_x + this.width / 2;
this.y = stage.stageHeight - my_y - this.height / 2;
knob = new JoystickKnob();
knob.x = 0;
knob.y = 0;
knob.origin_x = 0;
knob.origin_y = 0;
addChild(knob);
this.addEventListener(TouchEvent.TOUCH_BEGIN, onTouchBegin, true);
knob.addEventListener(TouchEvent.TOUCH_MOVE, onTouchMove, true);
stage.addEventListener(TouchEvent.TOUCH_END, onTouchEnd, true);
knob.buttonMode = true;
}
private function onTouchBegin(event:TouchEvent):void {
knob.x = this.mouseX;
knob.y = this.mouseY;
onTouchMove(null);
}
private function onTouchMove(event:TouchEvent):void {
if (knob_tween) {
knob_tween.kill();
}
this.addEventListener(Event.ENTER_FRAME, knobMoved);
knob.startDrag(false, new Rectangle( - this.width /2, - this.height /2, this.width, this.height));
}
private function knobMoved(event:Event):void {
// LEFT OR RIGHT
if (knob.x > 15) {
hero.move_right = true;
hero.move_left = false;
} else if (knob.x < -15) {
hero.move_right = false;
hero.move_left = true;
} else {
hero.move_right = false;
hero.move_left = false;
}
// UP OR DOWN
if (knob.y > 15) {
hero.move_down = true;
hero.move_up = false;
} else if (knob.y < -15) {
hero.move_down = false;
hero.move_up = true;
} else {
hero.move_down = false;
hero.move_up = false;
}
}
private function onTouchEnd(event:TouchEvent):void {
knob.stopDrag();
hero.move_left = false;
hero.move_up = false;
hero.move_right = false;
hero.move_down = false;
if (this.hasEventListener(Event.ENTER_FRAME)) {
this.removeEventListener(Event.ENTER_FRAME, knobMoved);
}
mover();
}
private function mover():void {
knob_tween = new TweenLite(knob, 0.5, {x: knob.origin_x, y:knob.origin_y, ease:Bounce.easeOut});
}
}
}
joystickKnob.as:
package com.controls {
import flash.display.Sprite;
import flash.display.MovieClip;
public class JoystickKnob extends MovieClip {
private var _origin_x:Number;
private var _origin_y:Number;
private var knob:Class;
public function JoystickKnob() {
var circle:Sprite = new Sprite();
circle.graphics.beginFill(0x32CD32);
circle.graphics.drawCircle(50, 50, 35);
circle.graphics.endFill();
addChild(circle);
}
public function get origin_x():Number {
return _origin_x;
}
public function set origin_x(o_x:Number):void {
_origin_x = o_x;
}
public function get origin_y():Number {
return _origin_x;
}
public function set origin_y(o_y:Number):void {
_origin_y = o_y;
}
}
}
Second joystick code looks the same, except that it is stored in files joystick2.as, joystickKnob2.as.
This is the main class of my program:
package com {
import flash.events.TouchEvent;
import flash.display.MovieClip;
import flash.events.MouseEvent;
import com.controls.Joystick;
import com.controls.Joystick2;
import com.Hero;
import com.Fire;
public class MyApp extends MovieClip {
private var joystick:Joystick;
private var hero:Hero;
private var joystick2:Joystick2;
private var fire:Fire;
public function MyApp() {
hero = new Hero();
hero.x = stage.stageWidth/1.7;
hero.y = stage.stageHeight/1.7;
addChild(hero);
fire = new Fire();
fire.x = stage.stageWidth/1.7;
fire.y = stage.stageHeight/1.7;
addChild(fire);
joystick = new Joystick(-350, 100, hero);
addChild(joystick);
joystick2 = new Joystick2(600, 100, fire);
addChild(joystick2);
}
}
}
When using the two joysticks at the same time, the problem also occurs with the knob graphics - instead move in a specific area, one of them almost always moves to the other end of the screen, near the area of the second joystick.
Has anyone of you already encountered such a problem and knows how to remedy it?
Best regards and thank you in advance for your help
Multitouch.inputMode = MultitouchInputMode.TOUCH_POINT; does not support multiple fingers as written in de documentation:
For user interaction with multiple points of contact (such as several fingers moving across a touch screen at the same time) use the related GestureEvent, PressAndTapGestureEvent, and TransformGestureEvent classes. And, use the properties and methods of these classes to construct event handlers that respond to the user touching the device.
so you want Multitouch.inputMode = MultitouchInputMode.GESTURE;
This post shows up when searching for info on touch_point so I want to make sure it's correct.
TOUCH_POINT does support multiple touch points. Each touch is unique and given a unique id. You can have 100s of simultaneous touches.
TOUCH_POINT is what you use if you want to code your own touch handlers. GESTURE is TOUCH_POINTs handled for you. GESTURE decides if the touchpoints are swiping, tapping, etc. TOUCH_POINT is like a mouse event - the raw event.

Working with video in actionscript

I have small Movie clips that needs to be played, throughout the game i am making. Currently i am making them in aftereffets and exporting them as FLV files and embedding them into timeline, making a moviclip symbol to play them.
But that obviously is a disaster. This way i get very small movie clips but they don't garbage collect at all. So it keeps getting stored in the memory. if I turn them into SWF, the files become like 10 times bigger, going as high as 24 mb for 2.4 mb flv file. It's really frustrating to work with it this way.
Can somebody please suggest a way to work with videos/clips in actionscript 3? I don't need any controls for these movie clips, they serve as cut scenes.
Adobe introduced StageVideo, leveraging hardware acceleration for high performance video playback.
To mitigate the performance impact of rendering video in the Video
object, Adobe has introduced stage video as a new way to render video.
This approach takes full advantage of the underlying video hardware.
The result is a much lower load on the CPU, which translates into
higher frame rates on less powerful devices and also less memory
usage.
Example implementation from Thibault Imbert:
package
{
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.DisplayObject;
import flash.display.Loader;
import flash.display.Shape;
import flash.display.Sprite;
import flash.display.StageAlign;
import flash.display.StageDisplayState;
import flash.display.StageScaleMode;
import flash.events.Event;
import flash.events.FullScreenEvent;
import flash.events.KeyboardEvent;
import flash.events.MouseEvent;
import flash.events.NetStatusEvent;
import flash.events.StageVideoAvailabilityEvent;
import flash.events.StageVideoEvent;
import flash.events.TimerEvent;
import flash.events.VideoEvent;
import flash.geom.Rectangle;
import flash.media.SoundTransform;
import flash.media.StageVideo;
import flash.media.StageVideoAvailability;
import flash.media.Video;
import flash.net.NetConnection;
import flash.net.NetStream;
import flash.system.LoaderContext;
import flash.text.TextField;
import flash.text.TextFieldAutoSize;
import flash.text.TextFormat;
import flash.ui.Keyboard;
/**
*
* #author Thibault Imbert
*
*/
[SWF(frameRate="1", backgroundColor="#000000")]
public class SimpleStageVideo extends Sprite
{
private static const FILE_NAME:String = "video-file.mov";
private static const INTERVAL:Number = 500;
private static const BORDER:Number = 20;
private var legend:TextField = new TextField();
private var sv:StageVideo;
private var nc:NetConnection;
private var ns:NetStream;
private var rc:Rectangle;
private var video:Video;
private var thumb:Shape;
private var interactiveThumb:Sprite;
private var totalTime:Number;
private var videoWidth:int;
private var videoHeight:int;
private var outputBuffer:String = new String();
private var rect:Rectangle = new Rectangle(0, 0, 0, BORDER);
private var videoRect:Rectangle = new Rectangle(0, 0, 0, 0);
private var gotStage:Boolean;
private var stageVideoInUse:Boolean;
private var classicVideoInUse:Boolean;
private var accelerationType:String;
private var infos:String = new String();
private var available:Boolean;
private var inited:Boolean;
private var played:Boolean;
private var container:Sprite;
/**
*
*
*/
public function SimpleStageVideo()
{
// Make sure the app is visible and stage available
addEventListener(Event.ADDED_TO_STAGE, onAddedToStage);
}
/**
*
* #param event
*
*/
private function onAddedToStage(event:Event):void
{
// Scaling
stage.scaleMode = StageScaleMode.NO_SCALE;
stage.align = StageAlign.TOP_LEFT;
legend.autoSize = TextFieldAutoSize.LEFT;
// Debug infos
legend.multiline = true;
legend.background = true;
legend.backgroundColor = 0xFFFFFFFF;
addChild(legend);
// Thumb seek Bar
thumb = new Shape();
interactiveThumb = new Sprite();
interactiveThumb.addChild(thumb);
addChild(interactiveThumb);
// Connections
nc = new NetConnection();
nc.connect(null);
ns = new NetStream(nc);
ns.addEventListener(NetStatusEvent.NET_STATUS, onNetStatus);
ns.client = this;
// Screen
video = new Video();
video.smoothing = true;
// Video Events
// the StageVideoEvent.STAGE_VIDEO_STATE informs you if StageVideo is available or not
stage.addEventListener(StageVideoAvailabilityEvent.STAGE_VIDEO_AVAILABILITY, onStageVideoState);
// in case of fallback to Video, we listen to the VideoEvent.RENDER_STATE event to handle resize properly and know about the acceleration mode running
video.addEventListener(VideoEvent.RENDER_STATE, videoStateChange);
// Input Events
stage.addEventListener(KeyboardEvent.KEY_DOWN, onKeyDown);
stage.addEventListener(Event.RESIZE, onResize);
stage.addEventListener(MouseEvent.CLICK, onClick);
}
/**
*
* #param event
*
*/
private function onNetStatus(event:NetStatusEvent):void
{
if ( event.info == "NetStream.Play.StreamNotFound" )
legend.text = "Video file passed, not available!";
}
/**
*
* #param event
*
*/
private function onFrame(event:Event):void
{
var ratio:Number = (ns.time / totalTime) * (stage.stageWidth - (BORDER << 1));
rect.width = ratio;
thumb.graphics.clear();
thumb.graphics.beginFill(0xFFFFFF);
thumb.graphics.drawRect(rect.x, rect.y, rect.width, rect.height);
}
/**
*
* #param event
*
*/
private function onClick(event:MouseEvent):void
{
if ( event.stageY >= interactiveThumb.y - BORDER && event.stageX <= stage.stageWidth - BORDER )
{
var seekTime:Number = (stage.mouseX - BORDER) * ( totalTime / (stage.stageWidth - (BORDER << 1) ) );
ns.seek( seekTime );
}
}
/**
*
* #param event
*
*/
private function onKeyDown(event:KeyboardEvent):void
{
if ( event.keyCode == Keyboard.O )
{
if ( available )
// We toggle the StageVideo on and off (fallback to Video and back to StageVideo)
toggleStageVideo(inited=!inited);
} else if ( event.keyCode == Keyboard.F )
{
stage.displayState = StageDisplayState.FULL_SCREEN;
} else if ( event.keyCode == Keyboard.SPACE )
{
ns.togglePause();
}
}
/**
*
* #param width
* #param height
* #return
*
*/
private function getVideoRect(width:uint, height:uint):Rectangle
{
var videoWidth:uint = width;
var videoHeight:uint = height;
var scaling:Number = Math.min ( stage.stageWidth / videoWidth, stage.stageHeight / videoHeight );
videoWidth *= scaling, videoHeight *= scaling;
var posX:uint = stage.stageWidth - videoWidth >> 1;
var posY:uint = stage.stageHeight - videoHeight >> 1;
videoRect.x = posX;
videoRect.y = posY;
videoRect.width = videoWidth;
videoRect.height = videoHeight;
return videoRect;
}
/**
*
*
*/
private function resize ():void
{
if ( stageVideoInUse )
{
// Get the Viewport viewable rectangle
rc = getVideoRect(sv.videoWidth, sv.videoHeight);
// set the StageVideo size using the viewPort property
sv.viewPort = rc;
} else
{
// Get the Viewport viewable rectangle
rc = getVideoRect(video.videoWidth, video.videoHeight);
// Set the Video object size
video.width = rc.width;
video.height = rc.height;
video.x = rc.x, video.y = rc.y;
}
interactiveThumb.x = BORDER, interactiveThumb.y = stage.stageHeight - (BORDER << 1);
legend.text = infos;
}
/**
*
* #param evt
*
*/
public function onMetaData ( evt:Object ):void
{
totalTime = evt.duration;
stage.addEventListener(Event.ENTER_FRAME, onFrame);
}
/**
*
* #param event
*
*/
private function onStageVideoState(event:StageVideoAvailabilityEvent):void
{
// Detect if StageVideo is available and decide what to do in toggleStageVideo
toggleStageVideo(available = inited = (event.availability == StageVideoAvailability.AVAILABLE));
}
/**
*
* #param on
*
*/
private function toggleStageVideo(on:Boolean):void
{
infos = "StageVideo Running (Direct path) : " + on + "\n";
// If we choose StageVideo we attach the NetStream to StageVideo
if (on)
{
stageVideoInUse = true;
if ( sv == null )
{
sv = stage.stageVideos[0];
sv.addEventListener(StageVideoEvent.RENDER_STATE, stageVideoStateChange);
}
sv.attachNetStream(ns);
if (classicVideoInUse)
{
// If we use StageVideo, we just remove from the display list the Video object to avoid covering the StageVideo object (always in the background)
stage.removeChild ( video );
classicVideoInUse = false;
}
} else
{
// Otherwise we attach it to a Video object
if (stageVideoInUse)
stageVideoInUse = false;
classicVideoInUse = true;
video.attachNetStream(ns);
stage.addChildAt(video, 0);
}
if ( !played )
{
played = true;
ns.play(FILE_NAME);
}
}
/**
*
* #param event
*
*/
private function onResize(event:Event):void
{
resize();
}
/**
*
* #param event
*
*/
private function stageVideoStateChange(event:StageVideoEvent):void
{
infos += "StageVideoEvent received\n";
infos += "Render State : " + event.status + "\n";
resize();
}
/**
*
* #param event
*
*/
private function videoStateChange(event:VideoEvent):void
{
infos += "VideoEvent received\n";
infos += "Render State : " + event.status + "\n";
resize();
}
}
}

away3d and cs6 external as3 file

i need some help to lunch external action script file lets say i have this file :
Basic_SkyBox.as
and this the code for it :
package
{
import away3d.cameras.lenses.*;
import away3d.containers.*;
import away3d.entities.*;
import away3d.materials.*;
import away3d.materials.methods.*;
import away3d.primitives.*;
import away3d.textures.*;
import away3d.utils.*;
import flash.display.*;
import flash.events.*;
import flash.geom.Vector3D;
[SWF(backgroundColor="#000000", frameRate="60", quality="LOW")]
public class Basic_SkyBox extends Sprite
{
// Environment map.
[Embed(source="../embeds/skybox/snow_positive_x.jpg")]
private var EnvPosX:Class;
[Embed(source="../embeds/skybox/snow_positive_y.jpg")]
private var EnvPosY:Class;
[Embed(source="../embeds/skybox/snow_positive_z.jpg")]
private var EnvPosZ:Class;
[Embed(source="../embeds/skybox/snow_negative_x.jpg")]
private var EnvNegX:Class;
[Embed(source="../embeds/skybox/snow_negative_y.jpg")]
private var EnvNegY:Class;
[Embed(source="../embeds/skybox/snow_negative_z.jpg")]
private var EnvNegZ:Class;
//engine variables
private var _view:View3D;
//scene objects
private var _skyBox:SkyBox;
private var _torus:Mesh;
/**
* Constructor
*/
public function Basic_SkyBox()
{
stage.scaleMode = StageScaleMode.NO_SCALE;
stage.align = StageAlign.TOP_LEFT;
//setup the view
_view = new View3D();
addChild(_view);
//setup the camera
_view.camera.z = -600;
_view.camera.y = 0;
_view.camera.lookAt(new Vector3D());
_view.camera.lens = new PerspectiveLens(90);
//setup the cube texture
var cubeTexture:BitmapCubeTexture = new BitmapCubeTexture(Cast.bitmapData(EnvPosX), Cast.bitmapData(EnvNegX), Cast.bitmapData(EnvPosY), Cast.bitmapData(EnvNegY), Cast.bitmapData(EnvPosZ), Cast.bitmapData(EnvNegZ));
//setup the environment map material
var material:ColorMaterial = new ColorMaterial(0xFFFFFF, 1);
material.specular = 0.5;
material.ambient = 0.25;
material.ambientColor = 0x111199;
material.ambient = 1;
material.addMethod(new EnvMapMethod(cubeTexture, 1));
//setup the scene
_torus = new Mesh(new TorusGeometry(150, 60, 40, 20), material);
_view.scene.addChild(_torus);
_skyBox = new SkyBox(cubeTexture);
_view.scene.addChild(_skyBox);
//setup the render loop
addEventListener(Event.ENTER_FRAME, _onEnterFrame);
stage.addEventListener(Event.RESIZE, onResize);
onResize();
}
/**
* render loop
*/
private function _onEnterFrame(e:Event):void
{
_torus.rotationX += 2;
_torus.rotationY += 1;
_view.camera.position = new Vector3D();
_view.camera.rotationY += 0.5*(stage.mouseX-stage.stageWidth/2)/800;
_view.camera.moveBackward(600);
_view.render();
}
/**
* stage listener for resize events
*/
private function onResize(event:Event = null):void
{
_view.width = stage.stageWidth;
_view.height = stage.stageHeight;
}
}
}
ok then i create new action script page how i can refer the above file script to run in main page of projects in flash cs6 ??
You need to set the Document Class to Basic_Skybox. Make sure the .fla and Basic_Skybox.as are in the same directory.
Here's a tutorial on doing so: http://active.tutsplus.com/tutorials/actionscript/quick-tip-how-to-use-a-document-class-in-flash/

Actionscript 3: User input events not firing from children blit sprite objects

Still programming an iPad game in Actionscript 3, I am encountering a problem that keeps me from advancing any further. I use blitting for animation, and as such, all my object use blitting for rendering. All objects are children of a game class which has a bitmapData canvas on which are rendered the game elements.
That's for how it should work. So far, there are no compilation or runtime errors, but for some reason I can't get any user input event from any object apart from the game itself. I have checked the event flow as well as the layering of the objects, but so far all I could find out is that for some reason the main canvas is the only element that can be targeted for events. Because players need to be able to touch them, two game elements are concerned: Twinkys and Racquets.
I have tried changing the layering of the elements, in order of instanciation and rendering, hiding some, changing event types (using mouse event instead of touch events) and toggling the mouseEnabled property of the game class with no positive result. All I can be sure of is that the game class is intercepting all events targeted at its children, making it impossible to play. I hope someone can see what I've done wrong.
Game class:
package Game
{
import Game.*;
import Game.Worlds.Level1.Level1;
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.Sprite;
import flash.display3D.IndexBuffer3D;
import flash.events.Event;
import flash.events.TouchEvent;
import flash.ui.Multitouch;
import flash.ui.MultitouchInputMode;
public class Game extends Sprite
{
/** Hold each racquet so as to retrieve them when collision detection is needed. **/
internal var racquetList:Vector.<Racquet>= new Vector.<Racquet>(2,true);
/** Hold each Zwig so as to retrieve them when collision detection is needed. **/
internal var zwigColliderList:Vector.<Collider>= new Vector.<Collider>(2,true);
/** Object that contains the coordinates for the Twinkys in the counter. **/
internal var twinkyScore0:Object= {firstX:727,firstY:950,secondX:710,secondY:911,
thirdX:690,thirdY:872,fourthX:674,fourthY:840,
fifthX:657,fifthY:808};
internal var twinkyScore1:Object= {firstX:41,firstY:74,secondX:58,secondY:113,
thirdX:78,thirdY:152,fourthX:94,fourthY:184,
fifthX:111,fifthY:216};
/** Speed decay coefficient. The closer to 1 the less speed decays. **/
private var friction:Number= .96;
/** Maximum speed cap for twinkys. The higher the number the grater the maximal speed. **/
private var speedMax:Number= 10;
/** Important positions for the placement of game elements.
* LianaHeight is the height at which the liana on the players' HUDs is ending their zone and on which the racquet travels.
* TwinkyHeight is the height at which the players stop controlling their Twinkys.
* YMargin is the vertical margin for the Twinkys. Used to place them at the end of the tube when added.
* XMargin is the horizontal margin for the Twinkys. Used to place them at the end of the tube when added. **/
private var positions:Object= {LianaHeight:165,TwinkyHeight:265,YMargin:8.0,XMargin:200.0};
private var _mRef:ZwigsIpad;
Multitouch.inputMode= MultitouchInputMode.TOUCH_POINT;
private var _Canvas:BitmapData= new BitmapData(ZwigsIpad.BORDERS.right,ZwigsIpad.BORDERS.bottom,false);
private var _Background:Background;
private var _HUD1:HUD;
private var _HUD2:HUD;
private var _Score:Score;
private var _Zwig1:Zwig;
private var _Zwig2:Zwig;
private var _Racquet1:Racquet;
private var _Racquet2:Racquet;
private var _Twinky1:Twinky;
private var _Twinky2:Twinky;
/** Create the first level. It will create the stage and add the background, HUDs, Zwigs, Racquets and Twinkys, and manages the game until the end. **/
public function Game(m:ZwigsIpad)
{
this._mRef= m;
this.addEventListener(Event.ADDED_TO_STAGE,init);
}
private function init(e:Event):void
{
this.removeEventListener(Event.ADDED_TO_STAGE,init);
// Add game canvas on which all assets are rendered
addChild(new Bitmap(this._Canvas));
// Get informations from Level1
// LATER make it dependant from what level was chosen (switch case)
this.positions.LianaHeight= Level1.LIANA_HEIGHT;
this.positions.TwinkyHeight= Level1.TWINKY_HEIGHT;
this.positions.YMargin= Level1.TWINKY_MARGIN_Y;
this.positions.XMargin= Level1.TWINKY_MARGIN_X;
this.friction= Level1.TWINKY_FRICTION;
this.speedMax= Level1.TWINKY_SPEED_MAX;
// Add background
this._Background= new Background(this._Canvas,0);
addChild(this._Background);
// Add HUD
this._HUD1= new HUD(this._Canvas);
this._HUD2= new HUD(this._Canvas,true,1);
addChild(this._HUD1);
addChild(this._HUD2);
// Add scoring
this._Score= new Score(this,this._mRef);
addChild(this._Score);
// Add zwigs
this._Zwig1= new Zwig(this._Canvas);
this._Zwig2= new Zwig(this._Canvas,true,1);
addChild(this._Zwig1);
addChild(this._Zwig2);
// Add zwigs' colliders to vector
this.zwigColliderList[0]= this._Zwig1.collider;
this.zwigColliderList[1]= this._Zwig2.collider;
// Add racquets
this._Racquet1= new Racquet(this.positions,this._Canvas);
this._Racquet2= new Racquet(this.positions,this._Canvas,false,1);
addChild(this._Racquet1);
addChild(this._Racquet2);
// Add racquets to vector
this.racquetList[0]= this._Racquet1;
this.racquetList[1]= this._Racquet2;
// Add twinkys
this._Twinky1= new Twinky(this,this._Score,this,this.positions,this.friction,this.speedMax,this._Canvas,0);
this._Twinky2= new Twinky(this,this._Score,this,this.positions,this.friction,this.speedMax,this._Canvas,1,false,1);
addChild(this._Twinky1);
addChild(this._Twinky2);
this.addEventListener(Event.ENTER_FRAME,renderLevel);
}
private function renderLevel(e:Event):void
{
this._Canvas.lock();
this._Background.render();
this._HUD1.render();
this._HUD2.render();
this._Score.render();
this._Zwig1.render();
this._Zwig2.render();
this._Racquet1.render();
this._Racquet2.render();
this._Twinky1.render();
this._Twinky2.render();
this._Canvas.unlock();
}
}
}
Twinky class:
package Game
{
import Game.Game;
import Game.Score;
import com.greensock.TweenMax;
import com.greensock.easing.*;
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.Sprite;
import flash.events.Event;
import flash.events.TouchEvent;
import flash.geom.Point;
import flash.geom.Rectangle;
import flash.ui.Multitouch;
import flash.ui.MultitouchInputMode;
/** The Twinky is the main player controlled class. **/
internal class Twinky extends Sprite
{
private var _mRef:Game;
private var _sRef:Score;
private var player:uint;
Multitouch.inputMode= MultitouchInputMode.TOUCH_POINT;
private var _touchMoveID:int= 0;
private var _speedX:Number= 0;
private var _speedY:Number= 0;
private var xOffset:Number;
private var yOffset:Number;
private var currentX:Number;
private var currentY:Number;
private var oldX:Number;
private var oldY:Number;
private var dragging:Boolean= false;
private var launched:Boolean= false;
private var _point:Point= new Point();
private var positions:Object;
private var friction:Number;
private var speedMax:Number;
private var canvas:BitmapData;
private var isAtBottom:Boolean;
private var skin:uint;
private var _image:BitmapData;
private var _idleArray:Array= new Array();
private var i:uint= 0;
// Yellow twinky
[Embed (source= "Assets/Players/twinky1.png")]
private const Twinky1idle:Class;
private var _twinky1idleArray:Array;
// Red twinky
[Embed (source= "Assets/Players/twinky2.png")]
private const Twinky2idle:Class;
private var _twinky2idleArray:Array;
private const twinkyWidth:uint= 64;
private const twinkyHeight:uint= 64;
private var t1i001:Rectangle= new Rectangle(0,0,twinkyWidth,twinkyHeight);
private var t2i001:Rectangle= new Rectangle(0,0,twinkyWidth,twinkyHeight);
/** Create Twinky. Twinkys must be flicked to the same colored Zwig to
* feed it and die when they lost momentum. **/
public function Twinky(daddy:Game,score:Score,m:Game,positions:Object,friction:Number,speedMax:Number,canvas:BitmapData,player:uint,isAtBottom:Boolean=true,skin:uint=0)
{
// Get score and game object reference
this._sRef= score;
this._mRef= daddy;
this.positions= positions;
this.friction= friction;
this.speedMax= speedMax;
this.canvas= canvas;
this.player= player;
this.isAtBottom= isAtBottom;
this.skin= skin;
this._twinky1idleArray= [t1i001];
this._twinky2idleArray= [t2i001];
this.addEventListener(Event.ADDED_TO_STAGE,init,false,0,true);
}
private function init(e:Event):void
{
this.removeEventListener(Event.ADDED_TO_STAGE,init);
// Get skin
switch (this.skin)
{
case 0:
this._image= new this.Twinky1idle().bitmapData;
this._idleArray= this._twinky1idleArray;
break;
case 1:
this._image= new this.Twinky2idle().bitmapData;
this._idleArray= this._twinky2idleArray;
break;
default:
this._image= new this.Twinky1idle().bitmapData;
this._idleArray= this._twinky1idleArray;
break;
}
// Give position
if (this.isAtBottom)
{
this.x= this.positions.XMargin;
this.y= ZwigsIpad.BORDERS.bottom - this.positions.YMargin;
// Animate entrance
TweenMax.from(this,1,{x:this.x-70,y:this.y-12,rotation:-180,alpha:.5});
}
else
{
this.x= ZwigsIpad.BORDERS.right - this.positions.XMargin;
this.y= this.positions.YMargin;
// Animate entrance
TweenMax.from(this,1,{x:this.x+70,y:this.y+12,rotation:-180,alpha:.5});
}
this._point.x= this.x;
this._point.y= this.y;
aText.appendText("\n position: "+this.x+" "+this.y);
// Detect touched
this.addEventListener(TouchEvent.TOUCH_BEGIN,touchDown);
// Always detect untouched
this._mRef.addEventListener(TouchEvent.TOUCH_END,touchUp);
// Always do kinetics
this._mRef.addEventListener(Event.ENTER_FRAME,freeMove);
}
/** Render the Twinky at its current coordinates by redrawing it. **/
internal function render():void
{
this._point.x= this.x - this._idleArray[i].width * .5;
this._point.y= this.y - this._idleArray[i].height * .5;
this.canvas.copyPixels(this._image,this._idleArray[0/*i*/],this._point);
// When idle finished restart, else pursue with animation
/*if (i==this._idleArray.length - 1)
i= 0;
else
i++;*/
}
// TWINKY AND RACQUET DO NOT DETECT TOUCH EVENTS because the main canvas covers them
// Start dragging when touched
private function touchDown(e:TouchEvent):void
{
aText.appendText("\n Twinky touched!");
if (this._touchMoveID != 0)
return;
this._touchMoveID= e.touchPointID;
this.dragging= true;
// Get the mouse's offset on the object
this.xOffset= e.localX;
this.yOffset= e.localY;
this._mRef.addEventListener(TouchEvent.TOUCH_MOVE,touchMove);
}
private function touchMove(e:TouchEvent):void
{
if (e.touchPointID != this._touchMoveID)
return;
// Move twinky to where the mouse is
this.x= e.stageX - this.xOffset;
this.y= e.stageY - this.yOffset;
// Don't go farther than borders
if (this.x <= this.width * .5)
{
this.x= (this.width * .5) + .1;
}
if (this.x >= ZwigsIpad.BORDERS.right - (this.width * .5))
{
this.x= ZwigsIpad.BORDERS.right - (this.width * .5) - .1;
}
if (this.y <= this.height * .5)
{
this.y= (this.height * .5) + .1;
}
if (this.y >= ZwigsIpad.BORDERS.bottom - (this.height * .5))
{
this.y= ZwigsIpad.BORDERS.bottom - (this.height * .5) - .1;
}
// Be undraggable if zone is left
if (this.isAtBottom)
{
if (this.y < (ZwigsIpad.BORDERS.bottom - this.positions.TwinkyHeight))
{
this._touchMoveID= 0;
this.dragging= false;
this._mRef.removeEventListener(TouchEvent.TOUCH_MOVE,touchMove);
return;
}
}
else
{
if (this.y > this.positions.TwinkyHeight)
{
this._touchMoveID= 0;
this.dragging= false;
this._mRef.removeEventListener(TouchEvent.TOUCH_MOVE,touchMove);
return;
}
}
// Refresh coordinates for display
this._point.x= this.x;
this._point.y= this.y;
e.updateAfterEvent();
}
private function touchUp(e:TouchEvent):void
{
if (e.touchPointID != this._touchMoveID)
return;
this._touchMoveID= 0;
this.dragging= false;
this._mRef.removeEventListener(TouchEvent.TOUCH_MOVE,touchMove);
}
private function freeMove(e:Event):void
{
// Be undraggable if liana crossed
if (this.isAtBottom)
{
if (this.y < (ZwigsIpad.BORDERS.bottom - this.positions.TwinkyHeight))
{
this.removeEventListener(TouchEvent.TOUCH_BEGIN,touchDown);
this._mRef.removeEventListener(Event.ENTER_FRAME,touchUp);
this.dragging= false;
this.launched= true;
}
}
else
{
if (this.y > this.positions.TwinkyHeight)
{
this.removeEventListener(TouchEvent.TOUCH_BEGIN,touchDown);
this._mRef.removeEventListener(Event.ENTER_FRAME,touchUp);
this.dragging= false;
this.launched= true;
}
}
// Move the twinky and calculate its speed if player is dragging it
if (this.dragging)
{
aText.appendText("\n Twinky dragged!");
this.oldX= currentX;
this.oldY= currentY;
currentX= this.x;
currentY= this.y;
// Calculate speed in X and Y axis
this._speedX= this.currentX - this.oldX;
this._speedY= this.currentY - this.oldY;
// Cap maximal speed
if (this._speedX > this.speedMax)
this._speedX= this.speedMax;
if (this._speedY > this.speedMax)
this._speedY= this.speedMax;
}
// Otherwise move the twinky using its speed
else
{
this.x+= this._speedX;
this.y+= this._speedY;
}
// Detect collision with zwigs
for (i= 0 ; i < this._mRef.zwigColliderList.length ; i++)
{
var cemp:Collider= this._mRef.zwigColliderList[i] as Collider;
if (this.hitTestObject(cemp))
{
this.removeEventListener(TouchEvent.TOUCH_BEGIN,touchDown);
this._mRef.removeEventListener(TouchEvent.TOUCH_END,touchUp);
this._mRef.removeEventListener(Event.ENTER_FRAME,freeMove);
this._sRef.die(this,this.player,true,i);
return;
}
}
// Detect collision with borders: left border
if (this.x <= this.width / 2)
{
// Don't go any further
this.x= (this.width / 2) + .1;
// Reverse speed to bounce
this._speedX*= -1;
}
// Right border
if (this.x >= ZwigsIpad.BORDERS.right - (this.width / 2))
{
this.x= ZwigsIpad.BORDERS.right - (this.width / 2) - .1;
this._speedX*= -1;
}
// Top border
if (this.y <= this.height / 2)
{
this.y= (this.height / 2) + .1;
this._speedY*= -1;
}
// Bottom border
if (this.y >= ZwigsIpad.BORDERS.bottom - (this.height / 2))
{
this.y= ZwigsIpad.BORDERS.bottom - (this.height / 2) - .1;
this._speedY*= -1;
}
// Detect collision with racquets
for (var i:uint= 0 ; i < this._mRef.racquetList.length ; i++)
{
var temp:Racquet= this._mRef.racquetList[i] as Racquet;
if (this.hitTestObject(temp))
{
this._speedY*= -1;
this.y+= this._speedY;
}
}
// Speed decay
this._speedX*= this.friction;
this._speedY*= this.friction;
// Set speed to 0 if speed is smaller than .5
if (Math.abs(this._speedX) < .5) this._speedX= 0;
if (Math.abs(this._speedY) < .5) this._speedY= 0;
// If speed is null and it has been launched, kill twinky
if (this._speedX == 0 && this._speedY == 0 && this.launched)
{
this.removeEventListener(TouchEvent.TOUCH_BEGIN,touchDown);
this._mRef.removeEventListener(TouchEvent.TOUCH_END,touchUp);
this._mRef.removeEventListener(Event.ENTER_FRAME,freeMove);
TweenMax.to(this, 1.5, {alpha:0, ease:Linear.easeNone});
this._sRef.die(this,this.player);
return;
}
// Refresh coordinates for display
this._point.x= this.x;
this._point.y= this.y;
}
}
}
Racquet class:
package Game
{
import Game.Worlds.Level1.Level1;
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.Sprite;
import flash.events.Event;
import flash.events.TouchEvent;
import flash.geom.Point;
import flash.ui.Multitouch;
import flash.ui.MultitouchInputMode;
internal class Racquet extends Sprite
{
Multitouch.inputMode= MultitouchInputMode.TOUCH_POINT;
private var _touchMoveID:int= 0;
private var xOffset:Number;
private var dragging:Boolean= false;
private var positions:Object;
private var canvas:BitmapData;
private var isAtBottom:Boolean;
private var skin:uint;
private var _image:BitmapData;
private var _point:Point= new Point();
// Yellow racquet
[Embed (source= "Assets/Players/racq1.png")]
private const Racquet1:Class;
// Red racquet
[Embed (source= "Assets/Players/racq2.png")]
private const Racquet2:Class;
public function Racquet(positions:Object,canvas:BitmapData,isAtBottom:Boolean=true,skin:uint=0)
{
this.positions= positions;
this.canvas= canvas;
this.isAtBottom= isAtBottom;
this.skin= skin;
this.addEventListener(Event.ADDED_TO_STAGE,init,false,0,true);
}
private function init(e:Event):void
{
this.removeEventListener(Event.ADDED_TO_STAGE,init);
// Get skin
switch (this.skin)
{
case 0:
//this._image= new R.Racquet1().bitmapData;
this._image= new this.Racquet1().bitmapData;
break;
case 1:
//this._image= new R.Racquet2().bitmapData;
this._image= new this.Racquet2().bitmapData;
break;
default:
this._image= new this.Racquet1().bitmapData;
break;
}
// Give position
if (this.isAtBottom)
{
this.x= ZwigsIpad.BORDERS.centerX;
this.y= ZwigsIpad.BORDERS.bottom - this.positions.LianaHeight;
}
else
{
this.x= ZwigsIpad.BORDERS.centerX;
this.y= this.positions.LianaHeight;
}
this._point.x= this.x;
this._point.y= this.y;
this.addEventListener(TouchEvent.TOUCH_BEGIN,touchDown,false,0,true);
this.parent.addEventListener(TouchEvent.TOUCH_END,touchUp,false,0,true);
}
internal function render():void
{
this._point.x= this.x - this._image.rect.width * .5;
this._point.y= this.y - this._image.rect.height * .5;
this.canvas.copyPixels(this._image,this._image.rect,this._point);
}
private function touchDown(e:TouchEvent):void
{
aText.appendText("\n Racquet touched!");
if(this._touchMoveID != 0)
return;
this._touchMoveID= e.touchPointID;
this.xOffset= e.localX;
this.parent.addEventListener(TouchEvent.TOUCH_MOVE,touchMove,false,0,true);
}
private function touchMove(e:TouchEvent):void
{
if(e.touchPointID != this._touchMoveID)
return;
Multitouch.inputMode= MultitouchInputMode.TOUCH_POINT;
this._point.x= e.stageX - this.xOffset;
if (this._point.x <= ZwigsIpad.BORDERS.left + (this._image.width*.5))
this._point.x= ZwigsIpad.BORDERS.left + (this._image.width*.5);
else if (this._point.x >= ZwigsIpad.BORDERS.right - (this._image.width*.5))
this._point.x= ZwigsIpad.BORDERS.right - (this._image.width*.5);
}
private function touchUp(e:TouchEvent):void
{
if(e.touchPointID != this._touchMoveID)
return;
this._touchMoveID= 0;
this.parent.removeEventListener(TouchEvent.TOUCH_MOVE,touchMove);
}
}
}
Touch events will only fire when you touch a sprite's graphics. But all your graphics are drawn onto a single bitmap so your various sprites have nothing to interact with.
Flash provides a display list and does a good job of rendering it, so you shouldn't need to build your own complicated structures like this.
You should consider making each sprite contain its own graphics and things will just work out easier. If performance is a huge concern, I suggest getting it working first, and then play around with different optimisation strategies afterwards (e.g. cacheAsBitmap, clipping/scrolling with scrollRect etc.)