cocoa collision detection question - objective-c

I get the concept of the NSIntersectionRect for collision detection but I can't seem to think of how to implement it for my project. It's nothing fancy, click a button and a view subclass is called and places a circle in the window at a random location. Click within the that view and the circle pulses (this makes it the active view). If you have an active view, clicking anywhere outside it (but not on another circle) will move that view to the click point.
I'm using [activeView animator setFrame: NSMakeRect(x, y, w, h)] to move the active view. Can I use this for collision detection or do I have to go with CABasicAnimation? Basically what I am looking to do is detect collisions with other circles (no physics needed at this point, just stop the movement) and/or with the bounds of the app window.
If someone could nudge me in the right direction (tutorial link, code snippet) I'd appreciate it.
Edit: Based on the well detailed answer below I need to be a bit more clear. I'm confused on where to implement the collision detection. The animator method of a view class is one line of code. How would I iterate through every static circle on the screen to run a collision check? Which is why I am wondering first, if I need to go with CoreAnimation, OpenGL or something like Chipmunk and then if I could get a nudge or assist that would be great.

Later .. in answer to your recent questions:
Which is why I am wondering first, if I need to go with CoreAnimation, OpenGL or something like Chipmunk and then if I could get a nudge or assist that would be great.
Answer - you absolutely definitely do not need OpenGL :) Next, you definitely do not need a physics library like Box2D or Chipmunk ... you could go that way if you wanted to, but, it would be a huge amount of unnecessary work. To be clear: until you are totally familiar with using DrawRect, things like Chipmunk are useless for you anyway, so just forget that.
Core Animation will not really help you. To be clear, you possibly want to interrupt an animation as it is happening. Is that correct?
I'm confused on where to implement the collision detection. The animator method of a view class is one line of code. How would I iterate through every static circle on the screen to run a collision check?
Bad news... if you actually want to interrupt the animation, if there is a collision, forget about Core Animation. Core Animation will let you send it from A to B as "one unit" of animation. It will NOT let you stop it in the middle (in case of a collision). So, that's that.
To be clear, that is what you want to do right? You set the circle in motion, and IF it hits something along the way, you want it to stop. Is this correct? if so, completely forget about Core Animation and throw away any work you've done so far.
You are going to have to dive in to "real" programming (whatever that means) and start using drawRect. Are you up for it?!
At this point I might just mention: consider buying a copy of Corona (it's like $100 -- I'm sure the demo is free). You can do everything you are describing in, literally, five minutes using Corona. (1/10th the time taken to write this post??) I always recommend this to people who are iPhone Curious. If you don't really want to spend 6 to 18 months becoming a gun iPhone programmer - just click to Corona for iPhone and in a fraction of the time it's taken you to use Stack Overflow, you can have your circles bouncing wildly on the iPhone screen.
So, failing that, you're gonna have to get to work and learn how to launch a timer (NSTimer) and use drawRect in a UIView.
Craate a new class called MyFirstView (.h and .m file) that is a subclass of UIView (not UIViewController, which is for wimps!). You'll need a drawRect method in MyFirstView and proceed from there!
Original answer..
I'm not sure I understand what you are saying, but to be clear:
You want to detect a collision between two circles. In your case, all the circles are the same diameter. Is that correct?
If so, fortunately it is very easy to do.
Write a routine that gets the distance between two CGPoints. (If you don't know how to do that I included it below.)
Next step, you must know the DIAMETER of your circles. Let's say it is 50.0 for the example.
Next, here is a routine that checks if two circles are colliding:
static inline bool areTwoCirclesColliding( CGPoint aa, CGPoint bb )
{
return ( distanceBetweenTwoCGPoints(aa,bb) < 50.0 );
}
(Note... if you are new to Objective C, note that the above is totally valid code. Simply paste it in at the top of your file. OK?)
Finally, you just have to check all your circles, one against the other, to see if any are colliding.
If you have a simple fixed number of circles, let's say three or so, just write out all the lines of code to check if any of the combinations are colliding, hence:
areTwoCirclesColliding(a,b)
areTwoCirclesColliding(a,c)
areTwoCirclesColliding(b,c)
If you have an array or some sort of list of circles, you just have to go through them all and check that each one is not touching any other. In pseudocode it might be something like this...
for n in 1 to numberCircles
oneCircle = circles[n]
for m in n+1 to numberCircles
anotherCircle = circles[m]
if ( areTwoCirclesColliding(oneCircle,anotherCircle) )
.. break, you found a collision
Alternately you could write it like this, makes no difference..
for each aa in circles
for each bb in circles
if (aa != bb) if (areTwoCirclesColliding(aa,bb)) .. break, found collision
{Aside - For the record it is utterly unimportant that you check each pair twice in that pseudocode, no problem.}
It is impossible for me to write the actual code for you as i have no idea what structure you are using, sorry.
Of course if your circle is an object, you could sensibly make it test itself against all the other circles, same idea. If you have an SQL database of circles, test them all against each other.
So fortunately you can see it is one (1) line of code to check if two circles are colliding. And it's about 3 or 4 lines of code to check all your circles for collisions. So fortunately about 5 lines in total!
So, that is an incredibly simple tutorial on video game physics, part 1.1.1.1 !!!! Hope it helps! If that is not what you were trying to achieve, it was a complete waste of typing! :)
For the record here's a routine to get the distance between two CGPoints:
static inline float rawDistance(float x, float y, float p, float q)
{
return sqrt( ((x-p)*(x-p)) + ((y-q)*(y-q)) );
}
static inline float distanceBetweenTwoCGPoints( CGPoint a, CGPoint b )
{
return rawDistance( a.x, a.y, b.x, b.y );
}
(Note... if you are new to Objective C, note that the above is totally valid code. Simply paste it in at the top of your file. OK? It's exactly like using any everyday function supplied by Apple such as x=CGLayerGetContext(), for example. Enjoy!)
Later .. and by popular demand, for an object, Circle...
-(bool)isTouchingOtherCircle:(circle)c
{
return areTwoCirclesColliding(self.center, c.center);
}
-(bool)isTouchingAnyOtherCircle
{
for oc in yourCircles
if (oc != self)
if ( [self isTouchingOtherCircle:oc] )
return false;
return true;
}

Related

Changing game size in Phaser dynamically

I'm building a game in which I can enter a building, which I'm handling via states. In other words, when my character overlaps with the door, the program starts a new state in which the interior of the building is built. Now, I want the interior to have smaller dimensions than the world, so I want to change the game size when I start this new state.
I tried this:
create: function()
{
//game size was 1000x700, I want to scale it to 700x450
game.width = 700;
game.height = 450;
//rest of creation code...
}
I also tried things like changing camera bounds, world bounds, world size, but method above shows the most promise.
The problem, however, is that the resize for some reason does not show until I click away from my browser tab and back. Calling game.width in the console yields 700 at all times, but it doesn't show it as such until tabbing out and back.
On top of that, the contents of the game (floor, furniture) are scaled down when the game resizes, defeating the purpose. I don't understand why it would, since there's no scaling anywhere in my code.
Any help would be greatly appreciated.
Edit:
I just saw that you were the one asking the question I linked to, so I guess the question is solved :D
I had a similar problem some time ago. As you described yourself: what you are doing is a resize! So the game resizes itself which means the same as re-scaling everything in the game.
if you want to cut the game smaller you can simply use
game.scale.setGameSize(700, 450);.
(see this post if you need more information)
As additional information: I later had problems with cutting the game size equally on all sides, so if you should come to face the same problem, have a look at this post

Special Kind of ScrollView

So I have my game, made with SpriteKit and Obj-C. I want to know a couple things.
1) What is the best way to make scroll-views in SpriteKit?
2) How do I get this special kind of scroll-view to work?
The kind of scroll-view I'd like to use is one that, without prior knowledge, seems like it could be pretty complicated. You're scrolling through the objects in it, and when they get close to the center of the screen, they get larger. When they're being scrolled away from the center of the screen, they get smaller and smaller until, when their limit is met, they stop minimizing. That limitation goes for getting bigger when getting closer to the center of the screen, too.
Also, I should probably note that I have tried a few different solutions for cheap remakes of scroll views, like merely adding the objects to a SKNode and moving the SKNode's position relative to the finger's, and its movement . . . but that is not what I want. Now, if there is no real way to add a scroll-view to my game, this is what I'm asking. Will I simply have to do some sort of formula? Make the images bigger when they get closer to a certain spot, and maybe run that formula each time -touchesMoved is called? If so, what sort of formula would that be? Some complicated Math equation subtracting the node's position from the center of the screen, and sizing it accordingly? Something like that? If that's the case, will you please give me some smart Math formula to do that, and give it to me in code (possibly a full-out function) format?
If ALL else fails, and there is no good way to do this, what would some other way be?
It is possible to use UIScrollViews with your SpriteKit scenes, but there's a bit of a workaround involved there. My recommendation is to take a look at this github project, that is what I based my UIScrollView off of in my own projects. From the looks of it, most of the stuff you'd want has actually been converted to Swift now, rather than Objective-C when I first looked at the project, so I don't know how that'll fare with you.
The project linked above would result in your SKScene being larger than the screen (I assume that is why it would need to be scrolled), so determining what is and is not close to the center of the scene won't be difficult. One thing you can do is use the update loop in SpriteKit to constantly update the size of Sprites (Perhaps just those on-screen) based on their distance from a fixed, known center point. For instance, if you have a screen of width and height 10, then the midpoint would be x,y = 5,5. You could then say that size = 1.0 - (2 * distance_from_midpoint). Given you are at the midpoint, the size will be 1.0 (1.0 - (2 * 0)), the farther away you get, the smaller your scale will be. This is a crude example that does not account for a max or min fixed size, and so you will need to work with it.
Good luck with your project.
Edit:
Alright, I'll go a bit out of my way here and help you out with the equation, although mine still isn't perfect.
Now, this doesn't really give you a minimum scale, but it will give you a maximum one (Basically at the midpoint). This equation here does have some flaws though. For one, you might use this to find the x and y scale of your objects based on their distance from a midpoint. However, you don't really want two different components to your scale. What if your Sprite is right next to the x midpoint, and the x_scale spits out 0.95? Well, that's almost full-sized. But if it is far away from the midpoint on the y axis, and it gives you a y scale of, say 0.20, then you have a problem.
To solve that, I just take the magnitude or hypotenuse of the vector between the current coordinate and the coordinate of the current sprite. That hypotenuse gives me an number that represents the true distance, which eliminates the problem with clashing scale values.
I've made an example of how to calculate this inside Google's Go-Playground, so you can run the code and see what different scales you get based on what coordinate you plug in. Also, the equation used in there is slightly modified, It's basically the same thing as above but without the maxscale - part of the front part of the equation.
Hope this helps out!
Embedding Attempt:
see this code in play.golang.org

How to code a random movement in limited area

I have a limited area (screen) populated with a few moving objects (3-20 of them, so it's not like 10.000 :). Those objects should be moving with a constant speed and into random direction. But, there are a few limitation to it:
objects shouldn't exit the area - so if it's close to the edge, it should move away from it
objects shouldn't bump onto each other - so when one is close to another one it should move away (but not get too close to different one).
On the image below I have marked the allowed moves in this situation - for example object D shouldn't move straight up, as it would bring it to the "wall".
What I would like to have is a way to move them (one by one). Is there any simple way to achieve it, without too much calculations?
The density of objects in the area would be rather low.
There are a number of ways you might programmatically enforce your desired behavior, given that you have such a small number of objects. However, I'm going to suggest something slightly different.
What if you ran the whole thing as a physics simulation? For instance, you could set up a Box2D world with no gravity, no friction, and perfectly elastic collisions. You could model your enclosed region and populate it with objects that are proportionally larger than their on-screen counterparts so that the on-screen versions never get too close to each other (because the underlying objects in the physics simulation will collide and change direction before that can happen), and assign each object a random initial position and velocity.
Then all you have to do is step the physics simulation, and map its current state into your UI. All the tricky stuff is handled for you, and the result will probably be more believable/realistic than what you would get by trying to come up with your own movement algorithm (or if you wanted it to appear more random and less believable, you could also just periodically apply a random impulse to a random object to keep things changing unpredictably).
You can use the hitTest: method of UIView
UIView* touchedView=[self.superview hitTest:currentOrigin withEvent:nil];
In This method you have to pass the current origin of the ball and in second argument you can pass nil.
that method will return the view with which the ball is hited.
If there is any hit view you just change the direction of the ball.
for border you can set the condition for the frame of the ball if the ball go out of the boundary just change the direction of the ball.

Cocos2d magnifying glass

This has already been asked at Add a magnifier in cocos2d games
But I didn't quite understand the answer. I am using the same tutorial Let's Spot It is using but I'm not sure where to put madhu's code. I also don't know what the runAction method looks like.
Thanks
Hmm... Cocos2d CCLens3D, makes the area that is set by the programmer to popup.. Please look at the example provided by cocos2d..
the codes:
id lens = [CCLens3D actionWithPosition:ccp(size.width/2,size.height/2) radius:240 grid:ccg(15,10) duration:0.0f];
[self runAction:lens];
self is the layer where your image should be..
ccp(size.width/2, size.height/2) should be changed to ccp(yourPosition.x, yourPosition.y), means the positions which you want the popUp to be at.. Radius is the size of the circle, duration is how long you want it to be, 0.0 meaning infinite.. grid just use the same values..

How can I detect a permanent collision with the Chipmunk Physics engine

I'm trying to play a "boing" sound when a ball shape hit's any other kind of shape. Which works. But works a little too well....
When the ball comes to rest, or starts to roll, it's in a permanent collision with whatever it's touching, so the "boing" sound fires constantly.
I can't find anything in the chipmunk documentation to tell me when two things are permanently colliding. So I'm thinking I will have to somehow figure it out myself, probably with some sort of timer that compare the last collision against the current collision. But that sounds hacky to me.
Has anyone tackled this issue? How did you solve it?
Couldn't you just play your "boing" sound when contact is BROKEN?
There is a callback for that in chipmunk, typedef void (*cpCollisionSeparateFunc)(cpArbiter *arb, struct cpSpace *space, void *data)
That way you get boings whenever it bounces, but not when it's just rolling along. 'course, you'll also get one when it rolls off of your shape, but that could be a feature depending on how you look at it.
I don't think that what I'm about to say is a good practice, but I'm sure it will solve your problem:
For each object, keep two state variables: (1) The last object collided with, (2) The last collision time.
Upon collision, only play a sound if the collided object is different (and a ball) OR a certain "delta time" has elapsed since the last collision. Then record the last collision stats.
This is pretty simple and very effective:
// In your ball interface
id lastCollisionObject;
double lastCollisionTime;
// When a collision occurs...
double now = GetTime();
id other = GetCollisionObject();
if ((now - lastCollisionTime) > 0.3 || other != lastCollisionObject) {
PlaySound(kBoingSound);
}
lastCollisionObject = other;
lastCollisionTime = now;
Shapes don't have velocity in chipmunk. The bodies they are attached to have it. You can access velocity like this: "myShape.body->v". I agree that you should just be able to check if the velocity is over a certain threshold to know when an 'impact' occurs. You can also check the rotational velocity to see if the ball is rolling.