This is a grade 12 object oriented programming project.
I have a class called Ball to construct my ball object.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.util.*;
public class Ball{
private double xPos;
private double yPos;
private int direction;
public Ball(int ixPos, int iyPos, int idirection){
xPos = ixPos;
yPos = iyPos;
direction = idirection;
}
public int returnX(){
return (int)xPos;
}
public int returnY(){
return (int)yPos;
}
public int returnDirection(){
return direction;
}
public void move(){
xPos += 1*Math.cos(Math.toRadians(direction));
yPos -= 1*Math.sin(Math.toRadians(direction));
}
public void collide(int collideWith){
if(collideWith==1){//collide with left wall
if(90<direction && direction<180){
direction = 180-direction;
}
if(180<direction && direction<270){
direction = 540-direction;
}
}
if(collideWith==2){//collide with right wall
if(0<direction && direction<90){
direction = 180-direction;
}
if(270<direction && direction<360){
direction = 540-direction;
}
}
if(collideWith==3){//collide with up wall
if(0<direction && direction<90){
direction = 360-direction;
}
if(90<direction && direction<180){
direction = 360-direction;
}
}
if(collideWith==4){//collide with down wall
direction = 360-direction;
}
}
public void collidePaddle(int collidePos){
if(collidePos!=50 && collidePos!=0){
direction = (50-collidePos)*180/50;
}
}
}
As you can see in the "move" function, right now the ball is going at a very low speed. But i need the ball to go faster. If I change the 1 into something like, 5, there would be a problem. In my main class where it checks if the ball is hitting the wall or blocks to change direction, the ball would go into the wall or the blocks if the amount of pixels the ball can move each time is greater than 1.
To me it seems like there's no way to solve this problem, no idea where I would start thinking, is there a better way of checking collide or something?
Thank you.
Instead of using absolute checks in your collidePaddle check, you should allow for ranges.
For example...
public void collidePaddle(int collidePos){
if (collidePos >= 50) {
direction = (50-collidePos)*180/50;
// Correct the position of the ball to meet the minimum requirements
// of the collision...
} else if (collidePos <= 0) {
direction = (50-collidePos)*180/50;
// Correct the position of the ball to meet the minimum requirements
// of the collision...
}
}
(Sorry, I'm having fun working out your code ;))
This will allow the ball the "pass" beyond the these points within a virtual context, but if you correct the position to componsate, it should make no difference...when it's rendered...
Updated
Here's a REALLY SIMPLE example of what I'm talking about...
public class SimpleBouncyBall {
public static void main(String[] args) {
new SimpleBouncyBall();
}
public SimpleBouncyBall() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (Exception ex) {
}
JFrame frame = new JFrame("Test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new CourtPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class CourtPane extends JPanel {
private Ball ball;
private int speed = 5;
public CourtPane() {
Timer timer = new Timer(40, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
Rectangle bounds = new Rectangle(new Point(0, 0), getSize());
if (ball == null) {
ball = new Ball(bounds);
}
speed = ball.move(speed, bounds);
repaint();
}
});
timer.setRepeats(true);
timer.setCoalesce(true);
timer.start();
}
#Override
public Dimension getPreferredSize() {
return new Dimension(100, 100);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (ball != null) {
Graphics2D g2d = (Graphics2D) g.create();
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
Point p = ball.getPoint();
g2d.translate(p.x, p.y);
ball.paint(g2d);
g2d.dispose();
}
}
}
public class Ball {
private Point p;
private int radius = 12;
public Ball(Rectangle bounds) {
p = new Point();
p.x = 0;
p.y = bounds.y + (bounds.height - radius) / 2;
}
public Point getPoint() {
return p;
}
public int move(int speed, Rectangle bounds) {
p.x += speed;
if (p.x + radius >= (bounds.x + bounds.width)) {
speed *= -1;
p.x = ((bounds.x + bounds.width) - radius) + speed;
} else if (p.x <= bounds.x) {
speed *= -1;
p.x = bounds.x + speed;
}
p.y = bounds.y + (bounds.height - radius) / 2;
return speed;
}
public void paint(Graphics2D g) {
g.setColor(Color.RED);
g.fillOval(0, 0, radius, radius);
}
}
}
My move method doesn't care if you've past the boundaries as it will reposition the ball back to sit within side those boundaries
public int move(int speed, Rectangle bounds) {
// Apply the delta
p.x += speed;
// Have we passed beyond the right side??
if (p.x + radius >= (bounds.x + bounds.width)) {
speed *= -1;
p.x = ((bounds.x + bounds.width) - radius) + speed;
// Have we past beyond the left side??
} else if (p.x <= bounds.x) {
speed *= -1;
p.x = bounds.x + speed;
}
p.y = bounds.y + (bounds.height - radius) / 2;
return speed;
}
Play around with the speed and see what you get ;)
Related
I have a Brush class
final class Brush
{
private final int size;
private final Color color;
private final Ellipse2D.Double blob=new Ellipse2D.Double();
private Brush(int size,Color color)
{
this.size=size;
this.color=color;
}
void paint(Graphics2D g2d,Point location)
{
g2d.setColor(color);
blob.setFrame(location.x-(size/2.0),location.y-(size/2.0),size,size);//Translate ecllipse so that the centre of it's bounding box is exactly at the cursor location for more accurate blobs
g2d.fill(blob);
}
}
I have a Blob class which keeps track of the user's current brush settings and where the user previously dragged his mouse so as to remember to draw a blob there.
final class Blob
{
final Brush brush;
final Point location;
private Blob(Brush brush,Point location)
{
this.brush=brush;
this.location=location;
}
private void paint(Graphics2D g){brush.paint(g,location);}
}
Finally my paint logic which is very simple.
Whenever the user drags his mouse add a blob at that current location with the current brush settings and inside paint() loop through all blobs and redraw them.
final class Painter extends Canvas
{
private Brush brush=new Brush(5,Color.red);//Can Change
private final ArrayList<Blob> blobs=new ArrayList();
private Painter(){addMouseMotionListener(new Dragger());}
#Override
public void paint(Graphics g)
{
super.paint(g);
blobs.forEach(blob->blob.paint(g));
}
private final class Dragger extends MouseAdapter
{
#Override
public void mouseDragged(MouseEvent m)
{
blobs.add(brush,m.getPoint());
repaint();
}
}
}
You can already see the problem here. The size of the list grows exponentially and my app quickly slows down. Is there an more efficient way to do this?
The much more efficient way to do this is to use a BufferedImage for your drawing, and than painting the BufferedImage in paintComponent
Code taken from PaintArea:
public void paintComponent(Graphics g) {
if (mSizeChanged) {
handleResize();
}
g.drawImage(mImg, 0, 0, null);
}
protected class MListener extends MouseAdapter implements MouseMotionListener {
Point mLastPoint;
public void mouseDragged(MouseEvent me) {
Graphics g = mImg.getGraphics();
if ((me.getModifiers() & InputEvent.BUTTON1_MASK) != 0) {
g.setColor(mColor1);
} else {
g.setColor(mColor2);
}
Point p = me.getPoint();
if (mLastPoint == null) {
g.fillOval(p.x - mBrushSize / 2, p.y - mBrushSize / 2, mBrushSize, mBrushSize);
//g.drawLine(p.x, p.y, p.x, p.y);
}
else {
g.drawLine(mLastPoint.x, mLastPoint.y, p.x, p.y);
//g.fillOval(p.x - mBrushSize / 2, p.y - mBrushSize / 2, mBrushSize, mBrushSize);
double angle = MathUtils.angle(mLastPoint, p);
if (angle < 0) {
angle += 2 * Math.PI;
}
#SuppressWarnings("unused")
double distance = MathUtils.distance(mLastPoint, p) * 1.5;
if (angle < Math.PI / 4 || angle > 7 * Math.PI / 4 || Math.abs(Math.PI - angle) < Math.PI / 4) {
for (int i = 0; i < mBrushSize / 2; i ++) {
g.drawLine(mLastPoint.x, mLastPoint.y + i, p.x, p.y + i);
g.drawLine(mLastPoint.x, mLastPoint.y - i, p.x, p.y - i);
}
}
else {
for (int i = 0; i < mBrushSize / 2; i ++) {
g.drawLine(mLastPoint.x + i, mLastPoint.y, p.x + i, p.y);
g.drawLine(mLastPoint.x - i, mLastPoint.y, p.x - i, p.y);
}
}
}
mLastPoint = p;
g.dispose();
repaint();
}
public void mouseMoved(MouseEvent me) {}
public void mouseReleased(MouseEvent me) {
mLastPoint = null;
}
}
Being new to coding, I watched a video on how to create Pong. That went well, and as a result I wanted to try and recreate Brick Breaker using some of the coding techniques that were used for Pong. So far I have the ball, paddle, and the base of the game. However, the ball does not collide properly with the paddle, instead of bouncing of it passes through.
Code for base game:
import java.applet.Applet;
import java.awt.Color;
import java.awt.Image;
import java.awt.Graphics;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
public class Breaker extends Applet implements Runnable, KeyListener{
final int WIDTH = 600, HEIGHT= 400;
Thread thread;
Graphics gfx;
Image img;
Ball b1;
Player p1;
public void init() {
this.resize(WIDTH, HEIGHT);
this.addKeyListener(this);
b1 = new Ball();
p1 = new Player(1);
img = createImage(WIDTH,HEIGHT);
gfx = img.getGraphics();
thread = new Thread(this);
thread.start();
}
public void paint(Graphics g) {
gfx.setColor(Color.black);
gfx.fillRect(0, 0, WIDTH, HEIGHT);
b1.draw(gfx);
p1.draw(gfx);
g.drawImage(img, 0, 0, this);
}
public void update (Graphics g) {
paint(g);
}
#Override
public void keyPressed(KeyEvent e) {
if(e.getKeyCode() == KeyEvent.VK_LEFT){
p1.setLeftAccel(true);
}
else if(e.getKeyCode() == KeyEvent.VK_RIGHT){
p1.setRightAccel(true);
}
}
#Override
public void keyReleased(KeyEvent e) {
if(e.getKeyCode() == KeyEvent.VK_LEFT){
p1.setLeftAccel(false);
}
else if(e.getKeyCode() == KeyEvent.VK_RIGHT){
p1.setRightAccel(false);
}
}
#Override
public void run() {
for(;;) {
p1.move();
b1.move();
b1.checkPlayerCollision(p1);
repaint();
getToolkit().sync();
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
#Override
public void keyTyped(KeyEvent arg0) {
}
}
Ball:
import java.awt.Graphics;
import java.awt.Color;
public class Ball {
int score;
double xVel, yVel, x, y;
public Ball() {
x= 350;
y = 250;
xVel= 0;
yVel = 1;
}
public void draw(Graphics g) {
g.setColor(Color.white);
g.fillOval((int)x - 10, (int)y - 10, 20, 20);
}
public void checkPlayerCollision(Player p1) {
if (x <= 50) {
if(x >= p1.getX() && x <= p1.getX() + 10)
xVel = -xVel;
}
else if (x >= 680) {
xVel = -xVel;
}
}
public void move() {
x += xVel;
y += yVel;
if (y < 10) //Bounce at top side of screen
yVel = -yVel;
if (x < 10) // Bounce at left side of screen
xVel = -xVel;
}
public int getX() {
return (int)x;
}
public int getY() {
return (int)y;
}
}
Player:
import java.awt.Color;
import java.awt.Graphics;
public class Player implements Paddle {
double x, xVel;
boolean leftAccel, rightAccel;
int player, y;
public Player(int player) {
leftAccel = false; rightAccel = false;
x=260; xVel=0;
}
#Override
public void draw(Graphics g) {
g.setColor(Color.white);
g.fillRect((int)x, 380, 80, 10);
}
#Override
public void move() {
if(leftAccel){
xVel -= 2;
}
else if (rightAccel) {
xVel += 2;
}
else if (!leftAccel && !rightAccel) {
xVel = 0;
}
if(xVel >= 5) {
xVel = 5;
}
else if (xVel <= -5) {
xVel = -5;
}
x += xVel;
if(x < 0)
x=0; //Collision with left wall
if(x > 520)
x = 520; //Collision with right wall
}
public void setLeftAccel(boolean input) {
leftAccel = input;
}
public void setRightAccel(boolean input) {
rightAccel = input;
}
#Override
public int getX() {
return (int)x;
}
}
Paddle:
import java.awt.Graphics;
public interface Paddle {
public void draw(Graphics g);
public void move();
public int getX();
}
I don't completely understand hit detection yet, so I just messed with what was used for pong, however, that doesn't work (and I'm sure it might look weird).
Collision detection can be hard to wrap your head around sometimes. What really helps me is to draw on a piece of paper the things I need to check for and write the checks in code one by one. It's also a good idea to keep your axes in mind, it's really easy to mix up an x and a y, but they will have an important effect on gameplay.
My eye was drawn to your checkPlayerCollision function as it seemed a little off, I have changed some checks around and commented what each check/function is doing.
public void checkPlayerCollision(Player p1) {
if (
// Is the ball at or below paddle height?
y <= 50
// AND Is the ball right of the left side of the paddle?
&& x >= p1.getX()
// AND Is the ball left of the right side of the paddle?
&& x <= p1.getX() + 10
) {
// Collision with the paddle!
// (Ball is lower than y=50 and between left and right side of the paddle!)
// As we want the ball to go back up, we will be changing its velocity
// along the Y-axis.
yVel -= yVel;
} else if (x >= 680) {
// This checks whether the ball went too far to the right..?
xVel -= xVel;
}
}
Best tip I can give you: grab a piece of paper and just draw a simple grid or graph and use that to draw out different things you need to check. Be sure to label your (0,0) point so when you work with the different borders, you know which ones are 0 (usually top and left borders) and which ones are equal to width and height of the canvas.
Is it possible to add collision effects to an image in Java, drawn using the drawImage() method ? If so, how could I do it?
Example:
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.event.KeyEvent;
public class Racquet {
private static final int Y = 330;
private static final int WIDTH = 60;
private static final int HEIGHT = 10;
int x = 0;
int xa = 0;
private Game game;
public Racquet(Game game) {
this.game = game;
}
public void move() {
if (x + xa > 0 && x + xa < game.getWidth() - WIDTH)
x = x + xa;
}
public void paint(Graphics2D g) {
g.fillRect(x, Y, WIDTH, HEIGHT);
}
public void keyReleased(KeyEvent e) {
xa = 0;
}
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_LEFT)
xa = -1;
if (e.getKeyCode() == KeyEvent.VK_RIGHT)
xa = 1;
}
public Rectangle getBounds() {
return new Rectangle(x, Y, WIDTH, HEIGHT);
}
public int getTopY() {
return Y;
}
}
Ball class:
import java.awt.Graphics2D;
import java.awt.Rectangle;
public class Ball {
private static final int DIAMETER = 30;
int x = 0;
int y = 0;
int xa = 1;
int ya = 1;
private Game game;
public Ball(Game game) {
this.game= game;
}
void move() {
if (x + xa < 0)
xa = 1;
if (x + xa > game.getWidth() - DIAMETER)
xa = -1;
if (y + ya < 0)
ya = 1;
if (y + ya > game.getHeight() - DIAMETER)
game.gameOver();
if (collision()){
ya = -1;
y = game.racquet.getTopY() - DIAMETER;
}
x = x + xa;
y = y + ya;
}
private boolean collision() {
return game.racquet.getBounds().intersects(getBounds());
}
public void paint(Graphics2D g) {
g.fillOval(x, y, DIAMETER, DIAMETER);
}
public Rectangle getBounds() {
return new Rectangle(x, y, DIAMETER, DIAMETER);
}
}
The above code detects the collision between the racquet and the ball, now, if my racquet/racket was an image, How wuold I be able to detect the collision of it with the ball? Also, are there easier ways for collision detection?(just asking)
class MyImage extends BufferedImage {
int x, y, xa, ya;
public Rectangle getBounds() {
return new Rectangle(x, y, getWidth(), getHeight());
}
// all other methods in raquet remain the same except you remove paint()
private Game game;
public MyImage(Game game) {
this.game = game;
}
public void move() {
if (x + xa > 0 && x + xa < game.getWidth() - WIDTH)
x = x + xa;
}
public void keyReleased(KeyEvent e) {
xa = 0;
}
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_LEFT)
xa = -1;
if (e.getKeyCode() == KeyEvent.VK_RIGHT)
xa = 1;
}
public int getY() {
return y;
}
}
To start an image you read it like this
MyImage myImage=null;
try {
myImage=ImageIO.read(new File(...));
}
catch (Exception ex) { ex.printStackTrace(); }
How wuold I be able to detect the collision of it with the ball?
I see that you already have a getBounds() methods which returns a Rectangle object. You can use this to check for collision.
You can do it like:
if(racquet.getBounds().intersects(ball.getBounds()))
//collision happens
If the ball must be within the racquet, then:
if(racquet.getBounds().contains(ball.getBounds()))
//collision happens
However, if the height of your racquet object includes then length of the racquet handle, you may implement a getHitBox() method for the racquet something like this:
public Rectangle getHitBox(){
return new Rectangle(x, Y, WIDTH, HEIGHT-handleHeight);
}
Is it possible to add collision effects to an image in Java, drawn using the drawImage() method ? If so, how could I do it?
Not sure how your drawImage() was implemented, so I can't comment on that. However, it is definitely possible to add some "collision effects" with custom painting. Whenever a collision is detected, play the animation at specific location (which will be the location where collision occurs).
You may construct a method like:
playAnimation(int locX, int locY, Animation anima, int duration)
In this case Animation class can just play the sprites from a sprite sheet.
Also, are there easier ways for collision detection?(just asking)
You will probably only have 1 ball and at most 4 racquets in your game. In this case, you only need to check whether the ball hits any of the racquets:
for(int x=0; x<allRacquets.size(); x++)
if(allRacquets.get(x).collidesWith(ball))
collidedRacquet = allRacquets.get(x);
CollidesWith() method can be implemented from the collision detection approach mentioned above:
//implement within Racquet class
public boolean collidesWith(Ball ball){
return (this.getBounds().intersects(ball.getBounds()));
}
I'm trying to create an awt applet in which the user can drag around a rectangle that has been drawn on the applet. I can't figure out why the rectangle in my applet only drags diagonally and in the positive x direction, I can't move it up or down or to the left, it only drags diagonally to the right. Can someone please tell me what's wrong with my logic ?
import java.applet.*;
import java.awt.*;
import java.awt.event.*;
public class DragRectangle extends Applet implements MouseMotionListener {
boolean clicked_in_rectangle = false;
int rectangleX, rectangleY, mouseX, mouseY;
int rectangle_width = 80, rectangle_height = 50;
public void init() {
rectangleX = 0;
rectangleY = 0;
mouseX = 0;
mouseY = 0;
addMouseMotionListener(this);
}
public void paint(Graphics g) {
g.drawRect(rectangleX, rectangleY, rectangle_width, rectangle_height);
if(clicked_in_rectangle) {
rectangleX = mouseX;
rectangleY = mouseY;
g.drawRect(rectangleX, rectangleY, rectangle_width, rectangle_height);
}
}
public void mouseDragged(MouseEvent e) {
mouseX = e.getX();
mouseY = e.getY();
clicked_in_rectangle = mouseX > rectangleX && mouseY > rectangleY &&
mouseX < rectangleX + rectangle_width && mouseY < rectangleY + rectangle_height;
repaint();
}
public void mouseMoved(MouseEvent e) {
}
}
I think the problem is that you're setting the rectangle's position to the mouse's pointer position and when you try to drag the rectangle up or to the left, the pointer will be outside of the rectangle's bounds and clicked_in_rectangle will be false.
You can try this:
if (clicked_in_rectangle) {
rectangleX = mouseX - 3;
rectangleY = mouseY - 3;
g.drawRect(rectangleX, rectangleY, rectangle_width, rectangle_height);
}
But this is still not an ideal solution, it stops working if you try to drag the rectangle (up or to the left) quickly, that's because the rectangleX and rectangleY don't get a chance to be updated to the new position.
If you want something more reliable, you can do this:
public class DragRectangle extends Applet implements MouseMotionListener, MouseListener {
boolean clicked_in_rectangle = false, dragStarted = false;
int x, y, px, py;
Rectangle rect = new Rectangle(0, 0, 80, 50);
public void init() {
addMouseMotionListener(this);
addMouseListener(this);
}
public void paint(Graphics g) {
if (clicked_in_rectangle) {
int nx = rect.x + (x - px);
int ny = rect.y + (y - py);
Rectangle bounds = g.getClipBounds();
boolean reset = false;
if (nx + rect.width > bounds.width || nx < 0) {
nx = rect.x;
reset = true;
}
if (ny + rect.height > bounds.height || ny < 0) {
ny = rect.y;
reset = true;
}
if (reset) {
px = 0;
py = 0;
} else {
px = x;
py = y;
}
rect = new Rectangle(nx, ny, rect.width, rect.height);
}
g.drawRect(rect.x, rect.y, rect.width, rect.height);
}
public void mouseDragged(MouseEvent e) {
if (dragStarted) {
x = e.getX();
y = e.getY();
if (px == 0 && py == 0) {
px = x;
py = y;
} else {
clicked_in_rectangle = new Rectangle(x, y, 1, 1).intersects(rect);
if (clicked_in_rectangle) {
repaint();
}
}
}
}
public void mouseMoved(MouseEvent e) {
}
#Override
public void mouseClicked(MouseEvent e) {
}
#Override
public void mouseEntered(MouseEvent e) {
}
#Override
public void mouseExited(MouseEvent e) {
}
#Override
public void mousePressed(MouseEvent e) {
if (e.getButton() == MouseEvent.BUTTON1) {
dragStarted = new Rectangle(e.getX(), e.getY(), 1, 1).intersects(rect);
}
}
#Override
public void mouseReleased(MouseEvent e) {
if (e.getButton() == MouseEvent.BUTTON1) {
px = 0;
py = 0;
}
}
}
I may have made this more complicated then it has to be, in any case, the idea is to change the shape's position based on the difference between consecutive pointer coordinates instead of setting its position to the same position as the pointer.
Is this the right site to ask this question, since I've been referred to another site two times by now.
I'm trying to create bouncing balls with realistic physics. At the moment, when the balls hit each other, they bounce back in the same direction they were coming from, now, I've searched the internet for how to do this, but I only find things about how to detect collision, not what to do after. I don't know a lot about physics, are their topics I should learn first before I would be able to do this? Here's an image of how I imagine balls would bounce in real life. Is this how it works?
(source: thewombatguru.nl)
Also, do I have bad practises in my code? (probably, but I'm learning a lot and I like it)
This is my current code:
Asteroids.java
package Asteroids;
import javax.swing.*;
public class Asteroids {
public static void createAndShowGui() {
GamePanel gamePanel = new GamePanel();
JFrame frame = new JFrame("Asteroids");
frame.getContentPane().add(gamePanel);
frame.pack();
frame.setVisible(true);
frame.setResizable(false);
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.setLocation(2000, 50);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createAndShowGui());
}
}
GamePanel.java
package Asteroids;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
public class GamePanel extends JPanel implements ActionListener {
private final int WIDTH = 1000;
private final int HEIGHT = 1000;
Timer animationTimer;
ArrayList<Rock> rocks;
public GamePanel() {
Dimension preferredDimension = new Dimension(WIDTH, HEIGHT);
setPreferredSize(preferredDimension);
animationTimer = new Timer(10, this);
setUp();
}
public void setUp() {
rocks = new ArrayList<>();
rocks.add(new Rock(475, 1000, 0, -1));
rocks.add(new Rock(0, 500, 1, 0));
//rocks.add(new Rock(300, 270, -2, 2));
//rocks.add(new Rock(400, 315, -5, -1));
animationTimer.start();
}
#Override
public void actionPerformed(ActionEvent e) {
repaint();
for (Rock rock : rocks) {
for (Rock rockToCheck : rocks) {
if (!rock.equals(rockToCheck)) {
rock.checkForCollisionWithRocks(rockToCheck);
}
}
rock.checkForCollisionWithFrame(WIDTH, HEIGHT);
rock.setxPos(rock.getxPos() + rock.getxVelocity());
rock.setyPos(rock.getyPos() + rock.getyVelocity());
}
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
RenderingHints mainRenderingHints = new RenderingHints(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setRenderingHints(mainRenderingHints);
for (Rock rock : rocks) {
rock.display(g2d);
}
g2d.dispose();
}
}
Rock.java
package Asteroids;
import java.awt.*;
public class Rock {
private int xPos;
private int yPos;
private int rockWidth;
private int rockHeight;
private int xVelocity;
private int yVelocity;
private int rockRadius;
private Color rockColor;
public Rock(int xPos, int yPos, int xVelocity, int yVelocity) {
this.xPos = xPos;
this.yPos = yPos;
this.xVelocity = xVelocity;
this.yVelocity = yVelocity;
rockWidth = 50;
rockHeight = rockWidth;
rockRadius = rockWidth / 2;
rockColor = new Color((int) (Math.random() * 255),(int) (Math.random() * 255),(int) (Math.random() * 255));
}
public void setxPos(int xPos) {
this.xPos = xPos;
}
public int getxPos() {
return xPos;
}
public int getRockWidth() {
return rockWidth;
}
public void setRockWidth(int rockWidth) {
this.rockWidth = rockWidth;
}
public int getRockHeight() {
return rockHeight;
}
public void setRockHeight(int rockHeight) {
this.rockHeight = rockHeight;
}
public int getyPos() {
return yPos;
}
public void setyPos(int yPos) {
this.yPos = yPos;
}
public int getxVelocity() {
return xVelocity;
}
public void setxVelocity(int xVelocity) {
this.xVelocity = xVelocity;
}
public int getyVelocity() {
return yVelocity;
}
public void setyVelocity(int yVelocity) {
this.yVelocity = yVelocity;
}
public int getRockRadius() {
return rockRadius;
}
public void setRockRadius(int rockRadius) {
this.rockRadius = rockRadius;
}
public void checkForCollisionWithRocks(Rock rock) {
int radiusOfBoth = rock.getRockRadius() + rockRadius;
int horDistance = Math.abs((rock.getxPos() + rock.getRockRadius()) - (xPos + rockRadius));
int verDistance = Math.abs((rock.getyPos() + rock.getRockRadius()) - (yPos + rockRadius));
int diagDistance = (int) Math.sqrt(Math.pow(horDistance, 2) + Math.pow(verDistance, 2));
if (diagDistance <= radiusOfBoth) {
xVelocity = -xVelocity;
yVelocity = -yVelocity;
rock.setxVelocity(-rock.getxVelocity());
rock.setyVelocity(-rock.getyVelocity());
rock.setxPos(rock.getxPos() + rock.getxVelocity());
rock.setyPos(rock.getyPos() + rock.getyVelocity());
}
}
public void checkForCollisionWithFrame(final int WIDTH, final int HEIGHT) {
if (xPos < 0) {
xVelocity *= -1;
xPos = 0;
} else if (xPos + rockWidth > WIDTH) {
xVelocity *= -1;
xPos = WIDTH - rockWidth;
}
if (yPos < 0) {
yVelocity *= -1;
yPos = 0;
} else if (yPos + rockHeight > HEIGHT) {
yVelocity *= -1;
yPos = HEIGHT - rockHeight;
}
}
public void display(Graphics2D g2d) {
g2d.setColor(rockColor);
g2d.fillOval(xPos, yPos, rockWidth, rockHeight);
}
}
Can anyone help ?
You can start with the law of conservation of momentum. When two objects collide the total momentum will not change, you can use this link to understand the calculations behind while trying to predict the trajectories of two objects after they collide.
As for your code, you seem to be missing a crucial field mass in your Rock.java. You need mass in order to calculate the momentum of an object which later you will use to predict the trajectories after the objects collide.
EDIT: Note that the examples in the link are somewhat limited to 2 directions where the objects collide against each other with 180* between them. However it is not that hard to generalize and find the velocity of an object after the collision by breaking down the momentum/velocity vectors to 4 directions, that are 0,90,180,270 degrees. You have to use vector math to express the speed of a given object in terms of the 4 directions.
Real life physics is tricky (gravity, inertia, etc), but to start with, bouncing the balls off of each other:
When the two balls hit, there's an angle of collision. Luckily, because they are circles (assuming) you can find the angle of incidence by finding the angle of the line going through the center of the two balls. Then you want to send 1 ball off 1 way perpendicular the that line, and the other the other way.
Make sense?
Answer here:
Also there is a nice gif,you can easily find out,how to calculate the new velocities ;)
Ball to Ball Collision - Detection and Handling