LWJGL FPS Drop When Loading Textures - java

Currently i'm using LWJGL to make a 2D game. But I've run into an issue. I am trying to make an "infinite world" but an issue comes up because if I create a lot of objects the frames drop and I believe it has to do with the amount of textures being loaded to objects.
Currently I'm creating my world in a grid fashion like this
for(int x = -WORLDWIDTH; x < WORLDWIDTH; x+= BW)
{
for(int y = -WORLDHEIGHT; y < WORLDHEIGHT; y += BH)
{
Tile newTile = new Tile(x,y,BW,BH,TileType.Grass);
tiles.add(newTile);
}
}
Where BW and BH are the block width and height. I try to keep texture loading to only objects on screen using this if statement
if(x >= 0-BW && x + width < WIDTH+BW && y >= 0-BH && y+ height < HEIGHT+BH)
{
DrawQuadTexRotate(getTexture(), getX(), getY(), getWidth(),getHeight(),angle);
}
To load textures I do this
public static void DrawQuadTexRotate(Texture tex, float x, float y, float width, float height, float angle)
{
tex.bind();
glTranslatef(x + width / 2, y + height / 2, 0);
glRotatef(angle, 0 ,0 , 1);
glTranslatef(- width / 2, - height / 2, 0);
glBegin(GL_QUADS);
glTexCoord2f(0,0);
glVertex2f(0,0);
glTexCoord2f(1,0);
glVertex2f(width,0);
glTexCoord2f(1,1);
glVertex2f(width,height);
glTexCoord2f(0,1);
glVertex2f(0,height);
glEnd();
glLoadIdentity();
}
public static Texture LoadTexture(String path, String fileType)
{
Texture tex = null;
InputStream in = ResourceLoader.getResourceAsStream(path);
try {
tex = TextureLoader.getTexture(fileType, in);
} catch (IOException e) {
e.printStackTrace();
}
return tex;
}
The Tile class basically has methods to do certain things based on what type it is. It holds the width, height, x, y and texture which my DrawQuadTex method uses
Here is the tile class
public class Tile {
public float x, y, width, height, angle;
private Texture texture;
private TileType type;
public long timeStart = 0;
public int filled = 1;
public int power = 0;
public int transmitPower = 0;
int connected = 0;
public boolean moveRight,moveLeft,moveUp,moveDown,moveAngle;
public Tile(float x, float y, float width, float height,TileType type)
{
this.x = x;
this.y = y;
this.width = width;
this.height = height;
this.type = type;
this.texture = QuickLoad(type.textureName);
timeStart = Timer.getTime();
updateType();
updateFill();
}
public void draw()
{
if(x >= 0-BW && x + width < WIDTH+BW && y >= 0-BH && y+ height < HEIGHT+BH)
{
DrawQuadTexRotate(getTexture(), getX(), getY(), getWidth(),getHeight(),angle);
}
}
public void addFood()
{
if(this.type == TileType.Farm && filled == 1)
{
long timing = Timer.getTime();
if(timing >= (timeStart + 10000))
{
Values.food += (1+Artist.riverAmount);
timeStart = timing;
}
}
}
public void mineOre()
{
if(this.type == TileType.Mine && filled == 1)
{
long timing = Timer.getTime();
if(timing >= (timeStart + 20000))
{
for(int i = 0; i < tiles.size();i++)
{
if(tiles.get(i).getType() == TileType.Ore)
{
tiles.get(i).setType(TileType.LandTile);
Values.oreAmount += 1;
timeStart = timing;
break;
}
}
}
}
}
public void move()
{
if(moveRight == true)
{
x -= 10;
}
if(moveLeft == true)
{
x += 10;
}
if(moveUp == true)
{
y += 10;
}
if(moveDown == true)
{
y -= 10;
}
}
public void testPower()
{
for(int i = 0; i < tiles.size(); i++)
{
if(tiles.get(i).x >= x - BW && tiles.get(i).x <= x + BW && tiles.get(i).y >= y - BH && tiles.get(i).y <= y + BH && tiles.get(i).getType() == TileType.Wire && tiles.get(i).transmitPower == 1 && type == TileType.HomeBasic)
{
power = 1;
break;
}
else
{
power = 0;
}
if(tiles.get(i).x >= x - BW && tiles.get(i).x <= x + BW && tiles.get(i).y >= y - BH && tiles.get(i).y <= y + BH && (tiles.get(i).transmitPower == 1 || tiles.get(i).type == TileType.PowerPlant) && type == TileType.Wire)
{
transmitPower = 1;
break;
}
else if(tiles.get(i).type == TileType.Wire && tiles.get(i).transmitPower == 0)
{
transmitPower = 0;
}
else
{
transmitPower = 0;
}
}
}
public void updateFill()
{
if(type == TileType.HomeBasic || type == TileType.Farm || type == TileType.Mine)
{
filled = 0;
}
}
public void stats()
{
if(type == TileType.HomeBasic)
{
//wt.drawString((int)x, (int)(y-25), Integer.toString(filled), Color.white);
}
}
public float getX() {
return x;
}
public void setX(float x) {
this.x = x;
}
public float getY() {
return y;
}
public void setY(float y) {
this.y = y;
}
public float getWidth() {
return width;
}
public void setWidth(float width) {
this.width = width;
}
public float getHeight() {
return height;
}
public void setHeight(float height) {
this.height = height;
}
public Texture getTexture() {
return texture;
}
public void setTexture(Texture texture) {
this.texture = texture;
}
public TileType getType() {
return type;
}
public void setType(TileType type) {
this.type = type;
updateType();
}
public void updateType()
{
this.texture = QuickLoad(type.textureName);
timeStart = Timer.getTime();
updateFill();
}
}
public static Texture QuickLoad(String name)
{
Texture tex = null;
tex = LoadTexture("res/" + name + ".png", "PNG");
return tex;
}
So how would I go about trying to fix this?

Related

Android stop sprite from changing subimages when staying

Currently my sprite animates like it was in movement not only when is in movement but also when it stays in one place. Of course I want to stay still without animation when it stays in one place. How to solve that?
public abstract class GameMovingObject {
private static final int ROW_TOP_TO_BOTTOM = 0;
private static final int ROW_RIGHT_TO_LEFT = 1;
private static final int ROW_LEFT_TO_RIGHT = 2;
private static final int ROW_BOTTOM_TO_TOP = 3;
public boolean justSeen=true;
protected Bitmap image;
private final int rowCount, colCount;
protected final int WIDTH, HEIGHT;
private final int width, height;
private int x;
public int getX() { return this.x; }
public void setX(int x) { this.x = x; }
private int y;
public int getY() { return this.y; }
public void setY(int y) { this.y = y; }
// Row index of Image are being used.
private int rowUsing = ROW_LEFT_TO_RIGHT;
private int colUsing;
private Bitmap[] leftToRights;
private Bitmap[] rightToLefts;
private Bitmap[] topToBottoms;
private Bitmap[] bottomToTops;
// Velocity of game character (pixel/millisecond)
public float velocity = 0.15f;
public int getMovingVectorX() {
return movingVectorX;
}
public int getMovingVectorY() {
return movingVectorY;
}
public int movingVectorX = 0;
public int movingVectorY = 0;
public long lastDrawNanoTime =-1;
public GameSurface gs;
public GameMovingObject(GameSurface gs, Bitmap image, int rowCount, int colCount, int x, int y) {
this.gs = gs;
this.image = image;
this.rowCount = rowCount;
this.colCount = colCount;
this.x = x;
this.y = y;
this.WIDTH = image.getWidth();
this.HEIGHT = image.getHeight();
this.width = this.WIDTH / colCount;
this.height = this.HEIGHT / rowCount;
this.topToBottoms = new Bitmap[colCount]; // 3
this.rightToLefts = new Bitmap[colCount]; // 3
this.leftToRights = new Bitmap[colCount]; // 3
this.bottomToTops = new Bitmap[colCount]; // 3
for(int col = 0; col< this.colCount; col++ ) {
this.topToBottoms[col] = this.createSubImageAt(ROW_TOP_TO_BOTTOM, col);
this.rightToLefts[col] = this.createSubImageAt(ROW_RIGHT_TO_LEFT, col);
this.leftToRights[col] = this.createSubImageAt(ROW_LEFT_TO_RIGHT, col);
this.bottomToTops[col] = this.createSubImageAt(ROW_BOTTOM_TO_TOP, col);
}
}
public Bitmap[] getMoveBitmaps() {
switch (rowUsing) {
case ROW_BOTTOM_TO_TOP:
return this.bottomToTops;
case ROW_LEFT_TO_RIGHT:
return this.leftToRights;
case ROW_RIGHT_TO_LEFT:
return this.rightToLefts;
case ROW_TOP_TO_BOTTOM:
return this.topToBottoms;
default:
return null;
}
}
public void setMovingVector(int movingVectorX, int movingVectorY) {
this.movingVectorX= movingVectorX;
this.movingVectorY = movingVectorY;
}
public Bitmap getCurrentMoveBitmap() {
Bitmap[] bitmaps = this.getMoveBitmaps();
return bitmaps[this.colUsing];
}
public void draw(Canvas canvas) {
Bitmap bitmap = this.getCurrentMoveBitmap();
canvas.drawBitmap(bitmap,x, y, null);
// Last draw time.
this.lastDrawNanoTime= System.nanoTime();
}
public void update() {
this.colUsing++;
if(colUsing >= this.colCount) {
this.colUsing =0;
}
// Current time in nanoseconds
long now = System.nanoTime();
// Never once did draw.
if(lastDrawNanoTime==-1) {
lastDrawNanoTime= now;
}
// Change nanoseconds to milliseconds (1 nanosecond = 1000000 milliseconds).
int deltaTime = (int) ((now - lastDrawNanoTime)/ 777777 );
// Distance moves
float distance = velocity * deltaTime;
double movingVectorLength = Math.sqrt(movingVectorX* movingVectorX + movingVectorY*movingVectorY);
// Calculate the new position of the game character.
this.x = x + (int)(distance* movingVectorX / movingVectorLength);
this.y = y + (int)(distance* movingVectorY / movingVectorLength);
// When the game's character touches the edge of the screen, then change direction
if(this.x < 0 ) {
this.x = 0;
this.movingVectorX = - this.movingVectorX;
} else if(this.x > this.gs.getWidth() -width) {
this.x= this.gs.getWidth()-width;
this.movingVectorX = - this.movingVectorX;
}
if(this.y < 0 ) {
this.y = 0;
this.movingVectorY = - this.movingVectorY;
}
// rowUsing (obraca postać)
if( movingVectorX > 0 ){
if(movingVectorY > 0 && Math.abs(movingVectorX) < Math.abs(movingVectorY)) {
this.rowUsing = ROW_TOP_TO_BOTTOM;
}
else if(movingVectorY < 0 && Math.abs(movingVectorX) < Math.abs(movingVectorY)) {
this.rowUsing = ROW_BOTTOM_TO_TOP;
}
else {
this.rowUsing = ROW_LEFT_TO_RIGHT;
}
}
else
{
if(movingVectorY > 0 && Math.abs(movingVectorX) < Math.abs(movingVectorY)) {
this.rowUsing = ROW_TOP_TO_BOTTOM;
}
else if(movingVectorY < 0 && Math.abs(movingVectorX) < Math.abs(movingVectorY)) {
this.rowUsing = ROW_BOTTOM_TO_TOP;
}
else if(movingVectorX!=0 || movingVectorY!=0) {
this.rowUsing = ROW_RIGHT_TO_LEFT;
}
}
}
protected Bitmap createSubImageAt(int row, int col) {
// createBitmap(bitmap, x, y, width, height).
Bitmap subImage = Bitmap.createBitmap(image, col * width, row * height, width, height);
return subImage;
}
public int getHeight() {
return height;
}
public int getWidth() {
return width;
}
I was trying to add
if(movingVectorY!=0) this.topToBottoms[col] = this.createSubImageAt(ROW_TOP_TO_BOTTOM, col);
else this.topToBottoms[1] = this.createSubImageAt(ROW_TOP_TO_BOTTOM, 1);
but then sprite blinks and is without animation even when moving. I think I added everything you need to know. It there is anything you want me to add just ask me. Thank you in advance.

Intersection of Rectangles for Java (Freeze Tag)

**Edited still not getting the right response **
I am not quite understanding how to figure out the intersection aspect of my project. So far I have determined the top, bottom, left and right but I am not sure where to go from there.
The main driver should call to check if my moving rectangles are intersecting and if the rectangle is froze the moving one intersecting with it should unfreeze it and change its color. I understand how to unfreeze it and change the color but for whatever the reason it isn't returning the value as true when they are intersecting and I know this code is wrong. Any helpful tips are appreciated.
*CLASS CODE*
import edu.princeton.cs.introcs.StdDraw;
import java.util.Random;
import java.awt.Color;
public class MovingRectangle {
Random rnd = new Random();
private int xCoord;
private int yCoord;
private int width;
private int height;
private int xVelocity;
private int yVelocity;
private Color color;
private boolean frozen;
private int canvas;
public MovingRectangle(int x, int y, int w, int h, int xv, int yv, int canvasSize) {
canvas = canvasSize;
xCoord = x;
yCoord = y;
width = w;
height = h;
xVelocity = xv;
yVelocity = yv;
frozen = false;
int c = rnd.nextInt(5);
if (c == 0) {
color = StdDraw.MAGENTA;
}
if (c == 1) {
color = StdDraw.BLUE;
}
if (c == 2) {
color = StdDraw.CYAN;
}
if (c == 3) {
color = StdDraw.ORANGE;
}
if (c == 4) {
color = StdDraw.GREEN;
}
}
public void draw() {
StdDraw.setPenColor(color);
StdDraw.filledRectangle(xCoord, yCoord, width, height);
}
public void move() {
if (frozen == false) {
xCoord = xCoord + xVelocity;
yCoord = yCoord + yVelocity;
}
else {
xCoord +=0;
yCoord +=0;
}
if (xCoord >= canvas || xCoord < 0) {
xVelocity *= -1;
this.setRandomColor();
}
if (yCoord >= canvas || yCoord < 0) {
yVelocity *= -1;
this.setRandomColor();
}
}
public void setColor(Color c) {
StdDraw.setPenColor(color);
}
public void setRandomColor() {
int c = rnd.nextInt(5);
if (c == 0) {
color = StdDraw.MAGENTA;
}
if (c == 1) {
color = StdDraw.BLUE;
}
if (c == 2) {
color = StdDraw.CYAN;
}
if (c == 3) {
color = StdDraw.ORANGE;
}
if (c == 4) {
color = StdDraw.GREEN;
}
}
public boolean containsPoint(double x, double y) {
int bottom = yCoord - height / 2;
int top = yCoord + height / 2;
int left = xCoord - width / 2;
int right = xCoord + width / 2;
if (x > left && x < right && y > bottom && y < top) {
color = StdDraw.RED;
return true;
} else {
return false;
}
}
public boolean isFrozen() {
if (frozen) {
return true;
} else {
return false;
}
}
public void setFrozen(boolean val) {
frozen = val;
}
public boolean isIntersecting(MovingRectangle r) {
int top = xCoord + height/2;
int bottom = xCoord - height/2;
int right = yCoord + width/2;
int left = yCoord - width/2;
int rTop = r.xCoord + r.height/2;
int rBottom = r.xCoord - r.height/2;
int rRight = r.yCoord + r.width/2;
int rLeft = r.yCoord - r.width/2;
if(right <= rRight && right >= rLeft || bottom <= rBottom && bottom
>= rTop){
return true;
} else {
return false;
}
}
}
Here is my main driver as well, because I might be doing something wrong here too.
import edu.princeton.cs.introcs.StdDraw;
import java.util.Random;
public class FreezeTagDriver {
public static final int CANVAS_SIZE = 800;
public static void main(String[] args) {
StdDraw.setCanvasSize(CANVAS_SIZE, CANVAS_SIZE);
StdDraw.setXscale(0, CANVAS_SIZE);
StdDraw.setYscale(0, CANVAS_SIZE);
Random rnd = new Random();
MovingRectangle[] recs;
recs = new MovingRectangle[5];
boolean frozen = false;
for (int i = 0; i < recs.length; i++) {
int xv = rnd.nextInt(4);
int yv = rnd.nextInt(4);
int x = rnd.nextInt(400);
int y = rnd.nextInt(400);
int h = rnd.nextInt(100) + 10;
int w = rnd.nextInt(100) + 10;
recs[i] = new MovingRectangle(x, y, w, h, xv, yv, CANVAS_SIZE);
}
while (true) {
StdDraw.clear();
for (int i = 0; i < recs.length; i++) {
recs[i].draw();
recs[i].move();
}
if (StdDraw.mousePressed()) {
for (int i = 0; i < recs.length; i++) {
double x = StdDraw.mouseX();
double y = StdDraw.mouseY();
if (recs[i].containsPoint(x, y)) {
recs[i].setFrozen(true);
}
}
}
for (int i = 0; i < recs.length; i++) {
//for 0
if(recs[0].isFrozen() && recs[0].isIntersecting(recs[1])){
recs[0].setFrozen(false);
}
if(recs[0].isFrozen() && recs[0].isIntersecting(recs[2])){
recs[0].setFrozen(false);
}
if(recs[0].isFrozen() && recs[0].isIntersecting(recs[3])){
recs[0].setFrozen(false);
}
//for 1
if(recs[1].isFrozen() && recs[1].isIntersecting(recs[2])){
recs[1].setFrozen(false);
}
if(recs[1].isFrozen() && recs[1].isIntersecting(recs[3])){
recs[1].setFrozen(false);
}
if(recs[1].isFrozen() && recs[1].isIntersecting(recs[4])){
recs[1].setFrozen(false);
}
//for 2
if(recs[2].isFrozen() && recs[2].isIntersecting(recs[0])){
recs[2].setFrozen(false);
}
if(recs[2].isFrozen() && recs[2].isIntersecting(recs[1])){
recs[2].setFrozen(false);
}
if(recs[2].isFrozen() && recs[2].isIntersecting(recs[3])){
recs[2].setFrozen(false);
}
if(recs[2].isFrozen() && recs[2].isIntersecting(recs[4])){
recs[2].setFrozen(false);
}
//for 3
if(recs[3].isFrozen() && recs[3].isIntersecting(recs[0])){
recs[3].setFrozen(false);
}
if(recs[3].isFrozen() && recs[3].isIntersecting(recs[1])){
recs[3].setFrozen(false);
}
if(recs[3].isFrozen() && recs[3].isIntersecting(recs[2])){
recs[3].setFrozen(false);
}
if(recs[3].isFrozen() && recs[3].isIntersecting(recs[4])){
recs[3].setFrozen(false);
}
//for 4
if(recs[4].isFrozen() && recs[4].isIntersecting(recs[0])){
recs[4].setFrozen(false);
}
if(recs[4].isFrozen() && recs[4].isIntersecting(recs[1])){
recs[4].setFrozen(false);
}
if(recs[4].isFrozen() && recs[4].isIntersecting(recs[3])){
recs[4].setFrozen(false);
}
if(recs[4].isFrozen() && recs[4].isIntersecting(recs[2]))
recs[4].setFrozen(false);
}
if (recs[0].isFrozen() && recs[1].isFrozen() &&
recs[2].isFrozen() && recs[3].isFrozen()
&& recs[4].isFrozen()) {
StdDraw.text(400, 400, "YOU WIN");
}
StdDraw.show(20);
}
}
}
Keep in mind you're using the OR operator here. So if right is less than rLeft, your intersector will return true. This isn't how it should work.
You need to check if right is INSIDE the rectangles bounds so to speak.
if(right <= rRight && right >= rLeft || the other checks here)
The above code checks if right is less than the rectangle's right, but also that the right is bigger than rectangle's left, which means it's somewhere in middle of the rectangle's left and right.
If this becomes too complicated you can simply use java's rectangle class, as it has the methods contains and intersects

Screen Snake Collision Issue

I am a self taught programmer and I am coding Screen Snake for fun. I am using not using integers to store the position of the snake or apples, I am using doubles. I am having an issue when the snake goes through the apple. When the collide, the code does not register that it collided. I am assuming that this is because their X and Y values might be like .1 off. I have been trying to fix this for 2 weeks but have not been able to. Sorry if my code is a bit messy. I don't know exactly what you guys need from the code so I posted all of it. Also I really appreciate the help! Thanks!!
Main class:
Random random = new Random();
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
double ScreenW = screenSize.getWidth();
double ScreenH = screenSize.getHeight();
int ScreenX = (int)Math.round(ScreenW);
int ScreenY = (int)Math.round(ScreenH);
JFrame frame = new JFrame();
double x = 1, y = 1;
int size = 5;
int ticks;
private int columnCount = 25;
private int rowCount = 15;
double a = (ScreenW / columnCount) - 1;
double b = (ScreenH / rowCount) - 1;
private Key key;
private List<Rectangle2D> cells;
private Point selectedCell;
boolean up = false;
boolean down = false;
boolean right = true;
boolean left = false;
boolean running = true;
private Thread thread;
private BodyP p;
private ArrayList<BodyP> snake;
private Apple apple;
private ArrayList<Apple> apples;
double width = screenSize.width;
double height = screenSize.height;
double cellWidth = width / columnCount;
double cellHeight = height / rowCount;
double xOffset = (width - (columnCount * cellWidth)) / 2;
double yOffset = (height - (rowCount * cellHeight)) / 2;
public Max_SnakeGame() throws IOException {
System.out.println(screenSize);
System.out.println(a + "," + b);
System.out.println(ScreenH + b);
System.out.println(ScreenW + a);
frame.getContentPane().add(new Screen());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setUndecorated(true);
frame.setBackground(new Color(0, 0, 0, 0));
frame.setLocationRelativeTo(null);
frame.setMaximumSize(screenSize);
frame.setExtendedState(JFrame.MAXIMIZED_BOTH);
frame.setVisible(true);
Image img = Toolkit
.getDefaultToolkit()
.getImage(
"C:/Users/Max/My Documents/High School/Sophomore year/Graphic Disign/People art/The Mods Who Tell Pointless Stories.jpg");
frame.setIconImage(img);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
try {
new Max_SnakeGame();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
}
public class Screen extends JPanel implements Runnable {
private static final long serialVersionUID = 1L;
public Screen() {
key = new Key();
addKeyListener(key);
setMaximumSize(screenSize);
setOpaque(false);
setBackground(new Color(0, 0, 0, 0));
setFocusable(true);
snake = new ArrayList<BodyP>();
apples = new ArrayList<>();
start();
}
public void start() {
running = true;
thread = new Thread(this);
thread.start();
}
public void run() {
while (running) {
MoveUpdate();
repaint();
}
}
protected void paintComponent(Graphics g) {
super.paintComponent(g);
repaint();
Graphics2D g2d = (Graphics2D) g.create();
cells = new ArrayList<>(columnCount * rowCount);
if (cells.isEmpty()) {
for (int row = 0; row < rowCount; row++) {
for (int col = 0; col < columnCount; col++) {
Rectangle2D cell = new Rectangle2D.Double(xOffset
+ (col * cellWidth), yOffset
+ (row * cellHeight), cellWidth, cellHeight);
cells.add(cell);
}
}
}
g2d.setColor(Color.GRAY);
for (Rectangle2D cell : cells) {
g2d.draw(cell);
}
for (int i = 0; i < snake.size(); i++) {
snake.get(i).draw(g);
}
for (int i = 0; i < apples.size(); i++) {
apples.get(i).draw(g);
}
}
}
private class Key implements KeyListener {
public void keyPressed(KeyEvent e) {
int keyCode = e.getKeyCode();
if (keyCode == KeyEvent.VK_RIGHT && !left) {
up = false;
down = false;
right = true;
}
if (keyCode == KeyEvent.VK_LEFT && !right) {
up = false;
down = false;
left = true;
}
if (keyCode == KeyEvent.VK_UP && !down) {
left = false;
right = false;
up = true;
}
if (keyCode == KeyEvent.VK_DOWN && !up) {
left = false;
right = false;
down = true;
}
}
#Override
public void keyTyped(KeyEvent e) {
// TODO Auto-generated method stub
}
#Override
public void keyReleased(KeyEvent e) {
// TODO Auto-generated method stub
}
}
public void MoveUpdate() {
if (snake.size() == 0) {
p = new BodyP(x, y, a, b);
snake.add(p);
}
if (apples.size() == 0){
double x1 = random.nextInt(25);
double Ax = ((x1*a+x1+1)*10)/10;
double y1 = random.nextInt(15);
double Ay = ((y1*b+y1+1)*10)/10;
double Afx = Math.round(Ax);
double Afy = Math.round(Ay);
System.out.println("Ax:"+Afx);
System.out.println("Ay:"+Afy);
apple = new Apple(Ax, Ay, a, b);
apples.add(apple);
}
for(int i = 0; i < apples.size(); i++) {
if(Math.round(x)-1 == apples.get(i).getx() || Math.round(x) == apples.get(i).getx() && Math.round(y)== apples.get(i).gety() || Math.round(y)-1 == apples.get(i).gety()) {
size++;
apples.remove(i);
i--;
}
}
ticks++;
if (ticks > 2500000) {
if (up == true) {
if (y <= 2) {
y = ScreenH - b;
System.out.println("Y:" + y);
} else {
y -= b + 1;
System.out.println("Y:" + y);
}
}
// down loop
else if (down == true) {
if (y >= ScreenH - b) {
y = 1;
System.out.println("Y:" + y);
}
else {
y += b + 1;
System.out.println("Y:" + y);
}
}
// left loop
else if (left == true) {
if (x <= 1) {
x = ScreenW - a;
System.out.println("X:" + x);
}
else {
x -= a + 1;
System.out.println("X:" + x);
}
}
// right loop
else if (right == true) {
if (x >= ScreenW - a) {
x = 1;
System.out.println("X:" + x);
}
else {
x += a + 1;
System.out.println("X:" + x);
}
}
ticks = 0;
p = new BodyP(x, y, a, b);
snake.add(p);
// rect.setFrame(x, y, a, b);
if (snake.size() > size) {
snake.remove(0);
}
}
}
}
Snake class:
public class BodyP {
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
double ScreenW = screenSize.getWidth();
double ScreenH = screen`enter code here`Size.getHeight();
double x = 1, y = 1;
private int columnCount = 25;
private int rowCount = 15;
double a = (ScreenW / columnCount) - 1;
double b = (ScreenH / rowCount) - 1;
public BodyP(double x, double y, double a, double b) {
this.x = x;
this.y = y;
this.a = a;
this.b = b;
}
public void MoveUpdate(){
}
public void draw(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
Rectangle2D rect = new Rectangle2D.Double(x, y, a, b);
g.setColor(Color.BLACK);
g2.fill(rect);
}
public double getx() {
return x;
}
public void setx(double x) {
this.x = x;
}
public double gety() {
return y;
}
public void sety(double y) {
this.y = y;
}
}
Apple class:
public class Apple {
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
double ScreenW = screenSize.getWidth();
double ScreenH = screenSize.getHeight();
double x = 1, y = 1;
private int columnCount = 25;
private int rowCount = 15;
double a = (ScreenW / columnCount) - 1;
double b = (ScreenH / rowCount) - 1;
public Apple(double x, double y, double a, double b) {
this.x = x;
this.y = y;
this.a = a;
this.b = b;
}
public void MoveUpdate(){
}
public void draw(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
Rectangle2D rect = new Rectangle2D.Double(x, y, a, b);
g.setColor(Color.RED);
g2.fill(rect);
}
public double getx() {
return x;
}
public void setx(double x) {
this.x = x;
}
public double gety() {
return y;
}
public void sety(double y) {
this.y = y;
}
}
If you think this is due rounding errors, use Euclidean distance and compare with the desired tolerance:
final double tolerance = 1.0; // or whatsoever
double dx = snake.x - apple.x;
double dy = snake.y - apple.y;
if ( dx*dx + dy*dy < tolearance * tolerance ) ...
I suggest to implement something like Point.distanceTo(Point) method to make this convenient.

Brick Collision Java [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 8 years ago.
Improve this question
I have been working on a Breakout game and have just about everything done except for the brick collision. The ball bounces of the wall and paddle fine, but when it comes to the brick it goes straight through them. I'm pretty sure the problem is in the checkBrick() part of the main class, but have no idea what to do about it.
Main Class:
import java.awt.*;
import java.awt.event.KeyEvent;
import java.applet.*;
import java.util.Random;
import javax.swing.JOptionPane;
public class Breakout extends Applet implements Runnable {
Ball ball = new Ball();
Paddle paddle = new Paddle(135, 375);
Brick[] brick = new Brick[50];
private int bX[] = new int[50];
private int bY[] = new int[50];
private int bW[] = new int[50];
private int bH[] = new int[50];
Thread t;
Random trajectory = new Random();
boolean lose;
Image buffer = null;
// The life cycle of the Applet
// Sets up window
public void init() {
setSize(377, 500);
buffer = createImage(377, 500);
// setBackground(Color.black);
System.out.println("init()");
}
public void start() {
if (t == null) {
t = new Thread(this);
t.start();
}
System.out.println("start()");
}
public void run() {
System.out.println("run()");
Thread.currentThread().setPriority(Thread.MIN_PRIORITY);
while (!lose) {
ball.move();
paddle.move();
checkWall();
checkPaddle();
checkBrick();
ball.move();
repaint();
try {
Thread.sleep(30);
} catch (InterruptedException ex) {
}
Thread.currentThread().setPriority(Thread.MAX_PRIORITY);
}
JOptionPane.showMessageDialog(null, "Game Over");
System.out.println("Termintated");
System.exit(0);
}
public void stop() {
System.out.println("stop()");
}
public void destroy() {
System.out.println("destroy()");
}
public void paint(Graphics g) {
Graphics screen = null;
screen = g;
g = buffer.getGraphics();
g.setColor(Color.black);
g.fillRect(0, 0, 377, 500);
createBricks(g);
createPaddle(g);
createBall(g);
screen.drawImage(buffer, 0, 0, this);
}
public void update(Graphics g) {
paint(g);
}
private void createBricks(Graphics g) {
int brickIndex = 0;
int brickX = 15, brickY = 160;
int brickW = 30, brickH = 10;
for (int i = 0; i <= 4; i++) {
brickX = 15;
brickY -= 20;
for (int n = 0; n < 10; n++) {
brick[brickIndex] = new Brick();
brick[brickIndex].setBounds(brickX, brickY, brickW, brickH);
bX[brickIndex] = brick[brickIndex].x();
bY[brickIndex] = brick[brickIndex].y();
bW[brickIndex] = brick[brickIndex].w();
bH[brickIndex] = brick[brickIndex].h();
brick[brickIndex].setColor(i);
brick[brickIndex].paint(g);
brickIndex++;
brickX += 35;
}
}
}
private void createPaddle(Graphics g) {
paddle.paint(g);
}
private void createBall(Graphics g) {
ball.paint(g);
}
private void checkWall() {
// If ball hits right wall it will bounce
if ((ball.getX() + ball.getR()) >= 380) {
ball.setVX(trajectory.nextInt(2) + -3);
}
// If ball hits left wall it will bounce
if ((ball.getX() - ball.getR()) < -10) {
ball.setVX(trajectory.nextInt(4) + 1);
}
// If ball hits ceiling it will bounce
if ((ball.getY() + ball.getR()) < 12)
ball.setVY(trajectory.nextInt(5) + 1);
// If ball goes through floor it will subtract a life
if ((ball.getY() + ball.getR()) > 515)
lose = true;
}
private void checkBrick() {
for (int i = 0; i < 50; i++) {
int tempX, tempY, tempW, tempH;
tempX = bX[i];
tempY = bY[i];
tempW = bW[i];
tempH = bH[i];
if ((ball.getX() + ball.getR()) < (tempX + tempW)
&& (ball.getX() + ball.getR()) >= tempX) {
if ((ball.getY() + ball.getR()) > (tempY + tempH)
&& (ball.getY() + ball.getR()) <= tempY) {
System.out.println("Brick " + i + " has been hit.");
}
}
}
}
private void checkPaddle() {
// Check for paddle
if ((ball.getX() + ball.getR()) < (paddle.getX() + 100)
&& (ball.getX() + ball.getR()) >= paddle.getX() + 5) {
if ((ball.getY() + ball.getR()) > (paddle.getY() - 5)
&& (ball.getY() + ball.getR()) <= (paddle.getY() + 5)) {
ball.setVX((trajectory.nextInt(7) + -2) + 1);
ball.setVY(trajectory.nextInt(1) + -3);
}
}
}
// Key Detectors
public boolean keyDown(Event e, int key) {
if (key == Event.RIGHT) {
paddle.setVX(0);
if ((paddle.getX() + 100) < 377)
paddle.setVX(10);
}
if (key == Event.LEFT) {
paddle.setVX(0);
if (paddle.getX() > 0)
paddle.setVX(-10);
}
return true;
}
// To make sure it doesn't just keep moving one way
public boolean keyUp(Event e, int key) {
paddle.setVX(0);
return true;
}
}
Ball Class:
import java.awt.Color;
import java.awt.Graphics;
import java.util.Random;
public class Ball
{
private int x, y; //Position
private int vx, vy; //Velocity
private int r; //radius
//constructor
public Ball()
{
x = 177;
y = 315;
vx = 0;
vy = 5;
r = 15;
}
public void paint(Graphics g)
{
g.setColor(Color.white);
g.fillOval(x, y, r, r);
}
//returns the x of origin
public int getX()
{
return x;
}
//returns the y of origin
public int getY()
{
return y;
}
public int getVX()
{
return vx;
}
//returns the y of origin
public int getVY()
{
return vy;
}
//returns the radius r of the ball
public int getR()
{
return r;
}
//sets the velocity of x to a different value
public void setVX(int vx)
{
this.vx = vx;
}
//sets the velocity of y to a different value
public void setVY(int vy)
{
this.vy = vy;
}
//sets the x value
public void setX(int x)
{
this.x = x;
}
//sets the y value
public void setY(int y)
{
this.y = y;
}
//starts making the ball move by changing its coords
public void move()
{
x+= vx;
y+= vy;
}
}
Paddle Class:
import java.awt.Color;
import java.awt.Graphics;
public class Paddle {
// declares variables for x and y coordinates
int x, y;
//The velocity of to move paddle
int vx;
// constructor that takes in x and y coordinates for paddle
public Paddle(int x, int y)
{
this.x = x;
this.y = y;
}
public void paint(Graphics g)
{
// paints paddle
g.setColor(Color.WHITE);
g.fillRect(x, y, 100, 15);
g.setColor(Color.GREEN);
g.drawRect(x, y, 100, 15);
}
// gets x coordinate of paddle
public int getX() {
return x;
}
// sets x coordinate of paddle
public void setX(int x) {
this.x = x;
}
// gets y coordinate of paddle
public int getY() {
return y;
}
// sets y coordinate of paddle
public void setY(int y) {
this.y = y;
}
public void setVX(int vx)
{
this.vx = vx;
}
//Moves the paddle
public void move()
{
x+=vx;
}
}
Brick Class:
import java.awt.Color;
import java.awt.Graphics;
public class Brick
{
private Color color =(Color.cyan);
private int x, y, w, h;
public Brick()
{
//Garbage values that are there just for declaration
x = 0;
y = 0;
w = 10;
h = 10;
}
//Sets color for the brick
public void setColor(int paintC)
{
switch(paintC)
{
case 0:
color = (Color.magenta);
break;
case 1:
color = (Color.blue);
break;
case 2:
color = (Color.yellow);
break;
case 3:
color = (Color.orange);
break;
default:
color = (Color.red);
break;
}
}
//Sets the location then size of the brick
public void setBounds(int x, int y, int w, int h)
{
this.x = x;
this.y = y;
this.w = w;
this.h = h;
}
//returns x value
public int x()
{
return this.x;
}
//returns y value
public int y()
{
return this.y;
}
//returns width value
public int w()
{
return this.w;
}
//returns height value
public int h()
{
return this.h;
}
//Sets x for the brick
public void setX(int x)
{
this.x = x;
}
//Sets y for the brick
public void setY(int y)
{
this.y = y;
}
public void setW(int w)
{
this.w = w;
}
public void setH(int h)
{
this.h = h;
}
public void paint(Graphics g)
{
g.setColor(color);
g.fillRect(x, y, w, h);
g.setColor(Color.green);
g.drawRect(x, y, w, h);
}
}
I've begin running over your code, quite frankly can't be bothered trying to figure out your logic, but what I believe you're trying to deduce is if the brick "contains" the ball, rather then if the ball intersects with the brick.
You don't care how much of the ball or brick are intersecting, only if the they do...for example...
private void checkBrick() {
int tx = ball.getX();
int ty = ball.getY();
int tw = ball.getR();
int th = ball.getR();
tw += tx;
th += ty;
for (int i = 0; i < 50; i++) {
int tempX, tempY, tempW, tempH;
tempX = bX[i];
tempY = bY[i];
tempW = bW[i];
tempH = bH[i];
int rw = tempW + tempX;
int rh = tempH + tempY;
// overflow || intersect
if ((rw < tempX || rw > tx) &&
(rh < tempY || rh > ty) &&
(tw < tx || tw > tempX) &&
(th < ty || th > tempY)) {
System.out.println("Hit");
}
}
}
Now, I stole this from Rectangle#intersects
Basically, if you used the geometry class from the 2D Graphics API, you could reduce this down to...
private void checkBrick() {
Rectangle b = new Rectangle(ball.getX(), ball.getY(), ball.getR(), ball.getR());
for (int i = 0; i < 50; i++) {
int tempX, tempY, tempW, tempH;
tempX = bX[i];
tempY = bY[i];
tempW = bW[i];
tempH = bH[i];
Rectangle brick = new Rectangle(tempX, tempY, tempW, tempH);
System.out.println("brick = " + brick);
if (b.intersects(brick)) {
System.out.println("Break");
}
}
}
And, yes, I did actually run your code
The problem is that the method checkBrick() is not changing anything, it is just printing if the ball has a collision with the brick.
You may want to change the Ball velocity, as you did within checkWall() and checkPaddle().
private void checkBrick() {
for (int i = 0; i < 50; i++) {
...
if (...) {
ball.setVX(...); // Add these lines setting the correct values
ball.setVY(...);
}
}
}
You may also want to check if your if-conditions are correct, and do what you expected.
Assuming tempH is positive,
((ball.getY() + ball.getR()) > (tempY + tempH)
&& (ball.getY() + ball.getR()) <= tempY)
can't ever be true. The > needs to be < and the <= needs to be >=.
Additionally, you'll need to take some kind of action if the brick is hit, rather than just printing out the fact. Sorry, I'm not sure what's supposed to happen - does the brick disappear? Or the ball bounce? Or both?
Second answer (in addition to other answer which I believe is ALSO a problem), your logic is asking if the ball is contained within a brick, but when you create the ball its radius is greater than the height of a brick, so even correcting that logic won't fix the problem.
You should refactor your code to make it read out like natural language, this would help a lot with debugging (or writing less bugs in the first place!) i.e.
in brick class:
public int bottom()
{
return y;
}
public int top()
{
return y + h;
}
in ball class:
public int bottom()
{
return y - r;
}
public int top() {
return y + r;
}
then in main class:
private boolean withinY(brick) {
return (ball.bottom => brick.bottom() && ball.top =< brick.top());
}
then the logic reads nicer (psuedo):
foreach brick in wall {
if (ball.withinY(brick) and ball.withinX(brick))
BAM!!
}
You're checking if the ball is between the left and right side of the brick, but then checking if the ball is both above AND below the brick, because you've got your greater than and less than's mixed up. Also the center of the ball needs to be subtracted from it's Y position.
if ((ball.getY() + ball.getR()) **>** (tempY + tempH) &&
(ball.getY() **+** ball.getR()) **<=** tempY)
could be
if ((ball.getY() + ball.getR()) < (tempY + tempH) &&
(ball.getY() - ball.getR()) >= tempY)
but I'd suggest finding if the top of the ball is between the top and bottom of the brick, OR if the bottom of the ball is between the top and bottom of the brick:
if (((ball.getY() + ball.getR()) < (tempY + tempH) && (ball.getY() - ball.getR()) >= tempY)) ||
((ball.getY() - ball.getR()) < (tempY + tempH) && (ball.getY() - ball.getR()) >= tempY))) {
CODE
}
And use similar logic for finding between left and right sides of the brick

Testing a class in Java (Junit4)

So I have code that runs, but I need to write the test for one of the classes (Cells) and I'm not sure how to go about this.
Typically, I'd have a helper class at the start of CellsTest, which would encapsulate the constructor call, which relies on the specific class name of the class that implements the overall program. This helper class would return an instance of that program.
So, what I'd think is that I'd need to have something like:
private Maze createMaze() {
return new Maze();
}
But then, my test methods can't access the Cell methods, just the Maze methods...So I'm guessing that that is wrong, and I'm not sure how I should actually be doing this.
//Maze.java
package falstad;
import java.awt.*;
import java.util.ArrayList;
import java.util.Iterator;
/**
* Class handles the user interaction for the maze.
*/
//public class Maze extends Panel {
public class Maze {
final private ArrayList<Viewer> views = new ArrayList<Viewer>() ;
MazePanel panel ; // graphics to draw on, shared by all views
private int state;
private int percentdone = 0;
private boolean showMaze;
private boolean showSolution;
private boolean solving;
private boolean mapMode;
//static final int viewz = 50;
int viewx, viewy, angle;
int dx, dy;
int px, py ;
int walkStep;
int viewdx, viewdy;
boolean deepdebug = false;
boolean allVisible = false;
boolean newGame = false;
int mazew; // width
int mazeh; // height
Cells mazecells ;
Distance mazedists ;
Cells seencells ;
BSPNode rootnode ;
// Mazebuilder is used to calculate a new maze together with a solution
// The maze is computed in a separate thread. It is started in the local Build method.
MazeBuilder mazebuilder;
final int ESCAPE = 27;
int method = 0 ; // 0 : default method, Falstad's original code
int zscale = Constants.VIEW_HEIGHT/2;
private RangeSet rset;
//Constructor
public Maze() {
super() ;
panel = new MazePanel() ;
}
//selects a generation method
public Maze(int method)
{
super() ;
if (1 == method)
this.method = 1 ;
panel = new MazePanel() ;
}
public void init() {
state = Constants.STATE_TITLE;
rset = new RangeSet();
panel.initBufferImage() ;
addView(new MazeView(this)) ;
notifyViewerRedraw() ;
}
// Method obtains a new Mazebuilder and computes new maze
private void build(int skill) {
state = Constants.STATE_GENERATING;
percentdone = 0;
notifyViewerRedraw() ;
// select generation method
switch(method){
case 1 : mazebuilder = new MazeBuilderPrim();
break ;
case 0:
default : mazebuilder = new MazeBuilder();
break ;
}
mazew = Constants.SKILL_X[skill];
mazeh = Constants.SKILL_Y[skill];
mazebuilder.build(this, mazew, mazeh, Constants.SKILL_ROOMS[skill], Constants.SKILL_PARTCT[skill]);
}
//Call back method for MazeBuilder to communicate newly generated maze
public void newMaze(BSPNode root, Cells c, Distance dists, int startx, int starty) {
if (Cells.deepdebugWall)
{
c.saveLogFile(Cells.deepedebugWallFileName);
}
showMaze = showSolution = solving = false;
mazecells = c ;
mazedists = dists;
seencells = new Cells(mazew+1,mazeh+1) ;
rootnode = root ;
setCurrentDirection(1, 0) ;
setCurrentPosition(startx,starty) ;
walkStep = 0;
viewdx = dx<<16;
viewdy = dy<<16;
angle = 0;
mapMode = false;
state = Constants.STATE_PLAY;
cleanViews() ;
addView(new FirstPersonDrawer(Constants.VIEW_WIDTH,Constants.VIEW_HEIGHT,
Constants.MAP_UNIT,Constants.STEP_SIZE, mazecells, seencells, 10, mazedists.getDists(), mazew, mazeh, root, this)) ;
addView(new MapDrawer(Constants.VIEW_WIDTH,Constants.VIEW_HEIGHT,Constants.MAP_UNIT,Constants.STEP_SIZE, mazecells, seencells, 10, mazedists.getDists(), mazew, mazeh, this)) ;
notifyViewerRedraw() ;
}
public void addView(Viewer view) {
views.add(view) ;
}
public void removeView(Viewer view) {
views.remove(view) ;
}
private void cleanViews() {
Iterator<Viewer> it = views.iterator() ;
while (it.hasNext())
{
Viewer v = it.next() ;
if ((v instanceof FirstPersonDrawer)||(v instanceof MapDrawer))
{
//System.out.println("Removing " + v);
it.remove() ;
}
}
}
private void notifyViewerRedraw() {
Iterator<Viewer> it = views.iterator() ;
while (it.hasNext())
{
Viewer v = it.next() ;
v.redraw(panel.getBufferGraphics(), state, px, py, viewdx, viewdy, walkStep, Constants.VIEW_OFFSET, rset, angle) ;
}
panel.update() ;
}
private void notifyViewerIncrementMapScale() {
Iterator<Viewer> it = views.iterator() ;
while (it.hasNext())
{
Viewer v = it.next() ;
v.incrementMapScale() ;
}
panel.update() ;
}
private void notifyViewerDecrementMapScale() {
Iterator<Viewer> it = views.iterator() ;
while (it.hasNext())
{
Viewer v = it.next() ;
v.decrementMapScale() ;
}
panel.update() ;
}
boolean isInMapMode() {
return mapMode ;
}
boolean isInShowMazeMode() {
return showMaze ;
}
boolean isInShowSolutionMode() {
return showSolution ;
}
public String getPercentDone(){
return String.valueOf(percentdone) ;
}
public Panel getPanel() {
return panel ;
}
private void setCurrentPosition(int x, int y)
{
px = x ;
py = y ;
}
private void setCurrentDirection(int x, int y)
{
dx = x ;
dy = y ;
}
void buildInterrupted() {
state = Constants.STATE_TITLE;
notifyViewerRedraw() ;
mazebuilder = null;
}
final double radify(int x) {
return x*Math.PI/180;
}
public boolean increasePercentage(int pc) {
if (percentdone < pc && pc < 100) {
percentdone = pc;
if (state == Constants.STATE_GENERATING)
{
notifyViewerRedraw() ;
}
else
dbg("Warning: Receiving update request for increasePercentage while not in generating state, skip redraw.") ;
return true ;
}
return false ;
}
private void dbg(String str) {
//System.out.println(str);
}
private void logPosition() {
if (!deepdebug)
return;
dbg("x="+viewx/Constants.MAP_UNIT+" ("+
viewx+") y="+viewy/Constants.MAP_UNIT+" ("+viewy+") ang="+
angle+" dx="+dx+" dy="+dy+" "+viewdx+" "+viewdy);
}
private boolean checkMove(int dir) {
int a = angle/90;
if (dir == -1)
a = (a+2) & 3;
return mazecells.hasMaskedBitsFalse(px, py, Constants.MASKS[a]) ;
}
private void rotateStep() {
angle = (angle+1800) % 360;
viewdx = (int) (Math.cos(radify(angle))*(1<<16));
viewdy = (int) (Math.sin(radify(angle))*(1<<16));
moveStep();
}
private void moveStep() {
notifyViewerRedraw() ;
try {
Thread.currentThread().sleep(25);
} catch (Exception e) { }
}
private void rotateFinish() {
setCurrentDirection((int) Math.cos(radify(angle)), (int) Math.sin(radify(angle))) ;
logPosition();
}
private void walkFinish(int dir) {
setCurrentPosition(px + dir*dx, py + dir*dy) ;
if (isEndPosition(px,py)) {
state = Constants.STATE_FINISH;
notifyViewerRedraw() ;
}
walkStep = 0;
logPosition();
}
private boolean isEndPosition(int x, int y) {
return x < 0 || y < 0 || x >= mazew || y >= mazeh;
}
synchronized private void walk(int dir) {
if (!checkMove(dir))
return;
for (int step = 0; step != 4; step++) {
walkStep += dir;
moveStep();
}
walkFinish(dir);
}
synchronized private void rotate(int dir) {
final int originalAngle = angle;
final int steps = 4;
for (int i = 0; i != steps; i++) {
angle = originalAngle + dir*(90*(i+1))/steps;
rotateStep();
}
rotateFinish();
}
//CLASS CONTROLLING PLAYER MOVEMENTS, REMOVED FOR CHARACTER COUNT
}
}
//Cells.java
package falstad;
import java.io.BufferedWriter;
import java.io.FileWriter;
//This class encapsulates all access to a grid of cells
public class Cells {
private int width;
private int height ;
private int[][] cells;
public Cells(int w, int h) {
width = w ;
height = h ;
cells = new int[w][h];
}
public Cells(int[][] target){
this(target.length, target[0].length);
for (int i=0; i<width; i++)
for (int j=0; j<height; j++)
this.cells[i][j]=target[i][j];
}
public int getCells( int x, int y )
{
return cells[x][y] ;
}
static public int[] getMasks() {
return Constants.MASKS ;
}
public boolean canGo(int x, int y, int dx, int dy) {
if (hasMaskedBitsTrue(x, y, (getBit(dx, dy) << Constants.CW_BOUND_SHIFT)))
return false;
return isFirstVisit(x+dx, y+dy);
}
private int getBit(int dx, int dy) {
int bit = 0;
switch (dx + dy * 2) {
case 1: bit = Constants.CW_RIGHT; break;
case -1: bit = Constants.CW_LEFT; break;
case 2: bit = Constants.CW_BOT; break;
case -2: bit = Constants.CW_TOP; break;
default: dbg("getBit problem "+dx+" "+dy); break;
}
return bit;
}
//CLASSES FOR BITWISE ADJUSTMENTS, REMOVED FOR CHARACTER COUNT
public void initialize() {
int x, y;
for (x = 0; x != width; x++) {
for (y = 0; y != height; y++) {
setBitToOne(x, y, (Constants.CW_VISITED | Constants.CW_ALL));
}
setBitToOne(x, 0, Constants.CW_TOP_BOUND);
setBitToOne(x, height-1, Constants.CW_BOT_BOUND);
}
for (y = 0; y != height; y++) {
setBitToOne(0, y, Constants.CW_LEFT_BOUND);
setBitToOne(width-1, y, Constants.CW_RIGHT_BOUND);
}
}
public boolean areaOverlapsWithRoom(int rx, int ry, int rxl, int ryl) {
int x, y;
for (x = rx-1; x <= rxl+1; x++)
{
for (y = ry-1; y <= ryl+1; y++)
{
if (isInRoom(x, y))
return true ;
}
}
return false ;
}
private void deleteBound(int x, int y, int dx, int dy) {
setBoundToZero(x, y, dx, dy);
setBoundToZero(x+dx, y+dy, -dx, -dy) ;
}
public void addBoundWall(int x, int y, int dx, int dy) {
setBoundAndWallToOne(x, y, dx, dy);
setBoundAndWallToOne(x+dx, y+dy, -dx, -dy);
}
public void deleteWall(int x, int y, int dx, int dy) {
setWallToZero(x, y, dx, dy);
setWallToZero(x+dx, y+dy, -dx, -dy);
if (deepdebugWall)
logWall( x, y, dx, dy);
public void markAreaAsRoom(int rw, int rh, int rx, int ry, int rxl, int ryl) {
int x;
int y;
for (x = rx; x <= rxl; x++)
for (y = ry; y <= ryl; y++) {
setAllToZero(x, y);
setInRoomToOne(x, y);
}
for (x = rx; x <= rxl; x++) {
addBoundWall(x, ry, 0, -1);
addBoundWall(x, ryl, 0, 1);
}
for (y = ry; y <= ryl; y++) {
addBoundWall(rx, y, -1, 0);
addBoundWall(rxl, y, 1, 0);
}
int wallct = (rw+rh)*2;
SingleRandom random = SingleRandom.getRandom() ;
for (int ct = 0; ct != 5; ct++) {
int door = random.nextIntWithinInterval(0, wallct-1);
int dx, dy;
if (door < rw*2) {
y = (door < rw) ? 0 : rh-1;
dy = (door < rw) ? -1 : 1;
x = door % rw;
dx = 0;
} else {
door -= rw*2;
x = (door < rh) ? 0 : rw-1;
dx = (door < rh) ? -1 : 1;
y = door % rh;
dy = 0;
}
deleteBound(x+rx, y+ry, dx, dy);
}
}
public boolean hasMaskedBitsTrue(int x, int y, int bitmask) {
return (cells[x][y] & bitmask) != 0;
}
public boolean isInRoom(int x, int y) {
return hasMaskedBitsTrue(x, y, Constants.CW_IN_ROOM);
}
private boolean isFirstVisit(int x, int y) {
return hasMaskedBitsTrue(x, y, Constants.CW_VISITED);
}
public boolean hasWallOnRight(int x, int y) {
return hasMaskedBitsTrue(x, y, Constants.CW_RIGHT);
}
public boolean hasWallOnLeft(int x, int y) {
return hasMaskedBitsTrue(x, y, Constants.CW_LEFT);
}
public boolean hasWallOnTop(int x, int y) {
return hasMaskedBitsTrue(x, y, Constants.CW_TOP);
}
public boolean hasWallOnBottom(int x, int y) {
return hasMaskedBitsTrue(x, y, Constants.CW_BOT);
}
public boolean hasNoWallOnBottom(int x, int y) {
return !hasMaskedBitsTrue(x, y, Constants.CW_BOT);
}
public boolean hasNoWallOnTop(int x, int y) {
return !hasMaskedBitsTrue(x, y, Constants.CW_TOP);
}
public boolean hasNoWallOnLeft(int x, int y) {
return !hasMaskedBitsTrue(x, y, Constants.CW_LEFT);
}
public boolean hasNoWallOnRight(int x, int y) {
return !hasMaskedBitsTrue(x, y, Constants.CW_RIGHT);
}
public boolean hasMaskedBitsFalse(int x, int y, int bitmask) {
return (cells[x][y] & bitmask) == 0;
}
public boolean hasMaskedBitsGTZero(int x, int y, int bitmask) {
return (cells[x][y] & bitmask) > 0;
}
private void dbg(String str) {
System.out.println("Cells: "+str);
}
public String toString() {
String s = "" ;
for (int i = 0 ; i < width ; i++)
{
for (int j = 0 ; j < height ; j++)
s += " i:" + i + " j:" + j + "=" + cells[i][j] ;
s += "\n" ;
}
return s ;
}
static boolean deepdebugWall = false;
static final String deepedebugWallFileName = "logDeletedWalls.txt" ;
StringBuffer traceWall = (deepdebugWall) ? new StringBuffer("x y dx dy\n") : null ;
private void logWall(int x, int y, int dx, int dy) {
if (null != traceWall)
{
traceWall.append(x + " " + y + " " + dx + " " + dy + "\n");
}
}
public void saveLogFile( String filename )
{
try {
BufferedWriter out = new BufferedWriter(new FileWriter(filename));
out.write(traceWall.toString());
out.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
//MazeBuilder.java
package falstad;
public class MazeBuilder implements Runnable {
protected int width, height ;
Maze maze;
private int rooms;
int expectedPartiters;
protected int startx, starty ;
protected Cells cells;
protected Distance dists ;
protected SingleRandom random ;
Thread buildThread;
public MazeBuilder(){
random = SingleRandom.getRandom();
}
public MazeBuilder(boolean deterministic){
if (true == deterministic)
{
System.out.println("Project 2: functionality to make maze generation deterministic not implemented yet! Fix this!");
}
random = SingleRandom.getRandom();
}
static int getSign(int num) {
return (num < 0) ? -1 : (num > 0) ? 1 : 0;
}
protected void generate() {
generatePathways();
final int[] remote = dists.computeDistances(cells) ;
final int[] pos = dists.getStartPosition();
startx = pos[0] ;
starty = pos[1] ;
setExitPosition(remote[0], remote[1]);
}
protected void generatePathways() {
int[][] origdirs = new int[width][height] ;
int x = random.nextIntWithinInterval(0, width-1) ;
int y = 0;
final int firstx = x ;
final int firsty = y ;
int dir = 0;
int origdir = dir;
cells.setVisitedFlagToZero(x, y);
while (true) {
int dx = Constants.DIRS_X[dir];
int dy = Constants.DIRS_Y[dir];
if (!cells.canGo(x, y, dx, dy)) {
dir = (dir+1) & 3;
if (origdir == dir) {
if (x == firstx && y == firsty)
break;
int odr = origdirs[x][y];
dx = Constants.DIRS_X[odr];
dy = Constants.DIRS_Y[odr];
x -= dx;
y -= dy;
origdir = dir = random.nextIntWithinInterval(0, 3);
}
} else {
cells.deleteWall(x, y, dx, dy);
x += dx;
y += dy;
cells.setVisitedFlagToZero(x, y);
origdirs[x][y] = dir;
origdir = dir = random.nextIntWithinInterval(0, 3);
}
}
}
protected void setExitPosition(int remotex, int remotey) {
int bit = 0;
if (remotex == 0)
bit = Constants.CW_LEFT;
else if (remotex == width-1)
bit = Constants.CW_RIGHT;
else if (remotey == 0)
bit = Constants.CW_TOP;
else if (remotey == height-1)
bit = Constants.CW_BOT;
else
dbg("Generate 1");
cells.setBitToZero(remotex, remotey, bit);
//System.out.println("exit position set to zero: " + remotex + " " + remotey + " " + bit + ":" + cells.hasMaskedBitsFalse(remotex, remotey, bit)
// + ", Corner case: " + ((0 == remotex && 0 == remotey) || (0 == remotex && height-1 == remotey) || (width-1 == remotex && 0 == remotey) || (width-1 == remotex && height-1 == remotey)));
}
static final int MIN_ROOM_DIMENSION = 3 ;
static final int MAX_ROOM_DIMENSION = 8 ;
private boolean placeRoom() {
final int rw = random.nextIntWithinInterval(MIN_ROOM_DIMENSION, MAX_ROOM_DIMENSION);
if (rw >= width-4)
return false;
final int rh = random.nextIntWithinInterval(MIN_ROOM_DIMENSION, MAX_ROOM_DIMENSION);
if (rh >= height-4)
return false;
final int rx = random.nextIntWithinInterval(1, width-rw-1);
final int ry = random.nextIntWithinInterval(1, height-rh-1);
final int rxl = rx+rw-1;
final int ryl = ry+rh-1;
if (cells.areaOverlapsWithRoom(rx, ry, rxl, ryl))
return false ;
cells.markAreaAsRoom(rw, rh, rx, ry, rxl, ryl);
return true;
}
static void dbg(String str) {
System.out.println("MazeBuilder: "+str);
}
public void build(Maze mz, int w, int h, int roomct, int pc) {
init(mz, w, h, roomct, pc);
buildThread = new Thread(this);
buildThread.start();
}
private void init(Maze mz, int w, int h, int roomct, int pc) {
maze = mz;
width = w;
height = h;
rooms = roomct;
expectedPartiters = pc;
cells = new Cells(w,h) ;
dists = new Distance(w,h) ;
//colchange = random.nextIntWithinInterval(0, 255);
}
static final long SLEEP_INTERVAL = 100 ;
try {
cells.initialize();
// rooms into maze
generateRooms();
Thread.sleep(SLEEP_INTERVAL) ;
// pathways into the maze,
generate();
Thread.sleep(SLEEP_INTERVAL) ;
final int colchange = random.nextIntWithinInterval(0, 255);
final BSPBuilder b = new BSPBuilder(maze, dists, cells, width, height, colchange, expectedPartiters) ;
BSPNode root = b.generateBSPNodes();
Thread.sleep(SLEEP_INTERVAL) ;
// dbg("partiters = "+partiters);
maze.newMaze(root, cells, dists, startx, starty);
}
catch (InterruptedException ex) {
// dbg("Catching signal to stop") ;
}
}
static final int MAX_TRIES = 250 ;
private int generateRooms() {
int tries = 0 ;
int result = 0 ;
while (tries < MAX_TRIES && result <= rooms) {
if (placeRoom())
result++ ;
else
tries++ ;
}
return result ;
}
public void interrupt() {
buildThread.interrupt() ;
}
}
Obviously, I'm not asking for someone to write a test for me - not that any of you would, as this is fairly obviously a homework assignment - but I'd like some help getting started on this. So if anyone could clue me into the surely obvious trick that I'm missing, that would be wonderful!
A unit test for Cells class can look like the below:
While you unit test the Cells class you might not need the Maze or MazeBuilder, you only need an instance of Cells class and call its methods in order to check that they work correctly isolated from the rest of the application.
Also take a look at this: Unit testing in Java - what is it? as it provides a good reference.
import org.junit.Assert;
import org.junit.Test;
public class CellsTest {
#Test
void testHasWallOnRight() {
//setup
int[][] target = new int[][] { { 0, 0, 0, 0 },
{ 0, 0, 0, 0 },
{ 0, 0, 0, 0 },
{ 0, 0, 0, 0 } };
Cells a = new Cells(target);
//act
boolean result = a.hasWallOnRight(1,1);
//assert
Assert.assertFalse(result);
}
}

Categories