I have an xcode project that's with the following code:
in fflayer.h
int *ffinjar;
in fflayer.m
-(void)ccTouchMoved:(UITouch *)touch withEvent:(UIEvent *)event {
CGSize winSize = [[CCDirector sharedDirector] winSize];
CGPoint touchLocation = [self convertTouchtoNodeSpace:touch];
CGPoint oldTouchLocation = [touch previousLocationInView:touch.view];
oldTouchLocation = [CCDirector sharedDirector] convertToGL:oldLocation];
oldTouchLocation = [self convertoToNodeSpace:oldTouchLocation];
CGPoint translation = ccpSub(touchLocation, oldTouchLocation);
[self panForTranslation:translation];
if (CGRectIntersectsRect(selSprite.boundingBox, eJar.boundingBox)) {
selSprite.userData = FALSE;
selSprite.visible = FALSE;
selSprite.position = ccp(winSize.width +40, winSize.height + 40);
_currentFlies--;
ffinjar++;
}
for some reason, this causes ffinjar to add 4 instead of 1. but the _currentFlies just subtracts 1. I have no idea. can anyone see what I may be doing wrong?
It's because your declaration is of a pointer, and incrementing a pointer has a different implication than incrementing an int (IIRC, it increments by sizeof(int), by I'm not sure).
int *ffinjar;
// perhaps should be
int ffinjar;
EDIT: I have done a test, and indeed incrementing a pointer-to-an-int adds 4 on my system (and sizeof(int) is 4 as well)
Related
I am trying to get multi touch working so that I can move two sprites at the same time. I followed this tutorial http://www.saturngod.net/detecting-touch-events-in-cocos2d-iphone-ganbaru-games and this is the code I have in ccTouchesBegan:
-(void) ccTouchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
NSArray *touchArray = [touches allObjects];
// We're going to track the first two touches (i.e. first two fingers)
// Create "UITouch" objects representing each touch
UITouch *fingerOne = [touchArray objectAtIndex:0];
UITouch *fingerTwo = [touchArray objectAtIndex:1];
// Convert each UITouch object to a CGPoint, which has x/y coordinates we can actually use
CGPoint pointOne = [fingerOne locationInView:[fingerOne view]];
CGPoint pointTwo = [fingerTwo locationInView:[fingerTwo view]];
// The touch points are always in "portrait" coordinates
// You will need to convert them if in landscape (which we are)
pointOne = [[CCDirector sharedDirector] convertToGL:pointOne];
pointTwo = [[CCDirector sharedDirector] convertToGL:pointTwo];
if (CGRectContainsPoint(ball.boundingBox, pointOne))
{
//ball.position = ccp(location.x , location.y);
areWeTouchingABall = YES;
//printf("*** ccTouchesBegan (x:%f, y:%f)\n", location.x, location.y);
}
if(CGRectContainsPoint(sp.boundingBox, pointOne)){
areWeTouchingASquare = YES;
// printf("*** ccTouchesBegan (x:%f, y:%f)\n", location.x, location.y);
}
// Only run the following code if there is more than one touch
if ([touchArray count] > 1)
{
if ( CGRectContainsPoint(ball.boundingBox, pointTwo))
{
//ball.position = ccp(location.x , location.y);
areWeTouchingABall = YES;
//printf("*** ccTouchesBegan (x:%f, y:%f)\n", location.x, location.y);
}
if(CGRectContainsPoint(sp.boundingBox, pointTwo)){
areWeTouchingASquare = YES;
// printf("*** ccTouchesBegan (x:%f, y:%f)\n", location.x, location.y);
}
}
}
this is in touchesMoved:
-(void) ccTouchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
NSArray *touchArray = [touches allObjects];
// We're going to track the first two touches (i.e. first two fingers)
// Create "UITouch" objects representing each touch
UITouch *fingerOne = [touchArray objectAtIndex:0];
UITouch *fingerTwo = [touchArray objectAtIndex:1];
// Convert each UITouch object to a CGPoint, which has x/y coordinates we can actually use
CGPoint pointOne = [fingerOne locationInView:[fingerOne view]];
CGPoint pointTwo = [fingerTwo locationInView:[fingerTwo view]];
// The touch points are always in "portrait" coordinates
// You will need to convert them if in landscape (which we are)
pointOne = [[CCDirector sharedDirector] convertToGL:pointOne];
pointTwo = [[CCDirector sharedDirector] convertToGL:pointTwo];
if (areWeTouchingABall == YES) //
{
ball.position = ccp(pointOne.x , pointOne.y);
ball.zOrder = 1;
sp.zOrder = 0;
}
if (areWeTouchingASquare == YES) //
{
sp.position = ccp(pointOne.x , pointOne.y);
sp.zOrder = 1;
ball.zOrder = 0;
}
// Only run the following code if there is more than one touch
if ([touchArray count] > 1)
{
/*if (areWeTouchingABall == YES && CGRectContainsPoint(ball.boundingBox, pointOne)) //
{
ball.position = ccp(pointOne.x , pointOne.y);
ball.zOrder = 1;
sp.zOrder = 0;
}*/
if (areWeTouchingABall == YES && CGRectContainsPoint(ball.boundingBox, pointTwo)) //
{
ball.position = ccp(pointTwo.x , pointTwo.y);
ball.zOrder = 1;
sp.zOrder = 0;
}
/*if (areWeTouchingASquare == YES && CGRectContainsPoint(ball.boundingBox, pointOne)) //
{
sp.position = ccp(pointOne.x , pointOne.y);
sp.zOrder = 1;
ball.zOrder = 0;
}*/
if (areWeTouchingASquare == YES && CGRectContainsPoint(ball.boundingBox, pointTwo)) //
{
sp.position = ccp(pointTwo.x , pointTwo.y);
sp.zOrder = 1;
ball.zOrder = 0;
}
}
}
and this is in touchesEnded:
-(void) ccTouchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
areWeTouchingABall = NO;
areWeTouchingASquare = NO;
//printf("*** ccTouchesEnded (x:%f, y:%f)\n", location.x, location.y);
}
Every time I touch anywhere with one finger, I get this error:
"Terminating app due to uncaught exception 'NSRangeException', reason: '* -[__NSArrayI objectAtIndex:]: index 1 beyond bounds [0 .. 0]'",
When I touch with two fingers, the error does not come up but multi touch does not work correctly ( I cannot drag a sprite with a finger each. The second sprite touched jumps straight to the other finger location so that both sprites are under one finger.)
I made sure to add the code:
[glView setMultipleTouchEnabled:YES];
to my AppDelegate.m file and I have touch enabled in my init method.
How can I fix this issue so that multi-touch works properly and the error is removed?
UITouch *fingerOne = [touchArray objectAtIndex:0];
UITouch *fingerTwo = [touchArray objectAtIndex:1];
There's no guarantee that you'll always receive two touches in a touch event. First test how many touches there are in touchArray using
UITouch *fingerOne = [touchArray objectAtIndex:0];
UITouch *fingerTwo = nil;
if (touchArray.count > 1)
{
fingerTwo = [touchArray objectAtIndex:1];
}
Even then this won't work logically because the second touch in the array may not always correspond to finger #2. I suggest to read up on tracking individual fingers here.
I have a class where I add multiple sprites as shown in the code below:
CCSprite *b = [CCSprite spriteWithFile:#"b"];
b.position = ccp(100, 160);
CCSprite *b2 = [CCSprite spriteWithFile:#"b2.png"];
b2.position = ccp(115, 150);
CCSprite *b3 = [CCSprite spriteWithFile:#"b3.png"];
b.position = ccp(200, 150);
CCSprite *b4 = [CCSprite spriteWithFile:#"b4.png"];
b4.position = ccp(220, 145);
b.anchorPoint = ccp(0.98, 0.05);
b2.anchorPoint = ccp(0.03, 0.05);
b3.anchorPoint = ccp(0.03, 0.05);
b4.anchorPoint = ccp(0.95, 0.05);
[self addChild:b z:1 tag:1];
[self addChild:b2 z:1 tag:2];
[self addChild:b3 z:1 tag:3];
[self addChild:b4 z:1 tag:4];
Here's the code for the touch event:
-(void)ccTouchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
NSSet *allTouch = [event allTouches];
UITouch *touch = [[allTouch allObjects]objectAtIndex:0];
CGPoint location = [touch locationInView:[touch view]];
location = [[CCDirector sharedDirector]convertToGL:location];
//Swipe Detection - Beginning point
beginTouch = location;
for(int i = 0; i < [hairArray count]; i++)
{
CCSprite *sprite = (CCSprite *)[hairArray objectAtIndex:i];
if(CGRectContainsPoint([sprite boundingBox], location))
{
//selectedSprite is a sprite declared on the header file
selectedSprite = sprite;
}
}}
-(void)ccTouchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
//Move touched sprite
NSSet *allTouch = [event allTouches];
UITouch *touch = [[allTouch allObjects]objectAtIndex:0];
CGPoint location = [touch locationInView:[touch view]];
location = [[CCDirector sharedDirector]convertToGL:location];
if(selectedSprite != nil)
{
selectedSprite.position = ccp(location.x, location.y);
}}
-(void) ccTouchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
//End point of sprite after dragged
NSSet *allTouch = [event allTouches];
UITouch *touch = [[allTouch allObjects]objectAtIndex:0];
CGPoint location = [touch locationInView:[touch view]];
location = [[CCDirector sharedDirector]convertToGL:location];
endTouch = location;
posX = endTouch.x;
//Minimum swipe length
posY = ccpDistance(beginTouch, endTouch);
[self moveSprite];}
Now, the actions itself work just fine but the trouble I'm having is that if I want to drag b2, I have to drag b3 and b4 first. I'm not sure if it has anything to do with the z-index or it is because of the transparent areas that is present for each sprite. Is there something I'm missing here?
if(CGRectContainsPoint([sprite boundingBox], location))
{
//selectedSprite is a sprite declared on the header file
selectedSprite = sprite;
}
This code updates the currently selected sprite as soon as a new one is found while looping on all sprites. This means that if 3 sprites overlap you will get that the selected one is the last one in the array of nodes of the parent.
You can't make any assumptions on the orders so this is not clearly what you want, you have to decide a policy to give sprites priority. Mind that editing the anchorPoint may alter the position of the sprite compared to the bounding box (so that the bounding box is even outside the sprite).
To be sure of it you should enable:
#define CC_SPRITE_DEBUG_DRAW 1
in ccConfig.h. This will render bounding boxes around sprites.
I need to be able to touch a specific moving sprite in my array and perform an action on it. However when I perform my MoveTo action, the sprite location doesn't update. Help!
Array:
int numbreds = 7;
redBirds = [[CCArray alloc] initWithCapacity: numbreds];
for( int i = 1; i<=numbreds; i++){
int xvalue = ((-50*i) + 320);
int yvalue= 160;
if (i==4)
{
CCSprite *parrot = [CCSprite spriteWithFile:#"taco.png"];
[birdLayer addChild:parrot];
[self movement]; //the action that moves the array horizontally
parrot.position = ccp(xvalue,yvalue);
parrot.tag=100;
Touch
-(void)ccTouchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
CGPoint location = [touch locationInView:[touch view]];
location = [[CCDirector sharedDirector] convertToGL:location];
CCSprite *mark = (CCSprite *)[birdLayer getChildByTag:100];
if (CGRectContainsPoint([mark boundingBox], location))
{
CCLOG(#"YAY!");
}
THe problem is that the location of the CCSprite doesn't actually update or move. YAY! only is generated at the origin location of the sprite.
Try this:
CCSprite *temp = [CCSprite spriteWithFile:#"taco.png"];
temp = [birdLayer getChildByTag:100];
if (temp.position.x == location.x) {
// do stuff...
}
In my test game i have some sprites (Bubbles = NSMutableArray) wich are appear in random location at bottom of the screen.
I have addBubble and spawBubble methods:
- (void) addBubble {
CGSize winSize = [[CCDirector sharedDirector] winSize];
bubbles = [[NSMutableArray alloc] init];
[[CCSpriteFrameCache sharedSpriteFrameCache] addSpriteFramesWithFile:#"bubbleSpriteList.plist"];
CCSpriteBatchNode *bubbleSpriteList = [CCSpriteBatchNode batchNodeWithFile:#"bubbleSpriteList.png"];
[self addChild:bubbleSpriteList];
bigBubble = [CCSprite spriteWithSpriteFrameName:#"bubble"];
[self addChild:bigBubble];
[bubbles addObject:bigBubble];
for (CCSprite *bubble in bubbles) {
int minX = bubble.contentSize.width/2;
int maxX = winSize.width-bubble.contentSize.width/2;
int rangeX = maxX - minX;
int actualX = (arc4random() % rangeX) + minX;
bubble.position = ccp(actualX, 0);
int minSpeed = 15.0;
int maxSpeed = 20.0;
int rangeSpeed = maxSpeed - minSpeed;
int actualSpeed = (arc4random() % rangeSpeed) + minSpeed;
ccBezierConfig bubblePath;
bubblePath.controlPoint_1 = ccp(200, winSize.height/3);
bubblePath.controlPoint_2 = ccp(-200, winSize.height/1.5);
bubblePath.endPosition = ccp(0, winSize.height+bubble.contentSize.height/2);
id bezierMove = [CCBezierBy actionWithDuration:actualSpeed bezier:bubblePath];
[bubble runAction:bezierMove];
}}
-(void)spawBubble:(ccTime)dt {
[self addBubble];}
Then in my init method i added background and spawBubble method with random time interval
[self schedule:#selector(spawBubble:) interval:actualTime];
I'm trying to make every bubble from Bubbles blow, when it was touched, with this code
- (BOOL)ccTouchBegan:(UITouch *)touch withEvent:(UIEvent *)event {
CGPoint touchLocation = [touch locationInView:[touch view]];
touchLocation = [[CCDirector sharedDirector] convertToGL:touchLocation];
touchLocation = [self convertToNodeSpace:touchLocation];
- (BOOL)ccTouchBegan:(UITouch *)touch withEvent:(UIEvent *)event {
CGPoint touchLocation = [touch locationInView:[touch view]];
touchLocation = [[CCDirector sharedDirector] convertToGL:touchLocation];
touchLocation = [self convertToNodeSpace:touchLocation];
for (CCSprite *bubble in bubbles) {
CGRect bubbleRect = CGRectMake(bubble.position.x - (bubble.contentSize.width/2),
bubble.position.y - (bubble.contentSize.height/2),
bubble.contentSize.width,
bubble.contentSize.height);
if (CGRectContainsPoint(bubbleRect, touchLocation)) {
NSLog(#"%i", [bubbles count]);
[bubble setDisplayFrame:[[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:#"bubbleBlow"]];
id disappear = [CCFadeTo actionWithDuration:0.1 opacity:0];
[bubble runAction:disappear];
}
}
return TRUE;}
Every bubbles blowing perfectly if only one bubble in the screen, but if one bubble on the screen and another one was appeared, only last one is detects touches.
What am i doing wrong?
Hard to tell without seeing more code - but here's where I'd start:
Above this line:
for (CCSprite *bubble in bubbles) {
add:
NSLog(#"%i", [bubbles count]);
EDIT:
Based on the code you added:
Your problem is with this line:
bubbles = [[NSMutableArray alloc] init];
which is effectively wiping out your bubbles array every time you add a new bubble.
So, there will only ever be one bubble in the array - the last one.
Hence the problem you're running into.
I changed addBubble methods by removing bubbles = [[NSMutableArray alloc] init];, and adding it to init method...
Now everything works perfectly! )
I have a spear like sprite. It rotation is decided by touchesMoved method. whenever the user slides his finger it points towards that touch. This is my method:
- (void)ccTouchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch* touch = [touches anyObject];
CGPoint location = [touch locationInView: [touch view]];
float angleRadians = atanf((float)location.y / (float)location.x);
float angleDegrees = CC_RADIANS_TO_DEGREES(angleRadians);
spear.rotation = -1 * angleDegrees;
}
This kinda works, but only from 0 to 45 degrees. and it goes opposite. So as I am moving from finger for bottom to top, it rotates clockwise (it should follow direction of fnger and rotate counter clockwise). From 45 to 90, it works fine (moves counter clickwise) but only if i start the touch in upper diagonal of the screen.
What am i doing wrong?
Thanks
#define PTM_RATIO 32
- (void)ccTouchesMoved:(NSSet *)touches withEvent:(UIEvent *)event{
for( UITouch *touch in touches ) {
CGPoint location = [touch locationInView: [touch view]];
location = [[CCDirector sharedDirector] convertToGL: location];
b2Vec2 locationWorld = b2Vec2(location.x/PTM_RATIO, location.y/PTM_RATIO);
spriteBody->SetTransform(locationWorld,spriteBody->GetAngle());
}
}
-(void) tick: (ccTime) dt
{
//It is recommended that a fixed time step is used with Box2D for stability
//of the simulation, however, we are using a variable time step here.
//You need to make an informed choice, the following URL is useful
//http://gafferongames.com/game-physics/fix-your-timestep/
int32 velocityIterations = 8;
int32 positionIterations = 1;
// Instruct the world to perform a single step of simulation. It is
// generally best to keep the time step and iterations fixed.
m_world->Step(dt, velocityIterations, positionIterations);
// for (int i = 0; i < (int)birds.size(); i++)
// birds[i]->render();
//Iterate over the bodies in the physics world
for (b2Body* b = m_world->GetBodyList(); b; b = b->GetNext())
{
if (b->GetUserData() != NULL) {
//Synchronize the AtlasSprites position and rotation with the corresponding body
CCSprite *myActor = (CCSprite*)b->GetUserData();
myActor.position = CGPointMake( b->GetPosition().x * PTM_RATIO, b->GetPosition().y * PTM_RATIO);
myActor.rotation = -1 * CC_RADIANS_TO_DEGREES(b->GetAngle());
}
}
}
Figured out what was wrong. I needed to change the CGPoint I got from the touches into GL point like this:
CGPoint location = [touch locationInView: [touch view]];
location = [[CCDirector sharedDirector] convertToGL: location];
Silly me. Should have thought about this before.
CGPoint touchLocation = [touch locationInView: [touch view]];
touchLocation = [[CCDirector sharedDirector] convertToGL:touchLocation];
touchLocation = [self convertToNodeSpace:touchLocation];
GPoint diff = ccpSub(touchLocation, _player.position);
//rotate to face the touch
CGPoint diff = ccpSub(_player.position, touchLocation);
float angleRadians = atanf((float)diff.y / (float)diff.x);
float angleDegrees = CC_RADIANS_TO_DEGREES(angleRadians);
float cocosAngle = -1 * angleDegrees;
if(diff.x < 0)
{
cocosAngle += 180;
}
id actionRotateTo = [CCRotateTo actionWithDuration:0.1 angle:cocosAngle];
[_player runAction:actionRotateTo];