quick question regarding my program. My program deals with circle objects that bounce around on a JFrame window. When 2 circles collide the smaller circle is consumed by the larger one and smaller one disappears. The method that does this is called:
checkCollsion();
In my program I'm calling it as such:
for ( int i = 0; i < blobs.length - 1; i++ )
{
for ( int j = i + 1; j < blobs.length; j++ )
{
blobs[i].checkCollision( blobs[j] );
}
}
My only question is, is that I do not understand how to reference blobs[i]. I get how to check if something collides, however I don't understand how I am suppose to compare blobs[i] with blobs[j] since in my method I can only pass in blobs[j] object.
Here's code from my blob class:
import java.awt.Color;
import java.util.Random;
#SuppressWarnings("serial")
public class Blob extends BouncingBall {
private int r;
private int g;
private int b;
private Color c;
private BouncingBall bb;
public Blob(int x, int y, int diameter, int windowSize) {
super(x, y, diameter, windowSize);
}
public void setRandomColor(){
Random r1 = new Random();
Random r2 = new Random();
Random r3 = new Random();
r = r1.nextInt(256);
g = r2.nextInt(256);
b = r3.nextInt(256);
c = new Color(r,g,b);
setBackground(c);
}
public void setRandomDirection(){
Random r1 = new Random();
Random r2 = new Random();
int rightOrLeft = r1.nextInt(2);
int upOrDown = r2.nextInt(2);
if (rightOrLeft == 0){
xDelta = LEFT;
}else{
xDelta = RIGHT;
}
if (upOrDown == 0){
yDelta = UP;
}else{
yDelta = DOWN;
}
}
public void checkCollision(Blob blobs){
//setRandomDirection();
//setRandomColor();
}
}
You have two Blob instances in checkCollision. The parameter blobs and this. For example,
public void checkCollision(Blob blobs) {
// this is blobs[i] and blobs is blobs[j]
if ((this.x + this.diameter) == (blobs.x + blobs.diameter)
&& ((this.y + this.diameter == blobs.y + blobs.diameter))) {
// ...
}
}
Related
For my project we have to have four square moving and bouncing off the sides and when it hits a side it changes color. When you click on one of the squares it freezes and turns red. So far i have the four squares and when I click them it says it freezes them. However, I'm not positive how to get them to move and bounce off the sides. Below is the code i have written so far.
MAIN:
import java.util.Random;
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
StationarySquare[] squares = new StationarySquare[4];
Random rng = new Random();
for (int i = 0; i < squares.length; i++) {
squares[i] = new StationarySquare(rng.nextDouble(), rng.nextDouble());
}
while (true) {
StdDraw.clear();
int count = 0;
for (int i = 0; i < squares.length; i++) {
squares[i].draw();
if (StdDraw.mousePressed()
&& squares[i].containsPoint(StdDraw.mouseX(), StdDraw.mouseY())) {
squares[i].freeze();
}
if (squares[i].isFrozen()) {
count++;
}
}
StdDraw.text(0.5, 0.5, "Frozen: " + count);
StdDraw.show(25);
}
}
}
My other class
import java.util.Random;
public class StationarySquare {
private double x;
private double y;
private double halfLength;
private int red;
private int green;
private int blue;
private boolean isFrozen;
public StationarySquare(double x, double y) {
this.x = x;
this.y = y;
halfLength = 0.1;
isFrozen = false;
randomColor();
}
public void draw() {
if (isFrozen) {
StdDraw.setPenColor(StdDraw.RED);
} else {
StdDraw.setPenColor(red, green, blue);
}
StdDraw.filledSquare(x, y, halfLength);
}
public void randomColor() {
Random rng = new Random();
red = rng.nextInt(256);
green = rng.nextInt(256);
blue = rng.nextInt(256);
}
public void freeze() {
isFrozen = true;
}
public boolean containsPoint(double a, double b) {
return a > x - halfLength &&
a < x + halfLength &&
b > y - halfLength &&
b < y + halfLength;
}
public boolean isFrozen() {
return isFrozen;
}
}
I'm creating a game that has randomly drawn Asteroids (to give the Asteroids a jagged look). After research I've only found that you can fill primitive shapes. Does anyone know a method I could use to fill these shapes?
package view.game_object;
import java.awt.Color;
import java.awt.Graphics;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Random;
public class Asteroid extends BaseGameObject {
public static final int BASE_SIZE = 10;
private final int fragmentCount;
private final int[][] points;
private final int level;
public Asteroid(int level, Random r) {
this.level = level;
this.setBound(level * Asteroid.BASE_SIZE);
int sizeRange = (int) (this.getBound() / 2);
this.fragmentCount = this.level * 6;
// generate random points to draw
this.setPosition(0, 0);
this.points = new int[fragmentCount][2];
ArrayList<Float> angleList = new ArrayList<>();
for (int i = 0; i < fragmentCount; i++) {
angleList.add(r.nextFloat() * (float) (Math.PI * 2));
}
Collections.sort(angleList);
for (int i = 0; i < this.points.length; i++) {
// base point
float x = r.nextInt(sizeRange) + this.getBound() - sizeRange / 3;
// rotate
float[] point = BaseGameObject.rotate(x, 0, this.getPosx(), this.getPosy(),
angleList.get(i));
this.points[i][0] = (int) point[0];
this.points[i][1] = (int) point[1];
}
}
public int getLevel() {
return level;
}
#Override
public void draw(Graphics g) {
g.setColor(Color.gray);
for (int i = 0; i < this.points.length; i++) {
int nextPoint = i + 1;
if (nextPoint >= this.points.length) {
nextPoint = 0;
}
g.drawLine(Math.round(this.getPosx()) + this.points[i][0],
Math.round(this.getPosy()) + this.points[i][1],
Math.round(this.getPosx()) + this.points[nextPoint][0],
Math.round(this.getPosy()) + this.points[nextPoint][1]
);
}
}
}
you can use the Graphics methods to draw a polygon. but you must 'transform' your points into a proper format getXs(), i didn't point that out, i'm pretty sure you can do this as good as i can =)
#Override
public void draw(Graphics g) {
g.setColor(Color.gray); //fillColor
int[] xPoints = getXs(this.points);
int[] yPoints = getYs(this.points);
int nPoints = xPoints.length;
g.fillPolygon(xPoints, yPoints, nPoints);
}
I'm finishing up a coding assignment that requires me to set an array of blocks in motion, bouncing off of the window and each other, but unfortunately I'm totally lost as to where to go next. Any help would be appreciated (still getting the hang of coding, so I'm looking for all the help possible). Specifically, I need the rectangles to appear first, and then troubleshoot movement, and finally help with collision detection.
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class Driver implements ActionListener
{
private JFrame window;
private Timer timer;
private ChaseBlock[] blocks = new ChaseBlock[15];
// constants for graphics
private final int windowSize = 500;
private final int blockSize = 20;
/**
* Simple initiating main().
*
* #param args Not used.
*/
public static void main( String[] args )
{
Driver d = new Driver();
d.createWindow();
}
/**
* Set up the basic graphical objects.
*/
private void createWindow()
{
// create the window
window = new JFrame( "The Great Chase" );
window.setVisible( true );
window.setLayout( null );
window.getContentPane().setBackground( Color.white );
window.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
window.setLocation( 50, 50 );
window.setSize(
windowSize + window.getInsets().left + window.getInsets().right,
windowSize + window.getInsets().top + window.getInsets().bottom );
window.setResizable( false );
window.repaint();
timer = new Timer(10, this);
timer.start();
blocks[1].setBackground(Color.blue);
window.repaint();
addBlocks();
}
private void addBlocks() {
for (int i = 0; i < blocks.length; i++) {
int x = i * blockSize + 10 * (i +1);
blocks[i] = new ChaseBlock(x, windowSize / x - blockSize / 2, blockSize, windowSize);
}
for (int i = 0; i < blocks.length; i++) {
window.add(blocks[i]);
}
}
private void animate() {
for (int i = 0; i < blocks.length; i++) {
blocks[i].move();
for (int b1 = 0; b1 < blocks.length; b1++)
for (int b2 = 0; b2 < blocks.length; b2++)
if (b1 != b2)
blocks[b1].checkCollision(blocks[b2]);
}
}
public void actionPerformed (ActionEvent e) {
animate();
}
}
This is the driver class that we use, with a Rectangle class also. Near to the bottom, the goal is to add the rectangles and make them move. My problem here is that the rectangles do not show up whatsoever or move.
import java.awt.Color;
public class ChaseBlock extends Rectangle {
private int dX, dY;
private int windowWidth = 500;
private int windowHeight = 500;
public ChaseBlock(int x, int y, int w, int h) {
super(x, y, w, h );
if (Math.random() < 0.5) {
dX = -1;
dY = -1;
setBackground(Color.green);
} else
dX = 1;
dY = 1;
setBackground(Color.blue);
}
public void move() {
setLocation(getX(), getY() + 5);
if(getX() < 0 || getY() + getWidth() >= windowWidth) {
dX = dX * -1;
}
if (getY() < 0 || getY() + getHeight() >= windowHeight) {
dY = dY * -1;
}
}
public void checkCollision(ChaseBlock blocks) {
boolean up = false;
boolean down = false;
boolean left = false;
boolean right = false;
boolean hit = false;
}
}
This is my class to define the movement and everything else. My problems here are that I need to use the checkCollision method to manage the collisions between the blocks themselves and the window, and in addition set colors for all the blocks.
First of all, the first condition for collision checks with window edges is incorrect. It should be
if(getX() < 0 || getX() + getWidth() >= windowWidth)
To detect collisions between two Axis Aligned Bounding Boxes (which is what you have as Rectangles), you just have to check whether the first's min and max points (x,y and x+h, y+h) are inside the second as follows:
if(a.x + a.h < b.x or a.x > b.x + b.h) return false;
if(a.y + a.h < b.y or a.y > b.y + b.h) return false;
return true;
If you want to find out which face (or which direction) the collision takes place on, you'll have to use the more long and slightly more complicated Separating Axis Theorem.
I have a bunch of variable sized rectangles, which are laid out randomly in an area.
I am attempting to do (recursive) collision detection that ensures that they do not collide, by shifting their positions.
But, something is still wrong (some of the rectangles still collide), and I can't figure out what.. probably my inability to do recursion right. I would be grateful if someone checked this out.
Here's the code, just copy & paste & run it, and you'll see the result instantly. Requires JavaFx:
import javafx.application.Application;
import javafx.geometry.Point2D;
import javafx.geometry.Rectangle2D;
import javafx.scene.Scene;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;
import java.util.*;
public class Example extends Application {
public static void main(String[] args) {
launch(args);
}
private Pane root = new Pane();
#Override
public void start(Stage stage) throws Exception {
Scene scene = new Scene(root, 800, 600);
stage.setTitle("Collision Problem");
stage.setScene(scene);
stage.setOnCloseRequest(e -> System.exit(0));
stage.show();
run();
}
private static class Node2D {
private double x, y, w, h;
public Node2D() {
w = randInt(40, 80);
h = randInt(20, 40);
}
public void setPosition(double x, double y) {
this.x = x;
this.y = y;
}
public double getWidth() {
return w;
}
public double getHeight() {
return h;
}
}
private static class LayoutEntity {
private Node2D obj = new Node2D();
private double x, y;
public void setLocationInLayout(double x, double y) {
this.x = x;
this.y = y;
}
public double getXInLayout() {
return x;
}
public double getYInLayout() {
return y;
}
}
public void run() {
LayoutEntity[] entitiesToLayout = new LayoutEntity[100];
for (int i = 0; i < entitiesToLayout.length; i++)
entitiesToLayout[i] = new LayoutEntity();
randomizePositions(entitiesToLayout);
collisionDetection(entitiesToLayout);
for (LayoutEntity entity : entitiesToLayout) {
Node2D node = entity.obj;
node.setPosition(entity.getXInLayout(), entity.getYInLayout());
}
// Print possible collisions
displayNodes(entitiesToLayout);
}
private void displayNodes(LayoutEntity[] all) {
for (LayoutEntity entity : all) {
Node2D node = entity.obj;
Rectangle rect = new Rectangle(node.x, node.y, node.w, node.h);
rect.setStroke(Color.BLACK);
rect.setFill(null);
root.getChildren().add(rect);
}
}
private void randomizePositions(LayoutEntity[] entities) {
for (LayoutEntity entity : entities) {
entity.setLocationInLayout(randInt(0, 512), randInt(0, 512));
}
}
private void collisionDetection(LayoutEntity[] entities) {
collisionDetection(Arrays.asList(entities));
}
private void collisionDetection(Collection<LayoutEntity> c) {
List<LayoutEntity> collisions = new ArrayList<>();
for (LayoutEntity e1 : c) {
for (LayoutEntity e2 : c) {
if (e1 == e2)
continue;
boolean collides = checkAndResolveCollision(e1, e2);
if (collides)
collisions.add(e1);
}
}
checkRecursively(collisions, c);
}
private void checkRecursively(List<LayoutEntity> collisions,
Collection<LayoutEntity> all) {
if (collisions.isEmpty())
return;
for (LayoutEntity e1 : all) {
for (int i = 0; i < collisions.size(); i++) {
LayoutEntity e2 = collisions.get(i);
if (e2 == e1)
continue;
boolean collides = checkAndResolveCollision(e1, e2);
if (collides) {
if (collisions.contains(e1))
continue;
collisions.add(e1);
checkRecursively(collisions, all);
}
}
}
}
private boolean checkAndResolveCollision(LayoutEntity e1, LayoutEntity e2) {
Node2D n1 = e1.obj;
// Ideally, I also want to add a gap around the boxes
double extraSpace = 0;
double w1 = n1.getWidth() + extraSpace * 2;
double h1 = n1.getHeight() + extraSpace * 2;
Rectangle2D b1 = new Rectangle2D(e1.getXInLayout() - extraSpace,
e1.getYInLayout() - extraSpace, w1, h1);
Node2D n2 = e2.obj;
double w2 = n2.getWidth() + extraSpace * 2;
double h2 = n2.getHeight() + extraSpace * 2;
Rectangle2D b2 = new Rectangle2D(e2.getXInLayout() - extraSpace,
e2.getYInLayout() - extraSpace, w2, h2);
if (b1.intersects(b2)) {
Point2D trans = getMinimumTranslation(b1, b2);
double x = e1.getXInLayout() + trans.getX();
double y = e1.getYInLayout() + trans.getY();
e1.setLocationInLayout(x, y);
return true;
}
return false;
}
private Point2D getMinimumTranslation(Rectangle2D source, Rectangle2D target) {
double mtdx, mtdy;
Point2D amin = new Point2D(source.getMinX(), source.getMinY());
Point2D amax = new Point2D(source.getMaxX(), source.getMaxY());
Point2D bmin = new Point2D(target.getMinX(), target.getMinY());
Point2D bmax = new Point2D(target.getMaxX(), target.getMaxY());
double left = (bmin.getX() - amax.getX());
double right = (bmax.getX() - amin.getX());
double top = (bmin.getY() - amax.getY());
double bottom = (bmax.getY() - amin.getY());
if (left > 0 || right < 0)
return Point2D.ZERO;
if (top > 0 || bottom < 0)
return Point2D.ZERO;
if (Math.abs(left) < right)
mtdx = left;
else
mtdx = right;
if (Math.abs(top) < bottom)
mtdy = top;
else
mtdy = bottom;
// zero the axis with the largest mtd value.
if (Math.abs(mtdx) < Math.abs(mtdy))
mtdy = 0;
else
mtdx = 0;
return new Point2D(mtdx, mtdy);
}
private static Random rand = new Random();
public static int randInt(int min, int max) {
return rand.nextInt((max - min) + 1) + min;
}
}
From reading your code, what I can predict is, the problem is in the logic. Inside checkAndResolveCollision(), when you assigning a new co-ordinate to the Node using
e1.setLocationInLayout(x, y);
you miss to check whether the new co-ordinate that you have assigned to this node, overlaps any of the other node's which we have already checked against this one.
You will have to generate the logic, as to whenever you are changing the co-ordinate of a Node, it must again be checked against every other Node
Hope it helps
Okay, so I'm in the progress of making a game, and I need the collisions to work. I have an if() { } else if() {} -statement, but BOTH of them are being called. Here is my code:
Inside my Player Class:
public Rectangle[] tileRect;
public void update() {
tileRect = new Rectangle[Level1.tiles.size()];
for (int w = 0; w < Level1.tiles.size(); w++) {
Tile m = (Tile) Level1.tiles.get(w);
tileRect[w] = m.getBounds();
if(tileRect[w].intersects(getRect())) {
System.out.println("intersecting");
dy = 0;
} else if (!tileRect[w].intersects(getRect())){
dy = 4;
}
}
x += dx;
y += dy;
}
public Rectangle getRect() {
return new Rectangle(x, y, 32, 32);
}
Here is my Tile class (the Level1.tiles is an arrayList of tiles):
package level;
import java.awt.Rectangle;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
public class Tile extends Rectangle {
// Defines the id of the tile, used for setting textures.
private static final long serialVersionUID = 1L;
public int id;
// Location
public int x;
public int y;
// Variables for the terrain sprite sheet.
public BufferedImage image;
public String imageLocation;
public BufferedImage[] sprite;
public int rows = 16;
public int collumns = 16;
public int width = 16;
public int height = 16;
public Tile(int idVal, int xPos, int yPos) {
x = xPos * 32;
y = yPos * 32;
id = idVal;
setBounds(x, y, 32, 32);
createImages();
}
public BufferedImage getImage() {
return sprite[id];
}
public void createImages() {
imageLocation = "res/tile/terrain.png";
try {
image = ImageIO.read(new File(imageLocation));
} catch (IOException e) {
System.out.println("Unable to find file " + imageLocation
+ ", printing stack trace!");
e.printStackTrace();
}
sprite = new BufferedImage[rows * collumns];
for (int i = 0; i < rows; i++) {
for (int j = 0; j < collumns; j++) {
sprite[(i * collumns) + j] = image.getSubimage(j * width, i
* height, width, height);
}
}
}
public int getXLoc() {
return x;
}
public int getYLoc() {
return y;
}
public void setX(int xPos) {
x = xPos;
}
public void setY(int yPos) {
y = yPos;
}
}
I'm getting the "intersecting" message in the console, but the player is still falling down (because dy = 4). Please help! I've been trying to solve this all morning...
If and Else cannot both be caught at the same time.
Looks like you are looping through, seeing an intersection, then continuing to loop through regardless.
Try adding a break command to your for loop.
if(tileRect[w].intersects(getRect())) {
System.out.println("intersecting");
dy = 0;
break;
} else if (!tileRect[w].intersects(getRect())){
dy = 4;
}
The break will stop your for loop from continuing and you will exit the loop with dy = 0; rather than going onto the next tile and changing it back to dy = 4;
if and else if cannot be called in the same run. If if condition is true, then any else is never run (not even checked). It's probably different runs. Debug or put a log to see the flow.
Also
if(tileRect[w].intersects(getRect())) {
System.out.println("intersecting");
dy = 0;
} else if (!tileRect[w].intersects(getRect())){
dy = 4;
}
is much simpler written as
if(tileRect[w].intersects(getRect())) {
System.out.println("intersecting");
dy = 0;
} else {
dy = 4;
}