Can I get a clarification on how to figure out the point in which 2 line segments intersect?
I have this code in which I am creating a pong game but I am having trouble with figuring out where the ball intersects with the paddle and if so basically bounce it back. I know some basic algebra is needed but for the sake of my code what is needed?
I have the current position of the ball, the old position of the ball, and the paddles current position (ballX,Y , oldBallX,Y , etc) What would I have to do to get the (x, y) intersection point for the collision of the ball on the paddle?
CODE
`
package com.example.pong;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Rect;
import android.graphics.Region;
import android.media.MediaPlayer;
import android.util.Log;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import androidx.annotation.NonNull;
public class PongView extends SurfaceView implements SurfaceHolder.Callback, Runnable {
private static final String TAG = "";
private final GameActivity gameActivity;
private Thread _thread;
private int screenWidth; // screen width
private int screenHeight; // screen height
Context _context;
private SurfaceHolder _surfaceHolder;
private boolean _run = false;
// All pong variables go in here
// Right Paddle
private float rPaddle; // variable set by touch event
// Left Paddle
private float lPaddle; // variable set by touch event
// Paddle variables
private int halfPaddle = 50;
private final static int MAX_FPS = 30; //desired fps
private final static int FRAME_PERIOD = 1000 / MAX_FPS; // the frame period
private Paint background = new Paint();
private Paint dark = new Paint();
private float ballX = 500.0f; // ball location
private float ballY = 250.0f;
/// pongSpeed variables
public float pongSpeed = 1.0f;
private long mLastTime = Long.MAX_VALUE;
private float timeElapsed; // Time since last frame in seconds
// The speed in pixels per second
private float ballSpeedX = 300.0f;
private float ballSpeedY = 300.0f;
// Variables for current pong position
private float oldBallX = 0.0f;
private float oldBallY = 0.0f;
private float xPos = 0.0f;
private float yPos = 0.0f;
private float xDir = 1.0f;
private float yDir = 1.0f;
//
public PongView(Context context) {
super(context);
_surfaceHolder = getHolder();
getHolder().addCallback(this);
this.gameActivity = (GameActivity) context;
_context = context;
setFocusable(true);
setFocusableInTouchMode(true);
}
//
public void setRPaddle(float rp) {
synchronized (_surfaceHolder) {
rPaddle = rp;
}
}
public void setLPaddle(float lp) {
synchronized (_surfaceHolder) {
lPaddle = lp;
}
}
#Override
public void run() {
float avg_sleep = 0.0f;
float fcount = 0.0f;
long fps = System.currentTimeMillis();
Canvas c;
while (_run) {
c = null;
long started = System.currentTimeMillis();
try {
c = _surfaceHolder.lockCanvas(null);
synchronized (_surfaceHolder) {
// Update game state
update();
}
// draw image
drawImage(c);
} finally {
// do this in a finally so that if an exception is thrown
// during the above, we don't leave the Surface in an
// inconsistent state
if (c != null) {
_surfaceHolder.unlockCanvasAndPost(c);
}
}
float deltaTime = (System.currentTimeMillis() - started);
int sleepTime = (int) (FRAME_PERIOD - deltaTime);
if (sleepTime > 0) {
try {
_thread.sleep(sleepTime);
}
catch (InterruptedException e) {
}
}
}
}
public void pause() {
_run = false;
boolean retry = true;
while (retry) {
try {
_thread.join();
retry = false;
} catch (InterruptedException e) {
// try again shutting down the thread
}
}
}
public void initialize(int w, int h) {
screenWidth = w;
screenHeight = h;
// create paints, rectangles, init time, etc
background.setColor(0xff200040); // should really get this from resource file
dark.setColor(0xffdddddd);
}
protected void update() {
// game update goes here
int width = getWidth();
int height = getHeight();
MediaPlayer pip = MediaPlayer.create(_context.getApplicationContext(), R.raw.lil_pip);
long now = System.currentTimeMillis(); // Current time
if (now > mLastTime)
{
timeElapsed = (now - mLastTime) / 1000.0f;
}
mLastTime = now;
ballX += ballSpeedX * timeElapsed;
ballY += ballSpeedY * timeElapsed;
oldBallX = ballX;
oldBallY = ballY;
collisionCheck();
//Treat paddle as line segment. Treat ball positions as points.
//Change ball direction if the two line segments intersect.
}
protected void collisionCheck()
{
// Bounce right side
if ((ballX > screenWidth) && (ballSpeedX > 0.0f))
{
ballSpeedX *= -1.0f;
pip.start();
}
// Bounce left side
// Not sure if using "80 *" is the best
if ((80 * ballX < screenHeight) && (ballSpeedX < 0.0f))
{
ballSpeedX *= -1.0f;
pip.start();
}
// Bounce bottom side
if ((ballY > screenHeight) && (ballSpeedY > 0.0f))
{
ballSpeedY *= -1.0f;
pip.start();
}
// Bounce top side
// Not sure if using "80 *" is the best
if ((80 * ballY < screenHeight) && (ballSpeedY < 0.0f))
{
ballSpeedY *= -1.0f;
pip.start();
}
Log.d("TAG", "Ball is moving");
}
private void rightPaddle (Canvas canvas)
{
canvas.drawRect(7 * screenWidth / 8, rPaddle * screenHeight + halfPaddle,
7 * screenWidth / 8 + 15, rPaddle * screenHeight - halfPaddle, dark);
}
private void leftPaddle (Canvas canvas)
{
canvas.drawRect( screenWidth / 8, lPaddle * screenHeight + halfPaddle,
screenWidth / 8 + 15, lPaddle * screenHeight - halfPaddle, dark);
}
private void pongBall (Canvas canvas)
{
canvas.drawRect(ballX, ballY, ballX + 10, ballY + 10, dark);
}
protected void drawImage(Canvas canvas) {
if (canvas == null) return;
// Draw commands go here
// Draw commands go here
canvas.drawRect(0, 0, getWidth(), getHeight(), background);
pongBall(canvas);
rightPaddle(canvas);
leftPaddle(canvas);
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
screenWidth = w;
screenHeight = h;
super.onSizeChanged(w, h, oldw, oldh);
initialize(w, h);
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
// TODO Auto-generated method stub
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
_run = true;
_thread = new Thread(this);
_thread.start();
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
// simply copied from sample application LunarLander:
// we have to tell thread to shut down & wait for it to finish, or else
// it might touch the Surface after we return and explode
boolean retry = true;
_run = false;
while (retry) {
try {
_thread.join();
retry = false;
} catch (InterruptedException e) {
// we will try it again and again...
}
}
}
#Override
public boolean onTouchEvent(MotionEvent event) {
int numPointers = event.getPointerCount();
int ptrIdx = 0;
while (ptrIdx < numPointers) {
int id = event.getPointerId(ptrIdx);
float xp = event.getX(ptrIdx) / screenWidth;
if (xp > 0.6) {
setRPaddle(event.getY(ptrIdx) / screenHeight);
} else if (xp < 0.4) {
setLPaddle(event.getY(ptrIdx) / screenHeight);
}
if ((ptrIdx > 0) || (id > 0)) {
Log.i(TAG, " Feel the power..." + ptrIdx + " " + id);
}
ptrIdx++;
}
return true;
}
}
`
I've tried making the paddles into Path's but my confusion is what exactly am I using for x1, x2, y1, y2 to find out the point of intersection.
You have to know some basic algebra knowledge. A line can be written in the form of Ax + By + C = 0 in a plain. (See Wikipedia-Line)
To calculate the intersect, you may first calculate the equation of the two lines.
A line passing from (x1, y1) and (x2, y2) can be written in the form of (y1 - y2) * x + (x2 - x1) * y + (x1 * y2 - x2 * y1) = 0. This way, you can calculate the equation of the two lines.
Now, you get the equation of the two lines. Say A1 * x + B1 * y + C1 = 0 and A2 * x + B2 * y + C2 = 0. Then the x-coordinate of the intersect will be (C2 * B1 - C1 * B2) / (A1 * B2 - A2 * B1), and the y-coordinate will be (C1 * A2 - C2 * A1) / (A1 * B2 - A2 * B1). Thus, you get the intersect.
Related
Im making a virtual joystick controller using SurfaceView but the drawn shapes in my java code is not rendered in the design view, im very new to java with just a few months experience.
public class JoystickView extends SurfaceView
implements SurfaceHolder.Callback,
View.OnTouchListener
{
private float centerX;
private float centerY;
private float baseRadius;
private float hatRadius;
private JoystickListener joystickCallback;
private void setupDimensions()
{
centerX = (float)getWidth()/2;
centerY = (float)getHeight()/2;
baseRadius = (float)Math.min(getWidth(), getHeight())/3;
hatRadius = (float)Math.min(getWidth(), getHeight())/5;
}
public JoystickView(Context context)
{
super(context);
getHolder().addCallback(this);
setOnTouchListener(this);
if(context instanceof JoystickListener){
joystickCallback = (JoystickListener) context;}
}
public JoystickView(Context context, AttributeSet attributes, int style)
{
super(context, attributes, style);
getHolder().addCallback(this);
setOnTouchListener(this);
}
public JoystickView(Context context, AttributeSet attributes)
{
super(context, attributes);
getHolder().addCallback(this);
setOnTouchListener(this);
}
This is where the joystick circle base and top(hat) where drawn using myCanvas.drawCircle()enter image description here
private void drawJoystick(float newX, float newY)
{
if(getHolder().getSurface().isValid())
{
Canvas myCanvas = this.getHolder().lockCanvas();
Paint colors = new Paint();
myCanvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
//These equations determine the sin and cos of the angle that the touched point is at relative to the center of the joystick
float hypotenuse = (float) Math.sqrt(Math.pow(newX - centerX, 2) + Math.pow(newY - centerY, 2));
float sin = (newY - centerY)/ hypotenuse;
float cos = (newX - centerX)/ hypotenuse;
//Drawing the base then shading
colors.setARGB(255, 50, 50, 50);
myCanvas.drawCircle(centerX, centerY, baseRadius, colors);
int ratio = 5;
for(int i = 1; i <= (int)(baseRadius/ ratio); i++)
{
colors.setARGB(150/i, 255, 0, 0); // Gradually reduce the black drawn to create an nice effect
myCanvas.drawCircle(newX- cos * hypotenuse * (ratio /baseRadius) * i,
newY - sin * hypotenuse * (ratio /baseRadius) * i, i * (hatRadius* ratio /baseRadius),colors); //gradually increase the size of the shading effect
}
//Drawing the joystick hat
for(int i = 1; i <= (int) (hatRadius / ratio); i++)
{
colors.setARGB(255, (int) (i * (255 * ratio / hatRadius)),(int)(i * (255 * ratio / hatRadius)), 255);//Change the joystick color for shading purposes
myCanvas.drawCircle(newX,newY, hatRadius - (float) i*(ratio) / 2, colors); // Drawing the shading of the hat
}
getHolder().unlockCanvasAndPost(myCanvas); //This writes the new drawing to the SurfaceView
}
}
#Override
public void surfaceCreated(SurfaceHolder holder)
{
setupDimensions();
drawJoystick(centerX, centerY);
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height)
{
}
#Override
public void surfaceDestroyed(SurfaceHolder holder)
{
}
public boolean onTouch(View v, MotionEvent e)
{
if(v.equals(this)) {
if (e.getAction() != MotionEvent.ACTION_UP)
{
float displacement = (float) Math.sqrt((Math.pow(e.getX() - centerX, 2)) + Math.pow(e.getY() - centerY, 2));
if (displacement < baseRadius)
{
drawJoystick(e.getX(), e.getY());
joystickCallback.onJoystickMoved((e.getX() - centerX)/baseRadius, (e.getY() - centerY)/baseRadius, getId());
}
else {
float ratio = baseRadius / displacement;
float constrainedX = centerX + (e.getX() - centerX) * ratio;
float constrainedY = centerY + (e.getY() - centerY) * ratio;
drawJoystick(constrainedX, constrainedY);
joystickCallback.onJoystickMoved((constrainedX-centerX)/baseRadius, (constrainedY-centerY)/baseRadius, getId());
}
}
else
drawJoystick(centerX, centerY);
joystickCallback.onJoystickMoved(0,0, getId());
}
return true;
}
public interface JoystickListener
{
void onJoystickMoved(float xPercent, float yPercent, int id);
}
}
I am making a game with android. The player is a rectangle that has to jump over obstacles. When i jump i decrease the height and the y coordinates. When i run the game the rectangle is jumping but when i try to jump over an obstacle its still hitting it. So i think i forget to change a value but i have no idea what value. Sorry for my bad english and i am a beginner at coding.
This is my Player class:
package com.example.niek.speelveld;
import android.graphics.Canvas;
import android.graphics.Paint;
/**
* Created by Niek on 15-8-2017.
*/
public class Player extends GameObject {
private int score;
private boolean up;
private boolean playing;
private long startTime;
private int h = 0;
private boolean jump;
public Player(int x , int y){
super.x = x;
super.y = y;
width = 100;
height = GamePanel.HEIGHT;
score = 0;
startTime = System.nanoTime();
}
public void setUp(boolean b){up = b;}
public void update(){
long elapsed = (System.nanoTime()-startTime)/1000000;
if(elapsed>100){
score++;
startTime = System.nanoTime();
}
if(up && h == 0){
jump = true;
up = false;
}
if (jump) {
if (h < 120) {
h = h + 7;
height = height - 7;
y = y - 7;
} else {
jump = false;
}
} else {
if (h > 0) {
h = h - 7;
height = height + 7;
y = y + 7;
}
}
}
public void draw(Canvas canvas){
Paint myPaint = new Paint();
myPaint.setStyle(Paint.Style.STROKE);
myPaint.setStrokeWidth(7);
canvas.drawRect(x, y, width + x, height, myPaint );
myPaint.setStrokeWidth(1);
canvas.drawText("HIGHSCORE " + score, GamePanel.WIDTH - 100 , 0+myPaint.getTextSize(), myPaint);
}
public int getScore(){return score;}
public boolean getPlaying(){return playing;}
public void setPlaying(boolean b){playing = b;}
//public void resetScore(){score = 0;}
public boolean getJump() {
return jump;
}
}
And in my Gamepanel class i use these 2 methods. When i call the class obstacle.get(i).update(); its only updating the x value so its moving towards the player.
public void update(){
if(player.getPlaying()) {
bg.update();
player.update();
//Add obstacles with timer
long obstacleElapsed = (System.nanoTime()-obstacleStartTime)/1000000;
if(obstacleElapsed >(2000 - player.getScore()/4)){
obstacles.add(new Obstacle(BitmapFactory.decodeResource(getResources(), R.drawable.rsz_spike1), WIDTH + 10, HEIGHT - 51, 14, 51, player.getScore()));
//reset timer
obstacleStartTime = System.nanoTime();
}
}
//Loop through every obstacle and check collision
for(int i = 0; i<obstacles.size(); i++){
obstacles.get(i).update();
if (collision(obstacles.get(i), player)) {
obstacles.remove(i);
player.setPlaying(false);
Intent intent = new Intent(c, Result.class);
intent.putExtra("SCORE", player.getScore());
c.startActivity(intent);
break;
}
//Remove obstacles that are out of the screen
if (obstacles.get(i).getX() < -100) {
obstacles.remove(i);
break;
}
}
}
public boolean collision(GameObject o, GameObject p){
if(Rect.intersects(o.getRectangle(), p.getRectangle())){
return true;
}
return false;
}
#Override
public void draw(Canvas canvas){
//Get Width and Height from screen
final float scaleFactorX = (float)getWidth()/WIDTH;
final float scaleFactorY = (float)getHeight()/HEIGHT;
if(canvas!=null) {
final int savedState = canvas.save();
canvas.scale(scaleFactorX, scaleFactorY);
bg.draw(canvas);
player.draw(canvas);
//Draw obstacles
for(Obstacle o : obstacles ){
o.draw(canvas);
}
canvas.restoreToCount(savedState);
}
}
And finally the Player and the Obstacle class extends Gameobject where i have the getRectangle method.
public Rect getRectangle(){
return new Rect(x, y, x+width, y+height);
}
I'm currently programming a game where you have to avoid asteroids. I had to deal with some messed up coordinates and I had to guess the coordinates for sprites. I now have arbitrary units that describe my world. Unfortunately, my game screen does not work fully. When I want to render my asteroids the game screen shows a black screen.
public class GameScreen extends Screen {
private OrthographicCamera cam;
private Spaceship spaceship;
private Asteroids asteroids;
private Background bg;
#Override
public void create() {
// TODO Auto-generated method stub
bg = new Background();
spaceship = new Spaceship();
asteroids = new Asteroids();
float aspectratio = 16/10;
cam = new OrthographicCamera(100, 100 * aspectratio);
cam.position.set(cam.viewportWidth / 2f, cam.viewportHeight / 2f, 0);
cam.update();
}
#Override
public void render(SpriteBatch batch) {
// TODO Auto-generated method stub
cam.update();
batch.setProjectionMatrix(cam.combined);
batch.begin();
bg.render(batch);
spaceship.render(batch);
batch.end();
}
The shown code above works just fine and shows me this:
When I add the render method for the asteroids in the GameScreen class the GameScreen is just black:
#Override
public void render(SpriteBatch batch) {
// TODO Auto-generated method stub
cam.update();
batch.setProjectionMatrix(cam.combined);
batch.begin();
bg.render(batch);
spaceship.render(batch);
batch.end();
}
Asteroid Class:
public class Asteroid {
private Vector2 p;
private Vector2 v;
private float mass;
private float radius;
public final float maxV = 200;
public final float minV = 50;
public final float rMin = 10;
public final float rMax = 30;
public final float minX = MyGdxGame.WIDTH;
public final float minY = MyGdxGame.HEIGHT;;
float alpha = MathUtils.random(0, 360);
public Asteroid(float maxX, float maxY, List<Asteroid> asteroids) {
do {
radius = MathUtils.random(rMin, rMax);
masse = radius * radius * radius;
float alpha = MathUtils.random(0, 360);
p = new Vector2(MathUtils.random(minX, maxX), MathUtils.random(minY,
maxY));
float vBetrag = MathUtils.random(minV, maxV);
v = new Vector2(vBetrag * MathUtils.cosDeg(alpha),
vBetrag * MathUtils.cosDeg(alpha));
} while (ueberlappMit(asteroids));
}
private boolean ueberlappMit(List<Asteroid> asteroids) {
for(Asteroid a: asteroids){
if(abstand(a) < radius + a.radius + 10){ //!
return true;
}
}
return false;
}
public void update(float deltaT, float xMin, float xMax, float yMin, float yMax) {
p.x += v.x * deltaT;
p.y += v.y * deltaT;
while(p.x > xMax)
{
p.x -= (xMax - xMin);
}
while(p.x < xMin)
{
p.x += (xMax - xMin);
}
while(p.y > yMax)
{
p.y -= (yMax - yMin);
}
while(p.y < yMin)
{
p.y += (yMax - yMin);
}
}
public float abstand(Asteroid a2) {
return p.dst(a2.p);
}
Asteroids Class:
public class Asteroids extends Entity {
private final int numberofAsteroids = 150;
private float xMin, xMax, yMin, yMax;
private List<Asteroid> asteroids = new ArrayList<Asteroid>();
private final int cyclicBoundaryConditionsMultiple = 2;
public Asteroids() {
xMin = MyGdxGame.WIDTH * (-cyclicBoundaryConditionsMultiple);
xMax = MyGdxGame.WIDTH * (cyclicBoundaryConditionsMultiple);
yMin = MyGdxGame.HEIGHT * (-cyclicBoundaryConditionsMultiple);
yMax = MyGdxGame.HEIGHT * (cyclicBoundaryConditionsMultiple);
for (int i = 0; i < anzahl; i++) {
Asteroid a = new Asteroid( xMax, yMax, asteroids);
asteroids.add(a);
}
}
#Override
public void update() {
for (Asteroid a : asteroids) {
a.update(Gdx.graphics.getDeltaTime(), xMin, xMax, yMin, yMax);
}
for (int i = 0; i < numberofAsteroids; i++) {
Asteroid a1 = asteroids.get(i);
for (int j = i + 1; j < anzahl; j++) {
Asteroid a2 = asteroids.get(j);
float abstand = a1.abstand(a2);
if (abstand < a1.getRadius() + a2.getRadius()) {
calculateCollision(a1, a2);
}
}
}
}
}
#Override
public void render(ShapeRenderer renderer) {
for (Asteroid a : asteroids) {
System.out.println("RENDER A");
renderer.setColor(0, 0, 0, 1);
renderer.circle(a.getP().x, a.getP().y, a.getRadius());
}
}
Thx alot for your help Guys, i solved the problem. The method private boolean ueberlappMit(List asteroids) checks if the asteroids overlap and if its the case the Asteroids shoud be created again. The Problem was that by selecting a too high radius the Game got stuck in the do while loop in the Asteroid class.
I want to move a sprite between two points.
first point is x=0 and y=0 and the second point is a point where the user touched the screen.
To move, I want to use an equation to go through the two points which is y=ax+b.
I have attempted this in the method move() but the sprite does not move.
Please help.
Class Display:
package com.example.name;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
public class Display extends SurfaceView {
private Bitmap bmp;
private SurfaceHolder holder;
private GameLoopThread gameLoopThread;
private Sprite sprite;
private long lastClick;
private float x = 0.0F;
private float y = 0.0F;
public Display(Context context) {
super(context);
bmp = BitmapFactory.decodeResource(getResources(), R.drawable.gonia);
sprite = new Sprite(this, bmp, x, y, x, y);
gameLoopThread = new GameLoopThread(this);
holder = getHolder();
holder.addCallback(new SurfaceHolder.Callback() {
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
boolean retry = true;
gameLoopThread.setRunning(false);
while (retry) {
try {
gameLoopThread.join();
retry = false;
} catch (InterruptedException e) {
}
}
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
gameLoopThread.setRunning(true);
gameLoopThread.start();
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format,
int width, int height) {
}
});
}
#Override
protected void onDraw(Canvas canvas) {
canvas.drawColor(Color.BLACK);
sprite.onDraw(canvas);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
if (System.currentTimeMillis() - lastClick > 500) {
lastClick = System.currentTimeMillis();
x = (float) sprite.ostatniaWartoscX();
y = (float) sprite.ostatniaWartoscY();
float gotox = (float) event.getX();
float gotoy = (float) event.getY();
synchronized (getHolder()) {
sprite = new Sprite(this, bmp, x, y, gotox, gotoy);
}
}
return true;
}
}
Class Sprite:
package com.example.name;
import android.graphics.Bitmap;
import android.graphics.Canvas;
public class Sprite {
private float a;
private float b;
private float x;
private float y;
private float gotox;
private float gotoy;
private int executeMove = 0;
private Display display;
private Bitmap bmp;
public Sprite(Display display, Bitmap bmp, float x, float y, float gotox,
float gotoy) {
this.display = display;
this.bmp = bmp;
this.x = x;
this.y = y;
this.gotox = gotox;
this.gotoy = gotoy;
}
void update() {
if (x < gotox) {x++;executeMove = 1;}
if (x > gotox) {x--;executeMove = 1;}
if (executeMove == 1) {move();}
executeMove = 0;
}
void move() {
float x1 = x;
float y1 = y;
float x2 = gotox;
float y2 = gotoy;
a = (y2-y1)/(x2-x1);
b = y1 - x1*a;
y = x1 * a + b;
}
public float ostatniaWartoscX() {
return x;
}
public float ostatniaWartoscY() {
return y;
}
public void onDraw(Canvas canvas) {
update();
canvas.drawBitmap(bmp, x, y, null);
}
}
Thank You!
You need Bresenham's line algorithm to move your player. You can even cut it short that you only need to calculate the next movement (not the whole line). It's a simple/easy and low-calorie-algorithm.
You must adjust it to your needs.
public static ArrayList<Point> getLine(Point start, Point target) {
ArrayList<Point> ret = new ArrayList<Point>();
int x0 = start.x;
int y0 = start.y;
int x1 = target.x;
int y1 = target.y;
int sx = 0;
int sy = 0;
int dx = Math.abs(x1-x0);
sx = x0<x1 ? 1 : -1;
int dy = -1*Math.abs(y1-y0);
sy = y0<y1 ? 1 : -1;
int err = dx+dy, e2; /* error value e_xy */
for(;;){ /* loop */
ret.add( new Point(x0,y0) );
if (x0==x1 && y0==y1) break;
e2 = 2*err;
if (e2 >= dy) { err += dy; x0 += sx; } /* e_xy+e_x > 0 */
if (e2 <= dx) { err += dx; y0 += sy; } /* e_xy+e_y < 0 */
}
return ret;
}
Here is an example of code I use to move an object between two points.
Math.atan2 calculates the theta angle (-pi to +pi) which is the trajectory the object needs to travel. Delta is the time between this this update and the last update and velocity is the desired speed of the object. These all need to be multiplied together and then added to the current position to get the new position.
#Override
protected void update(float delta) {
double theta = Math.atan2(targetPos.y - pos.y, targetPos.x - pos.x);
double valX = (delta * velocity) * Math.cos(theta);
double valY = (delta * velocity) * Math.sin(theta);
pos.x += valX;
pos.y += valY;
}
I have written the code for movement of two balls within a rectangle(canvas). The balls deflect in opposite direction when they hit the top, bottom, left or right of the rectangle. But,I've tried in vain to make the balls collide with each other and deflect in opposite direction. I have searched many sites and articles but in vain. Can someone please help.
This is MainActivity.java
package com.example.movements;
public class MainActivity extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(new MovementView(this));
}
}
This is MovementView.java
package com.example.movements;
public class MovementView extends SurfaceView implements SurfaceHolder.Callback{
private int xPos,xPos1;
private int yPos,yPos1;
private int xVel,xVel1;
private int yVel,yVel1;
private int width;
private int height;
private int circleRadius,circleRadius1;
private Paint circlePaint,circlePaint1;
UpdateThread updateThread;
public MovementView(Context context) {
super(context);
getHolder().addCallback(this);
circleRadius = 10;
circlePaint = new Paint();
circlePaint.setColor(Color.BLUE);
xVel = 10;
yVel = 10;
circleRadius1 = 10;
circlePaint1 = new Paint();
circlePaint1.setColor(Color.MAGENTA);
xVel1 = 11;
yVel1 = 11;
}
#Override
protected void onDraw(Canvas canvas) {
canvas.drawColor(Color.WHITE);
canvas.drawCircle(xPos, yPos, circleRadius, circlePaint);
canvas.drawCircle(xPos1, yPos1, circleRadius1, circlePaint1);
}
public void updatePhysics() {
xPos += xVel;
yPos += yVel;
if (yPos - circleRadius < 0 || yPos + circleRadius > height) {
if (yPos - circleRadius < 0) {
yPos = circleRadius;
}else{
yPos = height - circleRadius;
}
yVel *= -1;
}
if (xPos - circleRadius < 0 || xPos + circleRadius > width) {
if (xPos - circleRadius < 0) {
xPos = circleRadius;
} else {
xPos = width - circleRadius;
}
xVel *= -1;
}
xPos1 += xVel1;
yPos1 += yVel1;
if (yPos1 - circleRadius1 < 0 || yPos1 + circleRadius1 > height) {
if (yPos1 - circleRadius1 < 0) {
yPos1 = circleRadius1;
}else{
yPos1 = height - circleRadius1;
}
yVel1 *= -1;
}
if (xPos1 - circleRadius1 < 0 || xPos1 + circleRadius1 > width) {
if (xPos1 - circleRadius1 < 0) {
xPos1 = circleRadius1;
} else {
xPos1 = width - circleRadius1;
}
xVel1 *= -1;
}
}
public void surfaceCreated(SurfaceHolder holder) {
Rect surfaceFrame = holder.getSurfaceFrame();
width = surfaceFrame.width();
height = surfaceFrame.height();
xPos = width / 2;
yPos = circleRadius;
xPos1 = width / 2;
yPos1 = circleRadius1;
updateThread = new UpdateThread(this);
updateThread.setRunning(true);
updateThread.start();
}
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
}
public void surfaceDestroyed(SurfaceHolder holder) {
boolean retry = true;
updateThread.setRunning(false);
while (retry) {
try {
updateThread.join();
retry = false;
} catch (InterruptedException e) {
}
}
}
}
This is UpdateThread.java
package com.example.movements;
import android.view.SurfaceHolder;
public class UpdateThread extends Thread {
private long time;
private final int fps = 20;
private boolean toRun = false;
private MovementView movementView;
private SurfaceHolder surfaceHolder;
public UpdateThread(MovementView rMovementView) {
movementView = rMovementView;
surfaceHolder = movementView.getHolder();
}
public void setRunning(boolean run) {
toRun = run;
}
#Override
public void run() {
Canvas c;
while (toRun) {
long cTime = System.currentTimeMillis();
if ((cTime - time) <= (1000 / fps)) {
c = null;
try {
c = surfaceHolder.lockCanvas(null);
movementView.updatePhysics();
movementView.onDraw(c);
} finally {
if (c != null) {
surfaceHolder.unlockCanvasAndPost(c);
}
}
}
time = cTime;
}
}
}
To check wether they are hitting each other, you can just check if the distance between their centers is smaller than (radius*2). To make a nice deflection, you'll have to do some math that's beyond me. Here is another answer on that.
I've googled it a bit and apparantly the term used in physics for this problem is called elastic collision. I've found a nice tutorial on the subject here (especially the dynamic circle-circle collision bit). Also, here is an applet which demonstrates this. The source code for this can be found [here]