Cocos2dx - How to find if child is sprite or layer? - cocos2d-x

I have implemented an application in cocos2dx.
The issue that i am facing currently is that i am not able to find whether the child is a sprite or a layer as the getChildren() method returns list of CCObjects.
Any help appreciated.

When you have a child, you need to do a typecast in order to check whether it's a sprite or a layer:
for(int i = 0; i < myNode->getChildren()->count(); i++)
{
CCNode *child = myNode->getChildren()->objectAtIndex(i);
CCSprite* s = dynamic_cast<CCSprite*>(child);
if(s != 0) {
...
}
}

This is another sample may help:
Vector<Node*> allNodes=this->getChildren();
for(auto& node : allNodes){
if(dynamic_cast<Sprite*>(node)){ //It is Sprite
Sprite *target=dynamic_cast<Sprite*>(node);
//Do whatever you like
}
}

Related

How to give differents directions of bullets on one array?

im very new on javascript, i was doing a ship gaming that you have to kill some asteroids, and when you take some differents of "objects" on the screen we expand our number of bullets. Okey, going to the point i could get 3 bullets on the screen when you take diffirents objects, but now i want to give 2 of that 3 bullets of the array different directions. When i tried, i have the problem that i give the 3 bullets the same direction, i know why but im for at least 5hrs trying to fix this and i cant.
Im programming on Flash Builder 4.7 with different classes, i ll give the code of the array who is in the main, and the bullet class so as the hero class too.
Main Array
public function evUpdateBullet():void//here execute update of my class Bullets
{
var i:int;
for(i=myBullets.length-1; i >= 0; i--)
{
if(myBullets != null) //to be ?
{
if(myBullets[i].isDestroyed) //is destroyed Bullets?
{
myBullets[i] = null;
myBullets.splice(i, 1); //deleted elements.
}else
{
myBullets[i].evUpdate();
}
}
}
}
here i push the array and create the bullet, remember myBullets is the name of the array.
public function evShoot(posX:int, posY:int):void//here create the bullet and push in the array
{
attack1 = new Bullet;
attack1.Spawn(posX, posY);
myBullets.push(attack1);
}
here i show the Hero code, where i define the position of the bullet is going to spawn on the screen.
if (isPressing_Shoot && !isDestroyed)// Here execute the event shoot without power
{
Main.instace.evShoot(model.x, model.y);
isPressing_Shoot = false;
canShoot = false;
}
evDestroyed();
}
here is the code from Bullet class
first the spawn
public function Spawn(posX:int, posY:int):void
{
isDestroyed = false;//first parameter of my bullet
model = new MCbullet;
Main.layer1.addChild(model);//painting the hero in the stage
model.x = posX;//position in the stage wiht the hero
model.y = posY;
model.tigger.visible = false;
}
then the Update
public function evUpdate():void//here conect with update general
{
if (model != null)//to be?
{
model.y -= 12;//move of my bullet
//model.x -= 12;
if (model.y <= 0 )
{
evDestroyed();
}
}
}
in this update i set the movement of y, so i can shoot vertically, but.. when i try to add an x.move, i do for the all array, so i want to know how i can give different move, for differents bullets of the same array.
Iterate through the array elements. There are a few ways to do this, but the one I'm most accustomed to using would be the for loop. It looks like this:
// loop through myBullets array to update
// each x and y position dependent on unique
// property value _xSpeed and _ySpeed.
for (var i:int = 0; i < myBullets.length; i++)
{
myBullets[i].x += myBullets[i]._xSpeed;
myBullets[i].y += myBullets[i]._ySpeed;
}
Obviously, you will need the _xSpeed and _ySpeed properties of the array elements to be set to dynamic values. You would first need to give the bullet class these properties and then set their values when you instantiate the bullets. That might look something like this:
function makeBullet():void{
var b:Bullet = new Bullet();
b.x = hero.x;
b.y = hero.y;
b._xSpeed = hero._xSpeed; // or put here whatever makes sense for assigning the right value in your application
And in your bullet class constructor, before the function but inside the class brackets, add the property:
var _xSpeed:Number = 0;
var _ySpeed:Number = 0;
Basically this is allowing each bullet to hold it's own special property that is independent of any other instance of the class.
I hope that helps.

Actionscript 3.0 Movieclip modification on EXIT_FRAME

I have this baffling problem with Flash AS3 that I have been attempting to solve for a long time. I have a notion that perhaps this is a bug with the flash player, but perhaps you can shed some insight.
I have a MovieClip in Flash that is a star for 10 frames, a circle for another 10, and then a square for another 10, after which it will gotoAndPlay(1), replaying the animation. This MovieClip extends an AS3 class I have called FlipClip.
FlipClip has a function in it called reverseClip. This function's purpose is to flip certain graphic children around an axis every time Flash launches the EXIT_FRAME event.
public function FlipClip()
{
//as soon as this is instantiated, add the eventListener
addEventListener(Event.EXIT_FRAME,flipTheClip);
}
public function flipTheClip(e:Event)
{
trace("currentFrame = " + currentFrame);
//for sake of simplicity, we will flip every child
for (var i=0; i<numChildren; i++)
{
var targetClip = getChildAt(i);
var axis = 10;
//if the target child has not already been flipped...
if (Math.abs(targetClip.scaleX) / targetClip.scaleX != -1)
{
//reverse the child's direction with scaleX and move based on the axis
targetClip.scaleX *= -1;
var dist:Number = targetClip.x - axis;
targetClip.x = axis - dist;
}
}
}
The obvious outcome is that every time we exit a frame, all of the graphic elements are flipped horizontally around x=10, and every ten frames the shape of the MovieClip changes from a star, to a circle, to a square. Right?
Nope.
The MovieClip does successfully flip around that axis, but then a strange problem occurs. The animation stops. The MovieClip is stuck as an eternal star. And Flash doesn't even recognize that the animation has stopped, as we get this output over and over;
currentFrame = 1
currentFrame = 2
currentFrame = 3
currentFrame = 4
...
currentFrame = 30
currentFrame = 1
All the way up to 30, at which point it goes back to one. The clip is still playing, but somehow the graphic elements are not updating!
Is this a problem with the flash player? Is this a problem with the code? Any help is appreciated!
I've uploaded the files for the .fla and .as on dropbox. I'm still figuring out how to embed something like that, but for now I'm gonna hope this link works for you.
https://www.dropbox.com/sh/hcljutesblichpp/AABKQ4Kn8OTwfTaeh0I3nnOZa?dl=0
UPDATE:
If I convert every individual shape into a MovieClip within the parent MovieClip, it plays correctly. However, this is not very memory efficient or feasible with complex animations. Hopefully this bit of information can help you solve the problem.
There are couple of thing which you need to take care.
You don't need to flip element based on the numChildren as it always
return 1 as on each frame you will get single children.
you also don't need to do the check another condition
Math.abs(targetClip.scaleX) / targetClip.scaleX != -1 to set the
flip.
And also you need to use ENTER_FRAME instead of EXIT_FRAME.
ENTER_FRAME works for the current frame whereas EXIT_FRAME works for
previous frame.
Use the below code.
package
{
import flash.display.MovieClip;
import flash.events.*;
import flash.utils.setTimeout;
public class FlipClip extends MovieClip
{
var mInstance
var prevX;
public function FlipClip()
{
//as soon as this is instantiated, add the eventListener
addEventListener(Event.ENTER_FRAME,flipTheClip);
mInstance = this;
//mInstance.visible = false;
}
public function flipTheClip(e)
{
this.scaleX *= -1;
prevX = this.x;
if(this.scaleX < 0)
this.x = prevX + this.width
else
this.x = prevX - this.width
}
}
}
Paste above code in FlipClip.as file and change the frame rate to 1.
You need to update the moviClip placement based on your requirement.
Hope above answer solve your problem.
You need to remove listener for EXIT_FRAME before playing animation. Also you are Flipping your movieClip here but not adding any code for playing it.
Paste below code in your FlipClip.as file.
package
{
import flash.display.MovieClip;
import flash.events.*;
import flash.utils.setTimeout;
public class FlipClip extends MovieClip
{
var mInstance
public function FlipClip()
{
//as soon as this is instantiated, add the eventListener
addEventListener(Event.EXIT_FRAME,flipTheClip);
mInstance = this;
mInstance.visible = false;
}
private function playallAnimation()
{
this.gotoAndPlay(1);
}
public function flipTheClip(e)
{
removeEventListener(Event.EXIT_FRAME,flipTheClip);
//for sake of simplicity, we will flip every child
for (var i=0; i<numChildren; i++)
{
var targetClip = getChildAt(i);
var axis = 10;
//if the target child has not already been flipped...
if (Math.abs(targetClip.scaleX) / targetClip.scaleX != -1)
{
//reverse the child's direction with scaleX and move based on the axis
targetClip.scaleX *= -1;
var dist:Number = targetClip.x - axis;
targetClip.x = axis - dist;
}
}
setTimeout(function()
{
mInstance.visible = true;
playallAnimation();
},200);
}
}
}
Hope this will work for you.

Clearing tiles in tile based as3 game

I been searching for a way to handle this for hours but have found nothing. In my BuildMap function, I instantiate new MovieClips (Tile) with the instance name cell. Their frame is based on my 2d array (protoMap). The problem is that the cells are instantiated in the function. I don't know how to access them outside of it. I want to removeChild(cell) but the only way I know how is within the function that it's instantiated in.
public function BuildMap()
{
for (var i:int=0; i < mapHeight; i++)
{
for (var u:int=0; u < mapWidth; u++)
{
var cell:MovieClip = new Tile();
cell.gotoAndStop(protoMap[i][u]+1);
cell.x = tileSide*u;
cell.y = tileSide*i;
addChild(cell);
var currCellLabel:String = cell.currentFrameLabel;
mapLabels[i].push(currCellLabel);
}
}
}
I want a function called ClearMap() that loops through again and does removeChild(cell). I thought about doing a clearTiles:Boolean and in BuildMap() do
if(clearTiles == false)
{
build the map;
}else{loop again and removeChild(cell)}
but that didn't work... so then I tried to pass cell as an argument to BuildMap() but when I tried to remove it, it wasn't an object of the caller... or something like that. I was also thinking to put cell into its own array, but I don't want to waste memory unnecessarily. Any solutions for the noob?
Create a class instead of using functions.
The point of a class is to isolate concerns.
In your case, you want to deal with all those tiles. (create them according to protoMap and be able to delete them all.
Extending a DisplayObjectContainer such as Sprite, will allow you to add all the tiles to the map object, then you can add and remove the map easily.
Your BuildMap function becomes the constructor.
Here's some non working pseudo code that illustrates the idea:
package
{
public class Map extends Sprite
{
public function Map (data, width, height)
{
for (var i:int=0; i < height; i++)
{
for (var u:int=0; u < width; u++)
{
var cell:MovieClip = new Tile();
cell.gotoAndStop(data[i][u]+1);
cell.x = tileSide*u;
cell.y = tileSide*i;
addChild(cell);
var currCellLabel:String = cell.currentFrameLabel;
mapLabels[i].push(currCellLabel);
}
}
}
public function clear():void
{
removeChildren();
}
}
}
The whole map is contained in that class. You'd have to add the labels, but you didn't specify what they are or what they do, so I left them out.
You can use it like so:
var awesomeMap:Map = new Map(protoMap, mapWidth, mapHeight);
addChild(awesomeMap);
//later
awesomeMap.clear();
//or
removeChild(awesomeMap);
I'd like to point out that building tile maps with MovieClips this way is a bad idea. MovieClips are horrible for performance, because they carry the overhead of their timeline.
Removing all children is very wasteful, too.
So if you have performance problems, try reusing objects and/or employing a technique called "blitting"
See this article: http://www.adobe.com/devnet/flash/articles/blitting_mc.html

AS3 .addEventListener in a loop?

I am creating a line of Sprite elements. Every sprite element has different job, when it is clicked. How can I make the function inside the addEventListener to know which button was clicked?
In this case, the traced value of i when it is cliicked is always 6. Which is wrong, because 6 is only the last element of the array. What about the rest of them, the beginning?
for (var i:int = 0; i < 6; i++) {
var barPart:Sprite = new Sprite();
barPart.x = i * (30);
barPart.y = 0;
barPart.graphics.beginFill(0x000000, 0.2);
barPart.graphics.drawRect(0, 0, 10, 10);
barPart.graphics.endFill();
barPart.addEventListener(MouseEvent.CLICK, function(_event:MouseEvent):void {
trace(i);
});
}
When the application is build and the listeners are added, the loop has already executed, so the index "i" will always be six by the time the user ends up clicking the button.
To distinguish between the different items, use their "name" property (prop of DisplayObject) like shown ...
Try not to have listener function as a method closure in a loop, instead do this:
for (...)
{
... code
barPart.name = "barPart-" +i;
barPart.addEventListener(MouseEvent.CLICK, barPart_clickHandler);
}
and implement the function (event handler separately) like:
private function barPart_clickHandler(e:MouseEvent):void
{
// the event's target will let you know who dispatched the function
var name:String = Sprite(e.currentTarget).name;
name = name.replace("barpart-", "");
switch(name)
{
case '0':
// your code
break;
.
.
}
}
#Shally Virk - My mistake. I was thinking of MovieClip which is a dynamic object so it allows adding arbitrary fields. You are right, there are lots of ways to get around this problem, but your suggestion works fine.
While the cause is not clear to me, the answer is a little more simple,
The events are registered correctly, but flash takes the last computed value.
Knowing that we can work around.
The work around can either do like Shally Virk wrote, but that tends to get confusing on bigger scale. So we want something more general and simple.
Now here are the steps taking this in mind:
1. We know sprite are not dynamic, so we make class to extend spirte and make it dynamic. Since the class has basically 0 code, the only difference being the dynamic , the amount of memory added is small
2. Having the class here's the code:
for (var i:int = 0; i < 6; i++) {
var barPart:CustomSprite = new CustomSprite();
barPart.x = i * (30);
barPart.y = 0;
barPart.graphics.beginFill(0x000000, 0.2);
barPart.graphics.drawRect(0, 0, 10, 10);
barPart.graphics.endFill();
barPart.i = i;
barPart.addEventListener(MouseEvent.CLICK, function(_event:MouseEvent):void {
trace(_event.currentTarget.i);
});
}
:)

collision between a particle array and a box

Im working on a school project and I need to get collision between an array of particles and a box, here is my current code:
for(var i : int = 0; i < particles.length; i++)
{
particles[i].update();
if(Particle.hitTestPoint(Square))
{
particle = particles.shift();
particle.destroy();
}
}
I get an error telling me that im trying to call an undefined method (hittestpoint) through a reference with static type class.
Any help would be greatly appreciated, thank!
Here is the code for the Particle.
package
{
import flash.display.*;
public class Particle
{
public var clip : DisplayObject;
public var xVel : Number = 0;
public var yVel : Number = 0;
public var drag : Number = 1;
public var gravity : Number = 0.0;
public var shrink : Number = 1;
public var fade : Number = 0;
public function Particle(symbolclass : Class, target : DisplayObjectContainer, xpos : Number, ypos : Number)
{
clip = new symbolclass();
target.addChild(clip);
clip.x= xpos;
clip.y= ypos;
}
public function update() : void
{
clip.x += xVel;
clip.y += yVel;
xVel *= drag;
yVel *= drag;
yVel+=gravity;
clip.scaleX *= shrink;
clip.scaleY *= shrink;
clip.alpha -= fade;
}
public function destroy() :void
{
clip.parent.removeChild(clip);
}
}
}
I used this tutorial for the particles, and my goal is to add collision to them
The Particle class must extend MovieClip to have the hitTestPoint method. Try changing the class to:
import flash.display.MovieClip;
public class Particle extends MovieClip
{
//code here
and import specific classes in your code (see MovieClip class as that's the one you are using and it's methods) for better results as good practice.
I'm not sure what particle refers to in that code since it's not defined in what you posted, but particles[i] is the particle you want to test.
Your Particle class doesn't have a hitTestPoint function- but it contains a DisplayObject that does. So with those two things in mind, you can call hit tests using particles[i].clip.hitTestPoint.
Next problem: you're trying to pass the class Square to the hitTest rather than an instance. And still, hitTestPoint takes a single point as its argument, not an object like what a square would represent. So you will probably want to use hitTestObject instead.
Edit: Updated my answer now that Particle code was posted.
Your Particle class doesn't define hitTestPoint. In addition to that, you are calling a static method which I don't think you want here... you want an instance method.
Make sure you define hitTestPoint in your Particle class. Then, instead of Particle.hitTestPoint, try particle.hitTestPoint (note upper case, which refers to the class is changed to lower-case which refers to the instance.
Try this:
for(var i : int = 0; i < particles.length; i++)
{
var particle:Particle = particles[i];
particles.update();
if(particle.hitTestPoint(Square))
{
particle = particles.shift();
particle.destroy();
}
}