I'm attempting to make a Space Invaders clone. In doing so I'm having a difficult time grouping the invaders together so that they move at the same time.This is due to both CCLayer and CCNode being deprecated in v3.1 in cocos2dx. I saved my sprites to a vector that I can iterate over but when I attempt to move them only move one at a time. I need to group them together so I can move them all at once.
void Gameplay::moveInvaders(){
auto moveLeft = MoveBy::create(2, Vec2(-1, 0));
auto moveRight = MoveBy::create(2, Vec2(1, 0));
auto moveDown = MoveBy::create(2, Vec2(0, 1));
auto stay = MoveBy::create(20, Vec2(0,0));
// create a sequence with the actions and callbacks
auto seq = Sequence::create(moveLeft, stay, moveRight, stay, moveDown, stay, nullptr);
for (int i = 0; i < invaders.size(); i++) {
invaders.at(i)->runAction(seq);
}
Update: I ended up figuring out the issue. Instead of trying to use the sequence I ended up scripting the movements with some control logic and the system timer.
Add this to your init() function:
this->schedule(schedule_selector(Gameplay::moveInvaders), 1.0);
Of the form:
this->schedule(schedule_selector(<Class_Name>::<function_To_call>), <number_of_frames_to_run>);
Then decide what you want to do in your function that will be called that often. I used a couple of boolean and int values to keep a counter. That way I could control the direction the invaders would move.
Hopefully this helps somebody else! I couldn't find what I needed to know because most of the tutorials for cocos2dx were in Objective-C or Javascript.
How about adding all invaders into one sprite, say "InvaderGroup"? All transformations (and need to refer once, but most probably all Actions too) to a sprite are guaranteed to be calculated on children too, so no worries, I suppose.
So many invaders individually watching out for events sounds like overhead, especially the result movement is not supposed to be individually decided. You can use your own Sprite subclass if you prefer, but just to move them around it's not necessary.
P.S.
Your invaders will still be able to roam individually if you want them to, just the co-ordinates will be with reference to the parent Sprite.
Related
i've tried to make a project, but i can't draw a sprite as i want. I mean that everything works when i just draw a sprite, but it stop working when i am trying to draw the sprite by clicking left mouse button. There's code i tried:
if(zdarzenie.type == Event::MouseButtonPressed && zdarzenie.mouseButton.button == Mouse::Left)
{
pocisk.setPosition(10, 10);
oknoAplikacji.draw(pocisk);
}
Btw, I am writing in Polish as if it would change something.
And yes, i have everything good besides that.
(and i am using 2.4.1 version of SFML)
I don't know what you are doing now because you didn't provide enough of your code and I actually don't understand your if statement but, it can just be :
if (sf::Mouse::isButtonPressed(sf::Mouse::Left))
{
sprite.setPosition(sf::Mouse::getPosition());
renderTarget.draw(sprite);
}
By the way I strongly suggest that you do not use the draw function here but organize your code to have a draw method called in a render loop, because depending on where your code is in your program, the sprite could be drawn for only one frame and then erased since it's not updated.
From what I understand in your code in Polish, you have the right code to do what you want, but the problem comes from the fact that you draw the sprite only once.
The draw method is called every frame and it will erase everything on screen and then redraw them. Doing it only once, like in your code, will only draw it a single time then delete it the very next frame.
At that point multiple solution can be used. If its a GameObject clicking can activate the object to then draw it or a simple bool could be used has a switch in your draw to make it appear.
I'm working on a game project in c++ using programming oriented object and classes but I can't figure out a way to animate the following graphics.
What I need is while the player is holding left key or the right key, the graphics should be appearing to make the character like moving and when they stop holding the key it'll turn to idle graphic.
I can't paste the whole source code here, i have many classes, and functions.. All I need is a BASIC idea of how to implement it, an example or a function anything useful. I don't need libraries because i just have two sprites to animate so it's not necessary.
As an example be Sprites the class that creates the object and Koala the one that moves it and prints it in a certain position.
Sprites idleSprite, walkingSprite;
Koala koala;
These declarations are just for avoiding other explanations.
I would appreciate your help.
PD: Don't worry about the keyboard keys, or other classes all I need is how to animate a sprite.
Koala should have two states:
a direction state: enum Direction {Left,Right};
a movement state. enum Movement { Idle, Walk };
As you have only one picture for the walking status, moving graphically the picture around will give the impression of a floating body. I'd recomment that you'd really have at least two walking positions to show that the foots are moving:
a movement step counter
a constant for the maximum number of steps.
Then the states should be updated in your game loop according to keyboard status and elapsed time. The pseudo code would be something like:
if (!arrow_key_pressed()) {
status_movement = Idle;
lasttimer = gametimer(); // keep track of last event
}
else {
status_movement = Walk;
if (left_arrow_pressed() )
status_direction = Left;
else if (right_arrow_pressed() )
status_direction = Right;
if (gametimer() - lasttimer > 2 ms ) { // if enough time,
if (status_direction==Left)
position_x -= step_increment;
else if (status_direction==Right)
position_x += step_increment;
movement_step = (movement_step+1) % maxi_steps;
lasttimer = gametimer();
}
}
All you have then to do is to restore te background of the picture at tis old position, and draw the picture at the position. For this, youd could call a function with paramters position_x, direction, movement status and status step, to return/draw the sprite at the right place.
I have read this page to understand batch drawing details, but I still have questions. I know that in order to reduce draw call number we need to use batch drawing. I use it like this:
auto spritebatch = SpriteBatchNode::create("ingame.png");
SpriteFrameCache::getInstance()->addSpriteFramesWithFile("ingame.plist");
And now I need to create a Sprite I have to do this:
auto backgroundSprite = Sprite::createWithSpriteFrameName("back_gradient.png");
spritebatch->addChild(backgroundSprite);
But I don't understand the following things:
What if my game has several spritesheets. For example I have HUD spritesheet and ingame spritesheet. Now if I want to show ingame screen with HUD then I need to create 2 SpriteBatchNode? and add them into ingame layer?
What if the same spritesheet should be used in different Scenes. Should I do the following again?
auto spritebatch = SpriteBatchNode::create("ingame.png");
SpriteFrameCache::getInstance()->addSpriteFramesWithFile("ingame.plist");
What if I use sprites with Button, TextEdit, Label and other UI elements.
First of all can I initialize Button state images from spritesheet?
As I know I cannot add UI element as a child to SpriteBatchNode. In this case how to combile UI elements and sprite in the same view/scene?
Sorry for lots of questions. But the fact is that I could not find any resource that contains the explanations to this questions. While they are all related. If you don't know answers to these questions, you don't know how to use SpriteBatchNode.
Don't use CCSpriteBatchNode in cocos2d-x v3. Batching is automatic and best left to the renderer to optimize draw calls through batch drawing. It says so right in the article you've linked:
The Render graph was decoupled from the Scene graph.That means that auto-batching is supported, finally :-) And the new renderer is so fast, that we no longer encourage the use of SpriteBatchNode.
I don't agree, depending not how fast new render is we want to get most of it as we can.
Narek, you are correct.
During rendering the geometry will be sorted to reduce the quantity of GL calls. But don't expect it will sort children of different parents in one line. Example: you have
Node A with children ab and ac
Node B with children bd and be.
if b and d uses textures of same atlas it is not guaranted you will get any perfomance boost of using atlases at all.
But I can confirm, currently it is really fast, and at my case the GL calls are not the bottleneck at all :)
I'm making an endless running game in which users dodge obstacles, and I'm working on producing the obstacles right now. The plan I had where I'm spawning these obstacles is as follows:
obstacle->setPosition(CCPointMake(this->getContentSize().width, this->getContentSize().height*.75));
obstacle->setScale(.5);
this->addChild(obstacle);
_obstacles->addObject(obstacle);
obstacle->runAction(CCMoveBy::create(2.0, CCPointMake(-(this->getContentSize().width + obstacle->getContentSize().width/2), 0)));
obstacle->removeFromParent();
I set the position, set it's scale, add it to the scene, run an action on it so that it moves across the screen from right to left, add it to an array called _obstacles to be used elsewhere, and then I remove it from the scene so as to save memory. However, the problem is that once I try implement this, the obstacle doesn't show up at all as if it's nowhere to be seen. When I don't call obstacle->removeFromParent() it shows up and performs the action. What am I doing wrong here? If I don't call removeFromParent(), what do I call? Is there a problem in my code not related to removeFromParent()?
The reason that obstacle doesn't apeear at all is that it is removed as it start moving. You just have to create a sequence of move action and function call with obstacle as parameter and than remove this obstacle in that function , so that obstacle will be removed after moving out of screen.
CCCallFuncN *myCallFunc = CCCallFuncN::create(this, callfuncN_selector(CLASS_NAME::removeObstacles));
obstacle->runAction(CCSequence::create(CCMoveBy::create(2.0, CCPointMake(-(this->getContentSize().width + obstacle->getContentSize().width/2), 0)),myCallFunc,NULL));
Method to remove obstacle from array and from parent view
void CLASS_NAME::removeObstacles(CCObject* pSender){
// Type cast pSender to obstacle type e.g if obstacle is of CCSprite type.
CCSprite *tempObstacle = (CCSprite *)pSender;
_obstacle.pop_back(tempObstacle);
tempObstacle->removeFromParent();
}
Don't forget to replace CLASS_NAME by your class name
I would need more info on what removeFromParent is doing and how you use _obstacles
I'm taking a guess on how the parent is structured. I would guess that it has a list of children and when the parent is updated/render, it calls those functions for its children. If removeFromParent removes the object from its parent list, then that would explain why it is not being render or used in the scene. If you have a setup like this, then you should only call removeFromParent before destroying the parent object
I am designing a game in which I have used 40 CCSprite objects. I need to detect the collision in between them. I am able to detect the collision between 2 sprites. Now how can i check 1 objects against all the remaining objects? Is using a FOR loop will work? or is there any other way to do this?
I think for a first iteration you should implement the for loop and see if it's fast enough.
If it's not, I guess you could partition your game area into rectangles and distribute your objects to rectangles (an object that overlaps multiple rectangles belongs to all of them). Then when you do the collision you can check only in the rectangle where your initial object is placed. Of course this depends a lot on what you have there. If all objects move around a lot it might not be such a hot idea.
Why dob't you use Box2D or chipmunks
For Box2D this link will help.
For Cocos2D following code will help.
You need to add following lines
shape->collision_type = kCollisionTypeParticle;
cpSpaceAddCollisionHandler(space_, kCollisionTypeParticle, kCollisionTypeParticle, collisonDetect, NULL, NULL, NULL, self);
Here collisonDetect is a method we need to register as:
cpBool collisonDetect(cpArbiter *arb, struct cpSpace *space, void *data)
{
*layer = ( *)data;
[layer collisonDetect:arb];
return cpTrue;
}
Now here here you will handle rest of the code
-(void)collisonDetect:(cpArbiter*)arb
{
NSLog(#"COLLISION DETECTED");
}