Collision detection not working on all sides of UIImageView - ios

This code is used to test my collisions but it only works on 2 sides on each UIImageView. Why doesn't it work for 3 sides? It'll never work on top side and bottom side of UIImageView or left and right. It only works top and left or top and right or bottom and right or bottom and left. Why is that? How do i make it work on at least 3 sides?
int moveX;
int moveY;
viewController.h{
IBOutlet UIImageView *circle;
NSTimer *time;
IBOutlet UIImageView *platform;
}
-(IBAction)StartGame:(id)sender;
-(void)moveCircle;
-(void)bounce;
#end
viewcontroller.m
-(IBAction)StartGame:(id)sender{
start.hidden=YES;
time=[NSTimer scheduledTimerWithTimeInterval:0.02 target:self selector:#selector(moveCircle) userInfo:nil repeats:YES];
circleX=arc4random()%11;
circleX=circleX-5;
circleY=arc4random()%11;
circleY=circleY-5;
circleX=arc4random()%11;
circleX=circleX+5;
circleY=arc4random()%11;;
circleY=circleY+5;
if (circleX==0) {
circleX=1;
}
if (circleY==0) {
circleY=1;
}
-(void)moveCircle{
circle.center=CGPointMake(circle.center.x -circleX, circle.center.y -circleY);
if (circle.center.x <30) {
circleX=0-circleX;
}
if (circle.center.x >320) {
circleX=0-circleX;
}
if (circle.center.y <28 ) {
circleY=0-circleY;
}
if (circle.center.y >568) {
circleY=0-circleY;
}
[self bounce];
}
-(void)bounce{
if (CGRectIntersectsRect(circle.frame, platform.frame)) {
circleY=arc4random()%5;
circleY=0+circleY;
circleX=arc4random()%5;
circleX=0+circleX;
circleY=arc4random()%5;
circleY=0-circleY;
circleX=arc4random()%5;
circleX=0-circleX;
}
}

I see no sense at all in your question but let's look at your code:
Assuming you start with StartGame which hopefully happens only once:
You create a timer (this should be invalidated when the game ends but no matter at the moment)
you set circleX and circleY to some random position between -5 and 5
you set circleX and circleY to some random position between 5 and 15 (again?!)
you check if circleX and circleY are at 0 and set them to 1 (this is highly unlikely to happen due to the previous statement)
Then move circle:
you add to the circle center the circleX and circleY values where then I assume those 2 values are actually speed. (so far so good)
you check the circle position to be out of borders and negate appropriate speed. (This hardcoded values are a bit strange but ok for now I guess)
You call bounce
And the bounce method:
You check if circle and platform frames intersect. (O.K. I guess)
You set a random speed to circleX and circleY from 0 to 4
You set a random speed to circleX and circleY from 0 to -4 (again?!)
So what I can assume from this code is you have 2 views on your view controller where one is a static obstacle called platform and the other is a moving circle. The circle itself will be moving to some direction depending on some random values from the StarGame method and correctly bouncing off the hardcoded borders. If the circle intersects with the platform the circle will change speed to some random negative values from -4 to 0 in both X and Y.
So what is the issue here exactly? The bouncing off the platform will make the circle move toward your top-left corner of the screen no matter which side does the circle hit the platform from. Maybe you need some if statements in your bounce method to find a correct value for the new speed depending on which side is the platform hit from.

Related

2D physics / collision formula not working as intended

I have a 2D tile matrix (of walls for now) and for each wall I check if my player's next Rectangle (next as in where it will be in next frame) is colliding with that wall, and if it is, I want my player to stand right next to it, without going inside of it.
Here is the formula I came up with (this is just for left and right collision):
//*move entity
if (KState.Down(Keys.W)) en.AddForce(new Vector2(0, -10));
if (KState.Down(Keys.S)) en.AddForce(new Vector2(0, 10));
if (KState.Down(Keys.A)) en.AddForce(new Vector2(-10, 0));
if (KState.Down(Keys.D)) en.AddForce(new Vector2(10, 0));
foreach(Item i in map.Items)
{
//resolve left-right collision
if (en.NextBody(elapsedTime).Intersects(i.Body))
{
//check distance between top left corners
int distance = (int)Math.Abs(i.Position.X - en.Position.X);
//stop player in his horisontal movement
en.AddForce(new Vector2(-en.Force.X, 0));
//place player next to the wall his about to collide with
en.Position = new Vector2(en.Position.X - distance + i.Body.Width, en.Position.Y);
}
}
//stop player in place
if (KState.Clicked(Keys.Space)) en.AddForce(en.Force*-1);
en.Update(elapsedTime);
**
Which gave me this result (note that fps is not stable and that currently rectangles are squares 32x32):
Top line of text is players Rectangle, and bottom one is Rectangle of the wall that player collided with last.
Now, when the rocks (player) is moving to the left, I'm holding left key for some time, and when going to the right, I'm holding right key for some time.
Problem: As you can see in gif, when player's going left, he's moving 1 pixel to and from left wall. And when he's moving right, he bounces once, and then stays right next to the right wall. I don't want any bouncing but I don't know how to fix this in logic that I'm using.
Also, if you know good logic for how to resolve Rectangle collision so that they are not intersecting from any sides, I'd appriciate sharing it with me.
Edit 1: I managed to resolve collision to the right problem. Instead of the code above I've put
int sign = Math.Sign(i.Position.X - en.Position.X);
en.AddForce(new Vector2(-en.Force.X, 0));
//wall is right and player is left
if (sign > 0) en.Position = new Vector2(i.Body.Left - en.Body.Width, en.Position.Y);
//wall is left and player is right
if (sign < 0) en.Position = new Vector2(i.Body.Right, en.Position.Y);
but the problem with the left side collision is the same. I tried
if (sign < 0) en.Position = new Vector2(i.Body.Right + 1, en.Position.Y); and if (sign < 0) en.Position = new Vector2(i.Body.Right - 1, en.Position.Y); just in case, but the problem is the same (on "...-1..." case player gets stuck in wall).
Edit 2: As #paste requested, here is the code for NextBody(float elapsedTime) from player class.
public Rectangle NextBody(float elapsedTime)
{ return new Rectangle((int)(force.X * elapsedTime) + body.X, (int)(force.Y * elapsedTime) + body.Y, body.Width, body.Height); }
This is what's happening:
The first time the objects collide while the rocks are moving left, the algorithm works as it should. It sees that the objects are overlapping, it sets the force to Vector2.Zero, and it moves the en so that it is touching the item's right side. Good. Your object is stopped and in the right place.
What happens in the next frame is where things go wrong. You set up your force vector, and then call NextBody(). Let's just look at the X-coordinate. It gets set to:
(int)(force.X * elapsedTime) + body.X
What does this evaluate to? force.X is non-zero, and elapsedTime is also non-zero, but they're less than 1, so when they get converted to int, the result is zero. Therefore, your body is in the same place as it was before, which means the Rectangles do not overlap. This means your collision response code gets skipped and your force vector is still not zero!
Then, further down, you call your player's Update() method. I'm guessing that in that code you update the player's Position and Body. But since force is not zero, and you are using a Vector2 for Position, the x-coordinate will end up being something like 31.841304... instead of 32. If you use that number to calculate the new Body and use it in your Draw method, you'll end up drawing it at x = 31. The next time you check, it'll detect a collision, and the player will bounce out again.
There are a number of ways to fix this. What I do in my collision code is to actually move the objects first and keep a record of where they were in the previous frame. That way, the last adjustment to their position is when they are moved out of the collision area.

How do I put a border on the left and right side of my UIViewController

im currently building this game and im having some trouble, at the top of my screen there is a ball that I have buttons to make move left and right, I want them to be stopped at the right and left side of the screens because they just keep going when i hold the button to make them move, I was wondering if there is any way I can set some sort of boundary or border to prevent them from keep moving
add the following instead of your 'redBall.center' line - it checks to see if the ball's new position is inside the border before it moves it..
// some border screen coords
borderLeft = 20;
borderRight = 200;
// move ball left
if (redBall.center.x - 1 > borderLeft) {
redBall.center = CGPointMake(redBall.center.x - 1, redBall.center.y);
}
// move ball right
if (redBall.center.x + 1 < borderRight) {
redBall.center = CGPointMake(redBall.center.x + 1, redBall.center.y);
}
Hope that helps!

How do i resize an object created in actionscript with the point of origin staying central

widthEssentially, i am creating objects in Flash using actionscript. I currently have a problem where i am resizing the object in actionscript but as the point of reference seems to be the top left hand corner, the object when shrinking seems to also move towards the top left of the screen.
Is there a way to either code the point of origin for an object to the center of the object using code or to have it resize without seemingly moving?
my code for creating and resizing an object is like this (it will grow and shrink but at moment im just tryint to fix this problem before i move on):
var blob1:Loader = new Loader();
blob1.x = 1000;
blob1.y = 450;
blob1.load(new URLRequest("blob1.png"));
addChild(blob1);
blob1.addEventListener(Event.ENTER_FRAME, blobTween);
function blobTween(event:Event)
{
var size = 0;
if (size == 0){
blob1.width += 5;
blob1.height += 5;
}else if (size == 1){
}
Can't you update x and y while you change width and height ?
blob1.x += deltaWidth / 2
blob1.y += deltaHeight / 2
You increment width and height by 5, so deltaWidth = 5 and deltaHeight = 5 .
NOTE: deltaWidth / 2 doesn't divide equally, so you'll have slight shift. I suggest having deltaWidth = 6 and deltaHeight = 6 , or something similar.
GreenSock has a great library for doing just that; TransformManager.
http://www.greensock.com/transformmanageras3/
my solution in the end was a bit strange. I took the shape, divided it into 4 quarters and reattached them in flash by placing the objects in the same place and rotating them (as it rotates from the top left corner, the 4 quarters form a complete shape with each quarter having their top left corner in the centre of the "object"). I then resized them all at once to do it properly.
Whats weird is that the top right and bottom left corners required different math from the other two corners. Which makes no sense whatsoever. 2 corners required width and height to be adjusted. The other two corners required just width to be adjusted. very strange but worked :/

Positioning a view after transform rotation

I'm creating a custom popover background, so I subclassed the UIPopoverBackground abstract class. While creating the layout function I came across a problem with placing and rotating the arrow for the background.
The first picture shows the arrow at the desired position. In the following code I calculated the origin I wanted but the rotation seemed to have translated the new position of the image off to the side about 11 points. As you can see, I created a hack solution where I shifted the arrow over 11 points. But that still doesn't cover up the fact that I have a gapping hole in my math skills. If someone would be so kind as to explain to me what's going on here I'd be eternally grateful. What also would be nice is a solution that would not involve magic numbers, so that I could apply this solution to the cases with the up, down and right arrow
#define ARROW_BASE_WIDTH 42.0
#define ARROW_HEIGHT 22.0
case UIPopoverArrowDirectionRight:
{
width -= ARROW_HEIGHT;
float arrowCenterY = self.frame.size.height/2 - ARROW_HEIGHT/2 + self.arrowOffset;
_arrowView.frame = CGRectMake(width,
arrowCenterY,
ARROW_BASE_WIDTH,
ARROW_HEIGHT);
rotation = CGAffineTransformMakeRotation(M_PI_2);
//rotation = CGAffineTransformTranslate(rotation, 0, 11);
_borderImageView.frame = CGRectMake(left, top, width, height);
[_arrowView setTransform:rotation];
}
break;
Well, if the rotation is applied about the center of the arrow view (as it is), that leaves a gap of (ARROW_BASE_WIDTH - ARROW_HEIGHT) / 2 to the post-rotation left of the arrow, which is what you have to compensate for, it seems. By offsetting the center of the arrow view by this much, it should come back into alignment.

random bounce direction in Cocoa?

I have UIImageView (ball) and it moves around the screen but I want it to bounce in a random direction off a specific image (named computer.paddle)
This is my code:
if (CGRectIntersectsRect (ball.frame, computerPaddle.frame)) {
if (ball.center.x < computerPaddle.center.x) {
(ballVelocity.x =- ballVelocity.x);
}
}
NB I am using the rotation landscape right and I want it to bounce of the right side of the paddle to the right.
I am happy to make any UIIntegers or any thing else that is needed.
Add the following line in the inner block:
ballVelocity.y += arc4random() % (2 * MAX_VARIANCE) - MAX_VARIANCE;
MAX_VARIANCE, in this case, is the maximum amount of variation you want from the "normal" value of ballVelocity.y. If you need a finer degree of variation, you can increase MAX_VARIANCE by some double k and multiply the expression by 1/k. For example,
ballVelocity.y += (arc4random() % (2*100*MAX_VARIANCE) - 100*MAX_VARIANCE)*0.01;

Resources