Can I assign a getter function to a variable in AS3? - actionscript-3

I can do
function yea ():int {
...
}
var cool:Function=yea;
I don't know how to do something like
function get wat ():int {
...
}
var mmmh:Function=wat; // this (tries to) assign the wat returned value

Well, the only way I know is capturing getter/setter references from inside of them with arguments.callee. But that's a rather weird thing to do. :)
package
{
import flash.display.Sprite;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.utils.getTimer;
public class GetterTest extends Sprite
{
private var getterRef:Function;
private var setterRef:Function;
private var testValue:int = 0;
public function GetterTest()
{
stage.addEventListener(MouseEvent.MOUSE_DOWN, onMouseDown);
}
private function onMouseDown(event:Event):void
{
if (getterRef != null) {
setterRef(getTimer());
trace("references: test = ", getterRef());
} else {
test = getTimer();
trace("direct: test = ", test);
}
}
private function get test():int
{
trace("TEST! getter");
getterRef = arguments.callee;
return testValue;
}
private function set test(value:int):void
{
trace("TEST! setter");
setterRef = arguments.callee;
testValue = value;
}
}
}
While the above works, I think the correct answer to your question is "don't". :)

you could save the name of the getter as a string var fn:String = "wat" and then use it later to retrieve the return value of the method with myObjectFromClass[fn].

I am not sure what is that you are trying to accomplish.
If you just want to keep a reference to the getter, you could just wrap it in a closure function.
var mmh:Function = function():int { return wat; };

Related

Facebook abobe as3 api for air for mobile

I am planing a project that involves a cross platform (Android and I.O.S) mobile app that logs in using Facebook. I have no experience with the face book API and cant find any use full material for newbies. I want to use air for its cross platform capabilities so want to avoid multiple solutions for each platform. I have done many searches for help but haven't found much. Can any of you point me to resources you found use full starting off with this sort of thing.
The AS3 Facebook API is all you need. ( http://code.google.com/p/facebook-actionscript-api/ ) Maybe you will have to change a few things (like the JSON methods in there) but otherwise it seems to work alright. You can download several examples from there as well, you can see the usage for different types of environment.
Also, read this article from Tom Krcha http://www.adobe.com/devnet/games/articles/getting-started-with-facebooksdk-actionscript3.html
If you have more specific questions, ask. This one is too generic.
EDIT:
Here is a class I wrote some time ago for a small project
package com.company.social {
import com.facebook.graph.FacebookMobile;
import com.company.AppConst;
import com.company.IDestroyable;
import com.company.Main;
import com.company.displayassets.WebViewCloseStripe;
import com.company.events.FacebookControllerEvent;
import com.company.events.TwitterControllerEvent;
import flash.display.BitmapData;
import flash.display.PNGEncoderOptions;
import flash.display.Sprite;
import flash.display.Stage;
import flash.events.EventDispatcher;
import flash.events.MouseEvent;
import flash.geom.Rectangle;
import flash.media.StageWebView;
import flash.utils.ByteArray;
import flash.utils.clearTimeout;
import flash.utils.setTimeout;
public class FacebookController extends EventDispatcher implements IDestroyable {
private static const APP_ID:String = "1234512345"; // Your App ID.
private static const SITE_URL:String = "some_url";
//Extended permission to access other parts of the user's profile that may be private, or if your application needs to publish content to Facebook on a user's behalf.
private var _extendedPermissions:Array = ["publish_stream","user_website","user_status","user_about_me"];
private var _stage:Stage;
private var _webView:StageWebView;
private var _topStripe:WebViewCloseStripe;
private var _activity:String;
private var _timeoutID:uint;
public static const ACTIVITY_LOGIN:String = "login";
public static const ACTIVITY_POST:String = "post";
public function FacebookController(stage:Stage) {
_stage = stage;
init();
}
private function init():void {
_activity = ACTIVITY_LOGIN;
startTimeout();
FacebookMobile.init(APP_ID, onHandleInit, null);
}
private function onHandleInit(response:Object, fail:Object):void {
if (response) {
stopTimeout();
dispatchEvent(new FacebookControllerEvent(FacebookControllerEvent.LOGIN_COMPLETE));
//FacebookMobile.api("/me", handleUserInfo);
}
else {
/*trace("no response, login -->");
for(var prop in fail["error"]) {
trace(prop+": "+fail["error"][prop]);
}*/
loginUser();
}
}
private function startTimeout():void {
trace("timeout start");
clearTimeout(_timeoutID);
_timeoutID = setTimeout(timeout, AppConst.TIMEOUT_TIME);
}
private function timeout():void {
trace("timed out");
clearTimeout(_timeoutID);
dispatchEvent(new FacebookControllerEvent(FacebookControllerEvent.TIMEOUT));
}
private function stopTimeout():void {
trace("timeout stop");
clearTimeout(_timeoutID);
}
private function loginUser():void {
stopTimeout();
_topStripe = new WebViewCloseStripe();
_topStripe.getCloseButton().addEventListener(MouseEvent.CLICK, closeClickHandler);
_stage.addChild(_topStripe);
_webView = new StageWebView();
_webView.viewPort = new Rectangle(0, _topStripe.height, _stage.fullScreenWidth, _stage.fullScreenHeight - _topStripe.height);
FacebookMobile.login(handleLogin, _stage, _extendedPermissions, _webView);
}
private function handleLogin(response:Object, fail:Object):void {
if(_topStripe) {
_topStripe.getCloseButton().removeEventListener(MouseEvent.CLICK, closeClickHandler);
_topStripe.destroy();
_stage.removeChild(_topStripe);
_topStripe = null;
}
if(_webView) {
_webView = null;
}
if(response) {
dispatchEvent(new FacebookControllerEvent(FacebookControllerEvent.LOGIN_COMPLETE));
//FacebookMobile.api('/me', handleUserInfo);
}
else {
dispatchEvent(new FacebookControllerEvent(FacebookControllerEvent.LOGIN_ERROR));
}
}
private function closeClickHandler(e:MouseEvent):void {
dispatchEvent(new FacebookControllerEvent(FacebookControllerEvent.CLOSE));
}
private function handleUserInfo(response:Object, fail:Object):void {
if (response) {
for(var prop in response) {
trace(prop+": "+response[prop]);
}
}
}
private function handleUploadImage(result:Object, fail:Object):void {
stopTimeout();
if(result) {
dispatchEvent(new FacebookControllerEvent(FacebookControllerEvent.POST_COMPLETE));
}
else {
dispatchEvent(new FacebookControllerEvent(FacebookControllerEvent.POST_ERROR));
}
}
public function postWithImage(message:String, imageData:BitmapData):void {
_activity = ACTIVITY_POST;
var byteArray:ByteArray = imageData.encode(new Rectangle(0, 0, imageData.width, imageData.height), new PNGEncoderOptions());
var params: Object = new Object;
params.image = byteArray;
params.fileName = "image.png";
params.message = message;
startTimeout();
FacebookMobile.api("/me/photos", handleUploadImage, params, "POST");
}
public function reset():void {
FacebookMobile.logout(handleReset, SITE_URL);
}
public function handleReset(response:Object):void {
dispatchEvent(new FacebookControllerEvent(FacebookControllerEvent.RESET));
}
public function destroy():void {
if(_webView) {
_webView.dispose();
_webView = null;
}
if(_topStripe) {
_topStripe.getCloseButton().removeEventListener(MouseEvent.CLICK, closeClickHandler);
_topStripe.destroy();
_stage.removeChild(_topStripe);
_topStripe = null;
}
_stage = null;
}
}
}
Alternatively you can use a native extension like this:
http://www.milkmangames.com/blog/tools/#iosgv
There are free versions from other publishers available as well.

as3 - figure out the variable type from an empty variable

Is it possible to figure out the variable type when the variable isn't instantiated?
Example of what I'm trying to accomplish:
var foo:ExampleOne;
var bar:ExampleTwo;
var arr:Array = [foo, bar];
for each(var myVar:Object in arr)
{
myClass = new getDefinitionByName( getQualifiedClassName( myVar ) ) // doesn't work
}
No, because the variables are a reference to objects that are not created in the vm until you create them using the "new" keyword. So until you do this, the references (foo/bar etc) will always be null no matter what operation you're running on them.
I don't know what do you want to do, but you could may be use describeType :
package
{
import flash.display.Sprite;
import flash.text.TextField;
import flash.utils.ByteArray;
import flash.utils.describeType;
import flash.utils.getDefinitionByName;
public class TestTextfield extends Sprite
{
public var foo:TextField;
public var bar:ByteArray;
public function TestTextfield()
{
var arr:Array = ["foo", "bar"];
for each(var myVar:String in arr)
{
var varClass : String = describeType(this)..variable.(#name == myVar).#type.toString();
var myClass : * = new (getDefinitionByName(varClass) as Class)
}
}
}
}
Try to use the "className" property.
It should return "TextInput", "Button", etc... depending the case
for each (var item:* in myArray)
{
if(item.hasProperty('className'))
{
trace("item ["+i+"] is :" + item['className']);
}
}
maybe you want to do something like this ?
var a:Class = MyClassA; //put a reference to a Class object into 'a' variable
var b:Class = MyClassB;
var classes:Array = [a,b];
for each(var classObj:Class in classes){
var objInstance : * = new classObj()
}

ActionScript 3 custom "call-later" almost working, expert wanted!

I have this class ('Scheduler.as'):
package
{
import flash.events.TimerEvent;
import flash.utils.Timer;
public class Scheduler
{
private var m_tmr:Timer = null;
private var m_the_this:* = null;
private var m_function:Function = null;
private var m_args:Array = null;
public function Scheduler(the_this:*, f:Function, interval:int, args:Array = null)
{
this.m_the_this = the_this;
this.m_function = f;
this.m_args = args;
if (this.m_args.length == 0)
this.m_args = null;
this.m_tmr = new Timer(interval, 1);
this.m_tmr.addEventListener(TimerEvent.TIMER, on_timer);
this.m_tmr.start();
}
private function on_timer(e:TimerEvent):void
{
if (this.m_args == null)
this.m_function.call(this.m_the_this);
else
this.m_function.call(this.m_the_this, this.m_args);
}
public static function schedule_call(the_this:*, f:Function, interval:int, ...args):Scheduler
{
return new Scheduler(the_this, f, interval, args);
}
}
}
And here's an AS3 FlashDevelop app that uses it ('Main.as'):
package
{
import flash.display.Sprite;
import flash.events.Event;
public class Main extends Sprite
{
public function Main():void
{
if (stage) init();
else addEventListener(Event.ADDED_TO_STAGE, init);
}
private function init(e:Event = null):void
{
removeEventListener(Event.ADDED_TO_STAGE, init);
// entry point
Scheduler.schedule_call(this, this.test_func_NO_PARAMS, 0);
Scheduler.schedule_call(this, this.test_func_ONE_PARAM, 0, 123);
Scheduler.schedule_call(this, this.test_func_TWO_PARAMS, 0, "HELLO", "WORLD");
}
private function test_func_NO_PARAMS():void
{
trace("No params was called successfully!");
}
private function test_func_ONE_PARAM(some_number:int):void
{
trace("One param was called successfully! 'some_number' = " + some_number);
}
private function test_func_TWO_PARAMS(stringA:String, stringB:String):void
{
trace("Two params was called successfully! 'stringA' = " + stringA + ", 'stringB' = " + stringB);
}
}
}
So as you see in your test-run the first two calls work fine, the one that calls a function that takes no parameters and the one that takes one parameter.
The problem is when I need to pass more than one parameter!
Solving the issue:
Well, I know it'd be solved if I could simply retain the ...args as is, and pass it on to the this.m_function.call call.
Another way, maybe is to have some sort of a foreach loop which would feed the designated ...args when the time comes, yet again, how would I refer/pass it?
There must be a nice trick here to make it work, you're welcome to sweat with me on this one!
Try changing this line:
this.m_function.call(this.m_the_this, this.m_args);
to this:
this.m_function.apply(this.m_the_this, this.m_args);
apply passes the parameters to the applied function as a list instead of a single array (the same effect as if you wrote the_function(arg[0],arg[1],arg[N])).
Edit:
Maybe I'm not understanding your problem, but this simplified sample of your code works fine (I'm not using a Timer and I'm not building any instance but I think the main thing here is how apply works; taking an array of parameters and passing them as a list of variable parameters to the invoked function):
private function arg0():void {
trace("arg0");
}
private function arg1(a:*):void {
trace("arg1");
}
private function arg2(a:*,b:*):void {
trace("arg2");
}
private function arg3(a:*,b:*,c:*):void {
trace("arg3");
}
private function test():void {
schedule_call(this,arg0,10);
schedule_call(this,arg1,10,1);
schedule_call(this,arg2,10,1,2);
schedule_call(this,arg3,10,1,2,3);
}
public function schedule_call(the_this:*, f:Function, interval:int, ...args):void
{
var m_args:Array = args;
f.apply(the_this, m_args);
}

Error #1034, with a MouseEvent

I am making a basic point n' click game and I came upon this error:
TypeError: Error #1034: Type Coercion failed: cannot convert 3 to cem.mouvement.
Here's my script:
package cem {
import flash.events.Event;
import flash.display.MovieClip;
import cem.microjeux.events.InfoJeuEvent;
import cem.mouvement;
import flash.events.MouseEvent;
public class monterJeu extends MovieClip
{
private static var pType:String = "type";
private static var pNom:String = "testNom";
private static var pCourriel:String = "test#hotmail.com";
private static var pDifficulte:int = 0;
private static var pLangue:int = 0;
private static var pTitre:String = "Veuillez sortir";
private static var pVersion:String = "1.5";
private static var pCoordonnees:Number;
private var environnementJeu:environnement = new environnement();
private var personnageJeu:personnage = new personnage();
public function monterJeu():void
{
jouer(pNom,pDifficulte,pLangue);
dispatchEvent(new InfoJeuEvent(pType,pNom,pCourriel,pTitre,pVersion));
stage.addEventListener(MouseEvent.CLICK, test);
}
public function jouer(PNom:String,PDifficulte:int,PLangue:int):void
{
addChild(environnementJeu);
addChild(personnageJeu);
}
function test(e:MouseEvent){
pCoordonnees = stage.mouseX;
trace(pCoordonnees);
mouvement(3);
}
}
}
And on mouvement();
package cem
{
public class mouvement {
public function mouvement(blabla) {
trace(blabla);
}
}
}
I searched everywhere I could, and didn't find anything. I have no instances on the stage. Everything is imported on the first frame. I am kind of a beginner (let's say i'm no good at programming), so you can notify at the same time if you something that needs to be corrected. (BTW, the strange words are in french ;D)
Thanks!
The error is due to you trying to cast 3 to mouvement.
I think what you want is something like
function test(e:MouseEvent){
pCoordonnees = stage.mouseX;
trace(pCoordonnees);
var mouve:mouvement = new mouvement(3);
}
Notice that you have to have new in order to create a new instance of a class.
On another note, you should capitilize classes so they stand out better. So I would name the class Mouvement.
You are trying to cast 3 to the class mouvement into the test function:
function test(e:MouseEvent){
pCoordonnees = stage.mouseX;
trace(pCoordonnees);
new mouvement().mouvement(3); // <-- here your error
}
If you have only a function into your class you don't need to create a class but you can put on the function alone:
package cem
{
public function mouvement(blabla):void {
trace(blabla);
}
}
and now you can call the mpuvement function normally into you test function:
function test(e:MouseEvent){
pCoordonnees = stage.mouseX;
trace(pCoordonnees);
mouvement(3);
}

In ActionScript 3, tracing all properties of a value object

I have a number of value objects and I want to be able to create a function within it to trace out the properties and the values without specifying them directly. It will allow me to use the same code in all value objects as opposed to referring to variables within the value object. Ideally, I would like to replace the code in blogURLVars with this code.
Here's a sample value object
package items {
public class Blog {
private var _itemID:uint;
private var _blogTitle:String;
private var _blogText:String;
private var _blogCreated:String;
private var _blogCategory:String;
private var _blogFrontpage:Boolean;
public function Blog (itemID:uint,blogTitle:String,blogText:String,blogCategory:String,blogCreated:String,blogFrontpage:Boolean=false) {
_itemID = itemID;
_blogTitle = blogTitle;
_blogText = blogText;
_blogCreated = blogCreated;
_blogCategory = blogCategory;
_blogFrontpage = blogFrontpage;
}
public function get itemID():uint {
return _itemID;
}
public function get blogTitle():String {
return _blogTitle;
}
public function get blogText():String {
return _blogText;
}
public function get blogCategory():String {
return _blogCategory;
}
public function get blogCreated():String {
return _blogCreated;
}
public function get blogFrontpage():Boolean {
return _blogFrontpage;
}
public function toString():void {
}
public function blogURLVars():String {
var s:String;
s = "itemID="+ _itemID;
s += "blogTitle="+ _blogTitle;
s += "blogText="+ _blogText;
s += "blogCategory="+ _blogCategory;
s += "blogCreated="+ _blogCreated;
s += "blogFrontpage="+ _blogFrontpage;
return s;
}
}
}
DescrybeType could be of help here. I'm basing this answer in this other answer (you might want to check it out): Fastest way to get an Objects values in as3
Basically, the describeType function will let you inspect the public interface of your object. That means public variables, getter/setters and methods (plus some other info not relevant to your problem). So you get a list of all the getters and with that, return the names of said properties plus their actual values for a given object. Not that this is not exactly the same as your sample code, since this will not use the private variables, but rather will call the getters.
In code, this could be something like this (based on code in the linked question).
package {
import flash.net.URLVariables;
import flash.utils.describeType;
import flash.utils.getQualifiedClassName;
public class PropertiesHelper {
public function PropertiesHelper() {
}
private static var typePropertiesCache:Object = {};
public static function getPropertyNames(instance:Object):Array {
var className:String = getQualifiedClassName(instance);
if(typePropertiesCache[className]) {
return typePropertiesCache[className];
}
var typeDef:XML = describeType(instance);
trace(typeDef);
var props:Array = [];
for each(var prop:XML in typeDef.accessor.(#access == "readwrite" || #access == "readonly")) {
props.push(prop.#name);
}
return typePropertiesCache[className] = props;
}
public static function getNameValuePairs(instance:Object):URLVariables {
var props:Array = getPropertyNames(instance);
var vars:URLVariables = new URLVariables();
for each(var prop:String in props) {
vars[prop] = instance[prop];
}
return vars;
}
}
}
Use:
var blog:Blog = new Blog(1,"title&","text","cat","created");
var urlVars:URLVariables = PropertiesHelper.getNameValuePairs(blog);
trace(urlVars);
I'm using a URLVariables object since it seems that's what you want (though not actually what you blogURLVars method does), but you could change that in the getNameValuePairs method to suit your needs if necessary. An advantage of using a URLVariables object is that it handles the url-encoding for you automatically, so reserved characters such as &, =, etc, should not be a problem.