In my current ios project, I have dedicated one side of the screen to one object and the other side of the screen to the other object and i have made it so that if you swipe your finger across one side of the screen on the designated object would move. However, I want to make it so that you can move both objects at the same time in different movement but i cannot figure out how to do so. Below is my current code.
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [[event allTouches] anyObject];
CGPoint location = [touch locationInView:touch.view];
if (location.x <= 270 ) {
[Person setCenter:CGPointMake(location.x, Person.center.y)];
}
else {
[Person1 setCenter:CGPointMake(location.x, Person1.center.y)];
}
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [[event allTouches] anyObject];
CGPoint location = [touch locationInView:touch.view];
if (location.x <= 270 ) {
[Person setCenter:CGPointMake(location.x, Person.center.y)];
}
else {
[Person1 setCenter:CGPointMake(location.x, Person1.center.y)];
}
}
you should start handling multiple touches that are delivered in the touches set - loop through all the UITouch objects and do your handling.
Edit:
here's your code:
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
for(UITouch *touch in [event allTouches]) {
CGPoint location = [touch locationInView:touch.view];
if (location.x <= 270 ) {
[Person setCenter:CGPointMake(location.x, Person.center.y)];
}
else {
[Person1 setCenter:CGPointMake(location.x, Person1.center.y)];
}
}
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
for(UITouch *touch in [event allTouches]) {
CGPoint location = [touch locationInView:touch.view];
if (location.x <= 270 ) {
[Person setCenter:CGPointMake(location.x, Person.center.y)];
}
else {
[Person1 setCenter:CGPointMake(location.x, Person1.center.y)];
}
}
}
If you move the -touchesBegan & touchesMoved code into the Person view class rather than the view/or viewController class it is in currently then those views can handle touches independent of each other and simultaneously.
*Edit: More info:
Currently you are handling touches events (in I'm guessing a UIViewController) using the code you pasted above, if you moved that code into your Person class you have created you could make the code simpler and achieve the result you desire.
This will have the effect that the Person will decide if it is being touched and where and will move itself accordingly.
In your Person.m file add this code,
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
UITouch *touch = [[event allTouches] anyObject];
CGPoint location = [touch locationInView:self.superview];
[self moveToLocation:location];
}
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event{
UITouch *touch = [[event allTouches] anyObject];
CGPoint location = [touch locationInView:self.superview];
[self moveToLocation:location];
}
-(void)moveToLocation:(CGPoint)location{
CGFloat halfOfPersonWidth = self.bounds.size.width /2.0f;
CGFloat halfOfSuperviewWidth = self.superview.bounds.size.width/2.0f;
// Stop Person from going off left screen edge
if ((location.x - halfOfPersonWidth) <= 0.0f){
return;
} // Stop Person from going off right screen edge
else if ((location.x + halfOfPersonWidth) >= self.superview.bounds.size.width){
return;
}
if (self.center.x < halfOfSuperviewWidth) {
// Person is on the left of the screen and should not move to right side
if ((location.x + halfOfPersonWidth) > halfOfSuperviewWidth) {
return;
}
} else{
// Person is on the right of the screen and should not move to left side
if ((location.x - halfOfPersonWidth) < halfOfSuperviewWidth) {
return;
}
}
// If we have made it this far then we can move the Person
// move to touch location on x axis only
[self setCenter:CGPointMake(location.x, self.center.y)];
}
Now in your View Controller class you can delete the original -touchesBegan & -touchesMoved code that you pasted here, Or just comment it out if you want to be cautious
/* put slash asterisks above the code and asterisks slash below the code to comment out */
If you build and run you should be able to move each Person view around as before but if you put a finger on each Person view at the same time you should be able to move them simultaneously.
Related
So... I am working on this small Mario-like game for iOS and have run into a problem that I cannot seem to fix.
When using my controls (see the screenshot) they sometime get "stuck" as in, the iOS device did not notice that I let go of a button. This causes the player to keep on moving in a direction after you have let go of the button.
Edit: It seems that the malfunction happens when I click two buttons at the exact same time.
Hopefully, someone will be able to spot what I can do differently in the following code:
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
for (UITouch *touch in touches) {
CGPoint touchLocation = [touch locationInNode:self];
[self touchStateChanged:touchLocation buttonState:YES];
}
}
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
for (UITouch *touch in touches) {
CGPoint prevTouchLocation = [touch previousLocationInNode:self];
[self touchStateChanged:prevTouchLocation buttonState:NO];
CGPoint touchLocation = [touch locationInNode:self];
[self touchStateChanged:touchLocation buttonState:YES];
}
}
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
for (UITouch *touch in touches) {
// Some other logic... {...}
[self touchStateChanged:touchLocation buttonState:NO];
}
}
-(void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
{
for (UITouch *touch in touches) {
CGPoint touchLocation = [touch locationInNode:self];
[self touchStateChanged:touchLocation buttonState:NO];
}
}
-(void)touchStateChanged:(CGPoint)location buttonState:(BOOL)state
{
SKNode *n = [self nodeAtPoint:location];
if ([n.name isEqualToString:#"LeftMove"]) {
self.player.moveLeft = state;
}
else if ([n.name isEqualToString:#"RightMove"]) {
self.player.moveRight = state;
}
else if ([n.name isEqualToString:#"Jump"]) {
self.player.didJump = state;
}
}
Screenshot showing buttons:
Thanks :-)
Partly Solved...
Current solution:
Added an instance variable called _touchEvent of type UIEvent and added the following line to touchesEnded:
_touchEvent = event;
Added the following code to my update method:
if (_touchEvent && (int)[[_touchEvent allTouches]count] == 0) {
self.player.moveLeft = NO;
self.player.moveRight = NO;
self.player.didJump = NO;
}
if (_touchEvent && (int)[[_touchEvent allTouches]count] == 1) {
for (UITouch *touch in [_touchEvent allTouches]) {
SKNode *n = [self nodeAtPoint:[touch locationInNode:self]];
if ([n.name isEqualToString:#"Jump"]) {
self.player.moveLeft = NO;
self.player.moveRight = NO;
}
}
}
I think the problem is the location of touch (in -(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event method) is outside any node.
Try to implement something like this
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
for (SKNode *node in yourButtonsArray) {
// Some other logic... {...}
[node setState:NO];
}
}
Or you should take a look at KKButtonBehaviour from KoboldKit framework.
I have been looking at how to invoke different touch methods depending on where the user touches on the screen. I presume this should be fairly simple in Sprite Kit but I can't find anything on it. Currently I am using the following to make the character jump.
How would I only use this method if it is touched on the left or the right of the screen? So a right touch calls one method and a left touch calls another. Thanks.
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
/* Called when a touch begins */
if (isJumping == NO){
isJumping = YES;
SKSpriteNode* charNode = (SKSpriteNode*)[self childNodeWithName:#"character"];
[charNode runAction:jumpAnimation];
[charNode runAction:jumpMovement];
}
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
CGPoint touchLocation = [touch locationInNode:self.scene];
if(touchLocation.x < self.size.width/2)
NSLog(#"left side");
if(touchLocation.x > self.size.width/2)
NSLog(#"right side");
}
I have a node that acts like an UIButton and a node that performs an action when the screen gets touched.
The problem is that the lion jump action does not get fired.
In addition: both names of the nodes are correct.
My code for the UIEvent:
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
CGPoint location = [touch locationInNode: self];
SKNode *node = [self nodeAtPoint:location];
UITouch *lionTouch = [touches anyObject];
CGPoint locationLion = [lionTouch locationInView:[self view]];
SKNode *lionNode = [self nodeAtPoint:locationLion];
if ([lionNode.name isEqualToString:#"veggieLion"]) {
if (!lionIsJumping) {
[self lionJump];
lionIsJumping = YES;
}
}
if ([node.name isEqualToString:#"repalyButton"]) {
// Button action
}
}
Apple documentation for SKNode says the method nodeAtPoint "Returns the deepest descendant that intersects a point."
I've had this trouble in the past. where the method would return the SKSpriteNode that I had used for the background, even if I were definitely tapping the target sprite/node!
Since you are checking for two nodes, I would approach it in the following way:
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
CGPoint location = [touch locationInNode: self];
SKNode * lionNode = [self childNodeWithName:#"veggieLion"];
SKNode * replayButton = [self childNodeWithName:#"repalyButton"];
if ([self.lionNode containsPoint:location]) {
if (!lionIsJumping) {
[self lionJump];
lionIsJumping = YES;
}
return;
}
if ([self.replayButton containsPoint:location]) {
// Button action
return;
}
/* test for other targets */
}
I'm trying to create a simple application where you can move your UIImageView by touching him and dragging him around.
my UIImageView is called imv
-(void ) touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event{
UITouch * touch = [touches anyObject];
if([touch view] == self.imv){
CGPoint location = [touch locationInView:self.view];
self.imv.center = location;
}
}
-(void ) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
UITouch * touch = [touches anyObject];
if([touch view] == self.imv){
CGPoint location = [touch locationInView:self.view];
self.imv.center = location;
}
}
i'am trying to solve this like whole day and i don't know what is wrong. If i disable if statement it's working else not. What can i do?
Thanks for the answers
Unless you've subclassed UIImageView (unlikely), your view is receiving the touch events.
These days it's simpler & more usual to use a UIGestureRecognizer for this kind of thing, in this case a UIPanGestureRecognizer.
e.g.
UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithTarget:self action:#selector(dragImageView:)];
[self.imv addGestureRecognizer:pan];
- (void)dragImageView:(UIPanGestureRecognizer *)dragImageView {
if(UIGestureRecognizerStateBegan == state) {
originalCenter = self.imv.center; // add CGPoint originalCenter; member
} else if(UIGestureRecognizerStateChanged == state) {
CGPoint translate = [pan translationInView:self.imv.superview];
self.imv.center = CGPointMake(originalCenter.x + translate.x, originalCenter.y + translate.y);
}
}
From a bit of experimenting, it seems that the [touch view] is returning the main UIView and not your subview, hence the problem with the if statement not working (I added the UIImageView in a storyboard xib). EDIT- it's because UIImageViews don't handle touch events by default - see here . When adding a regular UIView in the viewDidLoad seems to work as you would expect.
Anyway, this adapted version of your code works for me
-(void)moveImageForTouches:(NSSet*)touches
{
UITouch * touch = [touches anyObject];
CGPoint location = [touch locationInView:self.view];
if(CGRectContainsPoint(self.imv.frame, location))
{
self.imv.center = location;
}
}
-(void ) touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
[self moveImageForTouches:touches];
}
-(void ) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
[self moveImageForTouches:touches];
}
I found this code on a tutorial which pretty much sets a left or right side BOOL to YES if the touch started on a specific side of the screen and then checks when the touch moves to see if it changes sides on the screen in order to make the other BOOL yes.
So I am now trying to implement multi-touch but I am not sure how it would work with the following code? Does anyone have any idea how I would go upon it?
-(void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
touchStartPoint = [touch locationInView:self.view];
if (touchStartPoint.x < 160.0) {
touchLeftDown = TRUE;
}
else if (touchStartPoint.x > 160.0) {
touchRightDown = TRUE;
}
}
-(void) touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
CGPoint currentTouchPoint = [touch locationInView:self.view];
if (touchStartPoint.x < 160.0 && currentTouchPoint.x < 160.0) {
touchLeftDown = TRUE;
}
else if (touchStartPoint.x > 160.0 && currentTouchPoint.x > 160.0)
{
touchRightDown = TRUE;
}
}
-(void) touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
touchLeftDown = touchRightDown = FALSE;
}
Thanks!
Edit1:
These are what the bools are doing in the game loop, pretty much what I am trying to achieve is that if there is a touch on both sides at the same time, the TOUCH_INCREMENT will be 0 since the touches on each side will cancel each other out. How would I achieve that? Anyway this is the code I am talking about:
if (touchLeftDown == TRUE) {
touchStep -= TOUCH_INCREMENT;
}
else if (touchRightDown == TRUE) {
touchStep += TOUCH_INCREMENT;
}
else {
touchStep = SLOWDOWN_FACTOR * touchStep;
}
touchStep = MIN(MAX(touchStep, -MAX_ABS_X_STEP), MAX_ABS_X_STEP);
pos.x += touchStep;
You can probably make this work without the touchStartPoint (i)var. The important thing is to not use -anyObject and instead to inspect each touch. The following code modifications might work for you:
-(void) countTouches:(NSSet *)touches withEvent:(UIEvent *)event{
int leftTouches=0;
int rightTouches=0;
for (UITouch *touch in touches)
{
CGPoint location = [touch locationInView:touch.view];
//just in case some code uses touchStartPoint
touchStartPoint=location;
if (location.x < 160.0) {
leftTouches++;
}
else if (location.x > 160.0) {
rightTouches++;
}
}
//reset touch state
touchLeftDown=FALSE;
//set touch state if touch found
if(leftTouches>0){
touchLeftDown=TRUE;
}
touchRightDown=FALSE;
if(rightTouches>0){
touchRightDown=TRUE;
}
}
-(void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
[self countTouches:touches withEvent:event];
}
-(void) touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
[self countTouches:touches withEvent:event];
}
-(void) touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
touchLeftDown = touchRightDown = FALSE;
}
Here I have created a function that is called by touchesBegan and touchesMoved because they need to implement the same logic. You may see some unintended side effects if touchStartPoint is being used in the code somehow.