How to undo multitouch drawing in iOS - ios

Please help me to undo and forward my draw. I store all paths into an pathArray and now I want to undo and foward the path ( like app Notes (Apple) ).
Please help me to solve this!
This is my PathArray class
// PathArray.h
#import <Foundation/Foundation.h>
#interface PathArray : NSObject
#property (nonatomic) CGPoint start;
#property (nonatomic) CGPoint end;
#property (nonatomic) UIColor* color;
#property (nonatomic) CGFloat pathWidth;
- (instancetype) initWithStartPoint: (CGPoint)start andEnd: (CGPoint)end andColor: (UIColor *) color andPathWidth: (CGFloat) pathWidth;
#end
This is my Draw class
- (void)drawRect:(CGRect)rect
{
[strokecolor setStroke];
for (int i=0; i<pathArray.count; i++ ) {
CGContextRef contex = UIGraphicsGetCurrentContext();
CGContextSetLineCap(contex, kCGLineCapRound);
CGContextBeginPath(contex);
CGContextMoveToPoint(contex, pathArray[i].start.x, pathArray[i].start.y);
CGContextAddLineToPoint(contex, pathArray[i].end.x, pathArray[i].end.y);
CGContextSetStrokeColorWithColor(contex, pathArray[i].color.CGColor);
CGContextSetLineWidth(contex, pathArray[i].pathWidth);
CGContextStrokePath(contex);
}
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch* touch = [touches anyObject];
if ([touch type] == UITouchTypeStylus)
{
if(drawable){
[self.delegate changeScrollViewInteraction:NO];
UITouch *touch = [touches anyObject];
lastPoint = [touch locationInView:self];
}
}
else
{
[self.delegate changeScrollViewInteraction:YES];
return;
}
[super touchesBegan: touches withEvent: event];
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
if ([touch type] == UITouchTypeStylus) //pencil touch
{
if(drawable){
CGPoint newpoint = [touch locationInView:self];
PathArray *paths = [[PathArray alloc]initWithStartPoint:lastPoint andEnd:newpoint andColor:strokecolor andPathWidth:pathWidth];
[pathArray addObject:paths];
lastPoint = newpoint;
[self setNeedsDisplay];
NSLog(#"%#",pathArray[0]);
}
}
else
{
return;
}
[super touchesMoved: touches withEvent: event];
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event{
UITouch *touch = [touches anyObject];
if ([touch type] == UITouchTypeStylus && drawable) //pencil touch
{
[pathEndPointArray addObject:tempEndPointArray];
}
if ([touch type] == UITouchTypeStylus && !drawable)
{
[self.delegate CacheLIView_showPopup_message:#"Already cupped!"];
}
[self touchesMoved:touches withEvent:event];
}
-(void)undo{
}
-(void)foward{
}
-(void)re_draw_after_rotate{ }
I need to create these function.

I would suggest the following (no code here):
create a second array pathUndoArray
Upon undo, remove the last entry from pathArray (if exists) and add it (at the end) to pathUndoArray, then redraw.
Upon redo, remove the last entry from pathUndoArray (if exists) and add it (at the end) to pathArray, then redraw.
Upon a new touch, you'll have to delete the pathUndoArray
You could also take a look at NSUndoManager.

Related

How can I make UITouches offset?

In the image below, I draw and the result is at point A, right where my finger touches.
How can I make the image appear about 40pt above my actual touch. (B)
I'm using the classic coreGraphic UITouch code, like so:
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
// add the first touch
UITouch *touch = [touches anyObject];
previousPoint1 = [touch previousLocationInView:self];
currentPoint = [touch locationInView:self];
//transform = CGAffineTransformTranslate(self.transform, 5.0, 10.0)
// init the bezier path
self.currentTool = [self toolWithCurrentSettings];
self.currentTool.lineWidth = self.lineWidth;
self.currentTool.lineColor = self.lineColor;
self.currentTool.lineAlpha = self.lineAlpha;
[self.pathArray addObject:self.currentTool];
[self.undoStates addObject:[self.currentTool captureToolState]];
[self.currentTool setInitialPoint:currentPoint];
}
// call the delegate
if ([self.delegate respondsToSelector:#selector(drawingView:willBeginDrawUsingTool:)]) {
[self.delegate drawingView:self willBeginDrawUsingTool:self.currentTool];
}
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
// save all the touches in the path
UITouch *touch = [touches anyObject];
previousPoint2 = previousPoint1;
previousPoint1 = [touch previousLocationInView:self];
currentPoint = [touch locationInView:self];
[self.currentTool moveFromPoint:previousPoint1 toPoint:currentPoint];
[self setNeedsDisplay];
}
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
// make sure a point is recorded
[self touchesMoved:touches withEvent:event];
CGPoint point = [[touches anyObject] locationInView:self];
[self.currentTool setInitialPoint:point];
self.draggableTextView = ((ACEDrawingDraggableTextTool *)self.currentTool).labelView;
[self.pathArray addObject:self.currentTool];
[self finishDrawing];
[self finishDrawing];
}
}
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
{
// make sure a point is recorded
[self touchesEnded:touches withEvent:event];
}
previousPoint1 = [touch previousLocationInView:self];
currentPoint = [touch locationInView:self];
// add these 2 lines below:
previousPoint1 = CGPointMake(previousPoint1.x, previousPoint1.y+40);
currentPoint = CGPointMake(currentPoint.x, currentPoint.y+40);

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.

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.)

How to detect subclass sprite touch

I subclass a sprite called newSprite.h / newSprite.m, and I add a sprite in it
CCSprite *nsprite = [CCSprite spriteWithFile:#"mouse.png"];
[self addChild: nsprite];
and in gamelayer.m, I add the following code
newSprite *newp = [newSprite node];
newp.position = ccp(actualX, actualY);
[self addChild:newp];
[_NSMutableArrayName addObject:newp];
when I use following code to detect which sprite i touched
- (void)ccTouchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
CGPoint location = [self convertTouchToNodeSpace: touch];
for (CCSprite *target in _NSMutableArrayName) {
if (CGRectContainsPoint(target.boundingBox, location)) {
CCLOG(#"yes i am touched");
}
}
}
but it doesn't work, the sprite can not be detected, so where is the wrong? please help me, thanks
Try using this:
- (void)ccTouchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
CGPoint location = [self convertTouchToNodeSpace:touch];
for (CCSprite *target in _NSMutableArrayName) {
CGSize size = node.contentSize;
CGRect r = CGRectMake(0.f, 0.f,
size.width, size.height);
if (CGRectContainsPoint(r, local)) {
CCLOG(#"yes i am touched");
}
}
}
You are trying to detect touches on sub sprite and giving the bounds of parent sprite.
First, take nsprite as class variable in NewSprite to keep its reference when you call it from GameLayer. Then try changing this method like:
- (void)ccTouchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
CGPoint location = [self convertTouchToNodeSpace: touch];
for (CCSprite *target in _NSMutableArrayName) {
CCSize size = target.nSprite.contentSize;
CCRect rect = CCRectMake(target.position.x - size.width/2, target.position.y - size.height/2, width, height);
if (CGRectContainsPoint(rect, location)) {
CCLOG(#"yes i am touched");
}
}
}

Resources