How to get these methods to work with multi-touch? - ios

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.

Related

Receiving touchesBegan: on UIViewController - Objective C

I have added a UITableView as a subview on my UITableView.
I have troubling 'passing through' touches on my UITableView (subview) to the view of my UIViewController (where my touchesBegan: method works as expected).
I have tried:
Subclassing my UITableView and passing touchesBegan: to the superview from there
pointInside: in superview
hitTest: in subclassed tableView
Also: Disabling userInteraction on my tableView works, but of course, I still want to maintain the cellDidSelectRow.. functionality.
My Code implementation in ViewController:
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
NSLog(#"touchesBegan popup");
if (!self.draggable) {
//[super touchesBegan:touches withEvent:event];
return;
}
UITouch *touch = [touches anyObject];
if (!_moving) {
//(touch.view == self || touch.view.superview == self) &&
_moving = YES;
_movingStartY = [touch locationInView:self.view].y;
NSLog(#"moving popup");
}
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
if (!self.draggable) {
//[super touchesMoved:touches withEvent:event];
return;
}
if (_moving) {
NSLog(#"touchesMoved popup");
UITouch *touch = [touches anyObject];
float offset = [touch locationInView:self.view].y - _movingStartY;
if ([self.touchEventDelegate respondsToSelector:#selector(popupNavigationBar:touchDidMoveWithOffset:)]) {
[self.touchEventDelegate popupNavigationBar:self touchDidMoveWithOffset:offset];
}
}
}
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
{
if (!self.draggable) {
//[super touchesCancelled:touches withEvent:event];
return;
}
if (_moving) {
UITouch *touch = [touches anyObject];
float offset = [touch locationInView:self.view].y - _movingStartY;
[self movingDidEndWithOffset:offset];
}
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
if (!self.draggable) {
//[self touchesEnded:touches withEvent:event];
return;
}
if (_moving) {
UITouch *touch = [touches anyObject];
float offset = [touch locationInView:self.view].y - _movingStartY;
[self movingDidEndWithOffset:offset];
}
}
- (void)movingDidEndWithOffset:(float)offset
{
_moving = NO;
if ([self.touchEventDelegate respondsToSelector:#selector(popupNavigationBar:touchDidEndWithOffset:)]) {
[self.touchEventDelegate popupNavigationBar:self touchDidEndWithOffset:offset];
}
}
How can I accomplish this?

SKSpriteNode button stuck (iOS) after letting go. Advice needed

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.

moving 2 objects at same time

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.

Cocos2d (IOS) - How do I constantly get the location of the user's touch?

How do I constantly get the location of the user's touch? I'm working on controllers for a game, and as it stands I must lift and individually place my finger on the new control in order to make it work. It seems that the touchLocation variable only updates upon each tap, and I want it to update constantly, so that even if I slide my finger around it will know the location and update it accordingly. Here is the relevant code. Thank you!
-(void)update:(CCTime)delta{
if([playerDirection isEqual:#"left"]){
_player.position = ccp(_player.position.x - 2, _player.position.y);
}
if([playerDirection isEqual:#"right"]){
_player.position = ccp(_player.position.x + 2, _player.position.y);
}
if([direction isEqual:#"up"]){
_enemy.position = ccp(_enemy.position.x, _enemy.position.y + 2);
}
if([direction isEqual:#"down"]){
_enemy.position = ccp(_enemy.position.x, _enemy.position.y - 2);
}
if(_enemy.position.y >= self.contentSize.height){
direction = #"down";
}
if(_enemy.position.y <= 2){
direction = #"up";
}
if(isTouching){
_player.position = ccp(_player.position.x + 2, _player.position.y);
}
}
// -----------------------------------------------------------------------
#pragma mark - Touch Handler
// -----------------------------------------------------------------------
-(void) touchBegan:(UITouch *)touch withEvent:(UIEvent *)event {
CGPoint touchLocation = [touch locationInView:[touch view]];
touchLocation = [[CCDirector sharedDirector] convertToGL:touchLocation];
if(touchLocation.x > 400){
playerDirection = #"right";
}
if(touchLocation.x < 200){
playerDirection = #"left";
}
CGPoint touchLoc = [touch locationInNode:self];
//isTouching = true;
// Log touch location
CCLOG(#"Move sprite to # %#",NSStringFromCGPoint(touchLoc));
// Move our sprite to touch location
//CCActionMoveTo *actionMove = [CCActionMoveTo actionWithDuration:1.0f position:touchLoc];
//[_sprite runAction:actionMove];
}
- (void)touchEnded:(UITouch *)touch withEvent:(UIEvent *)event
{
playerDirection = #"none";
}
i see you've got a touchesBegan and touchesEnded... but you're missing touchesMoved.
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
for(UITouch *touch in touches) {
//do whatever you want
}
}
Hope that helps, good luck!
To get Touch you have to enable touch in -(id) init() method.
you can enable touch by
self.IsTouchEnable = YES
and after this you can get touch in following touch handling methods
- (void)ccTouchesBegan:(NSSet *)touches withEvent:(UIEvent *)event;
- (void)ccTouchesMoved:(NSSet *)touches withEvent:(UIEvent *)event;
- (void)ccTouchesEnded:(NSSet *)touches withEvent:(UIEvent *)event;
- (void)ccTouchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event;
hope This will help you

UIImageView touch handling

i have an image view as background image.
I am seeking that in some place on image view touches would be enabled.
I started with this:
- (id)initWithTouchPoint:(CGRect )point
{
self = [super init];
if (self) {
touchFrame = point;
[self setAccessibilityFrame:touchFrame];
}
return self;
}
/*
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect
{
// Drawing code
}
*/
-(BOOL)canResignFirstResponder{
return YES;
}
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
UITouch *touch = [[event allTouches] anyObject];
CGPoint touchLocation = [touch locationInView:self];
if (CGRectContainsPoint(touchFrame, touchLocation)) {
//[self setUserInteractionEnabled:NO];
}else{
//[self setUserInteractionEnabled:YES];
}
DLog(#"touchesBegan at x : %f y : %f",touchLocation.x,touchLocation.y);
}
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event{
}
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event{
}
Is it possible to let user touch over image view when user touches in touchFrame ?
Thank you.
Add UITapGestureRecognizer on UIImageView
UITapGestureRecognizer *gesture = [[UITapGestureRecognizer alloc] initWithTarget:self
action:#selector(handleGesture:)];
[gesture setNumberOfTapsRequired:1];
[imageView setUserInteractionEnabled:YES];
[imageView addGestureRecognizer:gesture];
Now within the HandleGesture Method :
-(void)handleGesture:(UITapGestureRecognizer *)_gesture
{
if (_gesture.state == UIGestureRecognizerStateEnded)
{
CGPoint touchedPoint = [_gesture locationInView:self.view];
}
}
you can check now wether the touchedPoint within the handleGesture method are in the specified area or not and you can perform your desired task accordingly
You can try having a boolean variable as a class member say BOOL allowTouch initialised with value NO:
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
UITouch *touch = [[event allTouches] anyObject];
CGPoint touchLocation = [touch locationInView:self];
if (CGRectContainsPoint(touchFrame, touchLocation)) {
allowTouch = YES;
}
}
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event{
if(allowTouch)
{
//handle moves here
}
}
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event{
allowTouch = NO;//you can put your condition too to end touches
}
It may help.

Resources