_ball = [CCSprite spriteWithFile:#"ball.png" rect:CGRectMake(0, 0, 52, 52)];
_ball.position = ccp(300, 300);
[self addChild:_ball];
_ball1 = [CCSprite spriteWithFile:#"ball.png" rect:CGRectMake(0, 0, 52, 52)];
_ball1.position = ccp(300, 300);
[self addChild:_ball1];
if (_ball1.position.x == _ball.position.x && _ball1.position.y == _ball.position.y) {
NSLog(#"Stop");
}
if _ball is touch _ball1 not worrking
in this something wrong?
Use CGRectIntersectsRect to determine if the sprites overlap:
if (CGRectIntersectsRect([_ball1 boundingBox], [_ball2 boundingBox])) {
NSLog(#"Stop");
}
Of course, this is just a rectangular intersection, which is probably unsuitable for circular objects, in which you can use the ideas presented in this webpage.
Related
//UPDATE
The updated code has been added that works as I expected. See didSimulatePhysics method in the updated code below. In my case, I only care about moving a character left or right on the x axis where 0 on the x axis is the absolute left and right on the x axis is a configurable value. The Apple adventure game really helped a lot too.
//ORIGINAL POST BELOW
I'm working with Apple SpriteKit and I'm struggling to implement a camera as I would like it to behave. What I've done in the code is load a sprite character, two buttons, and a red box that is off to the right outside of the view at the start. What I'd like to be able to do is move the character with the buttons, and once the player reaches the middle or end of the screen, the camera will then re-adjust to uncover what couldn't be seen in the view. So moving to the right should eventually show the red box that is off outside of the view initially once the player gets there. However, with the code I'm using below, I'm unable to get the camera to follow and adjust the coordinates to the main character at all. I've looked at Apple's advanced scene processing doc as well as a few other stack overflow posts but can't seem to get it right. If anyone could offer some advice it would be appreciated.
#define cameraEdge 150
-(id)initWithSize:(CGSize)size
{
if (self = [super initWithSize:size])
{
/* Setup your scene here */
//320 568
self.backgroundColor = [SKColor whiteColor];
myWorld = [[SKNode alloc] init];
[self addChild:myWorld];
mainCharacter = [SKSpriteNode spriteNodeWithImageNamed:#"0"];
mainCharacter.physicsBody.dynamic = YES;
mainCharacter.name = #"player";
mainCharacter.position = CGPointMake(20, 20);
CGRect totalScreenSize = CGRectMake(0, 0, 800, 320);
SKSpriteNode *box = [SKSpriteNode spriteNodeWithColor:[SKColor redColor] size:CGSizeMake(60, 60)];
SKSpriteNode *boxTwo = [SKSpriteNode spriteNodeWithColor:[SKColor greenColor] size:CGSizeMake(60, 60)];
SKSpriteNode *boxThree = [SKSpriteNode spriteNodeWithColor:[SKColor blueColor] size:CGSizeMake(60, 60)];
boxThree.position = CGPointMake(40, 50);
[myWorld addChild:boxThree];
boxTwo.position = CGPointMake(1100, 50);
box.position = CGPointMake(650, 50);
[myWorld addChild:box];
[myWorld addChild:boxTwo];
self.physicsBody = [SKPhysicsBody bodyWithEdgeLoopFromRect:totalScreenSize];
self.physicsWorld.gravity = CGVectorMake(0, -5);
mainCharacter.name = #"mainCharacter";
mainCharacter.physicsBody.linearDamping = 0;
mainCharacter.physicsBody.friction = 0;
mainCharacter.physicsBody.restitution = 0;
mainCharacter.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:mainCharacter.size];
[myWorld addChild:mainCharacter];
[self addChild:[self buildLeftButton]];
[self addChild:[self buildRightButton]];
}
return self;
}
- (void)didSimulatePhysics
{
SKSpriteNode *hero = mainCharacter;
if(hero)
{
CGPoint heroPosition = hero.position;
CGPoint worldPosition = myWorld.position;
NSLog(#"%f", heroPosition.x);
CGFloat xCoordinate = worldPosition.x + heroPosition.x;
if(xCoordinate < cameraEdge && heroPosition.x > 0)
{
worldPosition.x = worldPosition.x - xCoordinate + cameraEdge;
self.worldMovedForUpdate = YES;
}
else if(xCoordinate > (self.frame.size.width - cameraEdge) && heroPosition.x < 2000)
{
worldPosition.x = worldPosition.x + (self.frame.size.width - xCoordinate) - cameraEdge;
self.worldMovedForUpdate = YES;
}
myWorld.position = worldPosition;
}
}
-(SKSpriteNode *)buildLeftButton
{
SKSpriteNode *leftButton = [SKSpriteNode spriteNodeWithImageNamed:#"left"];
leftButton.position = CGPointMake(20, 20);
leftButton.name = #"leftButton";
leftButton.zPosition = 1.0;
return leftButton;
}
-(SKSpriteNode *)buildRightButton
{
SKSpriteNode *leftButton = [SKSpriteNode spriteNodeWithImageNamed:#"right"];
leftButton.position = CGPointMake(60, 20);
leftButton.name = #"rightButton";
leftButton.zPosition = 1.0;
return leftButton;
}
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
CGPoint location = [touch locationInNode:self];
SKNode *node = [self nodeAtPoint:location];
if([node.name isEqualToString:#"leftButton"])
{
[mainCharacter.physicsBody applyImpulse:CGVectorMake(-120, 0)];
}
else if([node.name isEqualToString:#"rightButton"])
{
[mainCharacter.physicsBody applyImpulse:CGVectorMake(120, 10)];
}
}
If you want the view to always be centered on your player's position, modify your code with these points in mind:
1) Create a SKNode and call it myWorld, worldNode or any other name like that.
2) Add the worldNode [self addChild:worldNode];
3) Add all other nodes to the worldNode, including your player.
4) In the didSimulatePhysics method, add this code:
worldNode.position = CGPointMake(-(player.position.x-(self.size.width/2)), -(player.position.y-(self.size.height/2)));
Your view will now always be centered on your player's position.
Update May 2015:
If you are using a map created with Tiled Map Editor, you can use the free SKAToolKit framework. Features include player camera auto follow, test player, test HUD and sprite buttons.
Hi how do i create a moving ball on iOS.
When the program starts, I will display the ball on the left of the screen. Subsequently, each time i click a UIButton, how do i move the ball to the right on the same x-axis.
I managed to display the ball but how do i update and redraw its location when the UIButton is pressed? currently each time i press the UIButton, it creates a new ball and the old balls are not cleared.
i understand its because i recreate a new instance of the ball. So how shall i go about fixing this?
Here is my code....
ballView.m
#implementation BallView
-(id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
[self setBackgroundColor:[UIColor clearColor]];
}
return self;
}
-(void)drawRect:(CGRect)dirtyRect
{
NSLog(#"in drawRect");
// Get the graphics context and clear it
CGContextRef ctx = UIGraphicsGetCurrentContext();
// Draw a solid ball
CGContextSetRGBFillColor(ctx, 0, 0, 0, 1);
CGContextFillEllipseInRect(ctx, dirtyRect);
[self setNeedsDisplay];
}
-(BOOL)canBecomeFirstResponder
{
return YES;
}
MoveBallController.m
-(void)moveBall
{
CGRect viewFrame = CGRectMake(0, 0, 30, 30);
BallView *ball = [[BallView alloc] initWithFrame:viewFrame];
[[self dotView] addSubview:ball];
}
Create one BallView instance and store it in an instance variable. Then when the button is clicked you simply update the ball's frame:
- (void)viewDidLoad {
[super viewDidLoad];
CGRect viewFrame = CGRectMake(0, 0, 30, 30);
_ball = [[BallView alloc] initWithFrame:viewFrame];
[[self dotView] addSubview:_ball];
}
- (void)moveBall {
CGRect frame = _ball.frame;
frame.origin.x += 5; // use some appropriate increment
_ball.frame = frame;
}
where _ball is your new instance variable.
I have two UIViews, one of which is rotated every .01 second using the following code:
self.rectView.transform = CGAffineTransformRotate(self.rectView.transform, .05);
Now, I want to be able to tell if another UIView, called view, intersects rectView. I used this code:
if(CGRectIntersectsRect(self.rectView.frame, view.frame)) {
//Intersection
}
There is a problem with this, however, as you probably know. Here is a screenshot:
In this case, a collision is detected, even though obviously they are not touching. I have looked around, but I cannot seem to find real code to detect this collision. How can this be done? Working code for detecting the collision in this case would be greatly appreciated! Or maybe would there be a better class to be using other than UIView?
when you rotate a view, its bounds won't change but its frame changes.
So, for my view with backgroundColor blue,
the initial frame i set to was
frame = (30, 150, 150, 35);
bounds={{0, 0}, {150, 35}};
but after rotating by 45 degree, the frame changed to
frame = (39.5926 102.093; 130.815 130.815);
bounds={{0, 0}, {150, 35}};
Because the frame always return the smallest enclosing rectangle of that view.
So, in your case, even-though it looks both views are not intersecting,their frames intersect.
To solve it you can use, separating axis test.
If you want learn on it, link here
I tried to solve it and finally got the solution.
If you like to check, below is the code.
Copy paste the below code into an empty project to check it out.
In .m file
#implementation ViewController{
UIView *nonRotatedView;
UIView *rotatedView;
}
- (void)viewDidLoad
{
[super viewDidLoad];
nonRotatedView =[[UIView alloc] initWithFrame:CGRectMake(120, 80, 150, 40)];
nonRotatedView.backgroundColor =[UIColor blackColor];
[self.view addSubview:nonRotatedView];
rotatedView =[[UIView alloc] initWithFrame:CGRectMake(30, 150, 150, 35)];
rotatedView.backgroundColor =[UIColor blueColor];
[self.view addSubview:rotatedView];
CGAffineTransform t=CGAffineTransformMakeRotation(M_PI_4);
rotatedView.transform=t;
CAShapeLayer *layer =[CAShapeLayer layer];
[layer setFrame:rotatedView.frame];
[self.view.layer addSublayer:layer];
[layer setBorderColor:[UIColor blackColor].CGColor];
[layer setBorderWidth:1];
CGPoint p=CGPointMake(rotatedView.bounds.size.width/2, rotatedView.bounds.size.height/2);
p.x = -p.x;p.y=-p.y;
CGPoint tL =CGPointApplyAffineTransform(p, t);
tL.x +=rotatedView.center.x;
tL.y +=rotatedView.center.y;
p.x = -p.x;
CGPoint tR =CGPointApplyAffineTransform(p, t);
tR.x +=rotatedView.center.x;
tR.y +=rotatedView.center.y;
p.y=-p.y;
CGPoint bR =CGPointApplyAffineTransform(p, t);
bR.x +=rotatedView.center.x;
bR.y +=rotatedView.center.y;
p.x = -p.x;
CGPoint bL =CGPointApplyAffineTransform(p, t);
bL.x +=rotatedView.center.x;
bL.y +=rotatedView.center.y;
//check for edges of nonRotated Rect's edges
BOOL contains=YES;
CGFloat value=nonRotatedView.frame.origin.x;
if(tL.x<value && tR.x<value && bR.x<value && bL.x<value)
contains=NO;
value=nonRotatedView.frame.origin.y;
if(tL.y<value && tR.y<value && bR.y<value && bL.y<value)
contains=NO;
value=nonRotatedView.frame.origin.x+nonRotatedView.frame.size.width;
if(tL.x>value && tR.x>value && bR.x>value && bL.x>value)
contains=NO;
value=nonRotatedView.frame.origin.y+nonRotatedView.frame.size.height;
if(tL.y>value && tR.y>value && bR.y>value && bL.y>value)
contains=NO;
if(contains==NO){
NSLog(#"no intersection 1");
return;
}
//check for roatedView's edges
CGPoint rotatedVertexArray[]={tL,tR,bR,bL,tL,tR};
CGPoint nonRotatedVertexArray[4];
nonRotatedVertexArray[0]=CGPointMake(nonRotatedView.frame.origin.x,nonRotatedView.frame.origin.y);
nonRotatedVertexArray[1]=CGPointMake(nonRotatedView.frame.origin.x+nonRotatedView.frame.size.width,nonRotatedView.frame.origin.y);
nonRotatedVertexArray[2]=CGPointMake(nonRotatedView.frame.origin.x+nonRotatedView.frame.size.width,nonRotatedView.frame.origin.y+nonRotatedView.frame.size.height);
nonRotatedVertexArray[3]=CGPointMake(nonRotatedView.frame.origin.x,nonRotatedView.frame.origin.y+nonRotatedView.frame.size.height);
NSInteger i,j;
for (i=0; i<4; i++) {
CGPoint first=rotatedVertexArray[i];
CGPoint second=rotatedVertexArray[i+1];
CGPoint third=rotatedVertexArray[i+2];
CGPoint mainVector =CGPointMake(second.x-first.x, second.y-first.y);
CGPoint selfVector =CGPointMake(third.x-first.x, third.y-first.y);
BOOL sign;
sign=[self crossProductOf:mainVector withPoint:selfVector];
for (j=0; j<4; j++) {
CGPoint otherPoint=nonRotatedVertexArray[j];
CGPoint otherVector = CGPointMake(otherPoint.x-first.x, otherPoint.y-first.y);
BOOL checkSign=[self crossProductOf:mainVector withPoint:otherVector];
if(checkSign==sign)
break;
else if (j==3)
contains=NO;
}
if(contains==NO){
NSLog(#"no intersection 2");
return;
}
}
NSLog(#"intersection");
}
-(BOOL)crossProductOf:(CGPoint)point1 withPoint:(CGPoint)point2{
if((point1.x*point2.y-point1.y*point2.x)>=0)
return YES;
else
return NO;
}
Hope this helps.
This can be done much more efficiently and easily than what has been suggested... and both the black and blue views can be rotated if need be.
Just convert the 4 corners of the rotated blueView to their location in the superview and then convert those points to their location in the rotated blackView then check if those points are within the blackView's bounds.
UIView *superview = blueView.superview;//Assuming blueView.superview and blackView.superview are the same...
CGPoint blueView_topLeft_inSuperview = [blueView convertPoint:CGPointMake(0, 0) toView:superview];
CGPoint blueView_topRight_inSuperview = [blueView convertPoint:CGPointMake(blueView.bounds.size.width, 0) toView:superview];
CGPoint blueView_bottomLeft_inSuperview = [blueView convertPoint:CGPointMake(0, blueView.bounds.size.height) toView:superview];
CGPoint blueView_bottomRight_inSuperview = [blueView convertPoint:CGPointMake(blueView.bounds.size.width, blueView.bounds.size.height) toView:superview];
CGPoint blueView_topLeft_inBlackView = [superview convertPoint:blueView_topLeft_inSuperview toView:blackView];
CGPoint blueView_topRight_inBlackView = [superview convertPoint:blueView_topRight_inSuperview toView:blackView];
CGPoint blueView_bottomLeft_inBlackView = [superview convertPoint:blueView_bottomLeft_inSuperview toView:blackView];
CGPoint blueView_bottomRight_inBlackView = [superview convertPoint:blueView_bottomRight_inSuperview toView:blackView];
BOOL collision = (CGRectContainsPoint(blackView.bounds, blueView_topLeft_inBlackView) ||
CGRectContainsPoint(blackView.bounds, blueView_topRight_inBlackView) ||
CGRectContainsPoint(blackView.bounds, blueView_bottomLeft_inBlackView) ||
CGRectContainsPoint(blackView.bounds, blueView_bottomRight_inBlackView));
i have a ccsprite which i would like to place inside a CCLayerColor but for some reason its not showing up inside of it. i have the following code and i'm stumped why it isn't showing up.
[self setColor:ccGREEN];
[self setOpacity:255];
[self setPosition:(CGPointMake(0, 60/2+bottomPadding))];
self.inventoryHolder = [[CCSprite alloc] init];
[self.inventoryHolder setTextureRect:CGRectMake(0, 0, 100, 60)];
[self.inventoryHolder setColor:ccc3(255, 0, 0)];
self.inventoryHolder.anchorPoint = ccp(0, 0);
self.inventoryHolder.position = ccp(0, 60/2+50);
[self addChild:self.inventoryHolder z:100];
self being the CCLayerColor and self.inventoryHolder being the CCSprite. Any help would be awesome!
You haven't actually set a texture in the sprite, so there's nothing for it to display.
I am trying to implement city lights animations by having an array of CGRect's with the coordinates of each light. Then creating UIViews around these CGRects. This logic (Thanks to Darren for helping with this logic) is working fine however after the animation is complete, all other elements (UIButtons, Sliders, Other UIImageViews etc) on screen become inaccessible. Even my Swipe gestures are not responding. Before and during the animation, all elements respond well BUT once the animation is complete, they all become inaccessible. I also tried [UIView bringSubviewToFront:] to bring some of the elements in front to see if that helps to make them accessible but it didn't help. I think that's not the issue because even if I try to create the lights view by sending them to background [self.view sendSubviewToBack:light]; everything becomes inaccessible after the animation is complete.
I would appreciate if someone can help/suggest me what am I missing.
Here is my code logic and corresponding scene for city lights animation. rects & lits are ivars.
- (void)viewDidLoad {
pageCount=5;
AVAudioSession * audioSession = [AVAudioSession sharedInstance];
//Setup the audio session
//...
pageNum=1;
//put imageviews in place
//...
//load a page
[self loadPage];
[self loadAudio];
[self cityLightsSetUp];
[super viewDidLoad];
}
-(void)loadPage{
//Logic to load page...
/...
if (pageNum == 3){
[self startCityLights];
}
}
- (void)cityLightsSetUp
{
rects = [[NSMutableArray alloc] init];
lit = [[NSMutableArray alloc] init];
[rects addObject:[NSValue valueWithCGRect:CGRectMake(58, 217, 10, 10)]];
[rects addObject:[NSValue valueWithCGRect:CGRectMake(71, 217, 10, 10)]];
[rects addObject:[NSValue valueWithCGRect:CGRectMake(84, 217, 10, 10)]];
[rects addObject:[NSValue valueWithCGRect:CGRectMake(97, 217, 10, 10)]];
[rects addObject:[NSValue valueWithCGRect:CGRectMake(58, 231, 10, 10)]];
[rects addObject:[NSValue valueWithCGRect:CGRectMake(71, 231, 10, 10)]];
[rects addObject:[NSValue valueWithCGRect:CGRectMake(84, 231, 10, 10)]];
[rects addObject:[NSValue valueWithCGRect:CGRectMake(97, 231, 10, 10)]];
[rects addObject:[NSValue valueWithCGRect:CGRectMake(58, 245, 10, 10)]];
[rects addObject:[NSValue valueWithCGRect:CGRectMake(71, 245, 10, 10)]];
[rects addObject:[NSValue valueWithCGRect:CGRectMake(84, 245, 10, 10)]];
[rects addObject:[NSValue valueWithCGRect:CGRectMake(97, 245, 10, 10)]];
[rects addObject:[NSValue valueWithCGRect:CGRectMake(58, 258, 10, 10)]];
[rects addObject:[NSValue valueWithCGRect:CGRectMake(71, 258, 10, 10)]];
}
- (void)startCityLights
{
[self lightRandomLight];
[self performSelector:#selector(switchOffRandomLight) withObject:nil afterDelay:1.0];
}
- (void)lightRandomLight
{
BOOL escape = NO;
int rand;
while (!escape) {
BOOL alreadyLit = NO;
rand = arc4random() % [rects count];
// Check if already lit
for (UIView *view in lit) {
CGRect litRect = view.frame;
CGRect ranRect = [[rects objectAtIndex:rand] CGRectValue];
if (CGRectContainsRect(litRect, ranRect)) {
alreadyLit = YES;
}
}
if (!alreadyLit) {
UIView *light = [[UIView alloc] initWithFrame:[[rects objectAtIndex:rand] CGRectValue]];
light.backgroundColor = [UIColor orangeColor];
[lit addObject:light];
[self.view addSubview:light];
//[self.view sendSubviewToBack:light];
escape = YES;
}
}
[self performSelector:#selector(lightRandomLight) withObject:nil afterDelay:0.2];
}
- (void)switchOffRandomLight
{
NSLog(#"switchOffRandomLight");
int rand = arc4random() % [lit count];
UIView *light = [lit objectAtIndex:rand];
[lit removeObject:light];
[light removeFromSuperview];
[self performSelector:#selector(switchOffRandomLight) withObject:nil afterDelay:0.5];
}
It appears that once all lights are lit, the while loop runs continuously trying to get a random number that isn't lit. This is what will be blocking the main thread.
All you need is to check if all lights are lit at the beginning of the method and continue if not.
At the bottom of your lightRandomLight method, replace
[self performSelector:#selector(lightRandomLight) withObject:nil afterDelay:0.2];
with
if ([lit count] != [rects count]) {
[self performSelector:#selector(lightRandomLight) withObject:nil afterDelay:0.2];
} else {
[NSObject cancelPreviousPerformRequestsWithTarget:self];
}
and it'll stop when all the lights are lit.
You are blocking the main thread - lightRandomLight calls itself when it is finished, with a 0.2 second delay. Therefore the main thread will never be responsive to user interaction. Look at the animation API provided by UIView - rather than "animating" by adding and removing subviews, you can set the alpha status or background colour of views, and you can set delays and set up loops.
My guess is that while (!escape) {} will never complete (so escape is never YES).