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
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.
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?
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.
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;
}
}
}
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) .