I'm using CCNode+SFGestureRecognizer https://github.com/krzysztofzablocki/CCNode-SFGestureRecognizers for some pan gestures on some cocos2d nodes, but I also have other nodes that just use the normal ccTouchBegan/Moved/Ended and use the CCTouchOneByOneDelegate.
But I'm running into conflicts. With the ccTouch's overlapping I just set swallowsTouches:NO. Because basically what I'm doing is determining which touch to use in ccTouchesMoved based on the direction of the touch (is it mostly horizontal or mostly vertical) and if the direction matches a particular nodes allowed direction, that node claims the touch by canceling all of the other targeted handlers.
But when some nodes use the gesture recognizer, there doesn't seem to be an easy way for me to tell the touch to cancel when the direction is not in the allowed direction of that node. The gestureRecognizerShouldBegin get's called before I can determine if the other touches should claim the touch. And I just don't know a proper way to cancel a gesture's touch.
Any ideas for a good, clean way to do this?
So the gestureRecognizerShouldBegin in the CCNode+SFGestureRecognizers.m didn't have the correct translation/velocity information, however putting my own in the delegate did. The shouldReceiveTouch method in the delegate also did NOT have this information.
- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer {
if ([gestureRecognizer isKindOfClass:[UIPanGestureRecognizer class]]) {
UIPanGestureRecognizer *pan = (UIPanGestureRecognizer*)gestureRecognizer;
CGPoint translation = [pan translationInView:pan.view];
CGPoint velocity = [pan velocityInView:pan.view];
CGPoint dragVector = /* detect direction of the translation/velocity */
// if it was a horizontal drag return YES, otherwise NO
if (dragVector.x != 0 && dragVector.y == 0) {
return YES;
}
return NO;
}
return YES;
}
Related
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'am using a CCParallaxNode to scroll 3 backgrounds along with Ray Wenderlich's category to move the backgrounds when they go out of the screen.
It is working just fine, my problem is that i want to add childs (enimies) on the fly, like every 5 seconds. Normally i would just add the enemies to the parent layer using a CCMoveTo action to animate him over the screen but I want my enimies to follow the foreground of the parallax layer.
I'am increasing the scroll speed slowly as the game progresses.
I can't seem to figure out the right offset when calling
CGFloat offset = self.gameBackground.position.x;
[self.gameBackground addChild:enimy z:5 parallaxRatio:ccp(0.1, 0.1) positionOffset:ccp(offset, 85)];
Can someone help me out with this?
edit:
I'am doing this to move the background:
- (void)update:(ccTime)delta
{
self.speed -= 0.5f;
CGPoint backgroundScrollVel = ccp(self.speed, 0);
self.gameBackground.position = ccpAdd(self.gameBackground.position, ccpMult(backgroundScrollVel, delta));
}
Thanks
Rays article: http://www.raywenderlich.com/3611/how-to-make-a-space-shooter-iphone-game
Final solution:
I ended up just adding the enimies to the CCLayer instead of the Parallax. To move the enimies in the same speed as the foremost layer child in Parallax i did the following:
in update:(ccTime)delta:
CGFloat parallaxRatio = 0.1f;
CGPoint backgroundScrollVel = ccp((self.backgroundSpeed * - 1) * parallaxRatio, 0);
for(WKEnimy *enemy in self.enimies)
{
enemy.position = ccpAdd(enemy.position, ccpMult(backgroundScrollVel, delta));
}
You could add your enemy CCSprites to your foreground CCLayer (instead of directly adding them to your CCParallaxNode). Besides, I wouldn't recommend using actions (such as CCMoveTo) for this particular case; you may update your sprites positions as your doing with your gameBackground, and 'manually' check wether or not they're off the screen.
I'm having a weird issue with cocos2d-x when trying to detect which character (currently a CCLayer-extending object) I'm touching. The problem is that the location of the sprite I'm clicking on never matches the touch location that is registered.
I've tried different conversion functions but neither of them seem to work.
Any idea about how can I detect in ccTouchesBegan where a map (CCLayer) is being touched in the same 'scale' than the characters (also CCLayer's)? How can I get the absolute position in the map of the touch poisition as I receive it (I will move the character to the clicked position)?
I know that they may be very basic questions, but I've been looking for the answer for some hours and I can't find the solution. Any suggestion either for cocos2d-x or cocos2d is really welcome.
Thanks in advance!
1) In order to detect whether world point is in the node, I use following function:
bool VUtils::isNodeAtPoint(cocos2d::CCNode* node, cocos2d::CCPoint& touchLocation) {
CCPoint nodePoint = node->convertToNodeSpace(touchLocation);
CCRect rect = CCRectMake(0, 0, node->getContentSize().width, node->getContentSize().height);
return rect.containsPoint(nodePoint);
}
2) touchLocation - is point in world coordinates, in order to get it use CCTouch::getLocation() method in your touch listeners.
I added sprite B to sprite A as a child..
[spriteA addChild:spriteB];
my game logic is based on if spriteB was touched or not.
However I was not able to get spriteB to detect the touch.
I have converted the touchLocation to nodeSpace..
And I can get spriteA to detect the touch with no problem..
The if-condition I use is
if (CGRectContainsPoint(spriteB.boundingBox, touchLocation))
It'll be sweet if someone can point me to a direction..
spriteA is added to spriteBatchNode if that matters.
Thanks in advance!
Update:
I figure that the child is actually detecting the touch.
the reason it wasn't working was because I have the dirty tag set.
In short here's how my game works.
Targets popping from some hides.. and player touches on targets to get points.
I have a few arrays to hold targets at different location.
And I set dirty tag for each target..
target.dirty = TRUE when it pops
target.dirty = FALSE when it hides
this is equivalent to
If it pops, then it's clickable.
If it's behind the hide, then it's NOT clickable.
so right before I enter my if-condition
if (CGRectContainsPoint(curTarget.boundingBox, touchLocation))
I have this
if(curTarget.dirty == FALSE) continue;
My problem is that when I have the above condition check.. I detect no touch..
But If I take the above condition away, I can detect all touches..
but the problem would become the reverse.. which is I am able to click on my targets even it's not visible..
the above logic works if I add the target sprites as a child of the layer instead...
Help!
I want to set the contentsize of scrollayer.
I have a scrollayer, it's CCLayer type and moving is set by ccTouchMove. I have one schedule for smoothing. BUT.
Problem is that scrolling layer is big like the whole display. I want to set the contentsize of scrollayer. Content in this layer will be scroll and showing ONLY in this layer. Not taking up the whole display. Something like this
Scrolling just in gray CCLayer (scrollayer) ....NOT WHOLE SCREEN.
Can you help me?
P.S.: Setting CCLayerColor and initWithColor:Width:Height: is not working. It just makes some stupid color box and it's moving too.
ok, honestly i would put the window frame at a higher z than the scrolling object ... if you dont you may have to crop and change sprite on the fly for the window content, nasty (at least that is the one way i could do this, without further research).
so :
// initialize this logic somewhere useful
CCNode scrollableContent;
CCSprite windowFrame;
BOOL isScrollPossible;
[self addChild:scrollableContent z:0];
[self addChild:windowFrame z:1];
// and in the touch delegate methods
-(void) ccTouchBegan:{
check if the touch happened in the window, if yes, scrolling is possible
}
-(void) ccTouchMoved:{
if (isScrollPossible) {
compute displacement
compute nextPosition for scrollableContent node;
if ( nextPosition in window ) {
// make scrollableContent follow touch
scrollableContent.position=nextPosition;
} else {
// stop any further scrolling until the next 'touch began'
isScrollPossible=NO;
}
} else {
// scroll not possible, do nothing
}
}
This is the basic idea. You may need clamping logic to prevent the creeping of scrollableContent beyond the edges of the window.
Edited for typos.
After trying desperately with masking and GL_SCISSOR, I settled on cutting a hole in the foreground and only moving the background object when onTouchMoved updated.
To see it in action, have a look at the Stats page of Angry Gran.