I have a Cocos2d and Box2D application. I have a image bubble.png. I want to draw a chain of bubbles when the user swipes the screen.
Can anyone tell me how to do this ?
Thanks
- (void)ccTouchesMoved:(NSSet *)touches withEvent:(UIEvent *)event{
{
//Add a new body/atlas sprite at the touched location
for( UITouch *touch in touches ) {
CGPoint location = [touch locationInView: [touch view]];
location = [[CCDirector sharedDirector] convertToGL: location];
b2Vec2 locationWorld = b2Vec2(location.x/PTM_RATIO, location.y/PTM_RATIO);
CCSprite *mist=[CCSprite spriteWithFile:#"bubble.png"];
mist.position=ccp(location.x,location.y);
[self addChild:mist];
}
}
You need to register with the touchdispatcher I think... ( [layer registerWithTouchDispatcher] )
[glView setMultipleTouchEnabled:YES]; (Maybe this is needed for swiping)
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 am loading a menu in which i have 7 layers through which i swipe. On first load the swiping is smooth at 60fps, but i then pop the scene and push it again, the swiping is very slow, though the app displays 60fps, and the ccTouchesMoved is called roughly at the same interval as on the first load.
On each layer, i add some statical CCSprites and a CCMenu.
All items are deallocated, and i am testing the app on ipad 3 (so speed isn't quite an issue).
I presume that the cause is more on the settings part and would like to find a solution for it. Here are my touch methods, if it helps:
- (void)ccTouchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
CGPoint location = [touch locationInView: [touch view]];
location = [[CCDirector sharedDirector] convertToGL:location];
//Swipe Detection Part 1
firstTouch = location;
}
-(void)ccTouchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
NSSet *allTouches = [event allTouches];
UITouch * touch = [[allTouches allObjects] objectAtIndex:0];
CGPoint location = [touch locationInView: [touch view]];
location = [[CCDirector sharedDirector] convertToGL:location];
CGSize winSize = [[CCDirector sharedDirector] winSize];
for(int i=0;i<[layerList count];i++)
{
[[layerList objectAtIndex:i] setPosition:CGPointMake((i-currentLayer)*winSize.width + (location.x - firstTouch.x),0) ];
}
}
-(void)ccTouchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
NSSet *allTouches = [event allTouches];
UITouch * touch = [[allTouches allObjects] objectAtIndex:0];
CGPoint location = [touch locationInView: [touch view]];
location = [[CCDirector sharedDirector] convertToGL:location];
//Swipe Detection Part 2
lastTouch = location;
//Swipe Detection Part 2
lastTouch = location;
//Minimum length of the swipe
float swipeLength = ccpDistance(firstTouch, lastTouch);
//Check if the swipe is a left swipe and long enough
if (firstTouch.x > lastTouch.x && swipeLength > 60) {
[self doStuffLeft];
}
else if (firstTouch.x < lastTouch.x && abs(swipeLength) > 60) {
[self doStuffRight];
}
}
Figured it out, [CCDirector sharedInstance] was paused.
my code:
-(void) ccTouchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
//Add a new body/atlas sprite at the touched location
for( UITouch *touch in touches ) {
CGPoint touchLocation = [touch locationInView: [touch view]];
CGPoint prevLocation = [touch previousLocationInView: [touch view]];
touchLocation = [[CCDirector sharedDirector] convertToGL: touchLocation];
prevLocation = [[CCDirector sharedDirector] convertToGL: prevLocation];
CGPoint diff = ccpSub(touchLocation,prevLocation);
[self setPosition: ccpAdd(self.position, diff)];
}
}
This code lets me move the layer with my fingers. That works fine. But now I want to let the user only move the layer within a predefined CGRect. How to do that?
For example:
CGRect rect = CGRectMake(0,0,600,320);
Now the player should be only allowed to move the layer within this rect. In that example he could only move it (on an ipod touch) to the left and right. (till 600px).
What do I need to change to achieve that?
Thank you for any help.
Have a nice day :)
Keep a variable to check.. eg..
distmoved = distmoved + touchlocation.x - prevlocation.x;
if(distmoved<600)
//move code
note that distmoved is a float..
You should make your own check. It's not hard in your case:
[self setPosition: ccpAdd(self.position, diff)];
if (self.position.x < minX)
{
//correct x position
}
if (...)
// ...
// ans so on
Is it possible to drag UIView around the iOS screen while it has both image and text? e.g. small cards. Could you point me to the similar (solved) topic? I haven't found any.
This is what a neat solution, based on pepouze's answer, would look like (tested, it works!)
- (void) touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *aTouch = [touches anyObject];
CGPoint location = [aTouch locationInView:self];
CGPoint previousLocation = [aTouch previousLocationInView:self];
self.frame = CGRectOffset(self.frame, (location.x - previousLocation.x), (location.y - previousLocation.y));
}
While UIView does not have a built-in support for moving itself along the user dragging, it should be not so difficult to implement it. It is even easier when you are only dealing with dragging on the view, and not other actions such as tapping, double tapping, multi-touches etc.
First thing to do is to make a custom view, say DraggableView, by subclassing UIView. Then override UIView's touchesMoved:withEvent: method, and you can get a current dragging location there, and move the DraggableView. Look at the following example.
-(void) touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *aTouch = [touches anyObject];
CGPoint location = [aTouch locationInView:self.superview];
[UIView beginAnimations:#"Dragging A DraggableView" context:nil];
self.frame = CGRectMake(location.x, location.y,
self.frame.size.width, self.frame.size.height);
[UIView commitAnimations];
}
And because all subviews of the DraggableView object will be moved, too. So put all your images and texts as subviews of the DraggableView object.
What I implemented here is very simple. However, if you want more complex behaviors for the dragging, (for example, the user have to tap on the view for a few seconds to move the view), then you will have to override other event handling methods (touchesBegan:withEvent: and touchesEnd:withEvent) as well.
An addition to MHC's answer.
If you don't want the upper left corner of the view
to jump under your finger, you can also override touchesBegan
like this:
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *aTouch = [touches anyObject];
offset = [aTouch locationInView: self];
}
and change MHC's touchesMoved to:
-(void) touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *aTouch = [touches anyObject];
CGPoint location = [aTouch locationInView:self.superview];
[UIView beginAnimations:#"Dragging A DraggableView" context:nil];
self.frame = CGRectMake(location.x-offset.x, location.y-offset.y,
self.frame.size.width, self.frame.size.height);
[UIView commitAnimations];
}
you should also define CGPoint offset in the interface:
#interface DraggableView : UIView
{
CGPoint offset;
}
EDIT:
Arie Litovsky provides more elegant solution that allows you to ditch the ivar: https://stackoverflow.com/a/10378382/653513
Even though rokjarc solution works, using
CGPoint previousLocation = [aTouch previousLocationInView:self.superview];
avoids the CGPoint offset creation and the call to touchesBegan:withEvent:
Here is a solution to drag a custom UIView (it can be scaled or rotated through its transform), which can hold images and/or text (just edit the Tile.xib as required):
- (void) touchesMoved:(NSSet*)touches withEvent:(UIEvent*)event
{
UITouch *touch = [touches anyObject];
CGPoint location = [touch locationInView:self];
CGPoint previous = [touch previousLocationInView:self];
if (!CGAffineTransformIsIdentity(self.transform)) {
location = CGPointApplyAffineTransform(location, self.transform);
previous = CGPointApplyAffineTransform(previous, self.transform);
}
self.frame = CGRectOffset(self.frame,
(location.x - previous.x),
(location.y - previous.y));
}
This work for me. My UIView rotated and scaled
- (void) touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
UITouch *touch = [touches anyObject];
CGPoint location = [touch locationInView:self];
CGPoint previous = [touch previousLocationInView:self];
if (!CGAffineTransformIsIdentity(self.transform)) {
location = CGPointApplyAffineTransform(location, self.transform);
previous = CGPointApplyAffineTransform(previous, self.transform);
}
CGRect newFrame = CGRectOffset(self.frame,
(location.x - previous.x),
(location.y - previous.y));
float x = CGRectGetMidX(newFrame);
float y = CGRectGetMidY(newFrame);
self.center = CGPointMake(x, y);
}
i dont get how to translate the coordinates of the iphone.
if i make a single touch i get the coordinate.
if i make a touch and keep it and release it it shows the difference of the starting and end point.
how do i get the absolute position of the touch?
thanks!
-(void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [[event allTouches] anyObject];
CGPoint location = [touch locationInView:touch.view];
NSLog(#"X: %f",location.x);
NSLog(#"Y: %f",location.y);
}
I want to resize an image with touch and drag(only the height)
The position of a touch is calculated relative to a view.
If you want the position relative to the screen do:
UITouch * touch = [touches anyObject];
CGPoint pos = [touch locationInView: [UIApplication sharedApplication].keyWindow];
NSLog(#"Position of touch: %.3f, %.3f", pos.x, pos.y);
(dry coded, might give errors)