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);
}
Related
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?
Most learned friends
I have a sprite that moves around on screen but at the moment it just moves diagonally from left to right and goes off screen and then comes back on the other side.
What I would like it to do is bounce off the edges of the screen in a random fashion but, not being all that clued up on maths, I'm struggling to figure out the coordinates to do this.
Below is what I have so far: (this is an updated code for the Sprite class:
public class Sprite {
//x,y position of sprite - initial position (0,50)
// int [] DIRECTION_TO_ANIMATION_MAP = {3, 1, 0, 2};
private static final int BMP_ROWS = 3;
private static final int BMP_COLUMNS = 4;
private int x = 0;
private int y = 0;
private int xSpeed = 5;//Horizontal increment of position (speed)
private int ySpeed;// Vertical increment of position (speed)
private int currentFrame = 0;
private GameView gameView;
private Bitmap spritebmp;
//Width and Height of the Sprite image
private int bmp_width;
private int bmp_height;
// Needed for new random coordinates.
//private Random random = new Random();
public Sprite(GameView gameView) {
this.gameView = gameView;
spritebmp = BitmapFactory.decodeResource(gameView.getResources(),
R.drawable.running_ninja_sprite);
this.bmp_width = spritebmp.getWidth() / BMP_COLUMNS;
this.bmp_height = spritebmp.getHeight() / BMP_ROWS;
/*Random rnd = new Random(System.currentTimeMillis());
xSpeed = rnd.nextInt(45)-5;
ySpeed = rnd.nextInt(25)-5;*/
}
//update the position of the sprite
public void update() {
//if (x < 0 || x > gameView.getWidth() ){ xSpeed = xSpeed * -1;}
//if (y < 0 || y > gameView.getHeight() ){ ySpeed = ySpeed * -1;}
if (x > gameView.getWidth() - bmp_width - xSpeed || x + xSpeed < 0) {
xSpeed = -xSpeed;
}
x = x + xSpeed;
if (y > gameView.getHeight() - bmp_height - ySpeed || y + ySpeed < 0) {
ySpeed = -ySpeed;
}
y = y + xSpeed;
currentFrame = ++currentFrame % BMP_COLUMNS;
//y = random.nextInt(gameView.getWidth());
//wrapAround(); //Adjust motion of sprite.
}
public void draw(Canvas canvas) {
update();
int srcX = currentFrame * bmp_width;
int srcY = 1 * bmp_height; //getAnimationRow()
Rect src = new Rect(srcX, srcY, srcX + bmp_width, srcY + bmp_height);
Rect dst = new Rect(x, y, x + bmp_width, y + bmp_height);
//Draw sprite image
canvas.drawBitmap(spritebmp, x, y, null);
}
/*private int getAnimationRow() {
double dirDouble = (Math.atan2(xSpeed, ySpeed) / (Math.PI / 2) + 2);
int direction = (int) Math.round(dirDouble) % BMP_ROWS;
return DIRECTION_TO_ANIMATION_MAP[direction];
}*/
public void wrapAround() {
//Code to wrap around
if (x < 0) x = x + gameView.getWidth(); //increment x whilst not off screen
if (x >= gameView.getWidth()) { //if gone of the right sides of screen
x = x - gameView.getWidth(); //Reset x
}
if (y < 0) y = y + gameView.getHeight();//increment y whilst not off screen
if (y >= gameView.getHeight()) {//if gone of the bottom of screen
y -= gameView.getHeight();//Reset y
}
}
// Checks if the sprite was touched
public boolean wasItTouched(float ex, float ey) {
boolean touched = false;
if ((x <= ex) && (ex < x + bmp_width) &&
(y <= ey) && (ey < y + bmp_height)) {
touched = true;
}
return touched;
}
}
It now does bounce off the edge but from top left, diagonally to the right and back up in the same direction and continues to do this back and forth. I'd like it to be random in its direction after hitting the edge. Any suggestions? As you can see from the code I have tried a lot of things but the sprite just keeps on doing this continuous back and forth diagonal motion and I'm at a loss as to what I can do.
Thanks
Just negate your speed every time you hit a wall
if (x < 0 || x > gameView.getWidth() ){ xSpeed = xSpeed * -1;}
if (y < 0 || y > gameView.getHeight() ){ ySpeed = ySpeed * -1;}
/////////////////////////////// Edit
It will fit something like this. You can also remove your wrap function as it is no longer applicable
//update the position of the sprite
public void update() {
x = x + xSpeed;
y = y + xSpeed;
bounce();
}
private void bounce(){
if (x <= 0 || x >= gameView.getWidth() ){ xSpeed = xSpeed * -1;}
if (y <= 0 || y >= gameView.getHeight() ){ ySpeed = ySpeed * -1;}
}
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;
}
}
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!
}