Showing posts with label actionscript-3. Show all posts
Showing posts with label actionscript-3. Show all posts

Wednesday, March 1, 2017

What is causing this card to change dimensions? [Video & Code]

Leave a Comment

I am programming a board game in Starling (Action Script 3). The Starling version that I am using has a class called Sprite3D, which allows me to conveniently and easily code the flipping of the cards used in this game. I am troubled by the fact that my card changes dimension when flipped, and I cannot find the source of the change.

All help is appreciated.

The problem can be viewed on this youtube video.

The code can be seen in full on github at this github page.

I will continue here with more detail... All the following information is covered in the video.

The Card class contains no visual information. It is a controller class. It does hold two sprites. One sprite fills the front face, and the other sprite fills the back face. The Card class also has a mask applied and dimension attributes so that the faces will be of equal size and shape.

The Card class also holds the animation code. The code to animate the card is very similar to the code used in a video found on the starling blog that shows how Stage3D can be used implemented in a 2D game of Memory very quickly and easily. The Card class animates the rotation by using a tween to change the card's rotationY property from 0 to PI and from PI to 0 on touch events. The error occurs during the flipping process, so I will include the flipping code here:

public function flip() : void {     _state = !(this._state);     if( this.animations ){         var tween : starling.animation.Tween = new Tween( this, 2, starling.animation.Transitions.EASE_OUT_BOUNCE );         var card : Card = this;         var didFlip : Boolean = false;         tween.animate("rotationY", this._state == Card.FACE_UP ? Math.PI : 0 );         tween.onUpdate = updateVisibility;         Starling.juggler.add( tween );     } } private function updateVisibility():void {     var sHelper:Vector3D = new Vector3D();     var card : Card = this;     stage.getCameraPosition( card, sHelper );     if( sHelper ){         this._front_face.visible = sHelper.z < 0;         this._back_face.visible = sHelper.z >= 0;     } } 

The FrontFace and BackFace classes both derive from the class CardFace. The CardFace class takes a card as a reference and sets a mask equal to the size and shape of the card's mask. This is likely redundant, as the card's mask should mask all children DisplayObjects, but we do it anyway.

The BackFace has text, a logo, a texture and a color.

The FrontFace does nothing. It is subclassed with specific behaviors and will convert a data object into a display layout.

In this case, we are subclassing FrontFace with ProfileFrontFace. ProfileFrontFace takes the card object and a profile data object as constructor arguments. The card object is passed to CardFace via super() calls, and the profile object is saved for later use.

When the ProfileFrontFace is added to the stage, the class extracts the title, income, and expenses from the profile data object. It creates text fields for each of these items. It also calculates a cash flow and creates a text field for this value. A background is created using a PNG texture, which is a simple white square, that is stretched over the whole face of the card's dimensions. Over this white square, we apply a color texture. After it is created, the background image is not altered. The code appears as follows:

//we remove the event listener so this function code is only executed once this.removeEventListener( Event.ADDED_TO_STAGE, onAddedToStage ); var width : int = this.cardWidth; /* 400 */ var height : int = this.cardHeight; /* 300 */ var bg : Image = new Image( Game.assets.getTexture("blank") ); /* start the background in the top left */ bg.x = 0; bg.y = 0; /* have the background fill the card dimension space */ bg.width = width; bg.height = height; /* apply a color so that the background is not pure white */ bg.color = ColorScheme.OPAL; /* add the background to the stage */ this.addChild( bg ); 

In the rest of the function, we create the text and display it. I am not including that code here for simplicity. In testing, I have removed that code and seen that it has no impact on the peculiar behavior that changes the dimensions of the card when flipped to the front face.

Has anyone seen a case where masks on a Sprite3D fail to perform as a mask?

Has anyone seen cases where a mask fails to perform on a regular Sprite object?

What about the Tween.animate() method might cause strange behavior when Tween is used to change the value of "rotationY" on an object?

Any and all answers will help. Thank you!

1 Answers

Answers 1

FIXED!!!!! I found it!

I discovered that the problem was not the front face. I had applied a mask to the card itself, which was the Sprite3D object. That mask was causing problems. When I removed it, the BackFace (a Sprite Object) expanded to the same size as the front face, and now when I set the card dimensions, both faces have equal sizing.

I have updated the card dimensions to 400x250 to match the original BackFace layout, and now everything is working well.

Tip: Set your masks on the Sprite objects and not the Sprite3D objects, when possible. That keeps the 2D manipulations on the 2D objects.

Read More

Saturday, October 8, 2016

Build Android native library with Adobe Air

Leave a Comment

I'm currently working on an Android application built with Adobe Air sdk, in AS3. I was wondering if it's possible to compile a kind of UI library that I can import in a Android native application (Java). Basically, I would like to build my UI with Adobe Air, but the main part of my application with Java, the native way.

What I have in mind is to convert the adobe air-generated APK into a Jar file I would import in the native application project, and call some functions that display something on the Screen.

Is it possible? I think it may be possible, because when I don't import Adobe Air SDK in the application, I must install Adobe Air application with the Play Store to make my application working. I don't find lot of things on Google about that :s.

Thank you for your help.

3 Answers

Answers 1

Yes it can be done (in theory), but hold on to your hat, it's a bumpy ride!

I see it is a very old question, with a new bounty (the questioner has not logged on for 3 years!), but here we go...
This method goes to the heart of how android java apps are constructed and run (i.e. DEX, so it will work with adobe-air or ANYTHING, it is fundamental [general method]). (by the way you use the word native in a confusing way, native is commonly understood to mean the JNI (c++) library element of an app).
You say:

"What I have in mind is to convert the adobe air-generated APK into a Jar file I would import in the native application project, and call some functions that display something on the Screen."

Android programs are compiled into .dex (Dalvik Executable)[now called ART but binary compatible] files, which are in turn zipped into a single .apk file on the device (with other things like the manifest and resources). (unzip a .apk and look inside).

A .jar file contains DEX files (zipped). (unzip a compiled .jar and look inside).

I have done some work like this before, here's a link to a tutorial and coding examples [tested by me] (in android studio + gradle) [custom build elements are usually needed (I also give an ant example)].

See my stack-overflow answer Dynamic loading of DEX files

This in theory answers your question, but it's fundamental stuff, complex and has limitations that make it hard to code and maintain (resources are a real pain in the a**e).

Question: This all seems very complicated and hard !

Yes it is ! It is an increadably silly an difficult thing to do! That is why we invented cross platform frameworks, (and for web based code javascript/css/html5...). Failing that PORT the code.

Answers 2

I am not a Adobe AIR developer at all, however, I have developed a few Android App with both native environment and with some kind of framework (specifically PhoneGap). So, may this can help you.

I don't think that there would be any tool which could directly convert mobile apps build using frameworks like Adobe AIR, PhoneGap or any other HTML5 based framework to a native Android app because technically it is very difficult and unfeasible to do a proper mapping between each and every element of HTML5 (or Flex element in your case) to a corresponding native control or logic. The best you can do is use plugin mechanism provided by your framework to interact with Java and vice-versa and basically that is why the framework is there. For most of HTML5 based frameworks there is a plugin mechanism which allows developer to interact with native functionality (like Background Services, Activity or any other native resource). Even these frameworks are build using the same modular or plugin based approach and there major functionality (accessing Camera, Audio, SD Card etc native resources) works like this. We have to enable that feature before using that in our app.

So, look for plugin type of mechanism in Adobe AIR.

Hope this helps.

Answers 3

Maybe this is a dirty way to help you, but you can :

  1. Install the adobe air program in one computer
  2. Copy the files of the install folder of the adobe air program
  3. Embed all this files in the java application
  4. Install the java application
  5. Save the adobe air files in one folder
  6. Start the adobe air with java (like you will do it with the console, a simple call to YourAirApp.exe)
Read More

Sunday, March 27, 2016

get the raw data of mp3 file which is downloading with the `Sound` object

Leave a Comment

I have dynamically created Sound object

var     files:Object={}; files["file1"]={}; files["file1"]["snd"]=new Sound(); ...... //url etc files["file1"]["snd"].addEventListener(ProgressEvent.PROGRESS, onLoadProgress);   function onLoadProgress(event:ProgressEvent):void  //// somehow I need to get the raw data (first 48 bytes to be exact) of the mp3 file which is downloading now } 

I tried URLRequest in that fuction

var myByteArray:ByteArray = URLLoader(event.target).data as ByteArray; 

but with no success

It's just funny that such a simple thing as the file data is so hard to get

1 Answers

Answers 1

flash.media.Sound is a high level class that allows you to play a sound file in one line : new Sound(new URLRequest('your url')).play(); but does not provide public access to the data being loaded

The class will handle streaming for you (more precisely, progressive download)

If you need to access id3 data, just listen the Event.ID3 event:

var sound:Sound = new Sound("http://archive.org/download/testmp3testfile/mpthreetest.mp3"); sound.addEventListener(Event.ID3, onId3); sound.play(); function onId3(e:Event):void {     var id3:ID3Info = (e.target as Sound).id3;     trace(id3.album, id3.artist, id3.comment, id3.genre,         id3.songName, id3.track, id3.year); } 

If you really need to get the raw first 48 bytes and process them by yourself, but keep in mind you will have to deal with various mp3 formats id3/no id3, and work directly on binary data, instead of letting actionscript do the work for you. Assuming you don't want to download the mp3 file twice, you can either:

  • Load the mp3 file as ByteArray with URLLoader, read the 48 bytes manually, and load the Sound instance from memory, thus losing any progressive download ability. :

    var l:URLLoader = new URLLoader; l.dataFormat = URLLoaderDataFormat.BINARY; l.addEventListener(Event.COMPLETE, onComplete); l.load(new URLRequest("http://archive.org/download/testmp3testfile/mpthreetest.mp3")); function onComplete(e:Event):void {     //do whatever you need to do with the binary data (l.data)     // ...     // load sound from memory     new Sound().loadCompressedDataFromByteArray(l.data, l.data.length); 
  • You could also load use the Sound class in the classic way (to allow progressive download), and load independently the first 48 bytes with a URLStream, and close the stream ASAP (only onie packet of network overhead, plus you might get it from cache anyway) :

    var s:URLStream = new URLStream; s.addEventListener(ProgressEvent.PROGRESS, onStreamProgress); s.load(new URLRequest("http://archive.org/download/testmp3testfile/mpthreetest.mp3")); function onStreamProgress(e:ProgressEvent):void {     if (s.bytesAvailable >= 48) {         // whatever you need to do with the binary data: s.readByte()...         s.close();     } } 

I'm still curious to know why you would need those 48 bytes ?

EDIT: since the 48 bytes are supposed to be fed to MP3InfoUtil, you don't need to do anything particular, just let the lib do the work :

MP3InfoUtil.addEventListener(MP3InfoEvent.COMPLETE, yourHandler); MP3InfoUtil.getInfo(yourMp3Url); 
Read More