Problems with ArrayIndexOutOfBoundsException - java

I'm quite new to java, and I'm going to need some help here:
package com.game.libs;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
public class Animation {
private int speed = 0; // defines in how many ticks the animation should go to the next frame
private int amountOfFrames = 0; //amount of frames in the animation
private int index = 0; //time value used in the method runAnimation()
private int currentFrameNumber = 0; //the number of the current frame
private BufferedImage frames[]; //images in the animation
private BufferedImage currentFrameImage; //current frame's image
//13 frame animation
public Animation(BufferedImage[] img, int fps){
frames = img;
amountOfFrames = img.length-1;
speed = 60/fps;
for (int i=0;i<img.length-1;i++){
this.frames[i] = img[i];
currentFrameNumber = 0;
currentFrameImage = img[0];
}
}
public void runAnimation(){
index++;
if(index > speed){
index = 0;
nextFrame();
}
}
public void nextFrame(){
currentFrameNumber++;
if(currentFrameNumber > amountOfFrames)
currentFrameNumber = 1;
currentFrameImage = frames[currentFrameNumber]; // THIS IS THE LINE WITH THE ERROR
}
public void drawAnimation(Graphics graphics, int x, int y, int offset){
graphics.drawImage(currentFrameImage, x - offset, y, null);
}
public void setCurrentFrame(int currentFrame){
this.currentFrameNumber = currentFrame;
}
public int getCurrentFrameNumber(){
return currentFrameNumber;
}
public int getFps(){
return speed;
}
public void setFps(int fps){
this.speed = 60/fps;
}
public void setFrames(BufferedImage[] img){
this.frames = img;
amountOfFrames = img.length;
}
public BufferedImage[] getFrames(){
return frames;
}
}
the error that im getting is array index out bounds. in line 38 (nextFrame method, its in the code)
I've encountered this error before, and I know how to (and tried) to fix it but it says 1 and even 0 are out of bounds...
Plox help, I know this is vague :(, but i tried to make my question (and the code) clear.
remember, im new to java, have had experience with waaaaaaay easier languages/engines but understand quite a bit.

Do note that Java arrays are indexed starting at 0, so it is strange (but not wrong) that in nextFrame() you reset currentFrameNumber to 1 instead of 0 when it runs over.
Also, it's pretty redundant to use amountOfFrames to control the iteration count. The usual Java idioms involve using the array .length directly, maybe
if(currentFrameNumber >= frames.length) {
currentFrameNumber = 0;
}
None of that really explains the exception you get, though, so there must be more to it.
Or something else to it: perhaps the class that is throwing the exception was not compiled from the same version of the code that you present.

Related

Why no speedup with more than one thread?

I'm creating a toy program in java using synchronized block. I have n "Pixelator" threads which pick a random pixel in a 1000x1000 image and assign it to the color of the Pixelator. Each pixel can only be assigned once. I write to a bufferedImage using a wrapper class that uses a synchronized method to write to the image. However, when I test with more than 1 thread, I do not see a speedup. Do you have a hint as to why that would be?
Relavant Code:
import java.awt.Color;
import java.awt.image.*;
import java.io.*;
import javax.imageio.*;
import java.util.ArrayList;
import java.util.Random;
public class q2 {
// The image constructed
public static BufferedImage img;
// Image dimensions; you could also retrieve these from the img object.
public static int width;
public static int height;
// simplified method for stack overflow example
public static int rgbFromN(int n) {
return -16755216;
}
public static void main(String[] args) {
Random r = new Random();
try {
// arg 0 is the width
width = 1000;
// arg 1 is the height
height = 1000;
// arg 2 is the number of threads
int nt = 1;
// create an image and initialize it to all 0's
img = new BufferedImage(width,height,BufferedImage.TYPE_INT_ARGB);
synchronizedIMG simg = new synchronizedIMG(img);
for (int i=0;i<width;i++) {
for (int j=0;j<height;j++) {
img.setRGB(i,j,0);
}
}
Thread[] threads = new Thread[nt];
long startTime = System.currentTimeMillis();
for (int i = 0; i < threads.length; i++) {
threads[i] = new Thread(new Pixelator(rgbFromN(i),width,height,((width*height)/nt),simg));
threads[i].start();
}
for (int i = 0; i < threads.length; i++) {
threads[i].join();
}
long endTime = System.currentTimeMillis();
System.out.println("Time(ms): " + (endTime-startTime));
// Write out the image
File outputfile = new File("outputimage.png");
ImageIO.write(img, "png", outputfile);
} catch (Exception e) {
System.out.println("ERROR " +e);
e.printStackTrace();
}
}
}
class Pixelator implements Runnable {
int color;
int width;
int height;
int numPixels;
int currentPixels = 0;
synchronizedIMG simg;
public Pixelator(int color, int width, int height,int numPixels, synchronizedIMG simg){
this.color = color;
this.width = width;
this.height = height;
this.numPixels = numPixels;
this.simg = simg;
}
public void run() {
int randomX = 0;
int randomY = 0;
boolean success = false;
while(currentPixels < numPixels){
randomX = 0 + (int)(Math.random() * (width));
randomY = 0 + (int)(Math.random() * (height));
success = simg.setColor(color, randomX, randomY);
if(success){
currentPixels++;
}
}
return;
}
}
class synchronizedIMG{
BufferedImage img;
public synchronizedIMG(BufferedImage img){
this.img = img;
}
public synchronized boolean setColor(int color, int x, int y){
if(img.getRGB(x, y) == 0){
img.setRGB(x, y, color);
return true;
} else{
return false;
}
}
}
It requires a certain amount of time to the machine to manage the threads. In image processing, use two threads instead of one, does not reduce the processing time by 50%, but between 30 % to 40 according to the processing (empirical estimation with the multi-threaded classes of my own java library).
Moreover in your case, you don't do any major processing just simple computation. So it's longer to manage the threads than doing the processing on a single thread. Try to do a big convolution.
The biggest problem you face is that adding more threads will not increase the memory bandwidth of your system.
Your threads do nothing except compute random numbers and write them out to memory. Adding more threads potentially increases the speed with which you can compute the random numbers, but that probably was pretty fast to begin with. Math.random() is not a crypto-quality random number generator. It probably is very fast.
Unfortunately, your job isn't done until all of the bytes have been written out to memory. Your system has only one memory bus, and it can only go so fast. All of the threads have to contend for that resource.

Why doesn't my GUI show squares after repaint()? [duplicate]

I posted this question a bit earlier and was told to make it SSCCE so here goes (if I can make any improvements feel free to let me know):
I'm wondering why when my button "confirm" is clicked the old squares disappear and the redrawn squares do not appear on my GUI (made with swing). The Squares class draws 200 spaced out squares with an ID (0, 1, 2, or 3 as String) inside obtained from a different class (for the purpose of this question, let's assume it is always 0 and not include that class). For clarification: Squares draws everything perfectly the first time (also retrieves the correct IDs), but I want it to redraw everything once the button is clicked with new IDs.
Code for Squares:
import javax.swing.*;
import java.awt.*;
import java.awt.geom.*;
import java.util.ArrayList;
public class Squares extends JPanel{
private ArrayList<Rectangle> squares = new ArrayList<Rectangle>();
private String stringID = "0";
public void addSquare(int x, int y, int width, int height, int ID) {
Rectangle rect = new Rectangle(x, y, width, height);
squares.add(rect);
stringID = Integer.toString(ID);
if(ID == 0){
stringID = "";
}
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
FontMetrics fm = g2.getFontMetrics();
int fontAscent = fm.getAscent();
g2.setClip(new Rectangle(0,0,Integer.MAX_VALUE,Integer.MAX_VALUE));
for (Rectangle rect : squares) {
g2.drawString(stringID, rect.x + 7, rect.y + 2 + fontAscent);
g2.draw(rect);
}
}
}
Code for GUI:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class GUIReserver extends JFrame implements Runnable{
private int myID;
private JButton confirm = new JButton("Check Availability and Confirm Reservation");
private JFrame GUI = new JFrame();
private Squares square;
public GUIReserver(int i) {
this.myID = i;
}
#Override
public void run() {
int rows = 50;
int seatsInRow = 4;
confirm.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent evt) {
GUI.getContentPane().remove(square);
square = new Squares();
int spaceNum = 0;
int rowNum = 0;
int offsetX = 200;
int offsetY = 0;
for(int i = 0; i < rows * seatsInRow; i++){
square.addSquare(rowNum * 31 + offsetX,spaceNum * 21 + 50 + offsetY,20,20, 0); //normally the 4th parameter here would retrieve the ID from the main class
rowNum++;
if(rowNum == 10){
rowNum = 0;
spaceNum++;
}
if(spaceNum == 2){
spaceNum = 3;
rowNum = 0;
}
if(spaceNum == 5){
spaceNum = 0;
offsetY += 140;
}
}
GUI.getContentPane().add(square); //this does not show up at all (could be that it wasn't drawn, could be that it is out of view etc...)
GUI.repaint(); //the line in question
}
});
GUI.setLayout(new FlowLayout());
GUI.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
GUI.setLocation(0,0);
GUI.setExtendedState(JFrame.MAXIMIZED_BOTH);
square = new Squares();
int spaceNum = 0;
int rowNum = 0;
int offsetX = 200;
int offsetY = 0;
for(int i = 0; i < rows * seatsInRow; i++){
square.addSquare(rowNum * 31 + offsetX,spaceNum * 21 + 50 + offsetY,20,20, 0); //normally the 4th parameter here would retrieve the ID from the main class
rowNum++;
if(rowNum == 10){
rowNum = 0;
spaceNum++;
}
if(spaceNum == 2){
spaceNum = 3;
rowNum = 0;
}
if(spaceNum == 5){
spaceNum = 0;
offsetY += 140;
}
}
GUI.getContentPane().add(square); //this shows up the way I wish
GUI.add(confirm);
GUI.pack();
GUI.setVisible(true);
}
}
Code for main:
public class AircraftSeatReservation {
static AircraftSeatReservation me = new AircraftSeatReservation();
private final int rows = 50;
private final int seatsInRow = 4;
private int seatsAvailable = rows * seatsInRow;
private Thread t3;
public static void main(String[] args) {
GUIReserver GR1 = new GUIReserver(3);
me.t3 = new Thread(GR1);
me.t3.start();
}
}
One major problem: Your Squares JPanels preferred size is only 20 by 20, and will likely actually be that size since it seems to be added to a FlowLayout-using container. Next you seem to be drawing at locations that are well beyond the bounds of this component, and so the drawings likely will never be seen. Consider allowing your Squares objects to be larger, and make sure to only draw within the bounds of this component.
Note also there is code that doesn't make sense, including:
private int myID;
private JTextField row, column, instru draft saved // ???
package question2;ction1, instruction2, seatLabel, rowLabel; // ???
I'm guessing that it's
private int myID;
private JTextField row, column, instruction1, instruction2, seatLabel, rowLabel;
And this won't compile for us:
int rows = AircraftSeatReservation.getRows();
int seatsInRow = AircraftSeatReservation.getSeatsInRow(); // and shouldn't this take an int row parameter?
since we don't have your AircraftSeatReservation class (hopefully you don't really have static methods in that class).
And we can't compile or run your current code. We don't want to see your whole program, but rather you should condense your code into the smallest bit that still compiles, has no extra code that's not relevant to your problem, but still demonstrates your problem. So as Andrew Thompson recommends, for better help, please create and post your Minimal, Complete, and Verifiable example or Short, Self Contained, Correct Example.
I would try to OOP-ify your problem as much as possible, to allow you to divide and conquer. This could involve:
Creating a SeatClass enum, one with possibly two elements, FIRST and COACH.
Creating a non-GUI Seat class, one with several fields including possibly: int row, char seat ( such as A, B, C, D, E, F), a SeatClass field to see if it is a first class seat or coach, and a boolean reserved field that is only true if the seat is reserved.
This class would also have a getId() method that returns a String concatenation of the row number and the seat char.
Creating a non-GUI Airplane class, one that holds two arrays of Seats, one for SeatClass.FIRST or first-class seats, and one for SeatClass.COACH.
It would also have a row count field and a seat count (column count) field.
After creating all these, then work on your GUI classes.
I'd create a GUI class for Seats, perhaps GuiSeat, have it contain a Seat object, perhaps have it extend JPanel, allow it to display its own id String that it gets from its contained Seat object, have it override getBackground(...) so that it's color will depend on whether the seat is reserved or not.
etc.....

Rotating a String or char clockwise by 90 degrees

Folks, I'm having a really hard time with rotating a Shape clockwise by 90 degrees. I'm having troubles with completing it. If there is a shape:
.t.
ttt
The method rotateBy90() rotates the above shape by 90 degrees clockwise, so it'll be the following output:
t.
tt
t.
THe shapes are of a String type.
Here what I have and Im pretty sure Im completely doing it wrong. The method can be done by using either char[][], or char[], or String[], or String[][]. Another issue is that rotateBy90() is a void method. COuld smb please help me with this rotation algorithm? Thanks in advance!
import java.util.*;
public class CreateShape {
private int height;
private int width;
private char dc;
private Rotation initialPos;
private Rotation nextPos;
private char[][] shape = new char[height][width];
String[] shapeLayout = new String[height];
String[] rotatedArray;
public CreateShape(int height, int width, char dc)
{
this.height = height;
this.width = width;
this.dc = dc;
initialPos = Rotation.CW0;
}
public void rotateBy90()
{
nextPos = initialPos.next();
String newLayout = "";
int count = 0;
String[] newMatrixColumns= shape.split("\n");
while (count < shape.split("\n")[0].length()) {
for (int i = newMatrixColumns.length - 1; i > -1; i--) {
newLayout += newMatrixColumns[i].charAt(count);
}
newLayout = newLayout + "\n";
count++;
}
}
I don't quite get your approach and where your difficulties lie. I also don't get why you have so many unused fields. You may want to set your width and height fields final, as they shouldn't really change in this case.
Personally I think by far the easiest is to use a char[][]. All you have to do then is iterate your initial char[][] and place the element at the appropriate place in your new char[][]. So in your method you'd have something like
public void rotateBy90()
{
// bla bla
char[][] tempShape = new char[width][height];
for(int j = 0; j < width; j++) {
for(int i = 0; i < height; i++) {
tempShape[...][...] = myShape[i][j]; //I'll leave this as exercise
}
}
myShape = tempShape;
}
Word of caution: be careful with strings. Many string operations involve creating other strings (split, substring, concatenation etc). If you do them in a long loop, you may run out of memory fairly quickly.

Adding Offsets to My Java Game

So, as the title reads I am trying to add offsets to my java game. I was given a tip by a friend that I need to minus the offset from where I render the tiles onto my screen.
So I created a random world generator and did the offset thing, but I ran into a problem.
My Code:
public void generateMap(Graphics g) {
block = seed.nextInt(2);
//Render Dirt
if(block == 0) {
g.drawImage(Assets.dirt, x - GameState.xOffset, y - GameState.yOffset, null);
x += 32;
}
//Render Grass
if(block == 1) {
g.drawImage(Assets.grass, x - GameState.xOffset, y - GameState.yOffset, null);
x += 32;
}
//Check Where the X is
if(x > xFinish) {
if(y < yFinish) {
x = xStart;
y += 32;
}
}
}
looks simple enough right? after I do that I create code to add one to the offset every time I loop around:
public void tick() {
xOffset += 1;
}
So after that is done I run it but it does this:
is there any simple way I can fix this so that it appears that the screen "scrolls" to the left?
Is there any simple way I can fix this...
Probably not. Games are complicated. Don't let that dissuade you.
You are generating your game world and drawing in the same methods - you don't want to do this. Separation of responsibility is very important - you don't want a whole bunch of code in one spot doing the same thing. In this case, the functionality to generate the world and the drawing code need to be split.
For the world generation, generate the game world once, and persist it to storage using whatever format you like. Keep this away from the drawing code - it has no place there.
For representing blocks in your world, consider something like this:
class Block {
public BlockType getType() {
return type;
}
public int getxPosition() {
return xPosition;
}
public int getyPosition() {
return yPosition;
}
// hashCode(), equals(), etc omitted, they should be implemented
public static enum BlockType {
Dirt(Assets.dirt),
Grass(Assets.grass);
private final BufferedImage image;
BlockType(BufferedImage image) {
this.image = image;
}
public BufferedImage getImage() {
return image;
}
}
private final BlockType type;
private final int xPosition;
private final int yPosition;
private Block(BlockType type, int xPosition, int yPosition) {
this.type = type;
this.xPosition = xPosition;
this.yPosition = yPosition;
}
public static Block getInstance(BlockType type, int xPosition, int yPosition) {
return new Block(type, xPosition, yPosition);
}
}
You can then use Block.getInstance() to generate a map once, like this:
class GameState {
private final int WORLD_SIZE = 1024;
private Block[][] _world = new Block[WORLD_SIZE][WORLD_SIZE];
private static Random seed = new Random();
public void generateMap() {
int blockTypeLength = Block.BlockType.values().length;
for (int x = 0; x < WORLD_SIZE; x++) {
for (int y = 0; y < WORLD_SIZE; y++) {
int blockType = seed.nextInt(blockTypeLength);
_world[x][y] = Block.getInstance(Block.BlockType.values()[blockType], x, y);
}
}
}
public Block[][] getMap() {
return _world; // not thread safe, shares internal state, all the usual warnings
}
This obviously isn't the only way to generate a world - you would probably generate a world and save, then load from disk in later games (unless it was a short lived game - I don't know, that's your call).
Once you've got the world sorted out, you'd move on to a different module that would handle drawing. Assume GameState has two fields playerX and playerY that represent the player's coordinates in the game world (note: direct fields like this are bad practice, but used to simplify this example):
public void paintComponent(Graphics g) {
super.paintComponent(g);
Block[][] screen = new Block[16][16]; // declare a screen buffer to draw
// Assumes player is in the center of the screen
int screenRadiusX = GameFrame.Assets.SCREENBOUNDS_X / 2 / blockSize;
int screenRadiusY = GameFrame.Assets.SCREENBOUNDS_Y / 2 / blockSize;
for (int x = state.playerX - 8, xS = 0; x < state.playerX + 8; x++, xS++) {
for (int y = state.playerY - 8, yS = 0; y < state.playerY + 8; y++, yS++) {
screen[xS][yS] = world[x][y];
}
}
for (int x = 0; x < screen.length; x++) {
for (int y = 0; y < screen.length; y++) {
Block current = screen[x][y];
g.drawImage(current.getType().getImage(),
x * blockSize, // blockSize is the pixel dimension of
y * blockSize,
null
);
}
}
}
If this helps, then great! I'm glad I was able to help. If not, or if some ideas are still unclear, then I would consider perhaps running through a tutorial or book that walks you through making a game. Don't forget to learn the platform you're coding on during such a process.

Referencing indexed Arrays [duplicate]

This question already exists:
Closed 10 years ago.
Possible Duplicate:
Checking against indexed arrays
So i have my code, every time the mouse is pressed it draws a new particle at mouseX and mouseY and stores the position in an array so it can update until told to stop when it reaches the bottom of the screen. What i would like to do is check the current position against that of an already 'made' particle and have it stop sooner if it has the same coordinates, to give a stacking effect, can someone please help me?
import java.awt.Point;
import org.newdawn.slick.GameContainer;
import org.newdawn.slick.Graphics;
import org.newdawn.slick.SlickException;
import org.newdawn.slick.state.BasicGameState;
import org.newdawn.slick.state.StateBasedGame;
public class Control extends BasicGameState {
public static final int ID = 1;
public Methods m = new Methods();
public Point[] point = new Point[(800 * 600)];
int pressedX;
int pressedY;
int num = 0;
String Build = "1.1";
public void init(GameContainer container, StateBasedGame game) throws SlickException{
}
public void render(GameContainer container, StateBasedGame game, Graphics g) throws SlickException {
for (int index = 0; index < point.length; index++) {
Point p = point[index];
if (p != null) {
if (p.y >= 598) {
m.drawParticle(point[index].x,(point[index].y));
} else {
m.drawParticle(p.x, p.y);
p.y++;
}
}
}
g.drawString("Particle Test", 680, 0);
g.drawString("Build: " + Build, 680, 15);
g.drawString("Pixels: " + num, 10, 25);
}
public void update(GameContainer container, StateBasedGame game, int delta) {
}
public void mousePressed(int button, int x, int y) {
pressedX = x;
pressedY = y;
num = num + 1;
point[num] = new Point(pressedX, pressedY);
}
public int getID() {
return ID;
}
}
You can use the coordinates as a hash and store the points in a HashSet, just overload the hashing function of Point with something like x*y
You can write a new method that checks to see if the point is in the array at an index of less than "Index".
public boolean isInArray(int index)
{
for (int index2 = 0; index2 < index; index2++)
{
if( (point[index2].x == point[index].x) &&
(point[index2].y == point[index].y) )
{
return true; //point(index) is previously in array
}
}
return false; //point(index) is NOT previously in array
}
Then in your for..next loop, you'll need to use the break statement
if (isInArray(index))
{
//the break statement causes the program to exit the current loop
break;
}
However, you might be better served by testing it in your MousePressed method to avoid adding the point to the array in the first place if it's a duplicate.
Good luck!

Categories