I am trying to detect the coordinates where two sprites (shipLaser and baddie) intersect and then make a new sprite (speedPowerUp) in that position. Below is what I have attempted to do with nodeAtPoint but it is just running and then crashing when the two sprites intersect.
for (SKSpriteNode *baddie in _baddies)
{
baddie.name = #"baddie1";
if (baddie.hidden) {
continue;
}
for (SKSpriteNode *shipLaser in _shipLasers){
if (shipLaser.hidden) {
continue;
}
if ([shipLaser intersectsNode:baddie]) {
shipLaser.hidden = YES;
baddie.hidden = YES;
[shipLaser nodeAtPoint:*(_itemDrop)];
NSLog(#"You just destroyed a baddie");
_score = _score + 10;
_scoreLabel.text = [NSString stringWithFormat:#"%i", _score];
if (_score == 10)
{
_speedPowerUp.hidden = NO;
_speedPowerUp.position = *(_itemDrop);
[self addChild:_speedPowerUp];
}
Related
Ok i now manage to figure out the problem but now another issue appear, my robot seem to move on its own to another point which i have no idea where its from. Here my code
His code make this robot move to the location i click on the terrain.
bool DemoApp::nextLocation(void){
mDestination = mtoward;
mRobotDir = mDestination - mRobotNode[0]->getPosition();
mDistance = mRobotDir.normalise();
return true;
}
bool DemoApp::frameRenderingQueued(const Ogre::FrameEvent& evt)
{
if (mRobotDir == Ogre::Vector3::ZERO) {
if (nextLocation()) {
// Set walking animation
mAnimationState = mRobot[0]->getAnimationState("Walk");
mAnimationState->setLoop(true);
mAnimationState->setEnabled(true);
}//if
}else{
Ogre::Real move = mWalkSpeed * evt.timeSinceLastFrame;
mDistance -= move;
if (mDistance <= 0.0f){
mRobotNode[0]->setPosition(mDestination);
mRobotDir = Ogre::Vector3::ZERO;
// Set animation based on if the robot has another point to walk to.
if (!nextLocation()){
// Set Idle animation
mAnimationState = mRobot[0]->getAnimationState("Idle");
mAnimationState->setLoop(true);
mAnimationState->setEnabled(true);
}else{
// Rotation Code will go here later
Ogre::Vector3 src = mRobotNode[0]->getOrientation() * Ogre::Vector3::UNIT_X;
if ((1.0f + src.dotProduct(mRobotDir)) < 0.0001f) {
mRobotNode[0]->yaw(Ogre::Degree(180));
}else{
Ogre::Quaternion quat = src.getRotationTo(mRobotDir);
mRobotNode[0]->rotate(quat);
} // else
}//else
}else{
mRobotNode[0]->translate(mRobotDir * move);
} // else
} // if
mAnimationState->addTime(evt.timeSinceLastFrame);
}
Here is the raycast code for my mouse click
Ogre::Terrain* pTerrain = mTerrainGroup->getTerrain(0, 0);
Ogre::Viewport* vp = this->mWindow->getViewport(0);
Ogre::Ray mouseRay = mCamera->getCameraToViewportRay(static_cast<float>(mMouse->getMouseState().X.abs)/mMouse->getMouseState().width, static_cast<float>(mMouse->getMouseState().Y.abs)/mMouse->getMouseState().height);
std::pair <bool, Ogre::Vector3> result;
result = pTerrain->rayIntersects(mouseRay, true, 0);
if (result.first = true)
{
mtoward = result.second - mRobotNode[0]->_getDerivedPosition();
mRobotNode[0]->translate(mtoward, Ogre::Node::TS_LOCAL);
}
I am trying to detect collision between sprites from the same NSMutableArray. I am running a loop to compare one sprite with all of them, inclusing itself.
The thing is that the "CGRectEqualToRect" method is returning me a TRUE boolean, even though it is not!
- (BOOL)detectCollision: (CCSprite*)sprite{
BOOL result = FALSE;
CCSprite *toCollide;
CGRect rect1 = [GameScene positionRect:sprite];
for (int i = 0; i < [movableSprites count]; i++){
toCollide = [movableSprites objectAtIndex:i];
CGRect rect2 = [GameScene positionRect:toCollide];
if (!CGRectIsNull(CGRectIntersection(rect1, rect2))) {
if(!CGRectEqualToRect(rect1, rect2)){
//handle collision
NSLog(#"Collides");
result = TRUE;
}
}
}
return result;
}
For instance, when debugging, rect1 is returning the same sizes as rect2, but its x and y are completely different.
Any ideas on this one?
Thanks!
Try this..
- (BOOL)detectCollision: (CCSprite*)sprite
{
BOOL result = FALSE;
for (int i = 0; i < [movableSprites count]; i++)
{
CCSprite *toCollide; = [movableSprites objectAtIndex:i];
if(sprite==toCollide){
continue;
}
if (CGRectIntersectsRect(sprite.boundingBox, toCollide.boundingBox)) {
//handle collision
NSLog(#"Collides");
result = TRUE;
return result;
}
}
return result;
}
Make sure that all sprites are added to same object(Parent),otherwise you same to do some changes..
I'm trying to add a Sprite beside the player, but only when the Tile beside the player is NOT a Wall. I know that the Tiled tiles are working properly, as they do their job in this method:
CGPoint p = CGPointMake(tileCoord.x, tileCoord.y - 1);
if ([self isValidTileCoord:p] && ![self isWallAtTileCoord:p]) {
[tmp addObject:[NSValue valueWithCGPoint:p]];
t = YES;
I am checking for Tiled on coordinate with these two methods:
-(BOOL)isProp:(NSString*)prop atTileCoord:(CGPoint)tileCoord forLayer:(CCTMXLayer *)layer {
if (![self isValidTileCoord:tileCoord]) return NO;
int gid = [layer tileGIDAt:tileCoord];
NSDictionary * properties = [_tileMap propertiesForGID:gid];
if (properties == nil) return NO;
return [properties objectForKey:prop] != nil;
}
-(BOOL)isWallAtTileCoord:(CGPoint)tileCoord {
return [self isProp:#"Wall" atTileCoord:tileCoord forLayer:_bgLayer];
}
(Thanks RayWenderlich)
And my code for adding the sprite is
CGPoint tileCoord = ccp(_player.position.x - 24 +60, player.position.y);
CGPoint cTileCoord = [self tileCoordForPosition:tileCoord];
NSLog(#" t: %#, c: %#",
CGPointCreateDictionaryRepresentation(tileCoord),
CGPointCreateDictionaryRepresentation(cTileCoord)
);
if (![self isWallAtTileCoord:cTileCoord])
{
NSLog(#"False");
circle1.position = ccp(_player.position.x - 24 +60, _player.position.y);
[self addChild:circle1];
}
else
{
NSLog(#"True");
}
What I want this to do is to only add the Circle1 sprite to the left of the player when there isn't a Wall tile there. The problem is that this code always detects false, no matter if there is a wall there or not. Do any of you guys understand why it does not detect the walls properly and how I can fix it?
Last year me also observed same problem in retina mode. It worked in non retina but not detected in retina mode.
So finally used custom dictionary to check edge tile. Integer comparison takes less CPU time than string comparison. So replaced it with enum.
Go for this approach only if none other simple way worked.
I used this code to find edge of the tile that set in meta property.
typedef enum GRID_TYPE{
kGrideType_Normal = 4001,
kGrideType_Collidable,
kGrideType_Collectable,
kGrideType_Sea,
kGrideType_Edge,
kGrideType_enemy,
kGrideType_gold,
}GridType;
//Init tilemap and grid type
tileMap.meta = [tileMap layerNamed:PP_TILE_META_LAYER];
[tileMap initTileAnimation];
//Somewhere in code
CGPoint point = [self getTileCoordForPosition:position];
GridType type = [self getTileType:point];
if(type == kGrideType_Edge)
{
//touched edge tile....
}
Functions:
-(GridType)getTileType:(CGPoint)pos
{
// not defined USE_COCOS2D_FOR_TILE_IDENTIFICATION
#ifdef USE_COCOS2D_FOR_TILE_IDENTIFICATION
GridType type = kGrideType_Normal;
CGPoint tileCoord = position;//[self tileCoordForPosition:position];
unsigned int tileGid = [self.meta tileGIDAt:tileCoord];
if (tileGid) {
NSDictionary *properties = [self propertiesForGID:tileGid];
if (properties)
{
NSString *collision = [properties valueForKey:TILE_PROPERTY_COLLIDABLE];
if (collision && [collision caseInsensitiveCompare:#"true"] == NSOrderedSame)
{
type = kGrideType_Collidable ;
}
NSString *collectable = [properties valueForKey:TILE_PROPERTY_COLLECTABLE];
if (collectable && [collectable caseInsensitiveCompare:#"true"] == NSOrderedSame) {
type = kGrideType_Coin ;
}
NSString *collectable = [properties valueForKey:TILE_PROPERTY_CHEST];
if (collectable && [collectable caseInsensitiveCompare:#"true"] == NSOrderedSame) {
type = kGrideType_Chest ;
}
}
}
return type;
#else
int type = [[mTileInfoDict objectForKey:[NSString stringWithFormat:#"TILE(%d,%d)", (int)pos.x,(int)pos.y]] intValue];
GridType gType = kGrideType_Normal;
if(type!=0)
gType = (GridType)type;
return (GridType)gType;
#endif
}
-(void)initTileAnimation
{
mTileInfoDict = [[NSMutableDictionary alloc] init];
//Parse all the tile in map
mBgLayer = [self layerNamed:PP_TILE_MAP_BG_LAYER];
int rowSize = self.mapSize.width ;
int colSize = self.mapSize.height ;
for(int x=0; x<rowSize; x++)
{
for (int y=0; y<colSize; y++)
{
CGPoint tileCord = ccp(x,y) ;
NSString *key = [NSString stringWithFormat:#"TILE(%d,%d)", (int)tileCord.x,(int)tileCord.y];
GridType tileType = kGrideType_Normal;
unsigned int tileGid = [self.meta tileGIDAt:tileCord];
if (tileGid)
{
NSDictionary *properties = [self propertiesForGID:tileGid];
if (properties)
{
/* Check Tile : IS SEA - TILE */
NSString *sea = [properties valueForKey:TILE_PROPERTY_SEA];
if (sea && [sea isEqualToString:#"true"])
{
tileType = kGrideType_Sea;
[mTileInfoDict setObject:[NSNumber numberWithInt:tileType] forKey:key];
continue;
}
/* Check Tile : IS Inky - TILE */
/* Check Tile : IS COLLECTABLE - COIN */
NSString *collectable = [properties valueForKey:TILE_PROPERTY_COLLECTABLE];
if (collectable && [collectable isEqualToString:#"true"])
{
tileType = kGrideType_Collectable;
[mTileInfoDict setObject:[NSNumber numberWithInt:tileType] forKey:key];
PPCoins *coinSprite = [PPCoins spriteWithSpriteFrameName:#"coin_0000.png"];
coinSprite.tag = kTagCoinSprite;
coinSprite.anchorPoint = ccp(0.5f,0.5f);
CCSprite *sprite = [mBgLayer tileAt:tileCord];
coinSprite.position = ccp(sprite.position.x+coinSprite.contentSize.width*0.5f, sprite.position.y+coinSprite.contentSize.height*0.5f) ;
[self addChild:coinSprite z:3 tag:kTagCoinSprite];
[coinSprite runAnimation];
{
coinSprite.key = key;
[mCoinDict setObject:coinSprite forKey:key];
}
continue;
}
/* Check Tile : IS COLLIDABLE - TILE */
NSString *collidable = [properties valueForKey:TILE_PROPERTY_COLLIDABLE];
if (collidable && [collidable isEqualToString:#"true"])
{
tileType = kGrideType_Collidable;
[mTileInfoDict setObject:[NSNumber numberWithInt:tileType] forKey:key];
continue;
}
/* Check Tile : IS Edge - TILE */
NSString *edge = [properties valueForKey:TILE_PROPERTY_EDGE];
if (edge && [edge isEqualToString:#"true"])
{
tileType = kGrideType_Edge;
[mTileInfoDict setObject:[NSNumber numberWithInt:tileType] forKey:key];
continue;
}
NSString *redTargetCoin = [properties valueForKey:TILE_PROPERTY_TARGET_COIN];
if (redTargetCoin && [redTargetCoin isEqualToString:#"true"])
{
tileType = kGrideType_TargetCoins;
[mTileInfoDict setObject:[NSNumber numberWithInt:tileType] forKey:key];
}
}
else
{
[mTileInfoDict setObject:[NSNumber numberWithInt:kGrideType_Normal] forKey:key];
}
}
}
}
}
- (CGPoint)getTileCoordForPosition:(CGPoint)position
{
// CGPoint nodeSpace1 = [self convertToNodeSpace:position];
// float x = floor(nodeSpace1.x / self.tileSize.width);
// float y = floor(self.mapSize.height - (nodeSpace1.y / self.tileSize.height));
//
// if( x >= TILE_IN_ROW)
// x = TILE_IN_ROW - 1;
//
// if( y >= TILE_IN_COL)
// y = TILE_IN_COL - 1;
//
// return ccp(x, y);
int maxTileCol = self.mapSize.height;// (_tileMap.contentSize.height)/TILE_SIZE;
int x = ( (position.x-self.position.x)/TILE_SIZE);
int y = maxTileCol - ( ((position.y)-self.position.y)/TILE_SIZE);
if( x >= TILE_IN_ROW)
x = TILE_IN_ROW - 1;
if( y >= TILE_IN_COL)
y = TILE_IN_COL - 1;
return ccp(x, y);
}
You should check if your tile map has the correct layer settings. I did a mistake with this once, it is easy to forget
For my collision detection I need to check of the ball rect intersects any of the wall rects. Right now I have it working but its checking to see if the ball's position is at one of the tile's GID, using this.
-(void) checkHits:(CGPoint)position {
CGPoint tileCoord = [self tileCoordForPosition:position];
int tileGid = [levelLayer tileGIDAt:tileCoord];
//NSLog(#"%g",tileRect.origin);
if (tileGid) {
NSDictionary *properties = [level propertiesForGID:tileGid];
if (properties) {
NSString *collision = [properties valueForKey:#"break"];
if (collision && [collision compare:#"True"] == NSOrderedSame) {
//for blocks
//[[SimpleAudioEngine sharedEngine] playEffect:#"hit.caf"];
[levelLayer removeTileAt:tileCoord];
velocity.y *= -1;
}
if (collision && [collision compare:#"False"] == NSOrderedSame) {
//for edges
//[[SimpleAudioEngine sharedEngine] playEffect:#"hit.caf"];
velocity.y *= -1;
}
}
}
}
I need to know how to change this to checking to see if the balls rect/boundingbox intersects with any of the tiles rects/boundingboxex(and how to get the tiles rect/boundingbox in the first place) that have the property break.
P.S. I'm using the Tiled map editor.
Figured this out a little while ago:
CCSprite *tile;
for (int i = 0; i < level.contentSize.width/level.tileSize.width; i ++)
for (int j = 0; j < level.contentSize.height/level.tileSize.height; j ++){
tile = [levelLayer tileAt:ccp(i,j)];
if (CGRectIntersectsRect(ball.boundingBox, tile.boundingBox)) {
//Do whatever...
}
}
}
I recommend having a collide layer to make map making easier.
I am using the ccTouchBegan and ccTouchEnded, and for some reason there is a block of code that runs perfectly on iPhone simulator and doesn't run at all on iPhone 4. This is what my methods look like:
-(BOOL)ccTouchBegan:(UITouch*)touch withEvent:(UIEvent *)event {
firstTouch = [self convertTouchToNodeSpace:touch];
if (!self.currentFootball.footballHasEmbarked) {
//arrow.position = ccp(fPos.x, fPos.y);
float newAnc = (120 + (self.currentFootball.contentSize.width * .5f) + (arrow.contentSize.width * .5f)) / arrow.contentSize.width;
arrow.anchorPoint = ccp(-newAnc, .5);//self.currentFootball.position;
arrow.position = self.currentFootball.position;//ccp(fPos.x-120, fPos.y);
arrow.rotation = 180;
arrow.visible = YES;
arrow.scale = 0.5f;
//powerLevel.position = fPos;
powerLevel.position = self.currentFootball.position;
powerLevel.rotation = 180;
powerLevel.percentage = 0;
powerLevel.visible = YES;
outLine.position = self.currentFootball.position;
outLine.rotation = 180;
outLine.visible = YES;
CCProgressFromTo *powerBarGoUp = [CCProgressFromTo actionWithDuration:1.0f from:0.0f to:100.0f];
CCProgressFromTo *powerBarGoDown = [CCProgressFromTo actionWithDuration:1.0f from:100.0f to:0.0f];
id action = [CCRepeatForever actionWithAction:[CCSequence actions:powerBarGoUp, powerBarGoDown, nil]];
[powerLevel runAction:action];
return YES;
}
else {
return NO;
}
}
-(void) ccTouchEnded:(UITouch*)touch withEvent:(UIEvent *)event {
const float max = 100;
CGPoint endTouch = [self convertTouchToNodeSpace:touch];
if (endTouch.x > firstTouch.x) {
endTouch = ccp(firstTouch.x, endTouch.y);
//CCLOG(#"I ran");
}
arrow.visible = NO;
powerLevel.visible = NO;
outLine.visible = NO;
self.currentFootball.footballHasEmbarked = YES;
self.currentFootball.spiraling = YES;
if (self.currentFootball) {
[smgr addBody:self.currentFootball.body];
}
if (CGPointEqualToPoint(endTouch, firstTouch)) {
CCLOG(#" I have run");
float anchorPointDist = ccpLength(endTouch);
float distFactor = distFromFb + anchorPointDist;
projectionAnchorPoint = ccp(firstTouch.x + distFactor,firstTouch.y);
}
CGPoint diff = ccpSub(endTouch, projectionAnchorPoint);
float len = powerLevel.percentage;
CGPoint norm = ccpNormalize(diff);
if (len > max){
len = max;
}
[self.currentFootball applyImpulse:ccpMult(norm, (len * 300))];
pos = self.currentFootball.position.y;
[self schedule:#selector(newFootball)];
}
This is the block of code that will not run on my iPhone.
if (CGPointEqualToPoint(endTouch, firstTouch)) {
CCLOG(#" I have run");
float anchorPointDist = ccpLength(endTouch);
float distFactor = distFromFb + anchorPointDist;
projectionAnchorPoint = ccp(firstTouch.x + distFactor,firstTouch.y);
}
Am I not doing something right?
Print out the values for endTouch and firstTouch. They may vary by a very small amount on device, as it's harder to keep your finger in the same location as opposed to a mouse pointer. If that's the case, you may want to accept end touches within a range of the first touch.
Perhaps there is some slight difference in the points you are comparing, making the result of that comparison always false. Try using this method instead of CGPointEqualToPoint.
BOOL ccpFuzzyEqual(CGPoint a, CGPoint b, float variance);