I am a beginner at Java programming. I am trying to create a checkers game in which players can move their own pieces. The problem is that when one piece is moved, all of them move it. I would really appreciate some help. Thanks!!!
Main Class
package Checkers_Own;
import resources.DrawingBoard;
import resources.Timer;
public class Game {
public static void main(String[] args) {
Board[][] boards = new Board[8][8];
DrawingBoard board = new DrawingBoard(840, 640);
Timer timer = new Timer();
for(int i = 0; i < 8; i++){
for(int j = 0; j < 8; j++){
if(i % 2 == 1){
if(j % 2 == 1)boards[i][j] = new Board(true, i, j);
else boards[i][j] = new Board(false, i, j);
}
else if(i % 2 == 0){
if(j % 2 == 1)boards[i][j] = new Board(false, i, j);
else boards[i][j] = new Board(true, i, j);
}
}
}
for(int i = 5; i < 8; i++) for(int j = 0; j < 8; j++) if(!boards[j][i].isWhite) PiecesManager.add1(new Pieces(true, j, i));
for(int i = 0; i < 8; i++) for(int j = 0; j < 3; j++) if(!boards[i][j].isWhite) PiecesManager.add2(new Pieces(false, i, j));
PiecesManager.properties(board);
while(true){
board.clear();
for(int i = 0; i < 8; i++) for(int j = 0; j < 8; j++) boards[i][j].draw(board);
PiecesManager.draw(board);
PiecesManager.move();
board.repaint();
timer.pause(30);
}
}
}
Pieces
package Checkers;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import resources.DrawingBoard;
public class Pieces implements MouseMotionListener, MouseListener{
boolean side1, changed = false;
int x, y, lastX, lastY, dx, dy;
public Pieces(boolean side1, int x, int y){
this.side1 = side1;
this.x = (x * 80) + 10;
this.y = (y * 80) + 10;
}
public void draw(DrawingBoard board){
Graphics2D g = board.getCanvas();
if(side1){
g.setColor(Color.blue);
g.fillOval(x, y, 60, 60);
}
else{
g.setColor(Color.red);
g.fillOval(x, y, 60, 60);
}
}
public Pieces moved(){
if(changed){
return this;
}
return null;
}
public void move(){
if(changed){
x += dx;
y += dy;
}
changed = false;
}
public void mousePressed(MouseEvent e) {
lastX = e.getX();
lastY = e.getY();
}
public void mouseDragged(MouseEvent e) {
int mx = e.getX();
dx = mx - lastX;
lastX = mx;
int my = e.getY();
dy = my - lastY;
lastY = my;
if(mx != x || my != y) changed = true;
}
public void mouseMoved(MouseEvent e) {}
public void mouseClicked(MouseEvent e) {}
public void mouseReleased(MouseEvent e) {}
public void mouseEntered(MouseEvent e) {}
public void mouseExited(MouseEvent e) {}
}
Board
package Checkers_Own;
import java.awt.Color;
import java.awt.Graphics2D;
import resources.DrawingBoard;
public class Board {
boolean isWhite;
private int x, y;
public Board(boolean isWhite, int x, int y){
this.isWhite = isWhite;
this.x = x * 80;
this.y = y * 80;
}
public void draw(DrawingBoard board){
Graphics2D g = board.getCanvas();
if(isWhite){
g.setColor(Color.white);
g.fillRect(x, y, 80, 80);
}
else{
g.setColor(Color.black);
g.fillRect(x, y, 80, 80);
}
}
}
PiecesManager
package Checkers_Own;
import resources.DrawingBoard;
public class PiecesManager {
private static int size1, size2;
private static Pieces[] p1 = new Pieces[12];
private static Pieces[] p2 = new Pieces[12];
public static void draw(DrawingBoard board){
for(int i = 0; i < size1; i++) p1[i].draw(board);
for(int i = 0; i < size2; i++) p2[i].draw(board);
}
public static void move(){
for(int i = 0; i < p1.length; i++) if(p1[i].moved() == p1[i]) p1[i].move();
for(int i = 0; i < p2.length; i++) if(p2[i].moved() == p2[i]) p2[i].move();
}
public static void add1(Pieces piece){
p1[size1] = piece;
size1 ++;
}
public static void add2(Pieces piece){
p2[size2] = piece;
size2 ++;
}
public static void properties(DrawingBoard board){
for(int i = 0; i < p1.length; i++){
board.addMouseListener(p1[i]);
board.addMouseMotionListener(p1[i]);
}
for(int i = 0; i < p2.length; i++){
board.addMouseListener(p2[i]);
board.addMouseMotionListener(p2[i]);
}
}
}
This is my game project. It's very simple version of "Flappy Bird" and I have some serious problems with how the collisions algorithm works. I wrote 2 separate code fragments for collision, for wall1 and wall2. The problem begins when the ball is trying to go through a hole because somehow the program is detecting a collision with a wall. I'm almost positive that the collision algorithm was written correctly because I have been checking it all day.
import java.applet.*;
import java.awt.*;
import java.awt.event.*;
import java.util.Random;
import java.util.Timer;
import java.util.logging.Level;
import java.util.logging.Logger;
public class Game extends Applet implements KeyListener, Runnable {
Image bground;
Random generator = new Random();
int r1;
int wall1x;
int wall1y;
int wall1long;
int wall2x;
int wall2y;
int wall2long;
Timer timer;
private Image i;
private Graphics doubleG;
int r2;
int blok_x1 = 800;
int blok_y1;
int blok_x = 800;
int blok_y = 0;
int blok_x_v = 2;
int ballX = 20;
int ballY = 20;
int dx = 0;
int dyclimb = 1;
int dyrise = 1;
double gravity = 3;
double jumptime = 0;
int FPS = 100;
public int tab[];
public boolean grounded = true, up = false;
boolean OVER = false;
#Override
public void init() {
bground = getImage(getCodeBase(), "12.png");
this.setSize(600, 400);
tab = new int[100];
for (int t = 0; t < 100; t++) {
tab[t] = generator.nextInt(380) + 1;
}
addKeyListener(this);
}
#Override
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_LEFT) {
ballX -= 10;
}
if (e.getKeyCode() == KeyEvent.VK_RIGHT) {
ballX += 10;
}
if (e.getKeyCode() == KeyEvent.VK_UP) {
ballY -= 10;
up = true;
}
if (e.getKeyCode() == KeyEvent.VK_DOWN) {
ballY += 10;
}
}
#Override
public void paint(Graphics g) {
g.drawImage(bground, 0, 0, this);
if (OVER == false) {
for (int i = 0; i < 100; i++) {
g.setColor(Color.green);
wall1x = blok_x + i * 400;
wall1y = blok_y;
wall1long = tab[i];
g.fillRect(wall1x, wall1y, 20, wall1long);
g.setColor(Color.green);
wall2x = blok_x1 + i * 400;
wall2y = tab[i] + 60;
wall2long = 400 - tab[i];
g.fillRect(wall2x, wall2y, 20, wall2long);
g.setColor(Color.green);
}
g.setColor(Color.red);
g.fillOval(ballX, ballY, 20, 20);
} else {
g.drawString("GAME OVER", 300, 300);
}
}
#Override
public void update(Graphics g) {
if (i == null) {
g.setColor(Color.green);
i = createImage(this.getSize().width, this.getSize().height);
doubleG = i.getGraphics();
g.setColor(Color.green);
}
doubleG.setColor(getBackground());
g.setColor(Color.green);
doubleG.fillRect(0, 0, this.getSize().width, this.getSize().height);
doubleG.setColor(getForeground());
g.setColor(Color.green);
paint(doubleG);
g.drawImage(i, 0, 0, this);
}
#Override
public void run() {
int time = 10;
while (true) {
if (up == true) {
ballY -= dyclimb;
time--;
} else {
ballY += dyrise;
}
if (time == 0) {
time = 10;
up = false;
}
blok_x--;
blok_x1--;
if (ballX > 600 || ballX < 0 || ballY > 400 || ballY < 0) {
OVER = true;
}
for (int i = 0; i < 100; i++) { // collision algorithm
wall1x = blok_x + i * 400;
wall1y = blok_y;
wall1long = tab[i];
if (ballX + 20 >= wall1x && ballX <= wall1x + 20 && ballY <= wall1y + wall1long && ballY >= wall1x - 20) { //wall1
OVER = true;
}
}
for (int i = 0; i < 100; i++) {
wall2x = blok_x1 + i * 400;
wall2y = tab[i] + 60;
wall2long = 400 - tab[i];
if (ballX + 20 >= wall2x && ballX <= wall2x + 20 && ballY <= wall2y + wall2long && ballY >= wall2x - 20) { //wall2
OVER = true;
}
}
repaint();
try {
Thread.sleep(17);
} catch (InterruptedException ex) {
Logger.getLogger(NewApplet.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
#Override
public void start() {
Thread thread = new Thread(this);
thread.start();
}
#Override
public void keyTyped(KeyEvent e) {
}
#Override
public void keyReleased(KeyEvent e) {
}
}
Use Rectangle class. There's a method called Intersect or Intersection or something like that.
Say you have one object moving. Make a Rectangle to match the object in position(basically an invisible cover for the object).
Do the same things with another object.
When both are to collide, use the intersection method to check on the collision by using the rectangles.
These might help
http://docs.oracle.com/javase/7/docs/api/java/awt/Rectangle.html
Java method to find the rectangle that is the intersection of two rectangles using only left bottom point, width and height?
java.awt.Rectangle. intersection()
im really new in Java. I just need to explain how to declare 2D array of objects, i have something like:
package breakout;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.Color;
import java.awt.Font;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JOptionPane;
public class Breakout extends JPanel {
public class Ball {
private
int x = 400;
int y = 300;
int speed = 2;
int dirx = 1;
int diry = -1;
public
void bounce(int px, int py, int lx, int ly) {
if ((x + 10 >= 800 && dirx == 1) || (x <= 0 && dirx == -1))
dirx *= -1;
if (y <= 0 && diry == -1)
diry *= -1;
if (y + 10 >= py && y <= py + ly && diry == 1 && x + 10 >= px && x <= px + lx)
diry *= -1;
}
int getX() {
return x;
}
int getY() {
return y;
}
void setDirx(){
dirx *= -1;
}
void setDiry(){
diry *= -1;
}
void move() {
x += speed*dirx;
y += speed*diry;
}
void paint(Graphics2D g) {
g.fillOval(x,y,10,10);
}
}
public class Paddle {
private
int x = 400;
int y = 520;
int width = 100;
int height = 6;
int speed = 6;
int dirL = 0;
int dirR = 0;
public
void move() {
x -= speed*dirL;
x += speed*dirR;
}
void stop() {
if (x <= 0)
x = 0;
if (x + width >= 800)
x = 800 - width;
}
int getX() {
return x;
}
int getY() {
return y;
}
int getWidth() {
return width;
}
int getHeight() {
return height;
}
void paint(Graphics2D g) {
g.fillRect(x,y,width,height);
}
public void keyReleased(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_LEFT)
dirL = 0;
else if (e.getKeyCode() == KeyEvent.VK_RIGHT)
dirR = 0;
else {
dirL = 0;
dirR = 0;
}
}
public void keyPressed(KeyEvent e) {
switch(e.getKeyCode()) {
case KeyEvent.VK_LEFT:
dirL = 1;
break;
case KeyEvent.VK_RIGHT:
dirR = 1;
break;
}
}
}
public class Brick {
private
int x;
int y;
int width;
int height;
boolean alive;
boolean inX = false,inY = false;
public
void setUpBrick(int px, int py, int w, int h, boolean al) {
x = px;
y = py;
width = w;
height = h;
alive = al;
}
void setAlive(boolean alive) {
this.alive = alive;
}
void paint(Graphics2D g) {
if (alive)
g.fillRect(x,y,width,height);
}
boolean collision(int bx, int by) {
if (alive) {
if (bx + 10 >= x && bx <= x + width && by + 10 >= y && by <= y + height) {
setAlive(false);
return true;
} else return false;
}
else return false;
}
void inAreaX(int bx) {
if (bx + 10 >= x && bx <= x + width) {
System.out.println("inAreaX");
inX = true;
} else {
inX = false;
}
}
void inAreaY(int by) {
if (by + 10 >= y && by <= y + height) {
System.out.println("inAreaY");
inY = true;
} else {
inY = false;
}
}
boolean isInAreaX () {
if (inX)
return true;
else return false;
}
boolean isInAreaY () {
if (inY)
return true;
else return false;
}
}
Ball ball = new Ball();
Paddle paddle = new Paddle();
Brick[][] brick = new Brick[8][4];
for (int i = 0; i < 8; i++) {
for (int j = 0; j < 4; j++) {
brick[i][j].setUpBrick(j * 101, i * 51, 100, 50, true);
}
}
void bounce() {
for (int i = 0; i < 8; i++) {
for (int j = 0; j < 4; j++) {
brick[i][j].inAreaX(ball.getX());
brick[i][j].inAreaY(ball.getY());
if (brick[i][j].collision(ball.getX(), ball.getY())) {
if (brick[i][j].isInAreaX()) {
ball.setDiry();
} else if (brick[i][j].isInAreaY()) {
ball.setDirx();
}
}
}
}
}
void move() {
ball.bounce(paddle.getX(), paddle.getY(), paddle.getWidth(),paddle.getHeight());
ball.move();
paddle.move();
paddle.stop();
bounce();
}
public Breakout() {
addKeyListener(new KeyListener() {
public void keyTyped(KeyEvent e) {
}
public void keyReleased(KeyEvent e) {
paddle.keyReleased(e);
}
public void keyPressed(KeyEvent e) {
paddle.keyPressed(e);
}
});
setFocusable(true);
}
public void paint(Graphics g) {
super.paint(g);
Graphics2D g2d = (Graphics2D) g;
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setColor(Color.RED);
ball.paint(g2d);
g2d.setColor(Color.BLACK);
paddle.paint(g2d);
g2d.setColor(Color.ORANGE);
for (int i = 0; i < 8; i++)
for (int j = 0; j < 4; j++)
brick[i][j].paint(g2d);
}
public static void main(String[] args) throws InterruptedException {
JFrame window = new JFrame("Tennis");
Breakout game = new Breakout();
window.add(game);
window.setSize(800,600);
window.setVisible(true);
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
while (true) {
game.move();
game.repaint();
Thread.sleep(10);
}
}
i need to inicialize 2d array of brick, but it says that first for is unexpected token. How to write it? Thank you.
Unless if I have miscounted your opening and closing braces, your for loop is not inside any method, it's directly in your class body. That's why you're getting unexpected token. You will probably want to move it into the Breakout constructor.
In order to create a 2D array in Java, you can create such an array like this:
Object testArray = new Object[10][10];
This array is now a 10*10 array with memory allocated for 100 Object references.
You can create pointers two Objects with a double for-loop:
for (int i = 0; i < testArray.length(); i++) {
for (int j = 0; j < testArray.length; j++) {
testArray[i][j] = Object; //here you input the objects that you want to point to
}
}
Move the logic from setUpBrick to a constructor.
public class Brick {
private int x;
private int y;
private int width;
private int height;
private boolean alive;
private boolean inX = false,inY = false;
public Brick(int px, int py, int w, int h, boolean al) {
x = px;
y = py;
width = w;
height = h;
alive = al;
}
...
}
Then change
brick[i][j].setUpBrick(j * 101, i * 51, 100, 50, true);
to
brick[i][j] = new Brick(j*101, i*51, 100, 50, true);
Also note that access modifiers don't apply to a whole section of your class. In your example,
private
int x;
int y;
int width;
int height;
boolean alive;
boolean inX = false,inY = false;
means that only x is going to be private. The rest of the members will get the default access modifier.
One more tip. A couple of your methods can be simplified.
boolean isInAreaY () {
if (inY)
return true;
else return false;
}
can be written as:
boolean isInAreaY() {
return inY;
}
I'm making Tetris in java for fun... I pretty much had everything working... but later found out that when I wanted to change the dimensions so it was square ([10 row][10 col] matrix, but instead a [12 row][10 col] matrix), that I started getting Index Out of Bound exceptions... see here: Java Tetris - weird row clearing issue
So I tried fixing everything so that the rows and columns weren't flip flopped... But am now getting hung up on the fact that the grid takes [row][col], but I’m moving around the tiles as (x, y) coordinates…
What’s confusing me is that row = y and col = x… which is reversed… so when I pass in coordinates I’m not sure when to swap them.
I know it’s a simple thing, but it’s confusing the hell out of me and I keep getting out of bounds exceptions whenever I think I have it right.
I'm not sure where the exact issue is, so I'm posting a full Sscce of my program... I think the issue is in the Board class...
Here, the block should still be able to move down... but if it tries to go down further than this...
I get:
Exception in thread "AWT-EventQueue-0" java.lang.ArrayIndexOutOfBoundsException: 10
at Board.getTileAt(Board.java:177)
at Tile.collision(Tile.java:31)
at Piece.isCollision(Piece.java:172)
at Board.collisionCheck(Board.java:192)
at Piece.movePieceCheck(Piece.java:87)
at Board.keyPressed(Board.java:160)
Sscce:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Toolkit;
import javax.swing.BoxLayout;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class MainSscce extends JPanel {
static MainSscce runMe;
BoardSscce gameBoard, scoreBoard;
public MainSscce() { //creates a new frame window and sets properties
JFrame f = new JFrame("Tetris");
//width (height), length, tilesize
gameBoard = new BoardSscce(12, 10, 35);
// scoreBoard = new BoardSscce(10, 10, 35);
f.add(gameBoard);
f.setSize(gameBoard.getWidth(), gameBoard.getHeight());
f.setVisible(true);
f.setResizable(false);
f.setVisible(true);
f.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
Dimension screensize = Toolkit.getDefaultToolkit().getScreenSize();
//set j frame location to appear in middle of screen
f.setLocation( (screensize.width - f.getWidth())/2,
(screensize.height - f.getHeight())/2-100 );
}
public static void main(String[] args) {
runMe = new MainSscce();
}
}
import java.awt.Graphics;
import java.awt.Color;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import javax.swing.JPanel;
import javax.swing.Timer;
import java.awt.event.*; // for ActionListener and ActionEvent
import java.util.Random;
public class BoardSscce extends JPanel implements KeyListener {
private TileSscce grid[][];
private int totalRows, totalCols, tilesize, level, totalScore;
private final int changeLevelMultiplier;
private PieceSscce newPiece, nextPiece;
private String randomPiece;
private boolean gameLost;
public BoardSscce(int r, int c, int ts) {
totalRows = r;
totalCols = c;
tilesize = ts;
//set grid size to [# rows][# columns], aka [height][width]
grid = new TileSscce[totalRows][totalCols];
gameLost = false;
System.out.println("TotalRows: " + totalRows + ", " + "TotalCols: " + totalCols);
//multiplier to determine what score the level changes, which is:
//level * changeLevelMultiplier;
changeLevelMultiplier = 40;
//initialize score to 0
totalScore = 0;
//initialize level to 0
level = 0;
newPiece = new PieceSscce(this, randomPiece(), getColor());
addKeyListener(this);
setFocusable(true);
//getTranspose();
timer();
}
public String randomPiece() {
String[] Pieces = {"L", "O", "Z", "RevZ", "Bar", "T", "RevL"};
int rand = (int) (Math.random() * Pieces.length);
randomPiece = Pieces[rand];
return randomPiece;
}
public Color getColor() {
Color color;
if (randomPiece.equals("L"))
color = new Color(17, 255, 0);
else if(randomPiece.equals("O"))
color = new Color(117, 168, 255);
else if(randomPiece.equals("Z"))
color = new Color(255, 187, 82);
else if(randomPiece.equals("RevZ"))
color = new Color(206, 27, 72);
else if(randomPiece.equals("Bar"))
color = new Color(50, 216, 219);
else if(randomPiece.equals("T"))
color = new Color(252, 148, 240);
else
color = new Color(255, 255, 52);
//Random rand = new Random();
//float r = rand.nextFloat();
//float g = rand.nextFloat();
//float b = rand.nextFloat();
//Color randomColor = new Color(r, g, b);
return color;
}
//dimensions of board = width * tilesize
public int getWidth() {
return totalCols * tilesize;
}
public int getHeight() {
return totalRows * tilesize;
}
public int getTileSize() {
return tilesize;
}
public void paintComponent(Graphics g) {
g.setColor(Color.black);
g.fillRect(0, 0, getWidth(), getHeight());
for(int row = 0; row < grid.length; row++) {
for(int col = 0; col < grid[row].length; col++) {
//System.out.println(row + ", " + col);
g.drawString("[" + row + "][" + col + "]", col * tilesize, row * tilesize+10);
System.out.println(row + ", " + col);
//if there is a non-null space, that is a Tetris piece... fill it
if(grid[row][col] != null) {
g.setColor(grid[row][col].getColor());
g.fillRect(row * tilesize, col * tilesize, tilesize, tilesize);
g.setColor(Color.WHITE);
}
}
}
// g.drawString("Level: " + level, this.getWidth()/2, this.getHeight()/2-130);
// g.drawString("Score: " + totalScore, this.getWidth()/2, this.getHeight()/2-100);
if (gameLost == true) {
g.drawString("Way to go, loser...", this.getWidth()/2, this.getHeight()/2);
messageTimer();
}
}
//Auto move piece
public void timer () {
int interval;
switch (level) {
//each level increases drop speed by .10 seconds
case 1: interval = 800;
break;
case 2: interval = 700;
break;
case 3: interval = 600;
break;
case 4: interval = 500;
break;
default: interval = 1000;
break;
}
Timer t = new Timer(interval, new ActionListener() {
public void actionPerformed(ActionEvent e) {
//newPiece.autoMove();
//repaint();
}
});
t.start();
}
public void messageTimer() {
Timer t = new Timer(5000, new ActionListener() {
public void actionPerformed(ActionEvent e) {
gameLost = false;
}
});
t.start();
}
//move piece on key input
public void keyPressed(KeyEvent e) {
newPiece.movePieceCheck(e.getKeyCode());
repaint();
}
public void keyReleased(KeyEvent e) {
}
public void keyTyped(KeyEvent e) {
}
public boolean isValidCoordinate(int x, int y) {
return x >= 0 && y >= 0 && x < totalCols && y < totalRows;
}
// returns the tile at (x, y) or null if empty
public Tile getTileAt(int x, int y) {
if(isValidCoordinate(x, y))
return grid[x][y];
return null;
}
// sets the tile at (x, y) to tile
public void setTileAt(Tile tile, int x, int y) {
if(isValidCoordinate(x, y))
grid[x][y] = tile;
}
public boolean isOpen(int x, int y) {
return isValidCoordinate(x, y) && (getTileAt(x, y) == null);
}
public void collisionCheck() {
if (newPiece.isCollision()){
newPiece = new PieceSscce(this, randomPiece(), getColor());
}
}
public void changeLevel () {
int max = (level+1)*changeLevelMultiplier;
if (totalScore >= max) {
System.out.println(max + "reached... next level");
level++;
totalScore = 0;
timer();
}
}
public int tallyScore(int totalLines) {
int score = 0;
switch (totalLines) {
case 1: score = 40 * (level + 1);
break;
case 2: score = 100 * (level + 1);
break;
case 3: score = 300 * (level + 1);
break;
case 4: score = 1200 * (level + 1);
break;
default: break;
}
return score;
}
//loop through all rows starting at bottom (12 rows)
public void checkBottomFull() {
int lines = 0;
for(int row = 12; row > 0; row--) {
/* while (isFull(row)) {
lines++;
// clearRow(row);
}*/
}
totalScore += tallyScore(lines);
//check if level needs to be changed based on current score...
changeLevel();
//reset lines after score has been incremented
lines=0;
}
//loop through all columns in that row (10 columns)
public boolean isFull(int row) {
for (int col = 0; col <= 10; col++) {
System.out.println(row + ", " + col);
if(grid[row][col] == null) {
return false;
}
}
return true;
}
public void clearRow(int rowToClear) {
for(int row = rowToClear; row > 0; row--) {
for(int col = 0; col < grid[row].length; col++) {
grid[col][row] = grid[col][row-1];
}
}
}
public void checkEndGame(int x, int y) {
//if currPiece y location = 0 AND the space below is filled...
if (y <= 2 && !isOpen(x, y+1)) {
gameLost = true;
level = 0;
totalScore = 0;
//reset timer
timer();
for(int row = 0; row < grid.length; row++) {
for(int col = 0; col < grid[row].length; col++) {
grid[row][col] = null;
}
}
}
}
}
import java.awt.Color;
import java.awt.event.KeyEvent;
public class PieceSscce {
public int[] pieceCoordinates;
public String shape, currRotation;
public Color color;
public BoardSscce board;
public int rotationsCounter;
public TileSscce tile[];
public int[] newPositionX, newPositionY, currPositionX, currPositionY;
//don't need to pass in board because I'm already utilizing the Tiles class, which knows about the board
public Piece(Board b, String randomPiece, Color randomColor) {
shape = randomPiece;
color = randomColor;
board = b;
newPositionX = new int[4];
newPositionY = new int[4];
currPositionX = new int[4];
currPositionY = new int[4];
pieceCoordinates = new int[8];
//set pieceCoordinates global variable
getShape(shape);
tile = new TileSscce[4];
int counterX = 0, counterY = 1;
System.out.print("\"" + shape + "\" Coordinates: ");
//generate 4 new Tiles at specified coordinates that will compose the Piece
for (int i = 0; i < tile.length; i++) {
tile[i] = new TileSscce(board, pieceCoordinates[counterX], pieceCoordinates[counterY]);
System.out.print("(" + pieceCoordinates[counterX] + ", " + pieceCoordinates[counterY] + ") ");
//increment by 2 because x,y values are next to each other in array
counterX+=2;
counterY+=2;
}
System.out.println("\n");
for (int i = 0; i < tile.length; i++) {
tile[i].setColor(color);
}
}
public void calcNewPosition(int newX, int newY, int currTile) {
newPositionX[currTile] = newX;
newPositionY[currTile] = newY;
}
public void clearCurrPosition() {
for (int i = 0; i < tile.length; i++) {
currPositionX[i] = tile[i].getX();
currPositionY[i] = tile[i].getY();
board.setTileAt(null, currPositionX[i], currPositionY[i]);
}
}
public void autoMove() {
for (int i = 0; i < tile.length; i++) {
calcNewPosition(tile[i].getX(), tile[i].getY()+1, i);
}
clearCurrPosition();
for (int i = 0; i < tile.length; i++) {
board.checkEndGame(tile[i].getX(), tile[i].getY());
System.out.println("Checking..." + tile[i].getX() + ", " + tile[i].getY());
}
board.checkBottomFull();
board.collisionCheck();
move();
}
public void movePieceCheck(int keycode) {
if (keycode == KeyEvent.VK_DOWN) {
for (int i = 0; i < tile.length; i++) {
calcNewPosition(tile[i].getX(), tile[i].getY()+1, i);
}
clearCurrPosition();
for (int i = 0; i < tile.length; i++) {
board.checkEndGame(tile[i].getX(), tile[i].getY());
System.out.println("Checking..." + tile[i].getX() + ", " + tile[i].getY());
}
board.checkBottomFull();
board.collisionCheck();
move();
}
if (keycode == KeyEvent.VK_RIGHT) {
for (int i = 0; i < tile.length; i++) {
calcNewPosition(tile[i].getX()+1, tile[i].getY(), i);
}
clearCurrPosition();
move();
}
if (keycode == KeyEvent.VK_LEFT) {
for (int i = 0; i < tile.length; i++) {
calcNewPosition(tile[i].getX()-1, tile[i].getY(), i);
}
clearCurrPosition();
move();
}
//rotate left
if (keycode == KeyEvent.VK_A) {
int[] rotatedCoords = calcRotation("left");
clearCurrPosition();
rotate(rotatedCoords, "left");
}
//rotate right
if (keycode == KeyEvent.VK_D) {
int[] rotatedCoords = calcRotation("right");
clearCurrPosition();
rotate(rotatedCoords, "right");
}
}
public boolean movePieceValid() {
boolean valid = true;
for (int i = 0; i < tile.length; i++) {
if(!tile[i].checkNewLocation(newPositionX[i], newPositionY[i]))
valid = false;
}
return valid;
}
public boolean validRotation(int[] rotatedCoordinates) {
boolean valid = true;
int counterX = 0, counterY = 1;
for (int i = 0; i < tile.length; i++) {
if(!tile[i].checkNewLocation(rotatedCoordinates[counterX], rotatedCoordinates[counterY]))
valid = false;
counterX +=2;
counterY +=2;
}
return valid;
}
public void move() {
if (movePieceValid()) {
for (int i = 0; i < tile.length; i++) {
tile[i].setLocation(newPositionX[i], newPositionY[i]);
}
} else {
for (int i = 0; i < tile.length; i++) {
tile[i].setLocation(currPositionX[i], currPositionY[i]);
}
}
}
public void rotate(int[] rotatedCoordinates, String rotation) {
int counterX = 0, counterY = 1;
if (validRotation(rotatedCoordinates)) {
for (int i = 0; i < tile.length; i++) {
tile[i].setLocation(rotatedCoordinates[counterX], rotatedCoordinates[counterY]);
counterX+=2;
counterY+=2;
}
//else, if not valid move set the original location
} else {
for (int i = 0; i < tile.length; i++) {
tile[i].setLocation(currPositionX[i], currPositionY[i]);
}
}
}
public boolean isCollision() {
boolean collision = false;
for (int i = 0; i < tile.length; i++) {
if(tile[i].collision(newPositionX[i], newPositionY[i])) {
collision = true;
}
}
return collision;
}
//calc curr coordinates, send them to getRotation... which will create new piece based on coords
public int[] calcRotation(String direction) {
for (int i = 0; i < tile.length; i++) {
currPositionX[i] = tile[i].getX();
currPositionY[i] = tile[i].getY();
System.out.println("Current position: (" + currPositionX[i] + "," + currPositionY[i]+")");
}
return getRotation(currPositionX, currPositionY, direction);
}
public int[] getRotation (int coordinatesX[], int coordinatesY[], String direction) {
int[] rotationDirection;
int[] coordinates = new int[8];
int[] origin = new int[2];
int[] newCoordinates = new int[8];
int[] resultCoordinates = new int[8];
int[] finalCoordinates = new int[8];
int vectorMatrix[][] = new int[2][4];
//set either R(90) or R(-90) rotation matrix values:
if (direction.equals("right")) {
rotationDirection = new int[] {0, -1, 1, 0};
}
else {
rotationDirection = new int[] {0, 1, -1, 0};
}
int counterX = 0, counterY = 1, x = 0;
while (counterY < coordinates.length) {
//add arrays coordinatesX and coordinatesY into a single array: coordinates
coordinates[counterX] = coordinatesX[x];
coordinates[counterY] = coordinatesY[x];
counterX+=2;
counterY+=2;
x++;
}
//set origin so it rotates around center...
if (shape.equals("RevZ")) {
origin[0] = coordinates[6];
origin[1] = coordinates[7];
}
else if (shape.equals("T")) {
origin[0] = coordinates[4];
origin[1] = coordinates[5];
}
else {
origin[0] = coordinates[2];
origin[1] = coordinates[3];
}
//subtract origin from vectors
System.out.println();
counterX = 0;
counterY = 1;
while (counterY < newCoordinates.length) {
//System.out.println(coordinates[counterX] + ", " + coordinates[counterY]);
newCoordinates[counterX] = coordinates[counterX] - origin[0];
newCoordinates[counterY] = coordinates[counterY] - origin[1];
System.out.println("Translated coordinates: (" + newCoordinates[counterX] + ", " + newCoordinates[counterY] + ")");
counterX+=2;
counterY+=2;
}
System.out.println();
System.out.println("vector matrix:");
//fill up vectorMatrix with coordinates
int k = 0;
for (int col = 0; col < 4; col++) {
for (int row = 0; row < 2; row++) {
vectorMatrix[row][col] = newCoordinates[k++];
}
}
//print vectorMatrix:
for (int i = 0; i < vectorMatrix.length; i++) {
System.out.print("[");
for (int j = 0; j < vectorMatrix[i].length; j++) {
System.out.print(vectorMatrix[i][j]);
}
System.out.println("]");
}
int rotationMatrix[][] = new int[2][2];
//fill up rotationMatrix
System.out.println();
System.out.println("multiplicative matrix:");
k = 0;
for (int row = 0; row < 2; row++) {
System.out.print("[");
for (int col = 0; col < 2; col++) {
rotationMatrix[row][col] = rotationDirection[k++];
System.out.print(rotationMatrix[row][col]);
}
System.out.println("]");
}
//perform matrix multiplication
int[][] result = multiplyMatrices(rotationMatrix, vectorMatrix);
//print resulting matrix
System.out.println();
System.out.println("result matrix:");
for (int i = 0; i < result.length; i++) {
System.out.print("[");
for (int j = 0; j < result[i].length; j++) {
System.out.print(result[i][j]);
}
System.out.println("]");
}
//load new matrix coordinates back into array
k = 0;
for (int col = 0; col < 4; col++) {
for (int row = 0; row < 2; row++) {
resultCoordinates[k] = result[row][col];
k++;
}
}
System.out.println();
System.out.println("result coordinates:");
counterX = 0;
counterY = 1;
while (counterY < resultCoordinates.length) {
finalCoordinates[counterX] = resultCoordinates[counterX] + origin[0];
finalCoordinates[counterY] = resultCoordinates[counterY] + origin[1];
System.out.print("("+finalCoordinates[counterX] + ", " + finalCoordinates[counterY]+")");
counterX+=2;
counterY+=2;
}
return finalCoordinates;
}
public int[][] multiplyMatrices(int rotationMatrix[][], int vectorMatrix[][]) {
int mA = rotationMatrix.length;
int nA = rotationMatrix[0].length;
int mB = vectorMatrix.length;
int nB = vectorMatrix[0].length;
if (nA != mB) throw new RuntimeException("Illegal matrix dimensions.");
int[][] C = new int[mA][nB];
for (int i = 0; i < mA; i++) {
for (int j = 0; j < nB; j++) {
for (int k = 0; k < nA; k++) {
C[i][j] += (rotationMatrix[i][k] * vectorMatrix[k][j]);
}
}
}
return C;
}
public int[] getShape(String shape) {
if (shape.equals("L")) {
//pieceCoordinates = new int[] {0, 1, 0, 2, 1, 2, 2, 2};
pieceCoordinates = new int[] {4, 0, 4, 1, 5, 1, 6, 1};
}
else if (shape.equals("O")) {
pieceCoordinates = new int[] {0, 1, 1, 1, 0, 2, 1, 2};
}
else if (shape.equals("Z")) {
pieceCoordinates = new int[] {0, 1, 1, 1, 1, 2, 2, 2};
}
else if (shape.equals("RevZ")) {
pieceCoordinates = new int[] {1, 1, 2, 1, 0, 2, 1, 2};
}
else if (shape.equals("Bar")) {
//pieceCoordinates = new int[] {0, 1, 1, 1, 2, 1, 3, 1};
pieceCoordinates = new int[] {0, 1, 1, 1, 2, 1, 3, 1};
}
else if (shape.equals("T")) {
pieceCoordinates = new int[] {1, 1, 0, 2, 1, 2, 2, 2};
}
else if (shape.equals("RevL")) {
pieceCoordinates = new int[] {0, 2, 1, 2, 2, 2, 2, 1};
}
return pieceCoordinates;
}
}
import java.awt.Color;
import java.util.Random;
public class TileSscce {
private BoardSscce board;
private int currX, currY;
private Color color;
public TileSscce(BoardSscce b, int x, int y) {
board = b;
//when Tile is instantiated, set its position
setLocation(x, y);
}
public int getX() {
return currX;
}
public int getY() {
return currY;
}
public boolean checkNewLocation(int newX, int newY) {
boolean newLocationOK = board.isOpen(newX, newY);
return newLocationOK;
}
public boolean collision(int newX, int newY) {
boolean collision = this.getY() == ((board.getHeight()/board.getTileSize()))-2 || board.getTileAt(newX, newY) != null;
return collision;
}
public void setLocation(int newX, int newY) {
// board.setTileAt(null, currX, currY);
currX = newX;
currY = newY;
board.setTileAt(this, currX, currY);
}
public Color getColor() {
return setColor(color);
}
public Color setColor(Color myColor) {
color = myColor;
return color;
}
}
Thanks!
EDIT----------
I've tried implementing both ValarDohaeris and Svend Hansen's suggestions... Now the block is moving right when I press down, up when I press left, and down when I press right...
It seems to have to do with these methods in Board class which get and set tile locations...
// returns the tile at (x, y) or null if empty
public Tile getTileAt(int row, int col) {
System.out.println("getTileAt: " + row + ", " + col);
if(isValidCoordinate(row, col))
return grid[row][col];
return null;
}
// sets the tile at (x, y) to tile
public void setTileAt(Tile tile, int row, int col) {
System.out.println("setTileAt: " + row + ", " + col);
if(isValidCoordinate(row, col))
grid[row][col] = tile;
}
And in Piece class... movements are defined as:
public void movePieceCheck(int keycode) {
if (keycode == KeyEvent.VK_DOWN) {
for (int i = 0; i < tile.length; i++) {
calcNewPosition(tile[i].getRow()+1, tile[i].getCol(), i);
}
clearCurrPosition();
for (int i = 0; i < tile.length; i++) {
board.checkEndGame(tile[i].getRow(), tile[i].getCol());
}
board.checkBottomFull();
if (isCollision()) board.createNewPiece();
move();
}
if (keycode == KeyEvent.VK_RIGHT) {
for (int i = 0; i < tile.length; i++) {
calcNewPosition(tile[i].getRow(), tile[i].getCol()+1, i);
}
clearCurrPosition();
move();
}
if (keycode == KeyEvent.VK_LEFT) {
for (int i = 0; i < tile.length; i++) {
calcNewPosition(tile[i].getRow(), tile[i].getCol()-1, i);
}
clearCurrPosition();
move();
}
You have
grid = new TileSscce[totalRows][totalCols];
So when you want to access grid[x][y], you should check
x >= 0 && y >= 0 && x < totalRows && y < totalCols
in isValidCoordinate(x, y).
Emm... Quite interesting question. So to find out where the problem(s) may be I'll try to analyze your code a little bit...
You paste stack trace as
Exception in thread "AWT-EventQueue-0" java.lang.ArrayIndexOutOfBoundsException: 10
at Board.getTileAt(Board.java:177)
...
and at the same time the getTileAt()
// returns the tile at (x, y) or null if empty
public Tile getTileAt(int row, int col) {
System.out.println("getTileAt: " + row + ", " + col);
if(isValidCoordinate(row, col))//isValidCoordinate()?
return grid[row][col];
return null;
}
public boolean isValidCoordinate(int x, int y) {
return x >= 0 && y >= 0 && x < totalCols && y < totalRows;
}
... so the isValidCoordinate method return terms as
x >= 0 && y >= 0 && x < totalCols && y < totalRows
...the method doesn't allow to avoid array out-of-bounds problems; Seems like you put wrong array element indexes.
A. As I can notice, you trying to put a classic math matrix on Java [][] arrays as
public void clearRow(int rowToClear) {
for(int row = rowToClear; row > 0; row--) {
for(int col = 0; col < grid[row].length; col++) {//<-- ?
grid[col][row] = grid[col][row-1];
}
}
}
... and here I must say that you should know that in [][] arrays x,y are backwards and it is y,x because :
y (or classic i) - sub-array index (vertical)
x (or classic j) - sub-array's element index (horizontal)
so you should use array index something this way grid[y][x] or grid[i][j]
As a useful tip, I recommend you to analyze your code for logic errors in this field...
B. According to your app screenshot as
... it seems like the x,y problem takes place here too because you trying to control y (vertical) coordinates but (in real) you control x (horizontal) coordinates only :S It is still because of the row,col instead of a classic Java (col,row or y,x) [][] array index positions.
C. And again concerning to the wrong directions...
...up when I press left, and down when I press right...
if (keycode == KeyEvent.VK_RIGHT) {
for (int i = 0; i < tile.length; i++) {
calcNewPosition(tile[i].getRow(), tile[i].getCol()+1, i);
}
clearCurrPosition();
move();
}
Here I'll try to analyze the event as (you press right but move down)...
OK... according to one of your tasks you need to move by x coordinate (horizontally) but look closer... you make tile[i].getCol()+1 so it is newY and, of course, it moves vertically :S In your case it really moves down because you make increment as y++ ...
public void calcNewPosition(int newX, int newY, int currTile) {
newPositionX[currTile] = newX;
newPositionY[currTile] = newY;
}
public void clearCurrPosition() {
for (int i = 0; i < tile.length; i++) {
currPositionX[i] = tile[i].getX();
currPositionY[i] = tile[i].getY();
board.setTileAt(null, currPositionX[i], currPositionY[i]);
}
}
public void move() {
if (movePieceValid()) {
for (int i = 0; i < tile.length; i++) {
tile[i].setLocation(newPositionX[i], newPositionY[i]);//<-- !
}
} else {
for (int i = 0; i < tile.length; i++) {
tile[i].setLocation(currPositionX[i], currPositionY[i]);
}
}
}
...as a conclusion, I may recommend to change code (move right) something this way...
if (keycode == KeyEvent.VK_RIGHT) {
for (int i = 0; i < tile.length; i++) {
calcNewPosition(tile[i].getRow()+1, tile[i].getCol(), i);
}
clearCurrPosition();
move();
}
I hope my tips will help you to figure out what to look closer. Anyway, if you have some additional information please do comment my answer
Report if that helped you
This is based on x corresponds to columns and y corresponds to rows.
However grid is indexed by [row][col].
TileSscce grid[][] = new TileSscce[totalRows][totalCols]; // 12 => totalRows, 10 => totalCols
public int getWidth() {
return totalCols * tilesize;
}
public int getHeight() {
return totalRows * tilesize;
}
Following changes (based on your initial code - Sscce: - without later edits) will get rid of the exception and allow drawing till bottom of the board.
public void paintComponent(Graphics g) {
for (int row = 0; row < grid.length; row++) {
for (int col = 0; col < grid[row].length; col++) {
if (grid[row][col] != null) {
g.setColor(grid[row][col].getColor());
g.fillRect(col * tilesize, row * tilesize, tilesize, tilesize); // changed, check below snippet from fillRect documentation
g.setColor(Color.WHITE);
}
}
}
}
public TileSscce getTileAt(int x, int y) {
if (isValidCoordinate(x, y))
return grid[y][x]; // changed to [y][x] as grid is indexed by [row][col]
return null;
}
public void setTileAt(TileSscce tile, int x, int y) {
if (isValidCoordinate(x, y))
grid[y][x] = tile; // changed to [y][x] as grid is indexed by [row][col]
}
From fillRect documentation.
public abstract void fillRect(int x, int y, int width, int height)
The left and right edges of the rectangle are at x and x + width - 1.
The top and bottom edges are at y and y + height - 1.
This is correct.
public boolean isValidCoordinate(int x, int y) {
return x >= 0 && y >= 0 && x < totalCols && y < totalRows;
}