Error on Processing when making an Ecosystem [duplicate] - java

This question already has answers here:
What causes a java.lang.ArrayIndexOutOfBoundsException and how do I prevent it?
(26 answers)
Closed 3 years ago.
I was doing an ecosystem on Processing when I couldn't make my animal reach the fruit, at first I was trying to make the animal find the food and then reach it, but it didn't work out as the animal was randomly walking the screen, so on my second try, I did something similar to gravitational attraction and made the fruit attract the animal, but I ended up with this error, "ArrayIndexOutOfBoundsException: 1" can anyone try to find the source of this problem?
This is the first page:
Animal[] animal = new Animal[1];
Predator predator;
Fruit[] fruit = new Fruit[2];
void setup() {
size(1536, 864);
for(int i = 0; i < animal.length; i++) {
animal[i] = new Animal();
}
predator = new Predator();
for(int i = 0; i < fruit.length; i++) {
fruit[i] = new Fruit();
}
}
void draw() {
background(60);
fill(255);
grid();
for(int i = 0; i < animal.length; i++) {
animal[i].display();
animal[i].update();
animal[i].checkEdge();
}
for(int i = 0; i < fruit.length; i++) {
PVector seek = fruit[i].attractAnimal(animal[i]);
animal[i].gatherFood(seek);
fruit[i].display();
}
}
void grid() {
strokeWeight(3);
stroke(65);
for(int i = 0; i < width; i++) {
line(70 * i, 0, 70 * i, height);
}
for(int i = 0; i < height; i++) {
line(0, 70 * i, width, 70 * i);
}
}
This is the Animal class:
class Animal {
PVector pos;
PVector vel;
PVector acc;
float mass;
Animal() {
pos = new PVector(random(0, width), random(0, height));
vel = new PVector(0, 0);
acc = new PVector(0, 0);
mass = random(5, 10);
}
void update() {
pos.add(vel);
vel.add(acc);
acc.mult(0);
}
void checkEdge() {
if(pos.x >= width || pos.x <= 0) {
vel.x = -vel.x;
}
if(pos.y >= height || pos.y <= 0) {
vel.y = -vel.y;
}
}
void gatherFood(PVector will) {
PVector w = PVector.div(will, mass);
acc.add(w);
}
void display() {
fill(255 , 150);
stroke(100);
strokeWeight(5);
ellipse(pos.x, pos.y, mass * 5, mass * 5);
}
}
This is the fruit class:
class Fruit {
PVector pos;
Fruit() {
pos = new PVector(random(0, width), random(0, height));
}
void display() {
fill(0, 185, 0);
stroke(0, 100, 0);
strokeWeight(3);
ellipse(pos.x, pos.y, 15, 15);
}
PVector attractAnimal(Animal animal) {
PVector dir = PVector.sub(pos, animal.pos);
dir.normalize();
float walk = 10 / animal.mass;
dir.mult(walk);
return dir;
}
}

Your problem is here:
for(int i = 0; i < fruit.length; i++) {
PVector seek = fruit[i].attractAnimal(animal[i]);
// this line and the previous for i = 1
animal[i].gatherFood(seek);
fruit[i].display();
}
You have 2 fruits and one animal. When you are accessing animal[i] for the I = 1, which is the second animal, you are out of the available index of the array, resulting to this exception.

Related

Change object color by mouse click in Processing

I am working on a school project in Processing (Java Mode). The task is to change the color of the Ball object if it is clicked.
Unfortunately I am stuck on changing just one object. If I click on the screen all objects change color.
Here are my classes:
Ball[] barray= new Ball[20];
void setup(){
size(400,400);
for (int i=0; i<20; i++){
barray[i] = new Ball();
}
strokeWeight(40);
}
void draw(){
background(255,255,255);
for (int i=0; i<barray.length; i++){
barray[i].paint();
}
for (int i=0; i<barray.length; i++){
barray[i].move();
}
if (mousePressed) {
for (int i = 0; i < barray.length; i++) {
barray[i].testHint();
}
}
}
Ball class:
public class Ball {
int x, diffx;
int y, diffy;
public Ball() {
x= (int) random(1, width);
diffx= (int) random(1, 5);
y= (int) random(1, height);
diffy= (int) random(1, 5);
}
public void move(){
x += diffx;
if (x<0 || x> width){
diffx *= -1;
}
y += diffy;
if (y<0 || y> height){
diffy *= -1;
}
}
public void paint(){
point(x,y);
}
public void testHint() {
float d = dist(mouseX,mouseY,this.x,this.y);
if ( d < 5){
stroke(255,0,0);
point(this.x,this.y);
}
}
}
Thank you for your help.
So here is working example (http://hello.processing.org/display/##-MDZNtlpRsdS_3GSlvvg):
public class Ball {
int x, diffx;
int y, diffy;
bool active;
public Ball() {
active = false;
x= (int) random(1, width);
diffx= (int) random(1, 5);
y= (int) random(1, height);
diffy= (int) random(1, 5);
}
public void move(){
x += diffx;
if (x<0 || x> width){
diffx *= -1;
}
y += diffy;
if (y<0 || y> height){
diffy *= -1;
}
}
public void paint(){
if(active) {
stroke(255,0,0);
}
point(x,y);
stroke(0,0,0);
}
public void testHint() {
float d = dist(mouseX,mouseY,this.x,this.y);
if ( d < 5 ) {
active = true;
}
}
}
Ball[] barray= new Ball[20];
void setup(){
size(400,400);
for (int i=0; i<20; i++){
barray[i] = new Ball();
}
strokeWeight(40);
}
void draw(){
background(255,255,255);
for (int i=0; i<barray.length; i++){
barray[i].paint();
}
for (int i=0; i<barray.length; i++){
barray[i].move();
}
if (mousePressed) {
for (int i = 0; i < barray.length; i++) {
barray[i].testHint();
}
}
}
The color you are giving in the stroke function will be active for all paints after that so that's why you have to reset it back to black after the point() call. And thus having active flag for all your balls to change the color before drawing it.

Trouble with 2d array to make freeze one object and duplicate said object 90 pixels to the right

I am trying to make it so that when I hit space, I can pause a moving rectangle stack on one position, and duplicate it 90 pixels to the right and complete the same motion. This should happen across the columns (grids) on the canvas. I'm thinking a 2D array will be needed, but I am stuck on how to do this.
If anyone knows how to do this I would greatly appreciate some assistance.
float loc;
float sizeW;
float sizeH;
float dir;
boolean moving = true;
void setup() {
size(1280, 720);
loc = 0;
dir = (float)height/720;
sizeW = (float)width/14.2;
sizeH = (float)height/8;
}
void draw() {
background(255);
Rectangle();
grid();
}
void Rectangle() {
fill(255, 147, 79);
stroke(0);
int steppedPos = (int)(loc/sizeH+0.5);
rect(0, steppedPos*sizeH, sizeW, sizeH);
for (int i =0; i<90*4; i+=90) {
rect(0, steppedPos*sizeH+i, sizeW, sizeH);
}
if (moving) {
loc = loc + dir;
if (loc + sizeH + 270 > height || loc < 0) {
dir = dir * -1;
loc = loc + dir;
}
}
}
void keyPressed() {
if (key == ' ') {
moving = !moving;
}
}
void grid() {
for (int i=0; i<width; i+=90) {
line(i, 0, i, height);
}
for (int j=0; j<height; j+=90) {
line(0, j, width, j);
}
}
So here is a quick way of duplicating the columns to the right.
What I'm doing is adding 90 to valueX every time you hit the spacebar. valueX then will be gone throw in the nested for-loop.
I hope that this is the output you wanted! (If not then leave a comment and I'll try to fix it.)
float loc;
float sizeW;
float sizeH;
float dir;
float valueX = 0;
boolean moving = true;
void setup() {
size(1280, 720);
loc = 0;
dir = (float)height/720;
sizeW = (float)width/14.2;
sizeH = (float)height/8;
}
void draw() {
background(255);
Rectangle();
grid();
}
void Rectangle() {
fill(255, 147, 79);
stroke(0);
int steppedPos = (int)(loc/sizeH+0.5);
// rect(0, steppedPos*sizeH, sizeW, sizeH);
for (int i =0; i<90*4; i+=90) {
for(int j = 0; j <= valueX; j+= 90){
rect(0 + j, steppedPos*sizeH+i, sizeW, sizeH);
}
}
if (moving) {
loc = loc + dir;
if (loc + sizeH + 270 > height || loc < 0) {
dir = dir * -1;
loc = loc + dir;
}
}
}
void keyPressed() {
if (key == ' ') {
moving = !moving;
valueX += 90;
}
}
void grid() {
for (int i=0; i<width; i+=90) {
line(i, 0, i, height);
}
for (int j=0; j<height; j+=90) {
line(0, j, width, j);
}
}
Your idea with the a 2d array isn't bad, but the problem is that arrays have a fixed size. So what you would like to use is an ArrayList for the x-axis and an Array for the y-axis (as long as this stays a fixed size). This would look similar to this:
ArrayList<int[]> list = new ArrayList<int[]>();
With this method you could look at Object Orientation, just to clean up things. (If you'd like to I can show you how your code would look like object-oriented)
Greetings and good Luck!

Java game a bullet killed all object on the screen

I am trying to make a plane shooting game.
I have a plane with a number of laser(maxLaser) and a number of random enemies.
When I create a single random enemy it is fine but when I make a number of enemy I have a tiny problem.
When I shot any of enemy with the bullet(laser) kills every enemies on the screen.
I guess I have a problem with two nested loops (maxLaser and maxEnemy) but I could not figure out.
This is the code I am trying to fix that calculate distance laser and enemy
public void updatehelicopter(double dt) {
helicopterSpin = getFrame(0.2, 4);
// nested loop for kill enemies
for(int l =0; l<maxHelicopter; l++){
helicopterPositionX[l] += helicopterVelocityX[l] * dt;
helicopterPositionY[l] += helicopterVelocityY[l] * dt;
// if(helicopterActive[l]==true){
for (int i = 0; i < maxLaser; i++) {
if (laserActive[i] == true) {
if (distance(laserPositionX[i], laserPositionY[i], helicopterPositionX[l], helicopterPositionY[l]) < 20* 1.2) {
// Destroy the laser
laserActive[i] = false;
helicopterActive[l]=false;
// Create an explosion
createExplosion(helicopterPositionX[i], helicopterPositionY[l]);
// Create a new random helicopter
randomhelicopter();
}
}
}
}
}
The idea is, I want to create 10 enemies and when shot one of them the program that I want to create one more simultaneously.
Here is my Laser and Enemies classes that you can imagine.
Enemy:
Image helicopters;
Image[] helicopterF = new Image[4];
Image[] helicopterR = new Image[4];
Image[] helicopterL = new Image[4];
Image helicopterImage;
// helicopter Position
double[] helicopterPositionX;
double[] helicopterPositionY;
double[] helicopterVelocityX;
double[] helicopterVelocityY;
double[] helicopterAngle;
int helicopterSpin;
boolean helicopterLeft;
boolean helicopterRight;
boolean[] helicopterActive;
int maxHelicopter;
int numhelicopter ;
public void inithelicopter() {
maxHelicopter = 10;
numhelicopter = maxHelicopter;
helicopterPositionX = new double[maxHelicopter];
helicopterPositionY = new double[maxHelicopter];
helicopterVelocityX= new double[maxHelicopter];
helicopterVelocityY= new double[maxHelicopter];
helicopterAngle = new double[maxHelicopter];
helicopterActive = new boolean[maxHelicopter];
for(int i =0; i<maxHelicopter;i++){
helicopterActive[i]=false;
}
// Load image
// helicopterPositionX= 300;
for (int i = 0; i < 4; i++) {
helicopterF[i] = subImage(helicopters, 0 + i * 300, 0, 300, 300);
}
for (int i = 0; i < 4; i++) {
helicopterR[i] = subImage(helicopters, 0 + i * 300 + 1200, 0, 300, 300);
}
for (int i = 0; i < 4; i++) {
helicopterL[i] = subImage(helicopters, 0 + i * 300 + 2400, 0, 300, 300);
}
// helicopterPositionY= 400;
// helicopterImage = subImage(spritesheet, 480, 0, 240, 240);
}
// Randomly position helicopter
public void randomhelicopter() {
for (int i = 0; i < numhelicopter; i++) {
// Random position
// random number between lower and upper limit for direction of items
helicopterPositionX[i] = (int) (Math.random() * (600 - 500)) + 500;
helicopterPositionY[i] = rand(-500);
// Random Velocity
helicopterVelocityX[i] = -20;
helicopterVelocityY[i] = 80;
// Random Angle
helicopterAngle[i] = 40;
}
}
// Function to update 'move' the helicopter
public void updatehelicopter(double dt) {
helicopterSpin = getFrame(0.2, 4);
//
for(int l =0; l<maxHelicopter; l++){
helicopterPositionX[l] += helicopterVelocityX[l] * dt;
helicopterPositionY[l] += helicopterVelocityY[l] * dt;
// if(helicopterActive[l]==true){
for (int i = 0; i < maxLaser; i++) {
if (laserActive[i] == true) {
if (distance(laserPositionX[i], laserPositionY[i], helicopterPositionX[l], helicopterPositionY[l]) < 20* 1.2) {
// Destroy the laser
laserActive[i] = false;
helicopterActive[l]=false;
// Create an explosion
createExplosion(helicopterPositionX[i], helicopterPositionY[l]);
// Create a new random helicopter
randomhelicopter();
}
}
}
}
}
public void drawhelicopter() {
// Save the current transform
for(int i=0; i<maxHelicopter; i++){
saveCurrentTransform();
// ranslate to the position of the helicopter
translate(helicopterPositionX[i], helicopterPositionY[i]);
// Rotate the drawing context around the angle of the helicopter
rotate(helicopterAngle[i]);
// Draw the actual helicopter
//int i = getAnimationFrame(explosionTimer, explosionDuration, 30);
drawImage(helicopterF[helicopterSpin], -30, -30, 110, 110);
// Restore last transform to undo the rotate and translate transforms
restoreLastTransform();
}
}
Laser:
Image laserImage;
double[] laserPositionX;
double[] laserPositionY;
// Laser velocity
double[] laserVelocityX;
double[] laserVelocityY;
// Laser Angle
double[] laserAngle;
// Laser active
boolean[] laserActive;
// Laser Mode
int laserMode;
double rapidFireDelay;
double rapidFireTimer;
int maxLaser, numLaser;
// NOTE: try first add 5 different level and if works then you should try make
// one laser and should cahnge only image
public void laserInit() {
maxLaser = 9;
numLaser = maxLaser;
laserMode = 0;
rapidFireDelay = 0.1;
laserPositionX = new double[maxLaser];
laserPositionY = new double[maxLaser];
laserVelocityX = new double[maxLaser];
laserVelocityY = new double[maxLaser];
laserAngle = new double[maxLaser];
laserActive = new boolean[maxLaser];
for (int i = 0; i < maxLaser; i++) {
laserActive[i] = false;
}
laserImage = subImage(laser, 1536, 0, 512, 512);
}
public void fireLaser(double x, double y, double angle) {
for (int i = 0; i < numLaser; i++) {
if (laserActive[i] == false) {
laserPositionX[i] = x;
laserPositionY[i] = y;
laserVelocityX[i] = sin(angle) * 350;
laserVelocityY[i] = -cos(angle) * 350;
laserAngle[i] = angle;
// laseractive[i] == true;
laserActive[i] = true;
break;
}
}
}
public void fireLaser() {
// NOTE: check variable of laserpower
if (laserMode == 0) {
// Normal Mode
fireLaser(airplanePositionX, airplanePositionY, airplaneAngle);
} else if (laserMode == 1) {
// Scatter Shot
int inactiveLasers = 0;
// For all lasers
for (int i = 0; i < numLaser; i++) {
// Check if laser is inactive
if (laserActive[i] == false) {
// Count number of inactive lasers
inactiveLasers++;
}
}
// Check if at least 3 lasers are free
if (inactiveLasers >= 3) {
// Fire three lasers
fireLaser(airplanePositionX, airplanePositionY, airplaneAngle - 15);
fireLaser(airplanePositionX, airplanePositionY, airplaneAngle);
fireLaser(airplanePositionX, airplanePositionY, airplaneAngle + 15);
}
} else if (laserMode == 2) {
// Rapid-Fire Mode
fireLaser(airplanePositionX, airplanePositionY, airplaneAngle + rand(20.0) - 10);
}
}
public void createLaser() {
saveCurrentTransform();
for (int i = 0; i < maxLaser; i++) {
if (laserActive[i]) {
saveCurrentTransform();
translate(laserPositionX[i], laserPositionY[i]);
rotate(laserAngle[i]);
drawImage(laserImage, -30, -30, 60, 60);
restoreLastTransform();
}
}
restoreLastTransform();
}
public void laserUpdate(double dt) {
if (laserMode == 2 && space) {
// Increment Timer
rapidFireTimer += dt;
// If Timer is greater than delay
if (rapidFireTimer > rapidFireDelay) {
// Decrement delay
rapidFireTimer -= rapidFireDelay;
// Fire laser
fireLaser();
}
}
for (int i = 0; i < maxLaser; i++) {
laserPositionX[i] += laserVelocityX[i] * dt;
laserPositionY[i] += laserVelocityY[i] * dt;
if (laserPositionX[i] < 0) {
laserActive[i] = false;
}
if (laserPositionX[i] >= width()) {
laserActive[i] = false;
}
if (laserPositionY[i] < 0) {
laserActive[i] = false;
}
}
}
I am not sure how correct I am so can I get your advise?
Externally some class in code:
public double distance(double x1, double y1, double x2, double y2) {
// Calculate and return the distance
return Math.sqrt(Math.pow(x2-x1, 2) + Math.pow(y2-y1, 2));
}

Java Tetris - Confused on grid[row][col] and coordinates (x, y)

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;
}

Detect mouseclick on object Slick2d

I've made this code that successfully creates a 16x12 grid by 50x50 squares on a 800x600px board.
As you can see, the player moves to the coordinates of the players mouseclick.
Each square of the grid has an object of Felt (field) on it, which can be laast (locked). If a fields lock attribute is set to 1, the player should not be moved to that position.
How do i detect the field a player tries to move on to achieve this?
public class SimpleGame extends BasicGame{
private Image plane;
private float planeX;
private float planeY;
public SimpleGame()
{
super("SpilTest");
}
#Override
public void init(GameContainer gc) throws SlickException {
plane = new Image("figur.png");
}
#Override
public void update(GameContainer gc, int delta) throws SlickException {
Input input = gc.getInput();
if (input.isMousePressed(input.MOUSE_LEFT_BUTTON)) {
this.planeX = input.getMouseX() - 30;
this.planeY = input.getMouseY() - 50;
}
}
public void render(GameContainer gc, Graphics g) throws SlickException {
Felt board[][] = nytGrid();
int distancex = 0;
int distancey = 0;
int counter = 0;
for (int i=0; i < board.length ; i++) {
for (int j=0; j < board[i].length ; j++) {
if (board[i][j].getLaast() == 1) {
g.setColor(Color.red);
g.fillRect(distancex, distancey, 50, 50);
}
distancex += 50;
counter++;
if (counter == 16) {
distancey += 50;
distancex = 0;
counter = 0;
}
}
}
g.drawImage(plane, planeX, planeY);
}
public static void main(String[] args) throws SlickException {
AppGameContainer app = new AppGameContainer(new SimpleGame());
app.setDisplayMode(800, 600, false);
app.setTargetFrameRate(60);
app.start();
}
public Felt[][] nytGrid() {
Felt [][] board = new Felt[16][12];
for (int i=0; i < board.length ; i++) {
for (int j=0; j < board[i].length ; j++) {
int x = i;
int y = j;
board[i][j] = new Felt(x, y);
if (i == 5 && j == 5) {
board[i][j].setLaast(1);
}
}
}
return board;
}
}
First off, you should probably initialize the board in the init() method instead of render, so it doesn't have to do it every frame, and move the declaration for the grid next to the plane, planeX and planeY declarations in the class.
Now to disable movement into a locked square, first add a method to check if a square at certain coordinates is locked, so something along the lines of:
private boolean isLocked(int x, int y) {
int square = board[x/50][y/50];
if (square == 1) return true;
else return false;
}
Next modify the part of your update() method where you update the plane coordinates, so vaguely something like:
if (input.isMousePressed(input.MOUSE_LEFT_BUTTON)) {
int destX = input.getMouseX() - 30;
int destY = input.getMouseY() - 50;
if (!isLocked(destX, destY)) {
this.planeX = destX;
this.planeY = destY;
}
}
It's easy!
int mx = Mouse.getX();
int my = Mouse.getY();
But, it gives you the world cordinates, and you have to translate it to pixels:
int mx = Mouse.getX();
int my = Mouse.getY() * -1 + (Window.WIDTH / 2) + 71;

Categories

Resources