Why initWithSpriteFrameName() and initWithFile() have different effect on Sprite? - cocos2d-x

I need a shatter effect, I can init my sprite with these two different methods successfully, but the shatter effect is different.
The Effect I use initWithFile()
The Effect I use initWithSpriteFrameName()
(Ignore the text in the images, the below is the code)
bool ShatterSprite::init(const string &texFileName, float gridSideLen, GameTextureResType resType)
{
m_gridSideLen = gridSideLen;
switch (resType) {
case PLIST:
Sprite::initWithSpriteFrameName(texFileName); //sprite Frame
break;
case LOCAL:
Sprite::initWithFile(texFileName);
break;
default:
CCASSERT(0, "no here");
break;
}
createShatter();
return true;
}
The method I use initWithSpriteFrameName cannot get the effect I need, somebody can tell me the reason?

initWithSpriteFrameName requires frame name and initWithFile requires file name. You are sending same in both. file means actual file on disk and frame means the frame name you have cached in memory. From following code you can add Frames in memory
SpriteFrameCache* cache = SpriteFrameCache::getInstance();
cache->addSpriteFramesWithFile("animations/grossini.plist");

Related

Flash AS3 Need help handling animations by script

Im trying to get a better solution for animating images like fade in slide to another location bump to another location fade out , bring in a new image, fade in, teleport to other location, let it fall down, slide out.
im in a learning progress of getting advanced with classes and my setup is like the following:
1 imgSheet, 1 tweenclass, 1 displayclass, 1 timerclass
so the display creates holderSprites, creates a bitmap out of the imagesheet and places it in the currentholderSprite, than the displayclass activates a animation function that animates the holder by triggering timers and tweens in those classes.
i understand using a timeline would be a easyer solution but this is for script learning purpose.
now my question is: Are there better solutions to handle this kind of animations and data passing other than using switch statements for everything. for example could i pass a tweenvar and timervar to the classes?
if i did so how do i have to handle that variables change them and recall the functions so it becomes a animation?
simple example in script:
i send this to the bitmap creater:
var rCutKongregate:Rectangle=new Rectangle(0,0,400,400);
the bitmap creater makes it a bitmap and places it in a sprite:
public function displayImage(rn:Rectangle, o:Object):void
{
var imgSourceFile:BitmapData=new spriteSheet ;
var imgHolderData=new BitmapData(400,400,true,0x666666);
var rCut:Rectangle=rn;
var pCut:Point=new Point(0,0);
imgHolderData.copyPixels(imgSourceFile, rCut, pCut);
var imgHolder:Bitmap=new Bitmap(imgHolderData);
currentTempSprite.addChild(imgHolder);
}
this is how the animation triggers timers/tweens
switch (loopNumber)
{
case 2 : timersHandling("07"); break;
case 4 : tweensHandling("04"); break;
}
public function tweenHandling(s:String)
{
switch (s) {
case "01" :var sFOTween:Tween=new Tween(object,"alpha",
Strong.easeInOut,1,0,2,true); trace("tween1 started");break;
case "02" :var sFITween:Tween=new Tween(object,"alpha",
Strong.easeInOut,0,1,2,true); trace("tween2 started");break;
public function timersHandling(s:String)
{
var timer01:Timer = new Timer(1000, 1);
var timer02:Timer = new Timer(2000, 1);
var timers:Array = new Array();
timers.push({Object:timer01, name:"timer01"});
timers.push({Object:timer02, name:"timer02"});
switch (s) {
case "01" : timer01.start(); break;
case "02" : timer02.start(); break;
well as you might understand making animations manualy by triggering functions in such a way is prob the most amature way you could do it so help will be welcome.
"Can you pass a tweenvar and a timervar to classes?" - yes, and you should make so that you don't have to track either variable after assignment. "Using a timeline could be an easier solution" - no, although for self-contained objects (that don't contain controls, referenced parts and code) a timeline animation is acceptable. And third, you are hardcoding too much in your code. You can instead use an array of them tweens, triggering and eliminating them as necessary. Indeed, you might want to look at any tween framework, Greensock, TweenMax, TweenIO and probably there are others, they have source code available for study and use, so you can find out how are they working inside.
I'm not clear exactly what you want to see happen but this can probably be done very simply with the greensock tween classes.
see: http://greensock.com/tweenmax

How to make a stick man running when pressing a key?

I created a movieclip named stickman. In that, I created an animation by drawing a sequence of move in everyframe, so that stickman can run. Now what I want is that when I press a key, the stick man will run from left to right and when I release the key, it will stop. This is my code:
RunningMan.stop();
stage.addEventListener(KeyboardEvent.KEY_DOWN,keypresseddown);
function keypresseddown(event:KeyboardEvent):void
{
var key:uint = event.keyCode;
switch (key) {
case Keyboard.LEFT :
{
RunningMan.play();
RunningMan.x-=10;
RunningMan.scaleX=-1;
if(RunningMan.x<=0)
{
RunningMan.x=0;
}
};
case Keyboard.RIGHT :
{
RunningMan.play(); //play animated run
RunningMan.x+=10;
RunningMan.scaleX=1;
if(RunningMan.x>=stage.width)
{
RunningMan.x=stage.width;
}
};
default: RunningMan.stop();
}
}
However, when I pressed and held a key, it moved from left to right without animated run.
How can I fix it?
Thanks in advance.
EDIT:
I have a movieclip called character containing 3 movieclip named: standing, running and jumping, respectively. When I pressed up arrow key, it would jump, but if I released the key right away, it did not jump high as the jump movieclip could not finish its frames. This is the code:
if (key.isDown(Keyboard.LEFT))
{
gotoAndStop("running");
BGround.x+=speed;
scaleX=-1;
if(BGround.x>=stage.stageWidth)
BGround.x=stage.stageWidth;
}
else if (key.isDown(Keyboard.RIGHT))
{
gotoAndStop("running");
BGround.x -= speed;
scaleX=1;
}
else
if (key.isDown(Keyboard.UP))
{
gotoAndStop("jumping");
}
else
gotoAndStop("standing");
How can I fix that?
First of all, I hope RunningMan is an instance of the class, not the class itself. And if it is an instance, you should really follow common naming conventions for when you share your code with others (like you are doing now) so it would be runningMan.
So 1st, make the 1st frame of the runnigMan's timeline a picture of the man standing still and name it "still" or something. then name the second "running" and extend that like 20 frames or however long your animation is. at the last frame you will have to use timeline code. just one line of gotoAndPlay("running") will cause those frames of 2 to 20 (or whatever) to loop. When you tell the timeline to go to frame 1 from outside the timeline code, it wont loop anymore and will stay on the frame of the man standing still. So from outside when you want the loop to start:
runningMan.gotoAndPlay("running"); // frame 2
To stop:
runningMan.gotoAndStop("still"); // frame 1
Or you could do it from inside the RunningMan class
public function startRunAnimation():void{
this.gotoAndPlay("running");
}
public function stopRunAnimation():void{
this.gotoAndStop("still");
}
And you could use them just by replacing these function names with the ones you have if your code ex( instead of play() it would be startRunAnimation() )
EDIT
What you could do for this problem is to have a boolean variable for when your character is in the air (somewhere in your code where you do collision detection with the ground or where you handle gravity - however it is set up) so that this part of your code know when your character is in the air. And then you could simple test for this however way you need it.
...
if (key.isDown(Keyboard.UP) || this.inAir==true)
{
gotoAndStop("jumping");
}
else
gotoAndStop("standing");
Although if your character does not inheirt from a collidable object that has gravity, friction etc... then you would have to make the inAir property of whatever other class, public or make getter function for it - so that you can access it here. I hope this helps.

A function that deletes an instance by removing it from stage and nulling it does not remove it from memory

I have an issue with a function I use to delete an instance and replace it with another. Basically, it keeps the item in memory no matter what. Inside the object I have weak listeners and I null everything after it gets removed, but the function I run to check if it is still active tells me that it is (just an Event.ENTER_FRAME tracing some text, with a weak link).
Even when I removed everything from the instances I am loading, it still seems to stay in memory, according to my trace it still is. How do I completely delete something from memory more thoroughly than nulling it out after removing it from the stage? Am I not seeing something?
This is the function:
private function loadArea(inputArea:String)
{
//This is for a checker to make sure that areas only get loaded once.
currentRoom = inputArea;
//If the area currently loaded is not null, make it null now.
if(selectedArea != null) selectedArea = null;
//Null any data inside of the reference used to create the name of the new area.
areaReference = null;
//Grab the class using the input.
areaReference = getDefinitionByName(inputArea + "Area") as Class;
//Null the sprite used to house the class
areaSprite = null;
//Set the holder as a new instance of the desired class.
areaSprite = new areaReference() as Sprite;
//If the selected area is still not null for some reason,
if(selectedArea != null)
{
//Remove the area from the container...
areaContainer.removeChild(selectedArea);
//...and nullify it.
selectedArea = null;
}
//Set the current area as the newly created instance.
selectedArea = areaSprite;
//If the area is not the "Game", load in the assets one way,
if(inputArea != "Game") selectedArea.construct(areaAssets);
//otherwise do it another way.
else selectedArea.construct(newScreenData,apiServer,cdnServer,areaAssets);
//This is for a checker that fades out the screen, which it needs to fade back in soon.
newScreenData = null;
//While the container for areas has any areas inside of it, remove them.
while(areaContainer.numChildren) areaContainer.removeChildAt(0);
//...then add the new instance area to the container.
areaContainer.addChild(selectedArea);
//...then let all the parts of the game know that a new area has been laoded in.
Global.echoEvent.echo("gameBootUp","playAreaIn");
}
The memory is actually released when Garbage Collector will find and erase an orphaned instance of yours. Before that, your memory usage will state there is an instance in memory. There is no way to force garbage collection, calling System.gc() only "instructs" Flash to run it, it might not obey. So, you have done what you had to, let it be.
Removing all references including stage and nulling an object is all it takes to free up memory.
If the object is not being released then you are missing something or doing something incorrectly or out of sequence.
Carefully go through your code, making sure you identify where objects are being referenced so you can remove them.
Looking at your example code:
if(selectedArea != null) selectedArea = null;
Here you are making sure that the selectedArea is null.
But immediately after you are testing selectedArea again
(you know it is null so this block is never used)
if(selectedArea != null){
//Remove the area from the container...
areaContainer.removeChild(selectedArea);
//...and nullify it.
selectedArea = null;
}
In every language its VERY DIFFICULT to "clear" memory... even HTML. That being said... try to reduce your memory footprint.
Correct Null:
1. remove all event listeners
2. remove all children
3. remove all mapped/referenced methods/parameters
4. set the class object to null
In most cases this is all you need to do, the WAY you do it will determine if the object gets cleared. Consider the following situation.
You have a custom sprite class (MEMORY FOOTPRINT #1) that has a mapped property (mapping happen when one class object references another). Once you map/reference one object to another = MEMORY FOOTPRINT #2. Adding events = MEMORY FOOTPRINT #3, etc and so on.
Custom Sprite
import flash.display.Sprite;
class CustomSprite extends Sprite{
private var _mappedProperty:Object;
public function addMapping(map:Object):void{
_mappedProperty = map;
}
public function finalize():void{
_mappedProperty = null;
}
}
Assuming we're using CustomSprite in many other methods, lets look at some common ways of removing the ojbect.
INCORRECT - in this situation [objToRemove] was not set to null to free its memory:
var objToRemove:CustomSprite = new CustomSprite;
function doSomething(referenceObj:CustomSprite):void{
var methodObj:CustomSprite = referenceObj;
//CRAZY LINES OF CODE
methodObj = null; //frees memory from [doSomething::methodObj]
referenceObj = null; //frees memory from [doSomething::referenceObj]
//objToRemove is not cleared and will remain in memory
}
INCORRECT - in this situation [objToRemove] has a reference object so it will not clean until the reference is removed:
var objToRemove:CustomSprite = new CustomSprite;
var mappedObject:Sprite = new Sprite;
objToRemove.addMapping(mappedObject);
objToRemove.addEventListener(Event.ENTER_FRAME,onEnterFrame);
//CRAZY LINES OF CODE
//remove all children
while(objToRemove.numChildren > 0){
objToRemove.removeChildAt(0);
}
//remove all event listeners
objToRemove.removeEventListener(Event.ENTER_FRAME,onEnterFrame);
//this will NOT work
objToRemove = null;
//reason is objToRemove has a reference object of [mappedObject]
//[mappedObject] is not a child so it needs to be removed manually
//from WHITIN the CustomSprite class using [CustomSprite::finalize()]
Ok... breath... the correct way is actually simple.
CORRECT - here we are using [Dynamic] objects rather than [Static] class objects, this is considered Object Mapping:
//think of this as a global list of objects
var objPool:Dictionary = new Dictionary;
//create a pool reference
objPool['poolObj'] = new CustomSprite;
//CRAZY LINES OF CODE;
//do the normal [null] process
//both of these will work
objPool['poolObj'] = null;
//or
delete objPool['poolObj'];
SUPER ADVANCED CORRECT - no example provided, I have to get back to work lol...
1. Take a ByteArray clone of the class
2. User a Loader to construct the ByteArray as the class, rather than using "new"
3. When finished... unload/remove the loader
4. EVERYTHING will clear... thats how a Loader works!
(Not getting into why and how... too long of an explanation)
Although this works flawlessly... its not generally accepted or suggested in a work environment.

Can't get a working progress bar for file download AS3

I'm currently enrolled in an ActionScript course, and cannot seem to get my progress bar to work correctly. We were tasked with creating a simple image loader application, which would access externally hosted images (through use of a PHP proxy script), and then spit the image onto the user's screen (with a progress event and progress bar to track the image's download progress).
However, when I run it, I get these mysterious black graphical glitches everywhere, as well as a non-functioning progress bar. In some browsers I get the following error: "ArgumentError: Error #2109: Frame label NaN not found in scene NaN. at flash.display.MovieClip/gotoAndStop() at Document/imageLoadProgress().
Here is my code - I cant for the life of me figure out what is wrong. I figure it has something to do with the imageLoadProgress() function, or my progress bar (which is just a simple 100-frame movie clip with a motion tween and a "stop()" command at the beginning).
public function loadImage()
{
var imageURL:String = imageArray[currentImageIndex];
if(loaderInfo.url.substr(0,4) == "http")
{
trace("we're online");
//use the proxy script
//escape() will replace spaces in file names with %20
imageURL = "./image_proxy.php?filename=" + escape(imageArray[currentImageIndex]);
}
var imageRequest:URLRequest = new URLRequest(imageURL);
this.imageLoader.contentLoaderInfo.addEventListener(IOErrorEvent.IO_ERROR, this.imageIOError);
this.imageLoader.contentLoaderInfo.addEventListener(ProgressEvent.PROGRESS, this.imageLoadProgress);
this.imageLoader.contentLoaderInfo.addEventListener(Event.COMPLETE, this.imageLoadComplete);
this.imageLoader.load(imageRequest);
//end loadImage
}
public function imageIOError(e:Event)
{
trace("ImageIOError called. Error=" + e);
//end imageIOError
}
public function imageLoadProgress(e:ProgressEvent)
{
var percentLoaded:Number = e.bytesLoaded/e.bytesTotal;
percentLoaded = Math.round(percentLoaded * 100);
//this.progress_mc.scaleY = percentLoaded;
if (percentLoaded < 1)
{
this.progressBar.gotoAndStop(1);
}
else
{
this.progressBar.gotoAndStop(percentLoaded);
}
//end imageLoadProgress
}
Your loader script seems absolutely fine to me, except for a tiny flaw:
The only way the NaN(== not a Number) in your error message makes sense to me is if your ProgressEvent's bytesTotal property equals 0 - because division by zero doesn't produce valid results, as we all know.
I can't say for sure why this happens, not knowing any of your server-side code, but I assume it would occur if your PHP proxy script does not set the Content-Length HTTP response header correctly. If you were loading an actual image file, the web server would automatically set the header for you - in the case of your proxy script, it seems you have to take care of it yourself.
Anyway, you can make your loader script more error-proof by testing for NaN, and making sure the frame you jump to is never greater than 100:
var frame:int = isNaN (percentLoaded) || percentLoaded < 1 ? 1 :
percentLoaded > 100 ? 100 : percentLoaded;
progressBar.gotoAndStop(frame);
(I chose shorthand notation, but this is essentially the same as writing two if statements and an else).

addressing a child from another class created by getdefinitionbyname

I have a class "pagecompiler" which does the following:
if(page){
removeChild(page);
}
switch (appModel.currentPage){
case "Programma":
case "Winkelwagen":
case "Films":
case "Contact":
case "Reserveer":
var pageClass:* = getDefinitionByName("be.reynaertvincent.view.pages."+appModel.currentPage+"Page");
page = new pageClass();
addChild( page );
break;
}
so it creates a page depending on the switch, the names are (contactpage, filmspage, contactpage, etc.)
each of these pages extend from a class called "page".
And in "page" class I do the following:
contentBg = new ContentBg();
sidebarBg = new SidebarBg();
addChild(contentBg);
addChild(sidebarBg);
Now what I would like is to apply a tween on contentBg when I do the following in pagecompiler:
if(page){
removeChild(page);
}
but I can't seem to address contentBg from there. I tried:
if(page.contentBg){
tweenlite.to(page.contentBg,blablabla);
//removeChild(page);
}
but it doesn't get recognized. Anyone having any ideas?
I see a number of problems with your code. If you correct them, your problem should be solved:
You should stick to naming conventions: Class names should start with an upper case letter. So it should be Page instead of page. Otherwise, you have a member variable with the same name as a type - and potential compilation errors.
getDefinitionByName() is a costly way of instantiating a class in terms of performance, and since it also isn't type safe, you are dealing with a potential problem. Since you already know which classes you are going to instantiate, why not just make page an instance of Page and extend your switch statement:
private var page:Page;
// some code here
switch (appModel.currentPage){
case "Programma":
page = new ProgrammaPage();
break;
case "Winkelwagen":
page = new WinkelwagenPage();
break;
case "Films":
page = new FilmsPage();
break;
case "Contact":
page = new ContactPage();
break;
case "Reserveer":
page = new ReserveerPage();
break;
}
addChild( page );
If you make page an instance of *, as is implied above, you need to cast to the Page class in order to access its contentBg property. Something like this:
tweenlite.to (Page(page).contentBg, ....);
This last point, however, should already be solved if you follow the first two hints, since the compiler now knows that page is of type Page. It is also a nice example why the lower case naming mentioned above doesn't work, as page(page).contentBg is obviously ambiguous.
In your page class , you could create a public method:
public function removeFromStage():void
{
TweenLite.to ( contentBg , etc... {..... onComplete: remove})
}
//Called when the Tween is complete
private function remove():void
{
parent.removeChild( this );
//may come handy , don't forget to add a listener if you do this :)
dispatchEvent ( new Event ( Event.COMPLETE ) );
}
Then you can call it like this
if(page != null ){
//add Complete event listener if necessary...
page.removeFromStage();
}