Hello I am making a game in java that requires collision from a ball into a rectangle.
pos.x = x value of ball
pos.y = y value of ball
vel.x = x velocity of ball
vel.y = y velocity of ball
sh = height of ball
sw = width of ball
W = width of rect
H = height of rect
So far I have :
boolean insideRect = pos.x >= X && pos.x <= X+W && pos.y >= Y && pos.y <= Y+H;
if(insideRect){
if(pos.y + sh/2 >= H){
vel.y = (-1*vel.y)*gravity;
vel.x *= .6;
if(pos.y < Y+H/2){
pos.y = Y;
} else{
pos.y = Y+H;
}
}
if(pos.x + sw/2 > W){
vel.x = -1*vel.x;
}
}
However this just says if it hit the left side of the rect or right, and if it hit the top or bottom.
So an output if you printed under the if statements would be : (left, up), (right, down), (left, down), (right, up)
So the problem is that for this to work I can only have one, either left, right, up, or down.
If I have two, then it thinks that it both hit the ceiling and the right wall, and has two visual outputs do to it.
How can I work around this?
/**
* checks to see if the obstacles and balls collide.
* Utilizes bounding boxes for obstacles and coordinates for ball:
* + = Obstacle
* ballTop
* : :
* : :
*ballLeft : : ballRight
* : :
* : :
* ballBottom
*
* ____
* |+++|
* |+++|
* |+++|
* ----
* #param ball
* #param rect
* #return boolean
*/
public boolean intersects(Ball ball, Obstacle rect){
double r = ball.getRadius();
double rectTop = rect.y;
double rectLeft = rect.x;
double rectRight = rect.x + rect.width;
double rectBottom = rect.y + rect.height;
double ballTop = ball.y - r;
double ballLeft = ball.x - r;
double ballRight = ball.x + r;
double ballBottom = ball.y + r;
//NO COLLISIONS PRESENT
if(ballRight < rectLeft){
return false;
}
if(ballTop > rectBottom){
return false;
}
if(ballBottom < rectTop){
return false;
}
if(ballLeft > rectRight){
return false;
}
//HAS TO BE A COLLISION
return true;
}
//In Logic File
private void collideBallObstacles(Ball ball,Obstacle rect){
if(rect.intersects(ball, rect)){
ball.velX *= -1;
ball.velY *= -1;
if (ball == player){
flashGreen();
obstaclesevaded--;
}
obstacles.remove(rect);
}
}
You will also have to render this, and change the variables or create ones that fit with this code.
Just curious-what would the name of this game happen to be?
Related
I am currently working on a 2D side scroller and have implemented the techniques use in this article for a grapple hook, and it works really well. My problem is I want my player to be able to swing around the rope a little bit to gain a bit of momentum, but currently I can't stop the player from moving all the way up to 90 degrees either side. What techniques can be applied to force this limit?
I have tried using a separate player speed for swinging but this only slows the process down I can still swing up to 90 deg each side.
Here's my update function in the player
public void update(float dt){
//handle friction and air resistance
if(dx !=0){
if(touchingGround) {
// apply friction
if (dx > 0) {
dx -= retardation;
} else {
dx += retardation;
}
} else {
//applied air resistance
if (dx > 0) {
dx -= airResistance;
} else {
dx += airResistance;
}
}
}
// handle gravity
dy -= Constants.GRAVITY * dt;
if(dy < -terminalVelocity){
dy = -terminalVelocity;
}
/*
Handle Player movement
*/
if(right){
if(dx <= maxSpeed){
dx += acceleration;
}
dx = maxSpeed;
}
if(left){
if(dx <= -maxSpeed){
dx -= acceleration;
}
dx = -maxSpeed;
}
if(isGrappling){
//If we collide with something we need to stop grappling
if(hasCollided){
isGrappling = false;
} else {
// This algorithm from here:
// http://gamedev.stackexchange.com/questions/61596/player-rope-swing
float currentD = (float) Math.sqrt(((grappleX - x) * (grappleX - x)) + ((grappleY - y) * (grappleY - y)));
float prevX = getX(), prevY = getY();
if (currentD > grappleRadius) {
Vector2 hookPos = new Vector2(grappleX, grappleY);
Vector2 testPos = (new Vector2(x, y).sub(hookPos)).nor();
y = (hookPos.y + testPos.y * grappleRadius);
x = (hookPos.x + testPos.x * grappleRadius);
// s = d / t
dx += (x - prevX) / dt;
dy += (y - prevY) / dt;
}
}
}
/*
Collision Detection, handle last always!
*/
float oldX = getX(), oldY = getY();
boolean collisionX = false, collisionY = false;
// move on x
x += dx * dt;
// calculate the increment for step in #collidesLeft() and #collidesRight()
increment = collisionLayer.getTileWidth();
increment = getWidth() < increment ? getWidth() / 2 : increment / 2;
if(dx < 0) // going left
collisionX = collidesLeft();
else if(dx > 0) // going right
collisionX = collidesRight();
// react to x collision
if(collisionX) {
setX(oldX);
dx = 0;
}
// move on y
y += dy * dt;
// calculate the increment for step in #collidesBottom() and #collidesTop()
increment = collisionLayer.getTileHeight();
increment = getHeight() < increment ? getHeight() / 2 : increment / 2;
if(dy < 0) {
touchingGround = collisionY = collidesBottom();
// we can only jump 2 times before we have to touch the floor again
if(collisionY){
numberOfJumps = 2;
}
} else if(dy > 0) {
collisionY = collidesTop();
}
// react to y collision
if(collisionY) {
setY(oldY);
dy = 0;
}
hasCollided = collisionX || collisionY;
}
As I am not using any physics engine I chose to just emulate the physics by limiting the angle at which the player can apply force to the swing.
// check if angle permits movement
if(grappleAngle < Math.PI/9 && grappleAngle > -Math.PI/9) {
// handle momentum gaining on rope
if (right) {
dx += swingAcceleration * dt;
}
if (left) {
dx -= swingAcceleration * dt;
}
}
I am working through the solution to the following problem:
Given two squares on a two-dimensional plane, find a line that would
cut these two squares in half. Assume that the top and the bottom
sides of the square run parallel to the x-axis.
This is the solution in the book:
public class Square {
public double left;
public double top;
public double bottom;
public double right;
public double size;
public Square(double left, double top, double size) {
this.left = left;
this.top = top;
this.bottom = top + size;
this.right = left + size;
this.size = size;
}
public Point middle() {
return new Point((this.left + this.right)/2.0, (this.top + this.bottom)/2.0);
}
public boolean contains(Square other) {
if (this.left <= other.left && this.right >= other.right && this.top <= other.top && this.bottom >= other.bottom) {
return true;
}
return false;
}
/* Return the point where the line segment connecting mid1 and
* mid2 intercepts the edge of square 1. That is, draw a line
* from mid2 to mid1, and continue it out until the edge of
* the square. */
public Point extend(Point mid1, Point mid2, double size) {
/* Find what direction the line mid2 -> mid1 goes */
double xdir = mid1.x < mid2.x ? -1 : 1;
double ydir = mid1.y < mid2.y ? -1 : 1;
/* If mid1 and mid2 have the same x value, then the slope
* calculation will throw a divide by 0 exception. So, we
* compute this specially. */
if (mid1.x == mid2.x) {
return new Point(mid1.x, mid1.y + ydir * size / 2.0);
}
double slope = (mid1.y - mid2.y) / (mid1.x - mid2.x);
double x1 = 0;
double y1 = 0;
/* Calculate slope using the equation (y1 - y2) / (x1 - x2).
* Note: if the slope is “steep” (>1) then the end of the
* line segment will hit size / 2 units away from the middle
* on the y axis. If the slope is “shallow” (<1) the end of
* the line segment will hit size / 2 units away from the
* middle on the x axis. */
if (Math.abs(slope) == 1) {
x1 = mid1.x + xdir * size / 2.0;
y1 = mid1.y + ydir * size / 2.0;
} else if (Math.abs(slope) < 1) {
x1 = mid1.x + xdir * size / 2.0;
y1 = slope * (x1 - mid1.x) + mid1.y;
} else {
y1 = mid1.y + ydir * size / 2.0;
x1 = (y1 - mid1.y) / slope + mid1.x;
}
return new Point(x1, y1);
}
public Line cut(Square other) {
/* Calculate where a line between each middle would collide with the edges of the squares */
Point p1 = extend(this.middle(), other.middle(), this.size);
Point p2 = extend(this.middle(), other.middle(), -1 * this.size);
Point p3 = extend(other.middle(), this.middle(), other.size);
Point p4 = extend(other.middle(), this.middle(), -1 * other.size);
/* Of above points, find start and end of lines. Start is farthest left (with top most as a tie breaker)
* and end is farthest right (with bottom most as a tie breaker */
Point start = p1;
Point end = p1;
Point[] points = {p2, p3, p4};
for (int i = 0; i < points.length; i++) {
if (points[i].x < start.x || (points[i].x == start.x && points[i].y < start.y)) {
start = points[i];
} else if (points[i].x > end.x || (points[i].x == end.x && points[i].y > end.y)) {
end = points[i];
}
}
return new Line(start, end);
}
public String toString() {
return "(" + left + ", " + top + ")|(" + right + "," + bottom + ")";
}
}
I have the following questions:
What is the size parameter in the extend function? The size of what? A side? The entire square (how can we quantify the size of the entire square?) Area?
In the cut() function, what are p1 through p4 ultimately doing? And why do we need 4 points to do it?
As I understand the problem, it's necessary and sufficient for the line to connect the two centres.
Assume that the top and the bottom sides of the square run parallel to the x-axis.
I'm not aware of why this assumption is necessary.
This answer might not be relevant to the TS. But in case if you are also wondering about this answer, the parameter "size" is misleading - it is referring to the length of the square (Eg. 3x3 square has the length of 3.) Why four points? Because the question assumes that the line here represents the two "farest" points that cut across two squares. Each square has two points that has the potential to become start/end of the line.
I am making a tank game like the Atari tank game and I ran into some troubles. I'm trying to make the enemy's tank move towards the player's tank but it can't move diagonally since the player isn't allowed to do that also. However, the way I implemented it, it goes diagonally when the distance from the x and y axis are equal to each other. Is there a way I can make it so that it would be forced go in one direction for a while after changing direction? The way do it is that it will compare its x and y values with the player's tank ( the tank that is being passed in ) and the four cases are for if the x-component is bigger than y and is it on theright or left, and if the y-component is bigger than xand is it above or below the player's tank. Thank you for the help!
public void enemyMove(Tank t) {
if ( Math.abs(getX() - t.getX()) >= Math.abs(getY() - t.getY()) && getX() > t.getX() )
goLeft();
else if ( Math.abs(getX() - t.getX()) > Math.abs(getY() - t.getY()) && getX() < t.getX() )
goRight();
else if ( Math.abs(getX() - t.getX()) <= Math.abs(getY() - t.getY()) && getY() > t.getY() )
goUp();
else if ( Math.abs(getX() - t.getX()) < Math.abs(getY() - t.getY()) && getY() < t.getY() )
goDown();
setX(getX() + dx);
setY(getY() + dy);
}
public void goUp() {
dx = 0;
dy = -1;
}
public void goDown() {
dx = 0;
dy = 1;
}
public void goLeft() {
dx = -1;
dy = 0;
}
public void goRight() {
dx = 1;
dy = 0;
}
You can use the Manhattan distance and find the median then move the tank in both directions.
The code below is a little gross, but should do what you want. In your current code the enemy is moving one pixel in the X direction in the first frame, then one pixel in the Y direction in the next frame, which makes the movement look diagonal. The code below sets a short-term target point for the enemy tank to head towards in either the X or Y direction, at some distance away defined by MOVE_BLOCK. The enemy will move until it passes that target point, then recalculate which direction it should be moving. Note that enemyMove will be called every time a new frame is created, so probably 60 times a second.
// The tank will move this distance in x or y before changing directions
private final int MOVE_BLOCK = 120;
// The short-term target of the enemy tank
Point target = null;
public void enemyMove(Tank t) {
/* true if enemy is moving left and enemy is already left of target point,
* or moving right and right of target... */
boolean passedTarget = target == null ||
(dx < 0 && getX() < target.getX()) ||
(dx > 0 && getX() > target.getX()) ||
(dy < 0 && getY() < target.getY()) ||
(dy > 0 && getY() > target.getY());
// Calculate a new target point if the old target was passed
if(passedTarget) {
int xDist = Math.abs(getX() - t.getX());
int yDist = Math.abs(getY() - t.getY());
if ( xDist > yDist ) {
// Cover the remaining distance when close to the target
int moveLength = xDist < MOVE_BLOCK ? xDist : MOVE_BLOCK;
if( getX() >= t.getX() )
goLeft();
target = new Point(getX() - moveLength, getY());
else
goRight();
target = new Point(getX() + moveLength, getY());
} else {
int moveLength = yDist < MOVE_BLOCK ? yDist : MOVE_BLOCK;
if ( getY() >= t.getY() ) {
goUp();
target = new Point(getX(), getY() - moveLength);
} else {
goDown();
target = new Point(getX(), getY() + moveLength);
}
}
}
setX(getX() + dx);
setY(getY() + dy);
}
So I am working on a blackjack game, I have wrote a render process which will render a card going out of the cards stack and sliding to the place where it shows all dealer's cards.
My method works fine, except one problem which I will elaborate:
Whenever Y coordinate reaches the target Y coordinate first, the sprite will only move on X-asis because it cant move Y anymore, instead of making a straight angle to the point.
So what it will do is move up diagonally and then instantly go to the right (in my case)
GIF:
(source: gyazo.com)
MP4 (choose mp4 in the (..) menu http://gyazo.com/bec6daadcb46bedc4777a3e4c5ff8c77)
As you can see, it does what I just said.
What did I do wrong? how can I make it motion in a straight angle to the target without going diagonal up and than turn right away?
My process code:
// If the target is on the right side of the start point
if (startPoint.getX() < endPoint.getX()) {
if (current.getX() < endPoint.getX()) {
current.x += moveSpeed;
if (current.getX() > endPoint.getX()) {
current.x = (int) endPoint.getX();
}
}
else {
xDone = true;
}
}
else {
if (current.getX() > endPoint.getX()) {
current.x -= moveSpeed;
if (current.getX() < endPoint.getX()) {
current.x = (int) endPoint.getX();
}
}
else {
xDone = true;
}
}
// Vise-versa
if (startPoint.getY() < endPoint.getY()) {
if (current.getY() < endPoint.getY()) {
current.y += moveSpeed;
if (current.getY() > endPoint.getY()) {
current.y = (int) endPoint.getY();
}
}
else {
yDone = true;
}
}
else {
if (current.getY() > endPoint.getY()) {
current.y -= moveSpeed;
if (current.getY() < endPoint.getY()) {
current.y = (int) endPoint.getY();
}
}
else {
yDone = true;
}
}
// Callback, dw about it
CardContainer.getCardSprite(CardContainer.SPECIAL, 0).drawSprite((int) current.getX(), (int) current.getY());
// Alert finished, in poisiuton
if (xDone && yDone) {
ch.submitCard(card);
}
current = current position
startPoint = the start point
endPoint = the end point
Thanks!
EDited code:
private void applyMovement(double alpha) {
double dx = endPoint.getX() - startPoint.getX();
double dy = endPoint.getY() - startPoint.getY();
this.current.setLocation(startPoint.getX() + alpha * dx, startPoint.getY() + alpha * dy);
}
public void process() {
double alpha = (double) stepsDone / distance;
applyMovement(alpha);
stepsDone++;
// Callback, dw about it
CardContainer.getCardSprite(CardContainer.SPECIAL, 0).drawSprite((int) current.getX(), (int) current.getY());
// Alert finished, in poisiuton
if (stepsDone >= distance) {
ch.submitCard(card);
}
}
Distance calculation:
this.distance = (int) start.distance(end);
Used Point2D distance method:
public double distance(Point2D pt) {
double px = pt.getX() - this.getX();
double py = pt.getY() - this.getY();
return Math.sqrt(px * px + py * py);
}
I would recommend to not use any form of "slope" in such a computation. You will run into problems when the difference in x-direction approaches zero, because then the slope will tend towards infinity.
Assuming that your points are Point2D.Double (or something similar - you should include this kind of information in your questions!), you can compute the movement as follows:
private Point2D.Double initial = ... // The initial position
private Point2D.Double current = ... // The current position
private Point2D.Double target = ... // The target position
void applyMovment(double alpha) {
double dx = target.getX() - initial.getX();
double dy = target.getY() - initial.getY();
current.x = initial.getX() + alpha * dx;
current.y = initial.getY() + alpha * dy;
}
The applyMovment method sketched here can be called with a double value between 0.0 and 1.0, where 0.0 corresponds to the initial position and 1.0 corresponds to the target position. This is just a Linear Interpolation.
So for example, when you have some sort of loop for the animation, you can use the method as follows:
int numberOfSteps = 10;
for (int i=0; i<=numberOfSteps; i++)
{
double alpha = (double)i / numberOfSteps;
applyMovement(alpha);
repaint();
}
This works for any arrangement of the start- and end points, without any sign- or direction issues. It just interpolates between the two positions.
Your calculation needs to be based upon moving the currentY and currentX along a specific line, not a specific set of intervals (moveSpeed). The formula for graphing points on a line is:
y = mx + b
Where x and y are the varying points, m is equal to the slope of the line, and b is what's called the y-intercept.
Your slope is calculated by the formula:
double slope = ((double) endPoint.getY() - startPoint.getY()) / ((double) endPoint.getX() - startPoint.getX());
And the Y intercept can be calculated by just plugging in a bunch of known values once you have them:
double yIntercept = (double) endPoint.getY() - (slope * endPoint.getX())
Then, just loop through the count of the difference in X:
for (int xVal = startPoint.getX(); xVal < endPoint.getX(); xVal++){
currentX = xVal;
currentY = (slope * xVal) + yIntercept;
}
And you should be good.
Warning: this is all off of the top of my head, I don't know if it'll compile.
I have a simple Java applet that has two user-controlled balls, drawn using java.awt. I need a way to detect a collision with between them. I have an algorithm for detecting collision with the walls:
if (xPosition > (300 - radius)){
xSpeed = -xSpeed;
}
else if (xPosition < radius){
xSpeed = -xSpeed;
}
else if (yPosition > (300 - radius)) {
ySpeed = -ySpeed;
}
else if (yPosition < radius){
ySpeed = -ySpeed;
}
xPosition += xSpeed;
yPosition += ySpeed;
and for the second ball:
if (xPosition2 > (300 - radius)){
xSpeed2 = -xSpeed2;
}
else if (xPosition2 < radius){
xSpeed2 = -xSpeed2;
}
else if (yPosition2 > (300 - radius)) {
ySpeed2 = -ySpeed2;
}
else if (yPosition2 < radius){
ySpeed2 = -ySpeed2;
}
xPosition2 += xSpeed2;
yPosition2 += ySpeed2;
The applet is 300 pixels by 300 pixels.
radius stores the radius of the circles.
xPosition and xPosition2 store the x coordinates for the two balls.
yPosition and yPosition store the y coordinates for the two balls,
xSpeed and xSpeed2 store the x velocities for the two balls.
ySpeed and ySpeed2 store the y velocities for the two balls.
Use http://java.sun.com/j2se/1.5.0/docs/api/java/awt/geom/Point2D.html, there's a distance method there, if it's less than the radius they're colliding.
EDIT:
Err, less than the radius * 2 , sorry
There's Point2D in Java or you can do it yourself, it is trivially easy for circle/circle collisions or sphere/sphere collisions.
int distXX = (xPosition1 - xPosition2) * (xPosition1 - xPosition2);
int distYY = (yPosition1 - yPosition2) * (yPosition1 - yPosition2);
if ( radius*radius > distXX * distYY ) {
... // There's a collision
}
public boolean colliding(Ball anotherBall) {
double xDelta = (this.x + this.ballSize/2 + this.dx) - (anotherBall.x + anotherBall.ballSize/2 + anotherBall.dx);
double YDelta = (this.y + this.ballSize/2 + this.dy) - (anotherBall.y + anotherBall.ballSize/2 + anotherBall.dy);
double distance = Math.sqrt(Math.pow(xDelta, 2) + Math.pow(YDelta, 2));
return (distance <= this.ballSize/2 + anotherBall.ballSize/2);
}
This Link is pretty useful!
Circle-Circle Collisions
It's very detailed and didatic
At the bottom of that page there are another links, to even more detailed stuff!
I used the Distance Between Centers method ---
Circles
By measuring the distance between each center you can say if they are colliding.
The distance should never be more then the sum of the 2 radius.
Here's what I did:
private boolean checkDrawContains(ShapeDrawable newHole)
{
long newCenterX = newHole.getBounds().left + (newHole.getBounds().width()/2); //Get the center of my shapes
long newCenterY = newHole.getBounds().top + (newHole.getBounds().height()/2);
for(ShapeDrawable hole: mHoles) // I was storing the circles in an ArrayList
{
long centerX = hole.getBounds().left + (hole.getBounds().width()/2); //Get the center of my shapes
long centerY = hole.getBounds().top + (hole.getBounds().height()/2);
long x = centerX - newCenterX;
long y = centerY - newCenterY;
long aux = (long) ((Math.pow(Math.abs(x),2)) + (Math.pow(Math.abs(y),2))); //Pythagoras the hard way :P
long distance = (long) Math.sqrt(aux);
long sRads = (newHole.getBounds().width()/2) + (hole.getBounds().width()/2);
if(distance <= sRads ) {
return true; //Is Colliding!
}
}
return false; // Is not Colliding!
}