Having trouble getting a touch location in sprite-kit screne - ios

I am making a game for a final project and I need to know where the user touches so I can move the player around.
here is the .h file
#import <SpriteKit/SpriteKit.h>
#interface BYFGameScene : SKScene
#end
the header of the .m
#import "BYFGameScene.h"
#interface BYFGameScene()
#property BOOL contentCreated;
#property (nonatomic)SKSpriteNode *player;
#end
#implementation BYFGameScene
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
CGPoint *location = [[touches anyObject] location];
NSLog(#"the location is %#",location);
}
I think that touches began would be the appropriate method to get the location and in previous apps this is how I would get the location but it keeps throwing a exception and I am not sure why.
I have also tried
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
CGFloat location = [[touches anyObject] locationInView:self];
NSLog(#"the location is %f",location);
}
but it gives an error saying that UIView and BYFGameScene(the current scene) are not compatible types
also how would I manipulate the players position?
\here is what I thought would work but it does not.
-(void)moveUp
{
if(self.player.position==CGpoint 700)
{
}
else
{
self.player.position = self.player.position +100;
}
}
700 would be the max position
Any help would be appreciated
thanks

I think this is what you're looking for:
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
//touch point, see locationInNode
CGPoint location = [touch locationInNode:self];
// SKNode *node = [self nodeAtPoint:location];

Related

SKNode Subclass Not Moving Children

I have a sprite that can't exist in my game without a pairing SKFieldNode so my solution was to create a subclass of SKSpriteNode and create a property for the SKFieldNode but it didn't work because the SKSpriteNode was acting weird (I don't remember exactly what happened). So my next approach was to change the subclass to SKNode and then I would make the SKSpriteNode and the SKFieldNode a property of this new SKNode. But then it turns out that touchesMoved will only move one of the properties (whichever is on top) which turns out to always be the SKSpriteNode.
What's the best approach to this problem, and how can I fix it so that I can have an SKFieldNode for every SKSpriteNode while still making sure that actions and methods still work properly.
Current code of SKNode subclass:
#interface Whirlpool : SKNode
- (instancetype)initWithPosition:(CGPoint)pos region:(float)region strength:(float)strength falloff:(float)falloff;
#property (nonatomic, strong) SKFieldNode *gravityField;
#end
#import "Whirlpool.h"
#import "Categories.h"
#implementation Whirlpool
- (instancetype)initWithPosition:(CGPoint)pos region:(float)region strength:(float)strength falloff:(float)falloff {
if (self = [super init]) {
// whirlpool sprite
SKSpriteNode *whirlpoolSprite = [[SKSpriteNode alloc] initWithImageNamed:#"whirlpool"];
whirlpoolSprite.size = CGSizeMake(100, 100);
whirlpoolSprite.position = pos;
//removing physicsBody and associated attributes for now so that the boat does not collide with the whirlpool
//whirlpoolSprite.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:whirlpoolSprite.size.width / 2];
//whirlpoolSprite.physicsBody.dynamic = NO;
whirlpoolSprite.zPosition = 1;
whirlpoolSprite.name = #"whirlpool";
[whirlpoolSprite runAction:[SKAction repeatActionForever:[self sharedRotateAction]]];
// whirlpool gravity field
_gravityField = [SKFieldNode radialGravityField];
_gravityField.position = pos;
_gravityField.strength = strength;
_gravityField.falloff = falloff;
_gravityField.region = [[SKRegion alloc] initWithRadius:region];
_gravityField.physicsBody.categoryBitMask = gravityFieldCategory;
_gravityField.zPosition = 1;
[self addChild:whirlpoolSprite];
[self addChild:_gravityField];
}
return self;
}
- (SKAction *)sharedRotateAction {
static SKAction *rotateWhirlpool;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
rotateWhirlpool = [SKAction rotateByAngle:-M_PI * 2 duration:4.0];
});
return rotateWhirlpool;
}
#end
- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
// we don't want the player to be able to move the whirlpools after the button is pressed
if (_isRunning) {
return;
}
for (UITouch *touch in touches) {
CGPoint location = [touch locationInNode:self];
SKNode *node = [self nodeAtPoint:location];
// if the finger touches the boat or the whirlpool, update its location
if ([node.name isEqualToString:#"boat"]) {
node.position = CGPointMake(location.x, node.position.y);
} else if ([node.name isEqualToString:#"whirlpool"]) {
node.position = location;
}
}
}
I believe your issues comes down to that fact that "whirlpool" is a child of your SKNode subclass. So when you are identifying that you are indeed touching a "whirlpool" you are moving it within its parent (the SKNode subclass) and the SKFieldNode and parent stay put. This little adjustment to your original code should work...if I understand the problem correctly.
- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
// we don't want the player to be able to move the whirlpools after the button is pressed
if (_isRunning) {
return;
}
for (UITouch *touch in touches) {
CGPoint location = [touch locationInNode:self];
SKNode *node = [self nodeAtPoint:location];
// if the finger touches the boat or the whirlpool, update its location
if ([node.name isEqualToString:#"boat"]) {
node.position = CGPointMake(location.x, node.position.y);
} else if ([node.name isEqualToString:#"whirlpool"]) {
//move the SKNode subclass the whirlpool is a child of
node.parent.position = location;
}
}
}
Hopefully that helps.
Yikes, the problem here is the way you are grabbing nodes, you may be grabbing the wrong nodes due to all the children. Instead take this approach:
We already know that you are subclassing your sprites, so in your subclasses, add the following code:
//Whirlpool
- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
for (UITouch *touch in touches) {
CGPoint location = [touch locationInNode:self.parent];//Unless you are retaining the scene in the child, then use that
self.position = location;
}
}
Then:
//Boat
- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
for (UITouch *touch in touches) {
CGPoint location = [touch locationInNode:self.parent];//Unless you are retaining the scene in the child, then use that
self.position.x = location.x;
}
}
Then for your Scene, do this:
- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
// we don't want the player to be able to move the whirlpools after the button is pressed
if (_isRunning) {
return;
}
//At this point it should call the children on touch events
[super.touchesMoved: touches withEvent:event];
}

Error when creating a ball object out of a skspritenode

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];
}
}

Why won't my ImageView move?

All in all I am trying to get a result when one image touches another image. That is not the problem I am having though. I can't get the UIImageView to even move when I click on it and drag. Below is the code I am using! Please let me know if you can help me! Thanks!
.h
{
IBOutlet UIImageView *image1;
IBOutlet UIImageView *image2;
}
#property (nonatomic, retain) UIImageView *image1;
#property (nonatomic, retain) UIImageView *image2;
-(void)collision;
.m
#synthesize image1, image2;
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch1 = [touches anyObject];
[self collision];
if ([touch1 view] != self.image1) {
return;
}
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch1 = [touches anyObject];
// If the touch was in the placardView, move the placardView to its location.
if ([touch1 view] == self.image1) {
CGPoint location = [touch1 locationInView:image1];
self.image1.center = location;
return;
}
}
-(void)collision
{
if (CGRectIntersectsRect(image1.frame, image2.frame)) {
NSLog(#"Touched");
}
}
** I was able to get the code to work where I am able to move the UIImageView.
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch1 = [[event allTouches] anyObject];
image1.center = [touch1 locationInView:self.view];
return;
}
The only problem with this is that where ever I touch on the screen the image moves to that location. How may I have it where you have to touch the actual UIImageView to move it? Thanks!!
UIImageView default userInteraction is false, so u are just enable userInteraction is True for
both image view.

IOS touch tracking code

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

how to stop my object to skip by clicking and move just by touch

I have some object on my screen view which moves by touch, but the problem is if I click somewhere else on my screen which has no object on, the last moved object skipped to that clicked position, anyone who know how I can be able to stop that? PostView contains code about my objects
in .h file
#property (weak, nonatomic) IBOutlet PostView *pv;
and .m file
- (void)viewDidLoad
{
[super viewDidLoad];
viewArray = [NSMutableArray arrayWithObjects: nil];
pv.frame = CGRectMake(10, 10, 100, 100);
pv.backgroundColor = [UIColor blackColor];
[viewArray insertObject:pv atIndex:0];
[self.view addSubview:pv];
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
CGPoint firstTouch = [touch locationInView:self.view];
for (PostView *view in viewArray) {
if (CGRectContainsPoint(view.frame, firstTouch)) {
toMove = view;
}
}
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
CGPoint location = [touch locationInView:self.view];
toMove.center = location;
// [_delegate dragViewDidMove:self];
// toMove.center = currentTouch;
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
currentTouch = [touch locationInView:self.view];
toMove.center = currentTouch;
}
Set toView to null at the start of touchesBegan:. This ensures that if the user makes a touch that touches nothing (and so toView doesn't get set to anything deliberately), nothing will happen when the touch moves (the setCenter: message will be sent to null which will return null and have no side effects.)

Resources