Dynamically display text in Flex, ActionScript 3 - actionscript-3

I've been having problems displaying text in ActionScript 3 using Flex SDK 4.6. Any method I try results in no change or a black screen; here is my project code and attempts.
MyProject.mxml is simply and mx:Application tag with the relevant parts being
<mx:Script>
<![CDATA[
include "MyProject.as"; //simply running my project file
]]>
</mx:Script>
and
<mx:Canvas id="gamePanel" x="0" y="0" width="100%" height="100%"/> //defining the canvas
In MyProject.as I have
import flash.display.*;
import flash.events.*;
import mx.events.*;
import mx.controls.*;
import Game;
public static const SCREEN_WIDTH:int = 960;
public static const SCREEN_HEIGHT:int = 720;
private var initializationCompleted:Boolean = false;
public var screenBuffer:BitmapData;
public var game:Game;
public function setup():void {
screenBuffer = new BitmapData(SCREEN_WIDTH, SCREEN_HEIGHT, false, 0x00000000);
game = new Game(SCREEN_WIDTH, SCREEN_HEIGHT, screenBuffer);
initializationCompleted = true;
}
private function updateFrame():void {
if (!initializationCompleted) {
return;
}
draw();
gamePanel.graphics.clear();
gamePanel.graphics.beginBitmapFill(screenBuffer, null, false, false);
gamePanel.graphics.drawRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
gamePanel.graphics.endFill();
}
private function draw():void {
game.update();
}
And in Game.as, I simply draw everything using the BitmapData class, and then copy everything to the screenBuffer:
screenBuffer.copyPixels(myBitmap, new Rectangle(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT), new Point(0,0));
(This is only the relevant code - I trimmed as much as possible to leave a "Minimal, Complete, and Verifiable example")
Now I have been having problems displaying text in my project. I know that TextField is a subclass of flash.display.Sprite which can be added to the canvas. Whenever I try using something like
var txtHello:TextField = new TextField();
txtHello.text = "Hello World";
gamePanel.addChild(txtHello)
this either changes nothing (if used in setup(), I'm assuming I'm drawing over it or else it is never displayed) or causes a black screen (if used anywhere in updateFrame(), I'm assuming I'm creating infinite sprites).
I have tried instead, creating a new file named "TextWithImage.as" with the contents
//this is ripped off the adobe help page
package {
import flash.display.Sprite;
import flash.text.*;
public class TextWithImage extends Sprite {
private var myTextBox:TextField = new TextField();
private var myText:String = "Hello World";
public function TextWithImage() {
addChild(myTextBox);
myTextBox.text = myText;
}
}
}
importing it in MyProject.as, and then using it as
gamePanel.addChild(new TextWithImage());
to the same effect as my previous attempt.
What is the simplest way to display text in Flex/AS3? Any help is appreciated, and thank you in advance!

There's a trick. Flex components, albeit having the same addChild method derived from DisplayObjectContainer class, cannot actually add regular Flash content - Shape, Sprite, MovieClip, TextField, Bitmap - directly. More to that, they don't produce any runtime error, which I personally think they totally could to not confuse new people.
Flex component can only addChild classes that extend the basic UIComponent class. At the same time, UIComponent can addChild regular Flash content. Thus you do it as following:
var proxyContainer:UIComponent = new UIComponent;
var txtHello:TextField = new TextField;
txtHello.text = "Hello World";
proxyContainer.addChild(txtHello);
gamePanel.addChild(proxyContainer);

Related

Actionscript 3 and Flex 4 Zoom Gesture on SWFLoader

I seem to be having issue with Zoom Gestures on a SWFLoader. I have an swf file which is a floor plan of a home, I want the user to be able to zoom in and out with two finger touch, the following code below is what I tried and does not work. When I test on a touchscreen, it does not zoom when I place two fingers inside the SWF and try to zoom in.
<s:SWFLoader id="floorplanImage" source="#Embed('assets/test2.swf')" width="100%" height="100%" smoothBitmapContent="true" horizontalAlign="center" />
here is my actionscript 3 code
import flash.ui.Multitouch;
import flash.ui.MultitouchInputMode;
Multitouch.inputMode = MultitouchInputMode.GESTURE;
import flash.events.Event;
public var selectedItem:Object;
public function init(): void
{
floorplanImage.addEventListener(TransformGestureEvent.GESTURE_ZOOM , onZoom);
}
public function onZoom (e:TransformGestureEvent):void{
floorplanImage.scaleX *= e.scaleX;
floorplanImage.scaleY *= e.scaleY;
}
Please Help!
UPDATE
I am going the route of gestouch, however with this code, I CANNOT zoom in or out on an SWF. With a regular image it works, but not with SWF unless I am missing something. Here is my code:
<mx:Script>
<![CDATA[
import org.gestouch.events.GestureEvent;
import org.gestouch.gestures.TransformGesture;
private var _zoom:TransformGesture;
[Embed(source="assets/test2.swf")]
private var myClass:Class;
private var myMovieClip:MovieClip;
private function initModel():void
{
myMovieClip = MovieClip(new myClass());
swfcontainer.addChild(myMovieClip);
_zoom = new TransformGesture(swfcontainer);
_zoom.addEventListener(org.gestouch.events.GestureEvent.GESTURE_BEGAN, onGesture);
_zoom.addEventListener(org.gestouch.events.GestureEvent.GESTURE_CHANGED, onGesture);
}
private function onGesture(event:org.gestouch.events.GestureEvent):void
{
const gesture:TransformGesture = event.target as TransformGesture;
var matrix:Matrix = swfcontainer.transform.matrix;
// Panning
matrix.translate(gesture.offsetX, gesture.offsetY);
swfcontainer.transform.matrix = matrix;
if (gesture.scale != 1)
{
// Scale and rotation.
var transformPoint:Point = matrix.transformPoint(swfcontainer.globalToLocal(gesture.location));
matrix.translate(-transformPoint.x, -transformPoint.y);
matrix.scale(gesture.scale, gesture.scale);
matrix.translate(transformPoint.x, transformPoint.y);
swfcontainer.transform.matrix = matrix;
}
}
]]>
</mx:Script>
<mx:Image id="swfcontainer" horizontalAlign="center" width="100%" height="100%" />
When I use this with a regular image, it still does not work properly...it doesn't keep the image center when zooming, it does not let me zoom in, only out and when I first use it, it moves the image to the right. HOW COME THIS IS SOOOOOO HARD?
Please keep in mind I am very very new to Adobe Flex and Actionscript, so please make your answers as clear as possible.
Your code has no problem,I'll explain what I did for my project. Maybe it helped, i have Window design app and i load SWF into starling and have issue
with zoom and pan;
FYI: I Use starling and load SWF file with native overlay in starling and zoom pan work
_mLoader = new Loader();
var mRequest:URLRequest = new URLRequest("drawer.swf" + "?nf=" + getTimer());
_mLoader.contentLoaderInfo.addEventListener(flash.events.Event.COMPLETE, onCompleteHandler);
_mLoader.load(mRequest);
private function onCompleteHandler(loadEvent:flash.events.Event):void
{
_mLoader.contentLoaderInfo.removeEventListener(flash.events.Event.COMPLETE,
Starling.current.nativeOverlay.addChild(LoaderInfo(loadEvent.currentTarget).content);
}
And because the library touching the flash was weak i use above lib,and this is to Strong
first of all test above lib maybe that's work Without Starling
better GESTURE lib than flash lib
my zoom code with this lib
var _zoom:
_zoom = new TransformGesture(this);
_zoom.addEventListener(GestureEvent.GESTURE_BEGAN, onGesture);
_zoom.addEventListener(GestureEvent.GESTURE_CHANGED, onGesture);
private function onGesture(event:org.gestouch.events.GestureEvent):void
{
const gesture:TransformGesture = event.target as TransformGesture;
var matrix:Matrix = container_movieclip.transform.matrix;
if (container_movieclip.scaleX!=1 || container_movieclip.scaleY!=1)
{
matrix.translate(gesture.offsetX, gesture.offsetY);
container_movieclip.transform.matrix = matrix;
}
if (gesture.scale != 1)
{
var transformPoint:Point = matrix.transformPoint(container_movieclip.globalToLocal(gesture.location));
matrix.translate(-transformPoint.x, -transformPoint.y);
matrix.scale(gesture.scale, gesture.scale);
matrix.translate(transformPoint.x, transformPoint.y);
container_movieclip.transform.matrix = matrix;
}
}
I hope I could help
simply your issue solved if you changed multiinputMethod to touchpoint
Multitouch.inputMode=MultitouchInputMode.TOUCH_POINT;

Gettling starling to work with box2d and debugdraw with as3

This topic has been raised before, but not one of the examples I've found online seem to work for me! I am trying to get starling to work with box2d, and also for the box2d debugdraw.
I have tried a bunch of different methods, and my code is now a bit of a mess due to commenting out to try different mixes of the "solution". Does anyone know how to do all this properly? I would be greatly in dept if someone could explain it.
Here is the last attempt I tried:
In my Startup class:
package {
import flash.display.Sprite;
import flash.display.StageAlign;
import flash.display.StageScaleMode;
//import flash.events.Event;
import starling.core.Starling;
//import starling.display.Sprite;
import flash.events.Event;
[SWF(width="640", height="480", frameRate="60", backgroundColor="#000000")]
public class Startup extends Sprite {
public static var mStarling:Starling;
public static var debugSprite:Sprite;
public function Startup() {
//addChild ( new Stats() );
super();
//stage.align = StageAlign.TOP_LEFT;
//stage.scaleMode = StageScaleMode.NO_SCALE;
// create our Starling instance
mStarling = new Starling(Game, stage);
// set anti-aliasing (higher the better quality but slower performance)
mStarling.antiAliasing = 1;
mStarling.showStats = true;
// start it!
mStarling.start();
stage.stage3Ds[0].addEventListener(Event.CONTEXT3D_CREATE, onContextCreated);
}
private function onContextCreated(e:Event):void{
////debug mode
// debugSprite=new Sprite();
// //addChild(debugSprite);
// Starling.current.nativeOverlay.addChild(debugSprite);
//var debugSprite:Sprite=new Sprite();
addChild(debugSprite);
(mStarling.stage.getChildAt(0) as Game).DebugDraw(debugSprite)
}
I call the debugdraw like this:
debugDraw(Startup.debugSprite);
Here is a heavily commented out debugdraw:
private function debugDraw(debugSprite:flash.display.Sprite):void {
/*var worldDebugDraw:b2DebugDraw=new b2DebugDraw();
//var debugSprite:flash.display.Sprite = new flash.display.Sprite();
var debugSprite:Sprite = new Sprite();
addChild(debugSprite);
//mStarling.current.nativeOverlay.addChild(debugSprite);
//worldDebugDraw.SetSprite(debugSprite);
//debugDraw.SetSprite(Starling.current.nativeOverlay); //DOESN'T SEEM TO WORK
worldDebugDraw.SetDrawScale(worldScale);
worldDebugDraw.SetFlags(b2DebugDraw.e_shapeBit|b2DebugDraw.e_jointBit);
//worldDebugDraw.SetFillAlpha(0.0);
//worldDebugDraw.SetAlpha(0.0);
//visible
worldDebugDraw.SetFillAlpha(0.8); //for testing
worldDebugDraw.SetAlpha(1); //for testing
world.SetDebugDraw(worldDebugDraw);*/
var worldDebugDraw:b2DebugDraw = new b2DebugDraw();
worldDebugDraw.SetSprite(debugSprite);
world.SetDebugDraw(worldDebugDraw);
}
DebudDraw works with ONE classic Flash Sprite (you keep creating new ones for some reason). Only one b2DebugDraw should be created and set with that ONE Sprite.
Starling pretends to own the stage and all displaylist but it doesn't. Use simply your StartUp instance or even directly the stage itself without passing through Starling it will avoid some confusion.
The right way to do all this:
public var debugSprite:Sprite;//no static var
Starting what?
//don't start it!
mStarling.start();
You star something that cannot be started. At this point you are trying to create a valid Context3D so be patient. Remove that line.
Now in onContextCreated:
mStarling.start();//now you can start
debugSprite = new Sprite();//create your sprite
addChild(debugSprite);
var game:Game = mStarling.stage.getChildAt(0) as Game;//Game? somebody is following a tutorial ...
if(game)
{
game.setDebug(debugSprite);//this is a new public method to create in Game
}
In Game in method setDebug (with one parameter Sprite):
var worldDebugDraw:b2DebugDraw = new b2DebugDraw();
worldDebugDraw.SetSprite(myspriteparameter);
world.SetDebugDraw(worldDebugDraw);
That's it, don't create new Sprite, don't create new debugdraw, you are good to go that's all you need.

AS3: Add layer overlay on top of everything?

I want to add some extra texturing for my current game, let's say an overlayed grunge texture on top of everything.
My entire project (except background image) is set on a Main Class.
Is it Possible? How?
Screenshot:
Sure, just disable any mouse input on the overlay and it will be like its not even there.
public function LuckyHitBeta()
{
...
var overlay:Sprite = new Sprite();
overlay.addChild( /* your texture goes here as a Bitmap */ );
overlay.mouseEnabled = false;
overlay.mouseChildren = false;
addChild(overlay);
}
Cant entirely remember the correct syntax but couldn't you just do:
import flash.display.Stage;
public class GlobalStage extends MovieClip
public static var theStage:Stage;
public static var theRoot:MovieClip;
public function GlobalStage() {
theStage = this.stage;
theRoot = this.root;
}
var grunge:MovieClip = new Grunge();
var topDepth:uint = theStage.numChildren()-1;
theStage.addChildAt(grunge, topDepth)

how do I access the main class's stage? + Can I pass functions as arguments like this?

There are two files in my actionscript project named "TestAPP", TestAPP.as and Draggable.as
TestAPP.as:
package {
import flash.display.Sprite;
import flash.display.Stage;
public class TestAPP extends Sprite
{
var _mainStage:Stage;
public function TestAPP()//This is where we test the UI components.
{
var sp:Sprite = new Sprite();
_mainStage = stage;
_mainStage.addChild(sp);
sp.graphics.beginFill(0x00FF00);
sp.graphics.drawCircle(0,0,10);
sp.graphics.endFill();
sp.x = 50;
sp.y = 50;
var draggable1:Draggable = new draggable(sp,_mainStage,limitingfunc);
}
public function limitingfunc(x:Number,y:Number):int{
return 0;
}
}
}
And for the draggable.as:
package
{
import flash.display.Sprite;
import flash.display.Stage;
import flash.events.MouseEvent;
public class Draggable
{
private var _limitingFunc:Function;
private var _which:Sprite;
private var _MouseSavedX:Number;
private var _MouseSavedY:Number;
private var _stage:Stage;
public function Draggable(which:Sprite,stage:Stage,limitingfunc:Function)
{
_limitingFunc = limitingfunc;
_which = which;
_stage = stage;
_which.addEventListener(MouseEvent.MOUSE_DOWN,begin_drag);
}
//limiting func: returns 0 when the object is free to move that place.
//returns -1 when the user wants to block X coordinate changes (but maintain Y free)
//returns -2 when the user wants to block Y ...
//returns -3 or less when the user wants to block both X and Y from changing.
//returns
private function Return_0(x:Number = 0,y:Number = 0):int{
return 0;
}
private function begin_drag(ev:MouseEvent):void{
var xTo:Number = _stage.mouseX - _MouseSavedX + _which.x;
var yTo:Number = _stage.mouseY - _MouseSavedY + _which.y;
var limitingFuncReturnValue:int = _limitingFunc(xTo,yTo);
if(limitingFuncReturnValue == 0){//free to move.
_which.x = xTo;
_which.y = yTo;
}
else if(limitingFuncReturnValue == -1){//free to move Y
_which.y = yTo;
}
else if(limitingFuncReturnValue == -2){
_which.y = yTo;
}
//else:do nothing.
}
}
}
In "my actionscript theory", I'm supposed to see a circle that follows the mouse when I click it. (The draggable is not fully implemented) But the circle doesn't even budge :(
...I've been trying to figure out how to access the main class's stage property. I've googled for it, but still no progress.
Please help this helpless newb!!! I'll really appreciate your help:)
Thank you!
You're implementing your 2nd class as "draggable", when you named it (and it has to be named) "Draggable" with an upper case. Change it and see if that works. You seem to be passing in the parent classes stage correctly though.
If TestAPP is your document class. You can access to the stage thru the stage property (like your are doing in your example).
If TestAPP is not the document class, you should listen first to the ADDED_TO_STAGE event and then access to the stage property.
There is no need to add _mainStage property because you already have the stage property.
In order to move objects around, you need to use the ENTER_FRAME event.
You can access the main class' stage property the same way you do it for any DisplayObject on the stage: Use this.stage.
So just this should be enough:
var sp:Sprite = new Sprite();
stage.addChild(sp);
You could then pass the sprite and the main class' stage as a parameter, the way you did - but I would recommend creating a subclass Draggable extends Sprite and instantiate the whole thing using new Draggable() instead.
The new object will automatically have its own reference to stage as soon as it is added to the display list, and limitingFunc could be a member of Draggable, as well.
Also, you can use the startDrag() and stopDrag() methods, no need to implement your own: You can specify a Rectangle as a parameter to startDrag() to limit the permitted movement.
if you need it so much you may:
private static var _instance: TestAPP;
//...
public function TestAPP(){
_instance = this;
//...
}
public static function get instance():TestAPP{
return _instance;
}
public static function set instance(newVal: TestAPP):void{
_instance = newVal;
}
and you'll be able to reference its stage from any class where your TestAPP will be imported just with TestAPP.instance.stage.
but _instance is a property of the class TestAPP itself, not its instances

Actionscript: How do I rotate an external png image using a matrix?

Okay so I have two import pieces of code involved in this. This first tiny bit is what creates an object called OBJECT_arrow. It is located in the main function of my main class:
new OBJECT_arrow().CREATE(this,200,200);
It isn't really all that important. Now this next bit is the OBJECT_arrow class. What it does is loads an external png image and draws it.
package
{
import flash.net.URLRequest;
import flash.display.*;
import flash.system.*;
import flash.events.*;
import Math;
public class OBJECT_arrow extends Sprite
{
public var X:Number = 0; public var Y:Number = 0;
public var DEPTH:int = 0 ;
public var CONTAINER:Sprite = new Sprite();
public var imageLoader:Loader = new Loader();
public var image:URLRequest = new URLRequest ('ARROW.png');
public function CREATE(CONTAINER:Sprite,X:Number,Y:Number):void
{
this.X = X; imageLoader.x = this.X;
this.Y = Y; imageLoader.y = this.Y;
this.CONTAINER = CONTAINER;
CONTAINER.stage.addEventListener(Event.ENTER_FRAME,STEP);
imageLoader.load(image);
DRAW();
}
public function STEP(event:Event):void
{
DRAW();
}
public function DRAW():void
{
addChild (imageLoader);
(CONTAINER as MAIN).DRAW_LIST[(CONTAINER as MAIN).DRAW_LIST.length] = this;
(CONTAINER as MAIN).DRAW_LIST[(CONTAINER as MAIN).DRAW_LIST.length] = DEPTH;
}
}
}
Now I know the mathematics behind rotation and know to rotate before I translate and everything but I simply don't know how to apply the transformation to an external image in as3.
When you load an image with Loader it is stored as an object of type DisplayObject.
If you want it to be rotated, just set the rotation property.
To apply a matrix, you can use the transform() method of the DisplayObject.
You should also take a look at the BitmapData (raw image data) and Bitmap (DisplayObject to hold the BitmapData) classes. Depending on the complexity of what you're trying to do, they may serve you better. Specifically, BitmapData will allow you to lock() the image while you are fiddling with its bits. Flash won't render the BitmapData until you unlock() it, which can be a great performance improvement if you're doing a lot of fiddling.