I have a certain point at the bottom of the screen . . . when I touch the screen somewhere, I'd like a dotted line to appear between the point, and the point my finger is at. The length and rotation of the line will change based on where my finger is, or moves to.
I'm assuming I'd make the dotted line with a repetition of a small line image, but I guess that's why I need your help!
Note that all this can be organized better, and I personally don't like SKShapeNode in any shape :) or form, but this is the one way to do it:
#import "GameScene.h"
#implementation GameScene{
SKShapeNode *line;
}
-(void)didMoveToView:(SKView *)view {
/* Setup your scene here */
line = [SKShapeNode node];
[self addChild:line];
[line setStrokeColor:[UIColor redColor]];
}
-(void)drawLine:(CGPoint)endingPoint{
CGMutablePathRef pathToDraw = CGPathCreateMutable();
CGPathMoveToPoint(pathToDraw, NULL, CGRectGetMidX(self.frame),CGRectGetMidY(self.frame));
CGPathAddLineToPoint(pathToDraw, NULL, endingPoint.x,endingPoint.y);
CGFloat pattern[2];
pattern[0] = 20.0;
pattern[1] = 20.0;
CGPathRef dashed =
CGPathCreateCopyByDashingPath(pathToDraw,NULL,0,pattern,2);
line.path = dashed;
CGPathRelease(dashed);
}
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
/* Called when a touch begins */
for (UITouch *touch in touches) {
CGPoint location = [touch locationInNode:self];
[self drawLine:location];
}
}
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event{
for (UITouch *touch in touches) {
CGPoint location = [touch locationInNode:self];
[self drawLine:location];
}
}
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event{
line.path = nil;
}
The result is:
Also I don't know how much performant this is, but you can test it, tweak it and improve it. Or even use SKSpriteNode like you said. Happy coding!
EDIT:
I just noticed that you said dotted (not dashed) :)
You have to change pattern to something like:
pattern[0] = 3.0;
pattern[1] = 3.0;
Related
So far, I have made my CCSprite move to the location of the user's touch on the screen using CCActionMoveTo, however I have only got it to work when the user simply taps.
I would like the CCSprite to move when the user drags their finger, instead of just tapping and moving along with the ability to change direction as the user drags changes direction - I am fairly new to cocos2d and have search for similar questions but have been unable to find any. I have posted my code below:
- (id)init
{
self = [super init];
if (!self) return(nil);
self.userInteractionEnabled = YES;
// Player sprite
_playerSprite = [CCSprite spriteWithImageNamed:#"PlayerSprite.png"];
_playerSprite.scale = 0.5;
_playerSprite.position = ccp(self.contentSize.width/2, 150);
[self addChild:_playerSprite];
return self;
}
-(void) touchBegan:(UITouch *)touch withEvent:(UIEvent *)event {
CGPoint touchLoc = [touch locationInNode:self];
CCActionMoveTo *actionMove = [CCActionMoveTo actionWithDuration:0.2f position:ccp(touchLoc.x, 150)];
[_playerSprite runAction:actionMove];
}
You will need to implement the touchMoved method and set your sprite position in there. Something like this:
- (void)touchMoved:(UITouch *)touch withEvent:(UIEvent *)event {
CGPoint touchLocation = [touch locationInNode:self];
_playerSprite.position = touchLocation;
}
Try this (add a CGPoint property called previousTouchPos):
-(void) touchBegan:(UITouch *)touch withEvent:(UIEvent *)event
{
CGPoint touchLoc = [touch locationInNode:self];
self.previousTouchPos = touchLoc;
CCActionMoveTo *actionMove = [CCActionMoveTo actionWithDuration:1.0f position:touchLoc];
[_playerSprite runAction:actionMove];
}
-(void) touchMoved:(UITouch *)touch withEvent:(UIEvent *)event
{
CGPoint touchLoc = [touch locationInNode:self];
CGPoint delta = ccpSub(touchLoc, self.previousTouchPos);
_playerSprite.position = ccpAdd(_playerSprite.position, delta);
self.previousTouchPos = touchLoc;
}
This sounds like an ideal use case for CCActionFollow:
https://www.makegameswith.us/gamernews/365/make-two-nodes-follow-each-other-in-cocos2d-30
If you use the variation where you provide the target position through a block you can use the latest touch position as target position.
I have an image at the bottom of the screen.
I want the user to to move the image upwards until it reaches a certain Y point as follows:
[door setCenter:CGPointMake(160,347)];
So far, as you drag the image (door) upwards it continues past my destination point but when you let go it snaps back to the correct position.
How do I stop the image moving when reaching a certain point if the user's finger is still swiping upwards? Would it be inside an if statement?
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
if (startPoint.y < 347) {
// something in here ?????
}
}
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event{
UITouch *myTouch = [touches anyObject];
startPoint = [myTouch locationInView:self.view];
NSLog(#"position = %f and %f",startPoint.x,startPoint.y);
[door setCenter:CGPointMake(160, startPoint.y)];
}
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event{
[door setCenter:CGPointMake(160,347)];
}
How about setting it in touchesMoved method. Something like,
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event{
UITouch *myTouch = [touches anyObject];
startPoint = [myTouch locationInView:self.view];
NSLog(#"position = %f and %f",startPoint.x,startPoint.y);
if (startPoint.y < 347) { //or suitable condition to verify your case
[door setCenter:CGPointMake(160, startPoint.y)]; //then only set the center
} else
{
[door setCenter:CGPointMake(160,347);
}
}
I am trying to record the locations of the touches. Below is my code. As far as I understand, a touch at the very far upper left corner would give me a location of (0,0), and the very far lower right corner would be (768, 1024) supposing I'm holding the iPad in portrait. However, I'm getting values like (-6, -18) for the upper left corner and (761,1003) for the lower right. It looks like the coordinates are shifted somehow. A trace of self.bounds does give me {{0,0}, {768, 1024}}. Can someone explain this to me? I would like to get x and y value that are between the bounds {{0,0}, {768, 1024}}. Thank you very much in advance.
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
CGRect bounds = [self bounds];
NSLog(#"frame: %#", NSStringFromCGRect(bounds)); // this value was traced as frame: {{0, 0}, {768, 1024}}
UITouch* touch = [[event touchesForView:self] anyObject];
location = [touch locationInView:self];
NSLog(#"Location: %#", NSStringFromCGPoint(location));
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
CGRect bounds = [self bounds];
UITouch* touch = [[event touchesForView:self] anyObject];
location = [touch locationInView:self];
NSLog(#"Location: %#", NSStringFromCGPoint(location));
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
CGRect bounds = [self bounds];
UITouch* touch = [[event touchesForView:self] anyObject];
location = [touch locationInView:self];
NSLog(#"Location: %#", NSStringFromCGPoint(location));
}
Since I cannot comment yet, I have to post an answer. Have you tried setting the background color of the view to a different color so that you can see if its in the top left corner for sure?
Here's what I have for the view:
#implementation TouchesView
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
[self setUserInteractionEnabled:YES];
[self setBackgroundColor:[UIColor colorWithRed:1.0f green:0.6f blue:0.6f alpha:1.0f]];
}
return self;
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
CGPoint touch = [[touches anyObject] locationInView:self];
NSLog(#"(%.1f, %.1f)", touch.x, touch.y);
NSLog(#"%#", NSStringFromCGPoint(touch));
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event{}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event{}
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event{}
#end
And this is the initialization and adding it to a view controller:
TouchesView *touchView = [[TouchesView alloc] initWithFrame:self.view.bounds];
[self.view addSubview:touchView];
This works fine for me.
The -20 offset on the y values is fixed by setting "Status bar is initially hidden" to YES. The rest of the problem looks like it's a hardware issue because I got a different range for x and y values each time I run the program on the iPad. I didn't get this problem while running the program on the simulator. On the simulator, x values range from 1 to 767 and y values range from 1 to 1023, which are pretty correct.
I am trying to implement a selection wheel in an iphone application. I have got the wheel to track the users finger but now for some reason when the user touches the screen the wheel jumps so the same section of the wheel tracks the finger each time.
How would I get it so the wheel rotates like the user is dragging it from any point?
-(void) touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
NSSet *allTouches = [event allTouches];
int tInput = [allTouches count]-1;
UITouch *touch =[[allTouches allObjects] objectAtIndex:tInput];
CGPoint location = [touch locationInView:self.view];
float theAngle = atan2( location.y-imageX.center.y, location.x-imageX.center.x );
CGAffineTransform cgaRotate = CGAffineTransformMakeRotation(theAngle);
imageX.transform = cgaRotate;
}
Any suggestion?
Right - that makes perfect sense - this is indeed what your code does.
What you need to add is the initial value where you started your drag as a relative rotation -- or track your last rotation.
A very elaborate way is shown below - but this should help get the point across.
#interface UntitledViewController : UIViewController {
CGPoint firstLoc;
UILabel * fred;
double angle;
}
#property (assign) CGPoint firstLoc;
#property (retain) UILabel * fred;
#implementation UntitledViewController
#synthesize fred,firstLoc;
- (void)viewDidLoad {
[super viewDidLoad];
self.fred = [[UILabel alloc] initWithFrame:CGRectMake(100,100,100,100)];
fred.text = #"Fred!"; fred.textAlignment = UITextAlignmentCenter;
[self.view addSubview:fred];
angle = 0; // we aint have rotated just yet...
};
// make sure we get them drag events.
- (BOOL)isFirstResponder { return YES; }
-(void)handleObject:(NSSet *)touches
withEvent:(UIEvent *)event
isLast:(BOOL)lst
{
UITouch *touch =[[[event allTouches] allObjects] lastObject];
CGPoint curLoc = [touch locationInView:self.view];
float fromAngle = atan2( firstLoc.y-fred.center.y,
firstLoc.x-fred.center.x );
float toAngle = atan2( curLoc.y-fred.center.y,
curLoc.x-fred.center.x );
// So the angle to rotate to is relative to our current angle and the
// angle through which our finger moved (to-from)
float newAngle = angle + (toAngle - fromAngle);
CGAffineTransform cgaRotate = CGAffineTransformMakeRotation(newAngle);
fred.transform = cgaRotate;
// we only 'save' the current angle when we're done with the drag.
//
if (lst)
angle = newAngle;
}
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch =[[[event allTouches] allObjects] lastObject];
// capture where we started - so we can later work out the
// rotation relative to this point.
//
firstLoc = [touch locationInView:self.view];
};
-(void) touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
[self handleObject:touches withEvent:event isLast:NO];
};
-(void) touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
[self handleObject:touches withEvent:event isLast:YES];
}
Obviously you can do this a lot more elegant - and above misses a bit of 0 .. 2xPI capping you need.
Because the view itself is still the old one. You may want to fetch the zip example file in:
http://bynomial.com/blog/?p=77
and in PuttyView.m change the:
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
....
else {
self.center = CGPointMake(self.center.x + touchPoint.x - touchStart.x,
self.center.y + touchPoint.y - touchStart.y);
into
else {
NSSet *allTouches = [event allTouches];
int tInput = [allTouches count]-1;
UITouch *touch =[[allTouches allObjects] objectAtIndex:tInput];
CGPoint location = [touch locationInView:self];
float theAngle = atan2( location.y-self.center.y, location.x-self.center.x );
CGAffineTransform cgaRotate = CGAffineTransformMakeRotation(theAngle);
self.transform = cgaRotate;
}
where you thus stay within the view and its relative angle. Alternatively - in your code - keep the relative angle itself.
I am trying to rotate an image. This I am succeeding in doing. The problem is that when I am clicking down and dragging slightly, the image rotates completely to reach the point where I have clicked and then rotates slowly as I drag the image clockwise. I am concerned to why it is rotating completely to the place that I am dragging. I want the dragging to start from the position it is found and NOT to rotate to the place my finger is down on and then starts from there.
This is my code:
-
(void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
}
-(void) touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
NSSet *allTouches = [event allTouches];
int len = [allTouches count]-1;
UITouch *touch =[[allTouches allObjects] objectAtIndex:len];
CGPoint location = [touch locationInView:[self superview]];
float theAngle = atan2( location.y-self.center.y, location.x-self.center.x );
totalRadians = theAngle;
[self rotateImage:theAngle];
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
}
-(void) rotateImage:(float)angleRadians{
self.transform = CGAffineTransformMakeRotation(angleRadians);
CATransform3D rotatedTransform = self.layer.transform;
self.layer.transform = rotatedTransform;
}
Am I doing anything wrong?
Thanks!
Instead of creating the transformation from the angle that your getting from the touch, try incrementing totalRadians by its difference from the new angle, and then create the transform from that.
-(void) touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
NSSet *allTouches = [event allTouches];
int len = [allTouches count]-1;
UITouch *touch =[[allTouches allObjects] objectAtIndex:len];
CGPoint location = [touch locationInView:[self superview]];
float theAngle = atan2( location.y-self.center.y, location.x-self.center.x );
totalRadians += fabs(theAngle - totalRadians);
totalRadians = fmod(totalRadians, 2*M_PI);
[self rotateImage:totalRadians];
}
My first advice would be to switch to using the UIRotateGestureRecognizer if your app is for 4.0 and higher. It does the right thing and provides you with a rotation property.