Dpad for sprite kit - sprite-kit

I an interested in trying to create a few games, namely in the new sprite kit. However, for the game that I have in mind I would rather use a directional pad vs a joy stick. Since I shall be moving over from Cocos, my old program no longer works (so neither will that dpad). Sadly, I have not come accross any tutorial that may help with implementing one in the new sprite kit (only joy sticks). I was wondering and hoping if anyone came across a simple dpad class from github or something or a helpful link that they would like to share. Thanks

Here's one way:
//Joystick node
- (SKSpriteNode *)controlPadNode
{
SKSpriteNode *controlPadNode = [SKSpriteNode spriteNodeWithImageNamed:#"game-controller-front"];
controlPadNode.position = CGPointMake(controlPadX,controlPadY);
controlPadNode.name = #"controlPadNode";
controlPadNode.zPosition = 1.0;
return controlPadNode;
}
//handle touch events
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
CGPoint location = [touch locationInNode:self];
SKNode *node = [self nodeAtPoint:location];
//if control pad touched
if ([node.name isEqualToString:#"controlPadNode"]) {
touchX = location.x;
touchY = location.y;
controlButtonDown = true;
}
}
//when touch moves
- (void) touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
CGPoint location = [touch locationInNode:self];
SKNode *node = [self nodeAtPoint:location];
//if control pad touched
if ([node.name isEqualToString:#"controlPadNode"]) {
touchX = location.x;
touchY = location.y;
controlButtonDown = true;
}
}
- (void) touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
CGPoint location = [touch locationInNode:self];
SKNode *node = [self nodeAtPoint:location];
//if control pad touched
if ([node.name isEqualToString:#"controlPadNode"]) {
controlButtonDown = false;
}
}
//update method
-(void)update:(NSTimeInterval)currentTime {
if (controlButtonDown) {
//the control pad
SKNode *controlNode = [self childNodeWithName:#"controlPadNode"];
//the node you want to move
SKNode *node = [self childNodeWithName:#"spaceShipNode"];
//compute the angle between parameters pad and the horizontal
float angle = atan2f (touchY - controlPadY, touchX - controlPadX) ;
//move the control pad for the player to have a sense of movement
SKAction *moveControlPad = [SKAction moveTo:CGPointMake(touchX, touchY) duration:0.00001];
double distance = sqrt(pow((touchX - controlPadX), 2.0) + pow((touchY - controlPadY), 2.0));
//make sure the control pad only moves 40 pixels
if( distance < 40 ){
[controlNode runAction:moveControlPad];
}
//move the ship
SKAction *moveShip = [SKAction moveByX: 6*cosf(angle) y:6*sinf(angle) duration:0.005];
[node runAction: moveShip];
}
}
EDIT:
Also can use this to move the control pad back when touch ends:
if (!controlButtonDown) {
SKNode *controlNode = [self childNodeWithName:#"controlPadNode"];
SKAction *moveControlPad = [SKAction moveTo:CGPointMake(controlPadX, controlPadY) duration:0.00001];
[controlNode runAction:moveControlPad];
}

I've built a small UIKit based game engine before the introduction of SpriteKit. My engine loads cocos2d compatible maps from Tiled, sprites from TexturePacker, and it comes with a joystick that I ported from cocos2d to UIKit. (Mine is based on sneaky-joystick.)
You can grab the whole library on GitHub and pull out the parts you need. It's fairly modular.

Related

intersectsNode not working?

I'm trying to detect when one node overlaps another. I am teaching myself sprite kit and cannot get intersectsNodes to give any output. I've loaded 2 nodes that can be moved around on the screen and then added intersectsNodes in the update section.
-(void)update:(CFTimeInterval)currentTime {
SKSpriteNode* playerShip1;
SKSpriteNode* playerShip2;
if ([playerShip1 intersectsNode: playerShip2]) {
NSLog(#"your ships overlap");
}
Any thoughts on why no intersection is found?
here is the whole m file.
#import "MyScene.h"
#implementation MyScene
-(id)initWithSize:(CGSize)size {
if (self = [super initWithSize:size]) {
SKSpriteNode* playerShip1 = [SKSpriteNode spriteNodeWithImageNamed:#"player"];
playerShip1.position = CGPointMake(self.frame.size.width/2, playerShip1.frame.size.height);
playerShip1.name = #"PLAYER_SHIP_1";
[self addChild:playerShip1];
SKSpriteNode* playerShip2 = [SKSpriteNode spriteNodeWithImageNamed:#"player"];
playerShip2.position = CGPointMake(self.frame.size.width/2, self.frame.size.height-playerShip2.frame.size.height);
playerShip2.name = #"PLAYER_SHIP_2";
[self addChild:playerShip2];
SKSpriteNode* playerShip3 = [SKSpriteNode spriteNodeWithImageNamed:#"player"];
playerShip3.position = CGPointMake(self.frame.size.width/2, self.frame.size.height/2);
playerShip3.name = #"PLAYER_SHIP_3";
[self addChild:playerShip3];
activeDragNode = nil;
}
return self;
}
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
// Identify where this touch is on the scene
CGPoint scenePosition = [touch locationInNode:self];
// Find the child node that contains this touch
SKNode* checkNode = [self nodeAtPoint:scenePosition];
// Make sure it is a player ship and not another node like the parent SKScene
if (checkNode && [checkNode.name hasPrefix:#"PLAYER_SHIP"]) {
activeDragNode = (SKSpriteNode*)checkNode;
SKAction *zoomAction = [SKAction scaleTo:1.5 duration:.2];
[checkNode runAction:zoomAction];
//NSLog(#"your ship has been hit!");
}
}
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
// Remove reference to which object we are dragging
activeDragNode=nil;
UITouch *touch = [touches anyObject];
CGPoint scenePosition = [touch locationInNode:self];
SKNode* checkNode = [self nodeAtPoint:scenePosition];
SKAction *shrinkAction = [SKAction scaleTo:1.0 duration:.2];
[checkNode runAction:shrinkAction];
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
// Be sure we have a reference to an object to drag
if (activeDragNode==nil) return;
UITouch *touch = [touches anyObject];
CGPoint scenePosition = [touch locationInNode:self];
CGPoint lastPosition = [touch previousLocationInNode:self];
// Calculate the new location of the dragged node
CGPoint newLoc = CGPointMake(activeDragNode.position.x + (scenePosition.x - lastPosition.x), activeDragNode.position.y + (scenePosition.y - lastPosition.y));
// Update this location
activeDragNode.position = newLoc;
}
-(void)update:(CFTimeInterval)currentTime {
SKSpriteNode* playerShip1;
SKSpriteNode* playerShip2;
if ([playerShip1 intersectsNode: playerShip2]) {
NSLog(#"your ships overlap");
}
/* Called before each frame is rendered */
}
#end
First you need to set a position for each node:
playerShip1.position = CGPointMake(0,0);
Second you need to add each node to the view:
[self addChild:playerShip1];
Also, you are adding the nodes in your update method which is the wrong place. As your code is now, you will continuously add each node 60 times a second.
I see you adding additional code. You are creating 3 SKSpriteNodes in your init method which is fine and works. However, you are not keeping a reference to these 3 nodes. This means once they are created, you have no way to access them again. To resolve this, you should create 3 SKSpriteNode class properties or add all 3 nodes into an array (class property for the array). If you don't know what I mean, that's ok, it just means you have a ways to learn.
I suggest you do a couple of tutorials as this will teach some additional fundamentals and prevent a ton of "why isn't this working" frustration in the future.

how many bullets have been fired?

I am super frustrated and I know it is just because I don't know what i am doing with cocos2d. I am following Ray Wenderlich tutorials on cocos2d and I am trying to put it all together. When the screen is tapped,one bullet is fired in the direction of the tap. I am using
- (void)ccTouchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
CGPoint touchLocation = [self convertTouchToNodeSpace:touch];
[self.officer shootToward:touchLocation];
[self.officer shootNow];
}
- (void)ccTouchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
CGPoint touchLocation = [self convertTouchToNodeSpace:touch];
[self.officer shootToward:touchLocation];
[self.officer shootNow];
}
which calls these methods in my Officer class
- (void)shootNow {
// 1
CGFloat angle = ccpToAngle(_shootVector);
_gun.rotation = (-1 * CC_RADIANS_TO_DEGREES(angle)) + 90;
// 2
CGSize winSize = [[CCDirector sharedDirector] winSize];
float mapMax = MAX(winSize.width, winSize.height);
CGPoint actualVector = ccpMult(_shootVector, mapMax);
// 3
float POINTS_PER_SECOND = 300;
float duration = mapMax / POINTS_PER_SECOND;
// 5
for(id item in self.children) {
NSString *bulletName = [NSString stringWithFormat:#"bullet.png"];
CCSprite * bullet = [CCSprite spriteWithSpriteFrameName:bulletName];
//bullet.tag = _type;
bullet.position = ccpAdd(self.position, ccpMult(_shootVector, _gun.contentSize.height));
CCMoveBy * move = [CCMoveBy actionWithDuration:duration position:actualVector];
CCCallBlockN * call = [CCCallBlockN actionWithBlock:^(CCNode *node) {
[node removeFromParentAndCleanup:YES];
}];
[bullet runAction:[CCSequence actions:move, call, nil]];
[self.batchNode addChild:bullet];
//[self addChild:bullet];
[_shotsFired addObject:bullet];
}
}
So I figured it would be a simple for loop go through the 5th step x amount of times then call a reload method. Well that didn't work. So I tried to count the touches on the screen, I figured if I got x amount of taps then call the reload method(which is not written yet)? The problem with that was every time you pressed a different area of the screen the count started over from one. Some please help me through this week long process of pulling my hair out? How do I count the amount of times I have fired the gun?
Couldn't you just make a property on your view controller and then every time the shoot now method is called just add 1 to your property, then reset it to 0 when you call the reload method?

cocos 2d detect simoultaneous touch in 2 sprites - like in fruit ninja game

I want to know how can i detect when i touch 2 sprites simoultaneously in cocos2d. Im creating a game similar to fruit ninja and i want to add some bonus points when i smash two sprites simultaneously with my blade. I have tried something like that but it doesn't work:
(void)ccTouchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
//Add a new body/atlas sprite at the touched location
for( UITouch *touch in touches ) {
CGPoint location = [touch locationInView: [touch view]];
location = [[CCDirector sharedDirector] convertToGL: location];
//[self addNewSpriteAtPosition: location];
[_blade dim:YES];
[_bladeSparkle stopSystem];
for (b2Body* b = world->GetBodyList(); b; b = b->GetNext())
{
if (b->GetUserData() != NULL) {
PolygonSprite *sprite = (PolygonSprite*)b->GetUserData();
NSLog(#"sprite entered, exited %d, %d",sprite.sliceEntered,sprite.sliceExited);
if(sprite.type == kTypeTrapPrice && CGRectContainsPoint(sprite.boundingBox, location))
{
NSLog(#"TOUCHED");
noTouch++;
}
}
}
}
// NSLog(#"NO TOUCH %i",noTouch);
[self clearSlices];
}
Have you seen the following tutorial?
http://www.raywenderlich.com/14302/how-to-make-a-game-like-fruit-ninja-with-box2d-and-cocos2d-part-1
Plus there are lots of other great ones there.

cocos2d for iPhone - Touch no longer works correctly after scale

I am rather new to using Cocos2d for iPhone and I am having an issue with touch locations. At the moment I am simply trying to touch and move a sprite on the screen, this works fine when the layer is unmoved as well as when I translate the layer (changing self.position in X direction in my case) however, when I scale my layer (example: self.scale = .5) the touch no longer moves the sprite. I have done a lot of forum searching/google searching and I think my issue has to do with my coordinate transforms (node space/world space etc.) But I am not 100% sure. I did notice that when I scale, if I click the location where the sprite would be without the scale, then I could move the sprite. This leads me to believe that my transforms are not taking the scale into account.
Here is the coordinate transform code I am currently using to get touch locations:
- (void)ccTouchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *myTouch = [touches anyObject];
CGPoint location = [myTouch locationInView:[myTouch view]];
location = [self convertToNodeSpace:location];
location = [[CCDirector sharedDirector] convertToGL:location];
}
Here is the code that is checking if the location (same location variable as above) is touching a sprite, although I feel much more confident that this code is correct, who knows!
for (CCSprite *sprite in movableSprites) {
if (CGRectContainsPoint(sprite.boundingBox, touchLocation)) {
NSLog(#"Woohoo, you touched a sprite!");
break;
}
}
Let me know if you need anymore information and thanks for reading!
I think you should double the bounding box with the scale
for (CCSprite *sprite in movableSprites) {
if (CGRectContainsPoint(sprite.boundingBox*sprite.scale, touchLocation)) {
//touch sprite action
}
}
About converting the point, if I need an absolut screen point I always use:
convertToWorldSpace:CGPointZero.
I'm not really sure why you need this on your touch location, I would usually do this on sprites when I need to disregard their position in a parent node.
Other then that, If your game is not real multi-touch game you better use ccTouchBegan and not ccTouchesBegan.
Use this function to get sprite rect.
-(CGRect)getSpriteRect:(CCNode *)inSprite
{
CGRect sprRect = CGRectMake(
inSprite.position.x - inSprite.contentSize.width*inSprite.anchorPoint.x,
inSprite.position.y - inSprite.contentSize.height*inSprite.anchorPoint.y,
inSprite.contentSize.width,
inSprite.contentSize.height
);
return sprRect;
}
- (void)ccTouchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *myTouch = [touches anyObject];
CGPoint location = [myTouch locationInView:[myTouch view]];
location = [[CCDirector sharedDirector] convertToGL:location];
for (CCSprite *sprite in movableSprites)
{
CGRect rect = [self getSpriteRect:sprite];
if (CGRectContainsPoint(rect, location))
{
NSLog(#"Woohoo, you touched a sprite!");
break;
}
}
}

ApplyLinearImpulse() working in one direction only

I am trying to use both b2PrismaticJoint and b2MouseJoint. I need to move my projectile along x-axis to position it for target and want to only swipe vertically without moving the projectile to throw it in that direction. I am using ApplyLinearImpulse() but no matter in which direction i swipe it's direction is always towards top-right. The code is:
- (void)ccTouchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *myTouch = [touches anyObject];
CGPoint location = [myTouch locationInView:[myTouch view]];
location = [[CCDirector sharedDirector] convertToGL:location];
b2Vec2 locationWorld = b2Vec2(location.x/PTM_RATIO, location.y/PTM_RATIO);
if (_mouseJoint) {
_world->DestroyJoint(_mouseJoint);
_mouseJoint = NULL;
}
if(_primJoint) {
_world->DestroyJoint(_primJoint);
_primJoint = NULL;
}
if (hit) {
_strikerBody->ApplyLinearImpulse(locationWorld, _strikerBody->GetPosition());
}
}
Looks like your locationWorld vector is pointing in the same direction every time. I think you want something like this:
b2Vec2 impulseDirection = locationWorld - _strikerBody->GetPosition();
impulseDirection.Normalize();
const double Force = 10 * _strikerBody->GetMass(); //or anything you want
_strikerBody->ApplyLinearImpulse( Force*impulseDirection, _strikerBody->GetPosition() );
Now the impulse will be applied to the center of the _strikerBody in the touch direction (relative to the _strikerBody) .