How to rotate BufferedImage as object itself - java

I have trouble with performance when I am rotating every image, when drawing it FPS has dropped from 1400 to 6. Can I rotate BufferedImage object just after creating it, so the calculation happens only once?
There is my Grid Control class: (Drawing class, problem method is drawRotated())
package cs.meowxiik.universes.graphics;
import java.awt.Canvas;
import java.awt.Graphics;
import java.awt.geom.AffineTransform;
import java.awt.image.AffineTransformOp;
import java.awt.image.BufferedImage;
import java.awt.image.ImageObserver;
import java.util.Observer;
import cs.meowxiik.universes.map.Map;
import cs.meowxiik.universes.map.Tile;
public class GridControl {
int width;
int height;
int xcells;
int ycells;
int cellWidth;
int cellHeight;
int maxZoom = 80;
int minZoom = 30;
private Map activeMap;
public GridControl(int width, int height, int xcells, int ycells) {
this.width = width;
this.height = height;
this.xcells = xcells;
this.ycells = ycells;
cellWidth = width / xcells;
cellHeight= height/ ycells;
}
public GridControl(int width, int height, int cellWidth, int cellHeight, int thisDoesntMatterJustForOverloading) {
this.width = width;
this.height = height;
this.cellWidth = cellWidth;
this.cellHeight = cellHeight;
xcells = width / cellWidth;
ycells = height / cellHeight;
}
public void drawGrid(Graphics g){
for(int i = 0; i < xcells; i++){
for(int ii = 0; ii <ycells; ii++){
g.drawRect(i * cellWidth, ii * cellHeight, cellWidth, cellHeight);
}
}
}
public int getCellSize() {
return cellWidth;
}
public void editCellSize(int i) {
if(i == 0)return;
System.out.println("Resizing: " + i);
//Pokud je i menší jak 0 -> člověk se pokouší přibližovat
if(i < 0 && xcells > maxZoom)return;
if(i > 0 && xcells < minZoom)return;
this.cellWidth += i;
this.cellHeight += i;
xcells = width / cellWidth;
ycells = height / cellHeight;
}
public void setActiveMap(Map map){
this.activeMap = map;
}
public void drawMap(Graphics g, Canvas canvas){
if(activeMap != null){
for(int i = 0; i < xcells; i++){
for(int ii = 0; ii <ycells; ii++){
drawRotated(activeMap.getTiles()[i][ii].getTexture(),activeMap.getTiles()[i][ii].getDegrees(), i*cellWidth, ii*cellWidth,canvas, g, null);
//ImageObserver observer = null;
//g.drawImage(activeMap.getTiles()[i][ii].getTexture(), i*cellWidth, ii*cellWidth, observer);
}
}
}
}
public Tile getTileByCoordinate(int x, int y){
int cellx = x / this.cellWidth;
int celly = y / this.cellHeight;
return activeMap.getTiles()[cellx][celly];
}
public boolean isWalkable(int x, int y){
return getTileByCoordinate(x,y).getWalkable();
}
public void drawRotated(BufferedImage img,double rotationRequired,int x,int y,Canvas canvas, Graphics g, Observer observer){
//double rotationRequired = Math.toRadians(degrees);
double locationX = img.getWidth() / 2;
double locationY = img.getHeight() / 2;
AffineTransform tx = AffineTransform.getRotateInstance(rotationRequired, locationX, locationY);
AffineTransformOp op = new AffineTransformOp(tx, AffineTransformOp.TYPE_BILINEAR);
// Drawing the rotated image at the required drawing locations
g.drawImage(op.filter(img, null), x, y, null);
}}
My Tile method:
public class Tile {
boolean walkable;
BufferedImage image;
double radians;
int ID; //0 - floor, 1 - wall
public Tile(boolean walkable, BufferedImage image, int ID) {
this.walkable = walkable;
this.image = image;
this.ID = ID;
}
public BufferedImage getTexture() {
return image;
}
public boolean getWalkable() {
return walkable;
}
public int getDegrees() {
return (int) Math.toDegrees(radians);
}
public int getID() {
return ID;
}
public void setTexture(BufferedImage image, int degrees) {
this.image = image;
this.radians = Math.toRadians(degrees);
}
}
And my Map creator: (the rotating part is broken, I'll fix that later, now I need to solve my 6-FPS problem)
package cs.meowxiik.universes.map;
import cs.meowxiik.universes.graphics.GraphicsManager;
public class MapCreator {
GraphicsManager graphics;
public MapCreator(GraphicsManager graphics) {
this.graphics = graphics;
}
public Map getSpaceStationMap(){
Map map;
int x = 32;
int y = 18;
Tile[][] tiles = new Tile[x][y];
for(int i = 0; i < x; i++){
for(int ii = 0; ii < y; ii++){
tiles[i][ii] = new Tile(true, graphics.floor, 0);
}
}
for(int i = 0; i < x; i++){
for(int ii = 0; ii < y; ii++){
if(i == 0 || ii == 0 || i == x-1 || ii == y-1)tiles[i][ii] = new Tile(false,graphics.stWallZero, 1); //tiles.get(i).set(ii, new Tile(false,graphics.wall));
}
}
for(int i = 0; i < x; i++){
for(int ii = 0; ii < y; ii++){
if(tiles[i][ii].getID() == 0)break;
boolean connectedUp = false;
boolean connectedLeft = false;
boolean connectedRight = false;
boolean connectedBottom = false;
if(i + 1 < tiles.length)
if(tiles[i + 1][ii + 0].getID() == 1)
connectedRight = true;
if(i != 0)
if(tiles[i - 1][ii + 0].getID() == 1)
connectedLeft = true;
if(ii + 1 < tiles[i].length)
if(tiles[i + 0][ii + 1].getID() == 1)
connectedBottom = true;
if(ii != 0)
if(tiles[i + 0][ii - 1].getID() == 1)
connectedUp = true;
if(connectedUp && !(connectedLeft || connectedRight || connectedBottom))tiles[i][ii].setTexture(graphics.stWallOne, 0);
if(connectedLeft && !(connectedUp || connectedRight || connectedBottom))tiles[i][ii].setTexture(graphics.stWallOne, 90);
if(connectedRight && !(connectedUp || connectedLeft || connectedBottom))tiles[i][ii].setTexture(graphics.stWallOne, 180);
if(connectedBottom && !(connectedUp || connectedRight || connectedLeft))tiles[i][ii].setTexture(graphics.stWallOne, 270);
if((connectedUp && connectedBottom) && !(connectedLeft || connectedRight))tiles[i][ii].setTexture(graphics.stWallTwo, 90);
if(!(connectedUp && connectedBottom) && !(connectedLeft || connectedRight))tiles[i][ii].setTexture(graphics.stWallTwo, 0);
}
}
map = new Map(x,y,tiles);
return map;
}
}

Given this code
public void drawRotated(BufferedImage img,double rotationRequired,int x,int y,Canvas canvas, Graphics g, Observer observer) {
//double rotationRequired = Math.toRadians(degrees);
double locationX = img.getWidth() / 2;
double locationY = img.getHeight() / 2;
AffineTransform tx = AffineTransform.getRotateInstance(rotationRequired, locationX, locationY);
AffineTransformOp op = new AffineTransformOp(tx, AffineTransformOp.TYPE_BILINEAR);
BufferedImage rotatedImage = op.filter(img, null); // my edit here
// Drawing the rotated image at the required drawing locations
g.drawImage(rotatedImage , x, y, null);
}
The rotation of the image to get rotatedImage is only dependant upon it's size (width/height) and the required rotation.
From my reading of your code the required rotation is largely fixed. The rotation is known when the setTexture method of Title is called.
Sine this is the case, rotatedImage can be computed in the setTexture method. Just create a new attribute that stores the computed rotated image. Don't destroy the original.
If setTexture is called as often as drawRotated then this won't deliver the performance increase you desire.

Related

problem with rendering a sprite sheet (pixels not rendering and shifting to the left)

this is my first time asking a question on stack overflow.
I've been following this tutorial on making a 2D game with java and have come across a problem...
When run my program it renders my sprite sheet very weirdly:
My JFrame:
his JFrame:
I have no Idea what is causing this problem but here is my code. i'm sorry if it is too long.
game.java:
import java.awt.BorderLayout;
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.image.BufferStrategy;
import java.awt.image.BufferedImage;
import java.awt.image.DataBufferInt;
import javax.swing.JFrame;
import com.leekman.game.gfx.screen;
import com.leekman.game.gfx.spriteSheet;
public class Game extends Canvas implements Runnable{
private static final long serialVersionUID = 1L;
public boolean running = false;
public static final int WIDTH = 160;
public static final int HEIGHT = WIDTH / 12 * 9;
public static final int SCALE = 3;
public static final String NAME = "Game";
private JFrame frame;
public int tickCount = 0;
private BufferedImage img = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB);
private int[] pixels = ((DataBufferInt)img.getRaster().getDataBuffer()).getData();
private screen scrn;
public Game() {
setMinimumSize(new Dimension(WIDTH * SCALE, HEIGHT * SCALE));
setMaximumSize(new Dimension(WIDTH * SCALE, HEIGHT * SCALE));
setPreferredSize(new Dimension(WIDTH * SCALE, HEIGHT * SCALE));
frame = new JFrame(NAME);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(this, BorderLayout.CENTER);
frame.pack();
frame.setResizable(false);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public void init() {
scrn = new screen(WIDTH, HEIGHT, new spriteSheet("/Sprite_sheet.png"));
}
private synchronized void start() {
running = true;
new Thread(this).start();
}
private synchronized void stop() {
running = false;
}
#Override
public void run() {
long lastTime = System.nanoTime();
double NSpertick = 1000000000D / 60D;
int ticks= 0;
int frames = 0;
long lastTimer = System.currentTimeMillis();
double unproccesedTime = 0;
init();
while (running) {
long now = System.nanoTime();
unproccesedTime += (now - lastTime) / NSpertick;
lastTime = now;
boolean shouldRender = true;
while (unproccesedTime >= 1) {
ticks++;
tick();
unproccesedTime -= 1;
shouldRender = true;
}
try {
Thread.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (shouldRender) {
frames++;
render();
}
if (System.currentTimeMillis() - lastTimer >= 1000) {
lastTimer += 1000;
System.out.println(frames+", "+ticks);
frames = 0;
ticks = 0;
}
}
}
public void tick() {
tickCount++;
for (int i = 0; i < pixels.length; i++) {
pixels[i] = i + tickCount;
}
}
public void render() {
BufferStrategy bs = getBufferStrategy();
if (bs == null) {
createBufferStrategy(3);
return;
}
scrn.render(pixels, 0, WIDTH);
Graphics g = bs.getDrawGraphics();
g.setColor(Color.BLACK);
g.drawRect(0, 0, getWidth(), getHeight());
g.drawImage(img, 0, 0, getWidth(), getHeight(), null);
g.dispose();
bs.show();
}
public static void main(String[] args) {
new Game().start();
}
}
spriteSheet.java:
import java.awt.image.BufferedImage;
import java.io.IOException;
import javax.imageio.ImageIO;
public class spriteSheet {
public String path;
public int width;
public int height;
public int[] pixels;
public spriteSheet(String path) {
BufferedImage image = null;
try {
image = ImageIO.read(spriteSheet.class.getResourceAsStream(path));
} catch (IOException e) {
e.printStackTrace();
}
if (image == null) {
return;
}
this.path = path;
this.height = image.getHeight();
this.width = image.getWidth();
pixels = image.getRGB(0, 0, width, height, null, 0, width);
for (int i = 0; i < pixels.length; i++) {
pixels[i] = (pixels[i] & 0xff) / 64;
}
for (int i = 0; i < 8; i++) {
System.out.println(pixels[i]);
}
}
}
screen.java:
public class screen {
public static final int MAP_WIDTH = 64;
public static final int MAP_WIDTH_MASK = MAP_WIDTH - 1;
public int[] tiles = new int[MAP_WIDTH * MAP_WIDTH];
public int[] colours = new int[MAP_WIDTH * MAP_WIDTH * 4];
public int Xoffset = 0;
public int Yoffset = 0;
public int height;
public int width;
public spriteSheet sheet;
public screen(int width, int height , spriteSheet sheet) {
this.height = height;
this.width = width;
this.sheet = sheet;
for (int i = 0; i < MAP_WIDTH * MAP_WIDTH; i++) {
colours[i * 4 + 0] = 0xff00ff;
colours[i * 4 + 1] = 0x00ffff;
colours[i * 4 + 2] = 0xffff00;
colours[i * 4 + 3] = 0xffffff;
}
}
public void render(int[] pixels, int offset, int row) {
for (int yTile = Yoffset >> 3; yTile <= (Yoffset + height) >> 3; yTile++) {
int yMin = yTile * 8 - Yoffset;
int yMax = yMin + 8;
if (yMin < 0) {
yMin = 0;
}
if (yMax > height) {
yMax = height;
}
for (int xTile = Xoffset >> 3; xTile <= (Xoffset + width) >> 3; xTile++) {
int xMin = xTile * 8 - Xoffset;
int xMax = xMin + 8;
if (xMin < 0) {
xMin = 0;
}
if (xMax > width) {
xMax = width;
}
int tileIndex = (xTile & (MAP_WIDTH_MASK)) + (yTile & (MAP_WIDTH_MASK)) * MAP_WIDTH;
for (int y = yMin; y < yMax; y++) {
int sheetpix = y + ((y + Yoffset) & 7) * sheet.width + ((xMin + Xoffset) & 7);
int tilepix = offset + xMin + y * row;
for (int x = xMin; x < xMax; x++) {
int colour = tileIndex * 4 + sheet.pixels[sheetpix++];
pixels[tilepix++] = colours[colour];
}
}
}
}
}
}
Any help would be very much appreciated, thanks!!

Raytracing: Dark rings appear

I am getting strange rings of black on my spheres when I render with lighting. I just added lighting and I cannot figure out why the black rings are being created.
Here is my code for my tracer.
public class Tracer {
public Camera Cam;
public int Width, Height;
public BufferedImage Image;
public Color BackGroundColor;
public int StartX, StartY, EndX, EndY,RowCount,ColCount;
public ArrayList<GeometricObject> GeoObjects;
public ArrayList<LightObject> LightObjects;
public boolean Tracing;
public double AmbientLight;
public Tracer(Camera cam, int width, int height, BufferedImage image, Color backGroundColor, int startX, int startY, int endX, int endY, int rowCount, int colCount, ArrayList<GeometricObject> Geoobjects,ArrayList<LightObject> Lightobjects,double ambientLight) {
super();
Cam = cam;
Width = width;
Height = height;
Image = image;
BackGroundColor = backGroundColor;
StartX = startX;
StartY = startY;
EndX = endX;
EndY = endY;
RowCount = rowCount;
ColCount = colCount;
GeoObjects = Geoobjects;
LightObjects = Lightobjects;
if(ambientLight > 1){
AmbientLight = 1;
}else if(ambientLight < 0){
AmbientLight = 0;
}else{
AmbientLight = ambientLight;
}
}
public void TracePixelFast(int x, int y) {
Color color = new Color(BackGroundColor.r,BackGroundColor.g,BackGroundColor.b);
for(int o = 0;o < GeoObjects.size();o++){
GeometricObject GO = GeoObjects.get(o);
Ray r = new Ray(Cam.GetRayPos(Width, Height, x, y, 1, 1, RowCount, ColCount), Cam.GetRayDir(Width, Height, x, y, 1,1, RowCount, ColCount));
double hit = GO.hit(r);
if (hit != 0.0) {
color = Cal_Pixel(x,y);
Image.setRGB(x, y, color.toInt());
break;
}
}
}
public void TracePixelSmooth(int x, int y) {
Image.setRGB(x, y,Cal_Pixel(x,y).toInt());
}
public Color Cal_Pixel(int x,int y){
Color color = new Color(BackGroundColor);
Color colorh = new Color(BackGroundColor);
Color bgc = new Color(BackGroundColor);
int HIT = 0;
int MISS = 0;
for (int row = 0; row < RowCount; row++) {
for (int col = 0; col < ColCount; col++) {
double min = Double.MAX_VALUE;
for (int o = 0; o < GeoObjects.size(); o++) {
GeometricObject GO = GeoObjects.get(o);
Ray r = new Ray(Cam.GetRayPos(Width, Height, x, y, row, col, RowCount, ColCount),Cam.GetRayDir(Width, Height, x, y, row, col, RowCount, ColCount));
double hit = GO.hit(r);
if (hit != 0.0 && hit < min) {
min = hit;
colorh = ShadePixel(GO, r, hit);
HIT++;
} else {
double min2 = Double.MAX_VALUE;
for (int o2 = 0; o2 < GeoObjects.size(); o2++) {
if(o!=o2){
GeometricObject GO2 = GeoObjects.get(o2);
double hit2 = GO2.hit(r);
if (hit2 != 0.0 && hit2 < min2) {
min2 = hit2;
bgc = ShadePixel(GO2, r, hit2);
}
}
}
MISS++;
}
}
}
}
for(int h = 0;h < HIT;h++){
color.Add(colorh);
}
for(int m = 0;m < MISS;m++){
color.Add(bgc);
}
color.Divide(RowCount * ColCount);
return color;
}
public Color ShadePixel(GeometricObject GO,Ray ray,double t){
ArrayList<Color> PixelShade = new ArrayList<Color>();
Normal normal = GO.Cal_Normal(ray, t);
for(int l = 0;l < LightObjects.size();l++){
LightObject light = LightObjects.get(l);
Vector3D r_Dir = light.Pos.Sub(normal.Origin);
r_Dir.normalize();
Ray raytolight = new Ray(normal.Origin,r_Dir);
int WAS_HIT = 0;
for(int o = 0;o < GeoObjects.size();o++){
GeometricObject NGO = GeoObjects.get(o);
double hit = NGO.hit(raytolight);
if (hit != 0.0) {
WAS_HIT = 1;
}
}
if(WAS_HIT == 0){
double Dot = normal.Direction.Dot(r_Dir);
if(Dot < 0){
Dot = 0;
}
double Diffuse = 1 - AmbientLight;
Color color = new Color(GO.Color);
double Shade = AmbientLight + Diffuse*Dot;
color.Mul(Shade);
PixelShade.add(color);
}else{
Color color = new Color(GO.Color);
double Shade = AmbientLight;
color.Mul(Shade);
PixelShade.add(color);
}
}
Color Final = new Color();
for(int s = 0;s < PixelShade.size();s++){
Final.Add(PixelShade.get(s));
}
Final.Divide(PixelShade.size());
return Final;
}
public void TraceArea(boolean SmoothTracing) {
Tracing = true;
if(SmoothTracing){
for (int x = StartX; x < EndX; x++) {
for (int y = StartY; y < EndY; y++) {
TracePixelSmooth(x,y);
}
}
}else{
for (int x = StartX; x < EndX; x++) {
for (int y = StartY; y < EndY; y++) {
TracePixelFast(x,y);
}
}
}
}
}
And here is the code for the sphere.
public class Sphere extends GeometricObject{
public Vector3D Center;
public double Radius;
public Sphere(Vector3D Center,double Radius,Color Color){
this.Center = Center;
this.Radius = Radius;
this.Color = Color;
}
public double hit(Ray ray) {
double a = ray.Direction.Dot(ray.Direction);
double b = 2 * ray.Origin.Sub(Center).Dot(ray.Direction);
double c = ray.Origin.Sub(Center).Dot(ray.Origin.Sub(Center))-Radius*Radius;
double discreminant = b*b-4*a*c;
if(discreminant < 0.0f){
return 0.0;
}else{
double t = (-b - Math.sqrt(discreminant))/(2*a);
if(t > 10E-9){
return t;
}else{
return 0.0;
}
}
}
public Normal Cal_Normal(Ray ray,double t) {
Vector3D NPos = new Vector3D(ray.Origin.x + ray.Direction.x*t,ray.Origin.y + ray.Direction.y*t,ray.Origin.z + ray.Direction.z*t);
Vector3D NDir = NPos.Sub(Center).Div(Radius);
return new Normal(NPos,NDir);
}
}
I am sure the problem is in shadepixel() but I could be wrong.
I just found out that the more objects that I add the more rings there are:
1 object no rings.
2 objects 1 ring.
3 objects 2 rings.
If you need me to post more of my code.Just ask and I will.
When I get back from school I will post my color class and fix the color problem. I still do not understand why the more objects (spheres) I add, the more rings there are. Can anyone explain to me why this is happening?
Here is my Color code.
public class Color {
public float r,g,b;
public Color(){
r = 0.0f;
g = 0.0f;
b = 0.0f;
}
public Color(float fr,float fg,float fb){
r = fr;
g = fg;
b = fb;
}
public Color(Color color){
r = color.r;
g = color.g;
b = color.b;
}
public void Add(Color color){
r += color.r;
g += color.g;
b += color.b;
}
public void Divide(int scalar){
r /= scalar;
g /= scalar;
b /= scalar;
}
public void Mul(double mul){
r *= mul;
g *= mul;
b *= mul;
}
public int toInt(){
return (int) (r*255)<<16 | (int) (g*255)<<8 | (int) (b*255);
}
There are multiple issues with this code, but the direct reason for the rings is that color component values are overflowing 0-255 range. This in turn is caused by incorrect calculations in what I take to be an attempt at antialiasing in Cal_Pixel(), as well as by no control whatsoever of numeric range in ShadePixel().
Think about how you can visually debug this scene.
First are the normals correct? Display them as the colour to see.
Taking the range for each component [-1..1] to the range [0..255]:
r = 255*(n.x + 1)/2;
g = 255*(n.y + 1)/2;
b = 255*(n.z + 1)/2;
Once you think they look correct move on to the next stage and build it up stage by stage.
e.g. you might look at if your dot product is as expected (again [-1..1] because the vectors are supposedly normalised):
r = 255*(dot + 1)/2;
g = 255*(dot + 1)/2;
b = 255*(dot + 1)/2;

How to make circle clickable

I am developing game using canvas. I have drawn grid of circles using loop. I want to get x,y coordinates of circles. For that I have to make those circles clickable so that whenever player click on a circle it should return its coordinates. I will pass those coordinates to lineDraw() method for drawing line between those circles.
This loop is defining grid of circles:
for (int y=0;y<rows;y++)
{
for (int x=0;x<cols;x++)
{
canvas.drawCircle((x + 1) * dw, (y + 1) *(3* dh), 20, pDot);
}
}
Here dw is (displayWidth) and dh is (displayHeight). Please suggest how I should make these circles clickable?
I had played with this project a little after your previous questions. I'm sure this isn't the most optimized way to do this, but without knowing how you plan to implement the game logic, I think this is flexible enough to adapt. The following is your custom View class, which I've renamed Board, in keeping with Java naming conventions.
public class Board extends View
{
Paint pBack = new Paint();
Paint pDot = new Paint();
Paint pLine = new Paint();
int cols = 5;
int rows = 6;
// Default initialization = false
boolean[][] dots = new boolean[cols][rows];
int canWidth = 0;
int canHeight = 0;
float xStep = 0;
float yStep = 0;
float[] xCoords = new float[cols];
float[] yCoords = new float[rows];
public Board(Context context)
{
super(context);
pBack.setARGB(255, 255, 102, 0);
pDot.setARGB(255, 255, 255, 255);
pLine.setStrokeWidth(5);
pLine.setARGB(255, 90, 10, 0);
}
public void setDots(boolean[][] dotSelected)
{
this.dots = dotSelected;
}
public boolean[][] getDots()
{
return dots;
}
protected void onSizeChanged(int w, int h, int oldw, int oldh)
{
canWidth = w;
canHeight = h;
xStep = canWidth / (cols + 1);
yStep = canHeight / (rows + 1);
for (int y = 0; y < rows; y++)
{
yCoords[y] = (y + 1) * yStep;
}
for (int x = 0; x < cols; x++)
{
xCoords[x] = (x + 1) * xStep;
}
}
protected void onDraw(Canvas canvas)
{
super.onDraw(canvas);
canvas.drawPaint(pBack);
// Grid, lines and box markings
for (int y = 0; y < rows; y++)
{
canvas.drawLine(xStep, yCoords[y], cols * xStep, yCoords[y], pDot);
for (int x = 0; x < cols; x++)
{
if (y == 0)
{
canvas.drawLine(xCoords[x], yStep, xCoords[x], rows * yStep, pDot);
}
if (dots[x][y])
{
boolean left = x > 0 && dots[x - 1][y];
boolean up = y > 0 && dots[x][y - 1];
if (left)
{
canvas.drawLine(xCoords[x], yCoords[y], xCoords[x - 1], yCoords[y], pLine);
}
if (up)
{
canvas.drawLine(xCoords[x], yCoords[y], xCoords[x], yCoords[y - 1], pLine);
}
if (left && up && dots[x - 1][y - 1])
{
canvas.drawCircle(xCoords[x] - xStep / 2, yCoords[y] - yStep / 2, 10, pLine);
}
}
}
}
// Dots
for (int y = 0; y < rows; y++)
{
for (int x = 0; x < cols; x++)
{
canvas.drawCircle(xCoords[x], yCoords[y], 20, pDot);
if (dots[x][y])
{
canvas.drawCircle(xCoords[x], yCoords[y], 15, pBack);
}
}
}
}
public boolean onTouchEvent(MotionEvent event)
{
super.onTouchEvent(event);
if (event.getAction() != MotionEvent.ACTION_DOWN)
return true;
int xNear = 0;
int yNear = 0;
float xMin = canWidth;
float yMin = canHeight;
for (int x = 0; x < cols; x++)
{
if (Math.abs(xCoords[x] - event.getX()) < xMin)
{
xMin = Math.abs(xCoords[x] - event.getX());
xNear = x;
}
}
for (int y = 0; y < rows; y++)
{
if (Math.abs(yCoords[y] - event.getY()) < yMin)
{
yMin = Math.abs(yCoords[y] - event.getY());
yNear = y;
}
}
dots[xNear][yNear] = !dots[xNear][yNear];
invalidate();
return true;
}
}
Store the data of your circles (for instance the position and the radius) in a list and check each of them for mouse collision(register a mouseeventlistener).
public class Circle
{
private int radius;
private int positionX;
private int positionY;
public Circle(int positionX, int positionY, int radius)
{
this.radius = radius;
this.positionX = positionX;
this.positionY = positionY;
}
public int getPositionX()
{
return this.positionX;
}
public int getPositionY()
{
return this.positionY;
}
public boolean contains(int posX, int posY)
{
int distanceX = this.positionX - posX;
int distanceY = this.positionY - posY;
return Math.sqrt((distanceX * distanceX) + (distanceY * distanceY)) <= this.radius;
}

2d array of objects

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

array out of bounds error

I have been working on a game via youtube tutorial, some of you may recognize it as the one presents by designsbyzephr and have run into an issue. I am fairly sure the code is correct as I have used the call before in a previous project. I am getting an array out of bounds exception even when using the full project source code posted on github. Any suggestions?
package Game;
import java.awt.BorderLayout;
import java.awt.Canvas;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.image.BufferStrategy;
import java.awt.image.BufferedImage;
import java.awt.image.DataBufferInt;
import javax.swing.JFrame;
import GFX.Screen;
import GFX.SpriteSheet;
public class Game extends Canvas implements Runnable {
private static final long serialVersionUID = 1L;
public static final int WIDTH = 160;
public static final int HEIGHT = WIDTH / 12 * 9;
public static final int SCALE = 3;
public static final String NAME = "Game";
private JFrame frame;
public boolean running = false;
public int tickcount = 0;
private BufferedImage image = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB);
private int[] pixels = ((DataBufferInt) image.getRaster().getDataBuffer()).getData();
private Screen screen;
public Game() {
setMinimumSize(new Dimension(WIDTH * SCALE, HEIGHT * SCALE));
setMaximumSize(new Dimension(WIDTH * SCALE, HEIGHT * SCALE));
setPreferredSize(new Dimension(WIDTH * SCALE, HEIGHT * SCALE));
frame = new JFrame(NAME);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(this, BorderLayout.CENTER);
frame.pack();
frame.setResizable(false);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public void init() {
screen = new Screen(WIDTH, HEIGHT, new SpriteSheet("/Sprites/spritesheet.png"));
}
public void render() {
BufferStrategy bs = getBufferStrategy();
if (bs == null) {
createBufferStrategy(3);
return;
}
screen.render(pixels, 0, WIDTH);
Graphics g = bs.getDrawGraphics();
g.drawImage(image, 0, 0, getWidth(), getHeight(), null);
g.dispose();
bs.show();
}
public synchronized void start() {
running = true;
new Thread(this).start();
}
public synchronized void stop() {
running = false;
}
public void run() {
long lastTime = System.nanoTime();
double nsPerTick = 1000000000D / 60D;
int ticks = 0;
int frames = 0;
long lastTimer = System.currentTimeMillis();
double delta = 0;
init();
while (running) {
long now = System.nanoTime();
delta += (now - lastTime) / nsPerTick;
lastTime = now;
boolean shouldRender = true;
while (delta >= 1) {
ticks++;
tick();
delta -= 1;
shouldRender = true;
}
try {
Thread.sleep(2);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if (shouldRender) {
frames++;
render();
}
if (System.currentTimeMillis() - lastTimer >= 1000) {
lastTimer += 1000;
frames = 0;
ticks = 0;
}
}
}
public void tick() {
tickcount++;
for (int i = 0; i < pixels.length; i++)
pixels[i] = i + tickcount;
}
public static void main(String[] args) {
new Game().start();
}
}
package GFX;
import java.awt.image.BufferedImage;
import java.io.IOException;
import javax.imageio.ImageIO;
public class SpriteSheet {
public String path;
public int width;
public int height;
public int[] pixels;
public SpriteSheet(String path) {
BufferedImage image = null;
try
{
image = ImageIO.read(SpriteSheet.class.getResourceAsStream(path));
}
catch (IOException e)
{
e.printStackTrace();
}
if (image == null) return;
this.path = path;
this.width = image.getWidth();
this.height = image.getHeight();
pixels = image.getRGB(0, 0, width, height, null, 0, width);
for (int i = 0; i < pixels.length; i++) {
pixels[i] = (pixels[i] & 0xff) / 64;
}
for (int i = 0; i < 8; i++)
System.out.println(pixels[i]);
}
}
package GFX;
public class Screen {
public static final int MAP_WIDTH = 64;
public static final int MAP_WIDTH_MASK = MAP_WIDTH - 1;
public int[] tiles = new int[MAP_WIDTH * MAP_WIDTH];
public int[] colors = new int[MAP_WIDTH * MAP_WIDTH];
public int xOffset = 0;
public int yOffset = 0;
public int width;
public int height;
public SpriteSheet sheet;
public Screen(int width, int height, SpriteSheet sheet) {
this.width = width;
this.height = height;
this.sheet = sheet;
for (int i = 0; i < MAP_WIDTH * MAP_WIDTH; i++) {
colors[i * 4 + 0] = 0xff00ff;
colors[i * 4 + 1] = 0x00ffff;
colors[i * 4 + 2] = 0xffff00;
colors[i * 4 + 3] = 0x0000ff;
}
}
public void render(int[] pixels, int offset, int row) {
for (int yTile = yOffset >> 3; yTile <= (yOffset + height) >> 3; yTile++) {
int yMin = yTile * 8 - yOffset;
int yMax = yMin + 8;
if (yMin < 0)
yMin = 0;
if (yMin > height)
yMax = height;
for (int xTile = xOffset >> 3; xTile <= (xOffset + width) >> 3; xTile++) {
int xMin = xTile * 8 - xOffset;
int xMax = xMin + 8;
if (xMin < 0)
xMin = 0;
if (xMin > width)
xMax = width;
int tileIndex = (xTile & (MAP_WIDTH_MASK))
+ (yTile & (MAP_WIDTH_MASK)) * MAP_WIDTH;
for (int y = yMin; y < yMax; y++) {
int sheetPixel = ((y + yOffset) & 7) * sheet.width
+ ((xMin + xOffset) & 7);
int tilePixel = offset + xMin + y * row;
for (int x = xMin; x < xMax; x++) {
int color = tileIndex * 4 + sheet.pixels[sheetPixel++];
pixels[tilePixel++] = colors[color];
}
}
}
}
}
}
That is all the code so far. the error is as follows
Exception in thread "Thread-2" java.lang.IllegalArgumentException: input == null!
at javax.imageio.ImageIO.read(Unknown Source)
at GFX.SpriteSheet.(SpriteSheet.java:22)
at Game.Game.init(Game.java:54)
at Game.Game.run(Game.java:91)
at java.lang.Thread.run(Unknown Source)
it is in this line
image = ImageIO.read(SpriteSheet.class.getResourceAsStream(path));
your program cannot find file so it is returning null and a null pointer exception is thrown when you try and read from null
you need to make sure there is a file"/Sprites/spritesheet.png" relative to where you are running the program

Categories

Resources