I have been following a tutorial on SpriteKit, and for the life of me, I don't know where this one method comes from. In a StartGameLayer, I have this code in its entirety:
#import "StartGameLayer.h"
#interface StartGameLayer()
#property (nonatomic, retain) SKSpriteNode* playButton;
#end
#implementation StartGameLayer
- (id)initWithSize:(CGSize)size
{
if(self = [super initWithSize:size])
{
SKSpriteNode* startGameText = [SKSpriteNode spriteNodeWithImageNamed:#"FlappyBirdText"];
startGameText.position = CGPointMake(size.width * 0.5f, size.height * 0.8f);
[self addChild:startGameText];
SKSpriteNode* playButton = [SKSpriteNode spriteNodeWithImageNamed:#"PlayButton"];
playButton.position = CGPointMake(size.width * 0.5f, size.height * 0.30f);
[self addChild:playButton];
[self setPlayButton:playButton];
}
return self;
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
CGPoint location = [touch locationInNode:self];
if ([_playButton containsPoint:location])
{
if([self.delegate respondsToSelector:#selector(startGameLayer:tapRecognizedOnButton:)])
{
[self.delegate startGameLayer:self tapRecognizedOnButton:StartGameLayerPlayButton];
}
}
}
#end
Where does the setPlayButton:(SKSpriteNode* ) method get set? In the help file it says it is declared in this file, but this is the only instance I see of it, and it is just driving me the tiniest bit nuts how this method is created.
Related
I am trying to make a game like flight control where there are x amount of cars and each one has its own path to follow. My idea was to make a car class of subtype SKNode and have a CGMutablePathRef instance variable for each object. I can make the CGMutablePathRef with touchsBegins, touchsMoved, and touchesEnded and figured I could then have each object follow its specific path with the SKAction followPath. Is this a good approach? If not how would you do it? This is what I have so far for the Vehicle class:
Vehicle.h
#interface Vehicle: SKNode
#property (nonatomic, assign) CGMutablePathRef pathToFollow;
#property (nonatomic) CGFloat speed;
#property (nonatomic) int direction;
- (instancetype)initWith:(CGMutablePathRef)pathPassed;
#end
Vehicle.m
#implementation Vehicle : SKNode
#synthesize pathToFollow;
#synthesize speed;
#synthesize direction;
- (id)init
{
self = [super init];
if (self) {
SKSpriteNode *vehicle = [SKSpriteNode spriteNodeWithImageNamed:#"Spaceship"];
[self addChild:vehicle];
[self setDirection:4];
[vehicle setName:#"car"];
[self setScale:.5];
}
return self;
}
- (id)initWith:(CGMutablePathRef)pathPassed {
self = [super init];
if (self) {
SKSpriteNode *vehicle = [SKSpriteNode spriteNodeWithImageNamed:#"Spaceship"];
[self addChild:vehicle];
[self setPathToFollow:pathPassed];
[self setDirection:4];
[vehicle setName:#"car"];
[self setScale:.1];
}
return self;
}
#end
EDIT: Adding GameScene in hopes that it will help. I am having a problem with my implementation now where the Vehicle object is following the path but only after it jumps up to the coordinates of the first point + the nodes position on the scene (ex: position = (200, 200), first point = (123, 456) it will go to (323, 656) then follow the path). It draws the line where I want it but then it follows from way up on this coordinate. Thanks again for the help!
GameScene.m
-(void)didMoveToView:(SKView *)view {
_car = [[Vehicle new] init]; // init the Vehicle object then set position
[_car setPosition:CGPointMake(self.scene.size.width/2, self.scene.size.height/2)];
[self addChild_car]; // add the child to the scene
}
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
// get the node that was touched
UITouch* touch = [touches anyObject];
CGPoint positionInScene = [touch locationInNode:self];
_nodeTouchedFirst = [self nodeAtPoint:positionInScene];
if ([_nodeTouchedFirst.name isEqualToString:#"car"]) {
if (lineNode != NULL) { // remove the previous path
[lineNode removeFromParent];
[CGPathRelease(pathToDraw);
}
//Start a new path and display it on the screen
pathToDraw = CGPathCreateMutable();
CGPathMoveToPoint(pathToDraw, NULL, positionInScene.x, positionInScene.y);
lineNode = [SKShapeNode];
lineNode.path = pathToDraw;
lineNode.strokeColor = [SKColor redColor];
[self addChild:lineNode];
}
} // touchesBegan
- (void)touchesMoved:(NSSet*)touches withEvent:(UIEvent*)event
{
if ([_nodeTouchedFirst.name isEqualToString:#"car"]) {
UITouch* touch = [touches anyObject];
CGPoint positionInScene = [touch locationInNode:self];
CGPathAddLineToPoint(pathToDraw, NULL, positionInScene.x, positionInScene.y);
lineNode.path = pathToDraw;
}
} // touchesMoved
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
if ([_nodeTouchedFirst.name isEqualToString:#"car"]) {
SKAction *followPath = [SKAction followPath:pathToDraw asOffset:YES orientToPath:NO duration:2];
[_nodeTouchedFirst runAction:followPath];
lineNode.strokeColor = [SKColor grayColor];
}
}
Some observations that may or may not help:
You're setting the position of _car and adding it to the scene before you give it a path to follow.
You're referencing both _nodeTouchedFirst and nodeTouchedFirst, "car" and "car1".
You're following a path with asOffset:YES, orientToPath:NO, duration:2 (rather than asOffset:NO, orientToPath:YES, speed:2).
direction doesn't correspond to the SKNode zRotation property.
I created a ball object to later show on screen when I tap it. However when I try to do that, it gives me an error. Unfortunately i can't make something out of it.
ballClass.h:
#import SpriteKit;
#import "ballClass.h"
#implementation ballClass
+ (SKSpriteNode*)ballNode {
SKSpriteNode* node = [SKSpriteNode spriteNodeWithImageNamed:#"Ball"];
return node;
}
#end
ballClass.m:
#import <Foundation/Foundation.h>
#interface ballClass : NSObject
+ (SKSpriteNode*)ballNode;
#end
My touchesBegan method in my game scene.m:
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
/* Called when a touch begins */
for (UITouch *touch in touches) {
CGPoint location = [touch locationInNode:self];
SKSpriteNode *ball = [ballClass ballNode];
ball.position = location;
[self addChild:ball];
}
}
Any help would be greatly appreciated. Thanks in advance.
It should be:
ballClass.h
#import SpriteKit;
#import <Foundation/Foundation.h>
#interface ballClass : NSObject
+ (SKSpriteNode*)ballNode;
#end
ballClass.m
#import "ballClass.h"
#implementation ballClass
+ (SKSpriteNode*)ballNode {
SKSpriteNode* node = [SKSpriteNode spriteNodeWithImageNamed:#"Ball"];
return node;
}
#end
In the YourScene.m:
//at the beginning of the file
#import ballClass.h
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
/* Called when a touch begins */
for (UITouch *touch in touches) {
CGPoint location = [touch locationInNode:self];
SKSpriteNode *ball = [ballClass ballNode];
ball.position = location;
[self addChild:ball];
}
}
I am newcomer to cocos2d v3.1
How to drag and drop the Physics body in cocos2d v3.1.
and then how to check the Collision & Detection between two Physics Body's.
Thank you in advance
First, you need a class named CCTouchJoint.
CCTouchJoint.h
#import "Box2D.h"
#interface CCTouchJoint : NSObject
{
#public
b2MouseJoint *mouseJoint;
UITouch *touch;
}
#property (assign) b2MouseJoint *mouseJoint;
#property (nonatomic, retain) UITouch *touch;
- (id)initLocal:(UITouch *)touch withMouseJoint:(b2MouseJoint *)mouseJoint;
+ (id)touch:(UITouch *)touch withMouseJoint:(b2MouseJoint *)mouseJoint;
// Public methods
/**
* Destroy the touch joint in the Box2d world.
*/
- (void)destroyTouchJoint;
#end
CCTouchJoint.mm
#import "CCTouchJoint.h"
#implementation CCTouchJoint
#synthesize mouseJoint;
#synthesize touch;
- (void)dealloc
{
[touch release];
[super dealloc];
}
- (id)initLocal:(UITouch *)_touch withMouseJoint:(b2MouseJoint *)_mouseJoint
{
if ((self = [super init]))
{
self.touch = _touch;
mouseJoint = _mouseJoint;
}
return self;
}
+ (id)touch:(UITouch *)_touch withMouseJoint:(b2MouseJoint *)_mouseJoint
{
return [[self alloc] initLocal:_touch withMouseJoint:_mouseJoint];
}
#pragma mark -
#pragma mark CCTouchJoint Public Methods
- (void)destroyTouchJoint
{
if (mouseJoint != NULL)
{
mouseJoint->GetBodyA()->GetWorld()->DestroyJoint(mouseJoint);
}
}
#pragma mark CCTouchJoint Private Methods
#end
Second. self.touchEnabled = YES; You need
NSMutableArray *touchJointList;
b2Body *groundBody and b2Body *b;
and this touch code:
- (void)ccTouchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
NSSet *allTouches = [event allTouches];
for(UITouch *touch in allTouches)
{
CGPoint location = [touch locationInView:touch.view];
location = [[CCDirector sharedDirector] convertToGL:location];
b2Vec2 worldLoc = b2Vec2(ptm(location.x), ptm(location.y));
for (b = world->GetBodyList(); b; b = b->GetNext())
{
if (b->GetType() == b2_dynamicBody)
for (b2Fixture *f = b->GetFixtureList(); f; f = f->GetNext())
{
// Hit!
if (f->TestPoint(worldLoc))
{
/// Mouse joint definition
b2MouseJointDef md;
md.bodyA = groundBody;
md.bodyB = b;
md.target = worldLoc;
md.maxForce = 3000.0 * b->GetMass();
md.dampingRatio = 5;
md.frequencyHz = 60;
// Joint of bodys
b2MouseJoint *m_touchJoint;
m_touchJoint = (b2MouseJoint *)world->CreateJoint(&md);
CCTouchJoint *tj = [CCTouchJoint touch:touch withMouseJoint:m_touchJoint];
[touchJointList addObject:tj];
b->SetAwake(true);
}
break;
}
}
}
}
- (void)ccTouchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
for (CCTouchJoint *tj in touchJointList)
{
if([tj.touch phase] == UITouchPhaseMoved)
{
// Update if it is moved
CGPoint location = [tj.touch locationInView:tj.touch.view];
location = [[CCDirector sharedDirector] convertToGL:location];
b2Vec2 worldLocation = b2Vec2(ptm(location.x), ptm(location.y));
tj.mouseJoint->SetTarget(worldLocation);
}
}
}
- (void)ccTouchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
NSSet *allTouches = [event allTouches];
NSMutableArray *discardedItems = [NSMutableArray array];
for(UITouch *touch in allTouches)
{
for (CCTouchJoint *tj in touchJointList)
{
if (tj.touch == touch)
{
// Defensive programming - assertion
NSAssert([tj isKindOfClass:[CCTouchJoint class]], #"node is not a touchJoint!");
// If safe - loop through
if ([tj.touch phase] == UITouchPhaseEnded)
{
[discardedItems addObject:tj];
[tj destroyTouchJoint];
[tj release];
}
}
}
}
[touchJointList removeObjectsInArray:discardedItems];
}
- (void)ccTouchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
{
[touchJointList removeAllObjects];
}
REMEMBER:Changing md.dampingRatio and md.frequencyHz will affect on behavior of mouse joint.
Try the Below link for collision detection. It will be helpful for you.
http://www.cocos2d-x.org/wiki/Chapter_5_-_How_to_Detect_the_Collisions
I'm making an app for iPhone in Xcode, and It requires a box to follow my finger only on the X axis. I couldn't find any solution online to this, and my coding knowledge isn't that great.
I've been trying to use touchesBegan and touchesMoved.
Could someone please write me up some code please?
First you need the UIGestureRecognizerDelegate on your ViewController.h file:
#interface ViewController : UIViewController <UIGestureRecognizerDelegate>
#end
Then you declare an UIImageView on your ViewController.m, like so, with a BOOL to track if a touch event is occurring inside your UIImageView:
#interface ViewController () {
UIImageView *ballImage;
BOOL touchStarted;
}
Then you initialize the UIImageView on viewDidLoad:
- (void)viewDidLoad
{
[super viewDidLoad];
UIImage *image = [UIImage imageNamed:#"ball.png"];
ballImage = [[UIImageView alloc]initWithImage:image];
[ballImage setFrame:CGRectMake(self.view.center.x, self.view.center.y, ballImage.frame.size.width, ballImage.frame.size.height)];
[self.view addSubview:ballImage];
}
After that you can start doing your modifications to what's best for you using these methods:
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
CGPoint touch_point = [touch locationInView:ballImage];
if ([ballImage pointInside:touch_point withEvent:event])
{
touchStarted = YES;
} else {
touchStarted = NO;
}
}
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
if ([touches count]==1 && touchStarted) {
UITouch *touch = [touches anyObject];
CGPoint p0 = [touch previousLocationInView:ballImage];
CGPoint p1 = [touch locationInView:ballImage];
CGPoint center = ballImage.center;
center.x += p1.x - p0.x;
// if you need to move only on the x axis
// comment the following line:
center.y += p1.y - p0.y;
ballImage.center = center;
NSLog(#"moving UIImageView...");
}
}
I am looking to have something which is marked in red, as marker but don't know whether it can be done or not.
It looks like marking using a calligraphy pen.
Trying out the following code as answered by "Andrey", I get the following output with spaces while drawing.
Brush image can be found here used is
Making further changes to the code, I found still I am not able to get the expected result.
Here I am trying to fill the path which exists between the current point and the next point.
- (void)drawRect:(CGRect)rect
{
// Drawing code
CGFloat w=5.0;
CGFloat h=2.0;
CGContextRef context=UIGraphicsGetCurrentContext();
CGContextSetFillColorWithColor(context, [UIColor redColor].CGColor);
for(int i=0;i<self.positions.count;i++){
CGPoint point=[[self.positions objectAtIndex:i] CGPointValue];
CGFloat x=point.x-(w/2.0);
CGFloat y=point.y-(h/2.0);
CGContextFillRect(context, CGRectMake(x, y, w, h));
if(i+1<self.positions.count){
CGPoint nextPoint=[[self.positions objectAtIndex:(i+1)] CGPointValue];
CGMutablePathRef myPath=CGPathCreateMutable();
CGPathMoveToPoint(myPath, NULL, x, y);
CGFloat x1=nextPoint.x-(w/2.0);
CGFloat y1=nextPoint.y-(h/2.0);
CGPathAddLineToPoint(myPath, NULL, x1, y1);
CGPathAddLineToPoint(myPath, NULL, w, y1);
CGPathAddLineToPoint(myPath, NULL, w, y);
CGPathCloseSubpath(myPath);
CGContextFillPath(context);
}
}
}
Those picture can be done via drawing an image in UIView subclass with overridden drawRect: message. You also need to add some kind of touch handler for catching touches. So here is some code:
#interface DrawingView ()
#property (nonatomic, strong) NSMutableArray *positions;
#end
#implementation DrawingView
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
[self awakeFromNib];
}
return self;
}
- (void)awakeFromNib
{
self.positions = [[NSMutableArray alloc] init];
}
- (void)drawRect:(CGRect)rect
{
[super drawRect:rect];
UIImage *brushImage = [UIImage imageNamed:#"brush.png"];
for (NSValue *object in self.positions) {
CGPoint point = [object CGPointValue];
[brushImage drawAtPoint:CGPointMake(point.x - brushImage.size.width / 2.0, point.y - brushImage.size.height / 2.0)];
}
}
- (void)addPoint:(CGPoint)point
{
[self.positions addObject:[NSValue valueWithCGPoint:point]];
[self setNeedsDisplay];
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
[self addPoint:[touch locationInView:self]];
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
[self addPoint:[touch locationInView:self]];
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
[self addPoint:[touch locationInView:self]];
}
#end
You only need to create a proper brush.png and place those view anywhere you want.