i use cocos2d-x for my game.
i have some question about cocos2d-x create method.
i always use create() method to create new Animation , Animate , RepeatForever Object when the game character needs to change the animation in Update Method
but i think this is not good because if i create new Animation, Animate , RepeatForever Object to change my game character's anitation like below
(below code is just a part of Update method )
auto anim = cocos2d::Animation::create();
anim->setDelayPerUnit(0.3);
anim->addSpriteFrameWithFile("./Hero/walk1_0.png");
anim->addSpriteFrameWithFile("./Hero/walk1_1.png");
anim->addSpriteFrameWithFile("./Hero/walk1_2.png");
anim->addSpriteFrameWithFile("./Hero/walk1_3.png");
auto animation = cocos2d::Animate::create(anim);
m_pBasicSprite->runAction(animation);
when the game character change the animation frequently, then it will cause create too many cocos object. so how should i gonna do?
p.s
i use class memeber variable for save that Object's instead of create new cocos animation object for each loop in update method,
but it cause error the error said "expression _referenceCount > 0"
p.s2
i'm sorry about my terrible english...
Inside ClassName.h:
CCAction* _aniRun;
void createAnimation();
Inside ClassName.cpp:
// create a function
void ClassName::createAnimation()
{
// run ani
CCAnimation* animation=CCAnimation::create();
animation->setDelayPerUnit(0.05f);
for (int i=0; i<1; i++)
{
char str[50];
sprintf(str,"game/bird/run%d.png", i);
animation->addSpriteFrameWithFileName(str);
}
_aniRun = CCRepeatForever::create(CCAnimate::create(animation));
_aniRun->retain();
}
Now wherever you want to play animation just call
player->runAction(aniRun);
Don't forget to release _aniRun inside destructor:
CC_SAFE_RELEASE(_aniRun);
I am also new for cocos2d-x .i do not have full command over it .. i have basic idea about retain() and release().
in cocos 2dx , there is a AutoreleasePool -- which takes care of referancecount , when you call object->autorelease() , this object
will be added to this autoreleasepool. this pool will help you to ratain the object for the lifetime of current frame.
There are 4 functions of Ref, the meanings are
retain: add reference count by 1
release: minus reference count by 1
autorelease: put the object in to AutoReleasePool, which means that cocos2d-x will invoke release automatically at the end of this frame
getReferenceCount: as the meaning of the function, it will retain the reference count of this object
cocos2dx has an autorelease pool which drains the objects which have retain count=0 which is a variable to keep in check the scope of the cocos2dx object.
Now when you create new object using the create method it is already added to the autorelease pool and you don't need to release it or delete it anywhere .
But when you create new object using 'new' you definitely need to release it in its destructor or after its use is over.
when your object is added to the autorelease pool but you need it somewhere else you could just retain it , this increments its retain count by one and then you have to manually release it after its use is over.
Whenever you add child your object it is retained automatically but you don't need to release it rather you remove it from the parent.
There are simple rules with retain() and autorelease():
everything I create with new are mine and I’m responsible for deleting them from memory
everything returned using a create()-method is autoreleased and will be released when the CURRENT METHOD ENDS. If the retainCount is zero, they will be purged from memory. When I need them in an instance variable I have to retain them.
everything I retain I’ll have to release this from memory.
See this retain/release thing as a reference counter. If the counter is down to zero the object will be deleted.
Related
I have a variable area which stores a number.
When the app is restarted, it is reset back to it's original value. How can I keep area persistent after being closed?
I'm using Flash CS6 for Android
You'll have to save the variable. There's multiple ways to do this but using a SharedObject is the easiest IMO.
First thing is you don't actually create a new instance of the SharedObject class, you instead call the static function getLocal and this sets your variable. So somewhere near the start of your program you'll want something like this:
var gameSave:SharedObject = SharedObject.getLocal("gameSave");
This either creates a new locally persistent shared object if one does not exist or it grabs the one with the same initialized name ("gameSave") on your computer. This way you can access the saved variables across multiple playthroughs.
Now to save a variable you simply use the dataObject on the shared object and write values to it, then you call the function flush when you're done writing values to immediately save the shared object to your computer.
So saving your area value would look something like this:
gameSave.data.area = Main.area;
gameSave.flush();
After that you'll want to set the area value to whatever the saved value is when your game launches:
if (gameSave.data.area !== undefined) Main.area = gameSave.data.area;
We check if the value is undefined because it might not exist yet if you're playing the game for the first time and the area hasn't been saved yet.
Last thing in case you want to expand the scope of this and save more values: you can only write specific values to the shared object. The way I understand it is you can only write certain class types and primitives. If you try to write anything that's not a primitive or the exception classes, it'll automatically convert that item to an Object and it more or less becomes useless. The classes that it can accept that you'll probably use the most are: int, uint, Number, String, Boolean, Object, and Array. It has a few others like ByteArray and XML, but you'll either not use those at all or not use them very frequently. If you want to save any other class type you'll have to add that functionality yourself.
Are there any general guide lines for using retain and release for objects in cocos2d-X ? When creating objects in a function, is it true that the functions memory is cleaned up the second the function returns. When a object is created, calling the retain function of the object, will retain object beyond the function return ?
Kind Regards
Generally in c++ you have this behaviour:
void foo() {
Object a;
Object *pA = new Object();
(…)
}
This would result in a being destroyed automatically at function end, as it was allocated on stack. The *pA would not get destroyed, as it was allocated on the heap (thus, you only loose the reference to it, but the object itself still lives).
Cocos implements a thing called "Automatic Reference Counting" : each CCObject has a reference counter and two methods retain() and release(). The way this works is, that every time you create an object, it gets registered in cocos structers (CCPoolManager). Then with every frame (between them being drawn) there is a maintenance loop which checks the reference counter of all objects : if it is 0 this means (to cocos) that no other objects reference it, so it is safe to delete it. The retain count of an object is automatically incresead when you use this object as an argument for an addChild function.
Example :
void cocosFoo() {
CCSprite *a = CCSprite::create(…);
CCSprite *b = CCSprite::create(…);
this->addChild(b);
}
What happens here is this :
Two CCSprites are created, cocos knows about them.
The b sprite is added to this object (say a CCLayer)
The function ends, no objects are destroyed (both of them being on heap).
Somewhere between this and next frame, the maintanance gets run. Cocos chcecks both sprites and sees that a has reference count == 0, so it deletes it.
This system is quite good, as you don't need to worry about memory management. If you want to create a CCSprite (for example), but not add it as a child yet, you can call retain() on it, which will raise its reference counter, saving it from automatic deletion. But then you'd have to remember about calling release() on it (for example, when adding it as a child).
The general things you have to remeber about are :
Each call to retain() by you needs to be paired with release().
You generally shouldn't delete CCObjects yourself. If you feel that you need to, there is a conveniece macro : CC_SAFE_DELETE(object)
So to answer your questions in short :
Are there any general guide lines for using retain and release for objects in cocos2d-X ?
Yes, you should generally not need to do it.
When creating objects in a function, is it true that the functions memory is cleaned up the second the function returns.
Answer to this is the whole text above.
When a object is created, calling the retain function of the object, will retain object beyond the function return ?
Yes, as will adding it as a child to another (retained in any way) object.
Here is the thing,
cocos2dx has an autorelease pool which drains the objects which have retain count=0 which is a variable to keep in check the scope of the cocos2dx object.
Now when you create new object using the create method it is already added to the autorelease pool and you don't need to release it or delete it anywhere , its like garbage collector in java, takes care of garbage objects behind your back.
But when you create new object using 'new' you definitely need to release it in its destructor or after its use is over.
Second thing,
when your object is added to the autorelease pool but you need it somewhere else you could just retain it , this increments its retain count by one and then you have to manually release it after its use is over.
Third Thing,
Whenever you add child your object it is retained automatically but you don't need to release it rather you remove it from the parent.
I have these three objects that i need to add on stage, when I extract them from the array on a later stage of the program.
I can't write var mall: Mall = new Mall (); because somebody told me before that, This will add in the object in the memory and will be really bad if a lot of objects are being handled. I will have a lot more objects to work with later on.
So I would like to know a way that when i run a for loop or an event listener i can add ... = new object (); automatically and then call addchild to make an instance of the object.
var mall:Mall;
var library:Library;
var music:Music;
var choices:Array = new Array ();
choices.push(mall,library,music);
test Code for Garbage Collection :
var waking: WakingUp = new WakingUp ();
addChild (waking);
waking.y=-30;
waking.addEventListener (Event.ENTER_FRAME, waking_up);
function waking_up (g:Event){
if (waking.currentFrame == waking.totalFrames)
{
waking.stop ();
waking.removeEventListener (Event.ENTER_FRAME,waking_up);
removeChild (waking);
removeChild(alarm_slide);
gotoAndStop (6);
}
}
This is all the ref I have to this code :D
Specific to instantiating your array with elements, you can:
var choices:Array = [ mall, library, music ];
Flash Player runtime uses both reference counting as well as mark and sweep.
So, any reference to the instance adds a count - collections, display list, event listeners, class members... as instances are dereferenced, the memory will ultimately be freed.
Reference Counting
Each object on the heap keeps track of the number of things pointing to it. Each time you create a reference to an object, the
object's reference count is incremented. When you delete a reference,
the object's reference count is decremented. If the object has a zero
reference count (nothing is pointing to it), it is added to the Zero
Count Table (ZCT). When the ZCT is full, the stack is scanned to find
any references from the stack to an object on the ZCT. Any object on
the ZCT without a stack reference is deleted.
One of the problems of deferred reference counting is circular references. If ObjectA and ObjectB refer to each other but no other
objects in the system point to them, they will never have a zero
reference count and will therefore never be eligible for garbage
collection using reference counting. This is where mark and sweep
garbage collection helps.
Mark/Sweep
Applications that run in Flash Player or AIR have multiple GCRoots.
You can think about a GCRoot as the trunk of a tree with the objects
of the application as the branches. The Stage is a GCRoot. Loaders are
GCRoots. Certain menus are GCRoots. Every object that is still in use
by the application is reachable from one of the GCRoots within the
application. GCRoots are never garbage collected.
Every object in an application has a "mark bit." When the Mark phase
of garbage collection begins, all of those mark bits are cleared. The
MMgc keeps track of all GCRoots in the application. The garbage
collector starts from those roots, traces through each object and sets
the mark bit for every object it reaches. Any object that is no longer
reachable from any of the roots is no longer reachable from anywhere
in the application – its mark bit does not get set during the Mark
phase. Once the collector is done marking all of the objects it finds,
the Sweep phase begins. Any object that doesn't have a set mark bit is
destroyed and its memory reclaimed.
addChild does not make an instance of the object, it simply adds the object to the displaylist of the current display container.
Using new Mall() is fine - just ensure that you remove references to it when it's no longer required so that it may be garbage collected. Alternatively you can just hold an array of primitives.
package
{
public class SomeClass
{
public var myBtn:Button ;
public function SomeClass()
{
myBtn.addEventListener( MouseEvent.CLICK, clickFunction) ;
}
function clickFunction(e:Event){
}
}
}
Main Class:
var someClass:SomeClass = new SomeClass(); // step 1
addChild(someClass); // step 2
removeChild(someClass); // step 3
someClass = null // step 4
In the above, I want to completely destroy the someClass instance, so in step 4 it's been assigned null value.
Q1) Is step 4 ( assignment to null ) right way to destroy the instances ?
Q2) I referred : http://gskinner.com/blog/archives/2006/06/as3_resource_ma.html using delete keyword for objects. But i don't think delete keyword can be used for class instances ? How to use it in this case then ?
Q3) What happens to myBtn eventListener in SomeClass. Should i add a removeEventListener manually, before destroying instances of SomeClass. Or would it get destroyed automatically ?
Thanks
1/ Yes. (I assume the someClass variable is an instance variable)
2/ delete does not only remove the value of a variable, but even the variable definition. Since classes in AS3 are sealed in general, it won't work. I.e. delete should only be used on dynamically created members. Mainly "keys" of Object or Dictionary instances. But obviously you can remove the member definition of any class marked as dynamic using delete.
3/ Yes, always remove event listeners manually. You can create weakly referenced event listeners when registering the handler as a listener, but it's best to always make sure event listeners are removed manually, it's more readable, clear and fail-safe.
I tend to have a destroy method in all my classes, which can be called by the instance owner when it's cleaning up its references to a certain instance. This destroy method will unregister all event listeners, nullify instance members and do all kinds of cleanup.
The SomeClass instance you created will get garbage-collected after there are no longer any references to it. By setting your variable to null, it removes that reference, and the SomeClass instance will get garbage-collected as long as there are no more references to it.
In the code above, you do not need to remove the event listener. When a SomeClass instance is collected, all of its member variables will be collected (unless they're referenced elsewhere). Because the event listener has been added to the button, it will be collected when the button is collected.
Something to note, however: if instead of myBtn.addEventListener you had used stage.addEventListener, the stage would retain a reference to your callback function and you could end up with a memory leak. Always remove event listeners that are assigned to objects that will still be around after you care about the listener.
Creynder's advice is good: remove event listeners as a matter of habit. It's only really necessary, however, when an event listener's dispatcher is going to hang around but you don't want the callback to stay in memory.
Riddle me this: I have my MouseEvent.MOUSE_DOWN which calls mouseHandler. The latter looks something like this:
public function mouseHandler(evt:MouseEvent):void
{
var p:Point = new Point(mouseX, mouseY);
var objs:Array = new Array(getObjectsUnderPoint(p));
}
Now what I want to know is thusly: will the objs array and p point be overwritten every time, simply causing the previous objs array and p point to be wiped and a new one generated, or...does it just create a new array and point over and over and over? Of course if I trace(objs) it gives me the expected results, but am I chocking up the system in the background without realising? Your expertise would be appreciated.
EDIT: well after learning a fair bit from the answerers -thanks btw- that made me think of something else and, a quick search later, found a way to theoretically reliably remove the references:
var a = null;
Now I appreciate that this is probably not needed as they'll be GCed at the end of the function, but considering it takes two ticks to write, better safe than sorry, no?
It works like this from what I understand - references for these variables will be lost after function will end. The values will be GC'ed then eventually.
If you will call the function second time, the new references will be created, and filled with new data, the values of previous references hovewer, may still exist in memory, and wait for Garbage Collector, but that may not necessarily happen! If they have attached listeners, the Flash Player will think that they are still useful, so they will exist in the memory to the end of the application run and listen, and even react to events - even if you theoretically cannot access them anymore.
Edit:
In your case whats happening is that you are creating two references that will disappear at the end of the function. They are not related to event listener, the listener creates them, but is not attached to them so it won't stop GC from collecting them after function will end. You creates an array of references, but that are just references to other objects that values are referred in other places (like the display list), if the array alone is not referred anywhere outside of this function, it should be GCted.
Since p is an object, not a primitive, the memory allocation for it will come from the Heap (and therefore need to be garbage collected) instead of the stack like local primitives (and are wiped once the function ends.
So new memory will be allocated every time this function is called, which will temporarily increase memory usage until they get GC'd, but the amount is probably insignificant (assuming that array isn't massive!).