Program doesn't work - NullPointerException - java

I am using eclipse to export my project as a runnable jar file, when I try to run it nothing happens, when I run it using cmd I get this error.
C:\Users\Enes\Desktop>cmd.exe
Microsoft Windows [Version 6.1.7601]
Copyright (c) 2009 Microsoft Corporation. All rights reserved.
C:\Users\Enes\Desktop>java -jar Game.Jar
Exception in thread "main" java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at org.eclipse.jdt.internal.jarinjarloader.JarRsrcLoader.main(JarRsrcLoa
der.java:58)
Caused by: java.lang.NullPointerException
at scrolls.Resources.createArray(Resources.java:111)
at scrolls.Player.<init>(Player.java:31)
at scrolls.Draw.<init>(Draw.java:27)
at scrolls.Frame.main(Frame.java:18)
... 5 more
C:\Users\Enes\Desktop>
When I run it using eclipse it runs fine with no errors or warnings.
This is my Resource file which seems to be causing the problem at line 111
package scrolls;
import java.awt.Font;
import java.awt.image.BufferedImage;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileReader;
import java.io.IOException;
import javax.imageio.ImageIO;
import org.imgscalr.Scalr;
public class Resources
{
Map map;
static BufferedImage[] textures = new BufferedImage[8];
static BufferedImage[] mapTextures = new BufferedImage[9];
static BufferedImage texture;
static BufferedImage[] waterAnimated = new BufferedImage[64];
static BufferedImage water;
static BufferedImage icon;
public static Font f, fs;
static int imageCounter = 0;
public Resources()
{
map = new Map();
textures();
createArray(texture, textures, 32, 1, 8);
createArray(water, waterAnimated, 32, 64, 1);
getFont();
buildMapTextures(textures, mapTextures);
}
public static void counter()
{
imageCounter++;
if (imageCounter >= 500)
imageCounter = 0;
//System.out.println(imageCounter / 8);
}
private void buildMapTextures(BufferedImage[] textures, BufferedImage[] mapTextures)
{
for (int i = 0; i <= 7; i++)
{
mapTextures[i] = resize(textures[i], 3, 3);
}
mapTextures[8] = resize(waterAnimated[2], 3, 3);
}
private BufferedImage resize(BufferedImage image, int newW, int newH)
{
BufferedImage thumbnail = Scalr.resize(image, Scalr.Method.ULTRA_QUALITY, Scalr.Mode.FIT_EXACT, newW, newH, Scalr.OP_ANTIALIAS);
return thumbnail;
}
public static BufferedImage waterAnimation()
{
return waterAnimated[imageCounter / 8];
}
private void textures()
{
try
{
texture = ImageIO.read(new File("src/resources/textures.png"));
} catch (IOException e)
{
}
try
{
water = ImageIO.read(new File("src/resources/water.png"));
} catch (IOException e)
{
}
try
{
icon = ImageIO.read(new File("src/resources/icon.png"));
} catch (IOException e)
{
}
}
static BufferedImage player()
{
BufferedImage player = null;
try
{
player = ImageIO.read(new File("src/resources/player.png"));
} catch (IOException e)
{
}
return player;
}
static void createArray(BufferedImage image, BufferedImage[] images, int size, int rows, int cols)
{
BufferedImage temp = image;
for (int i = 0; i < rows; i++)
{
for (int j = 0; j < cols; j++)
{
images[(i * cols) + j] = temp.getSubimage(j * size, i * size, size, size); // line 111
}
}
}
public static void readLevel(String filename, int[][] level, int part)
{
try
{
File f = new File("src/resources/levels/" + part + "/" + filename + ".txt");
FileReader fr = new FileReader(f);
BufferedReader in = new BufferedReader(fr);
StringBuilder sb = new StringBuilder();
byte b = 0;
while ((b = (byte) in.read()) != -1)
{
sb.append("" + ((char) b));
}
String str = sb.toString();
String[] lines = str.split("(\n|\r)+");
for (int i = 0; i < lines.length; i++)
{
for (int j = 0; j < lines[i].length(); j++)
{
level[i][j] = Integer.parseInt("" + lines[i].charAt(j));
}
}
in.close();
} catch (Exception e)
{
e.printStackTrace();
}
}
private static void getFont()
{
try
{
f = Font.createFont(Font.TRUETYPE_FONT, new FileInputStream("src/resources/Jet Set.ttf"));
fs = Font.createFont(Font.TRUETYPE_FONT, new FileInputStream("src/resources/Jet Set.ttf"));
} catch (Exception e)
{
System.out.println(e);
}
f = f.deriveFont(22f);
fs = fs.deriveFont(13f);
}
}
Player code
package scrolls;
import java.awt.Graphics2D;
import java.awt.GraphicsConfiguration;
import java.awt.GraphicsEnvironment;
import java.awt.Transparency;
import java.awt.event.KeyEvent;
import java.awt.image.BufferedImage;
public class Player
{
static int x, y, dx, dy;
BufferedImage[] sprites = new BufferedImage[8];
int rotation = 0;
int imageCounter = 0;
public static boolean moving = false;
static int playerEnergy = 150000;
static int playerLvl = 1;
static int playerExp = 3;
static int expNeeded = (((playerLvl + 1) * playerLvl) * 2);
static int playerHealth = 100;
static int playerMana = 100;
static int mapRow = 6;
static int mapColumn = 8;
static int playerRow, playerColumn;
public Player()
{
y = 40;
x = 700;
Resources.createArray(Resources.player(), sprites, 66, 1, 8);
}
private void changeImage()
{
imageCounter++;
if (imageCounter >= 80)
imageCounter = 0;
}
public void move()
{
y = y + dy;
x = x + dx;
changeImage();
playerPosition();
}
static void mapPosition()
{
if (y < 0)
playerRow = 0;
else
playerRow = (y / 32) + 1;
if (x < 0)
playerColumn = 0;
else
playerColumn = (x / 32) + 1;
}
private void playerPosition()
{
if (x >= 817 - 59)
{
x = -24;
mapColumn++;
}
if (x <= -25)
{
x = 817 - 59;
mapColumn--;
}
if (y <= -25)
{
y = 599 - 152 - 41;
mapRow--;
}
if (y >= 599 - 152 - 40)
{
y = -24;
mapRow++;
}
}
public static int playerExp()
{
return playerExp;
}
public static int getNextExp()
{
return expNeeded;
}
public static int playerLvl()
{
if (playerExp >= expNeeded)
{
playerLvl++;
}
return playerLvl;
}
public static int playerHealth()
{
return playerHealth;
}
public static int playerMana()
{
return playerMana;
}
public static int playerEnergy()
{
if ((dx != 0) || (dy != 0))
playerEnergy--;
if ((dx != 0) && (dy != 0))
playerEnergy--;
return playerEnergy;
}
public int getX()
{
return x;
}
public int getY()
{
return y;
}
public static BufferedImage rotate(BufferedImage image, double angle)
{
double sin = Math.abs(Math.sin(angle)), cos = Math.abs(Math.cos(angle));
int w = image.getWidth(), h = image.getHeight();
int neww = (int) Math.floor(w * cos + h * sin), newh = (int) Math.floor(h * cos + w * sin);
GraphicsConfiguration gc = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration();
BufferedImage result = gc.createCompatibleImage(neww, newh, Transparency.TRANSLUCENT);
Graphics2D g = result.createGraphics();
g.translate((neww - w) / 2, (newh - h) / 2);
g.rotate(angle, w / 2, h / 2);
g.drawRenderedImage(image, null);
g.dispose();
return result;
}
public BufferedImage getPlayerImage()
{
roatePlayer();
int image = animatePlayer();
double angle = Math.toRadians(rotation);
if (dy != 0 || dx != 0)
{
return rotate(sprites[image], angle);
}
return rotate(sprites[0], angle);
}
private int animatePlayer()
{
return imageCounter / 10;
}
private void roatePlayer()
{
if (dy > 0)
rotation = 0;
if (dy < 0)
rotation = 180;
if (dx > 0)
rotation = -90;
if (dx < 0)
rotation = 90;
if (dy > 0 && dx > 0)
rotation = -45;
if (dy > 0 && dx < 0)
rotation = 45;
if (dy < 0 && dx < 0)
rotation = 135;
if (dy < 0 && dx > 0)
rotation = -135;
}
public void keyPressed(KeyEvent e)
{
int key = e.getKeyCode();
if (key == KeyEvent.VK_A)
{
dx = -1;
rotation = -90;
}
if (key == KeyEvent.VK_S)
{
dy = 1;
rotation = 0;
}
if (key == KeyEvent.VK_D)
{
dx = 1;
rotation = 90;
}
if (key == KeyEvent.VK_W)
{
dy = -1;
rotation = 180;
}
}
public void keyReleased(KeyEvent e)
{
int key = e.getKeyCode();
if (key == KeyEvent.VK_A)
dx = 0;
if (key == KeyEvent.VK_S)
dy = 0;
if (key == KeyEvent.VK_D)
dx = 0;
if (key == KeyEvent.VK_W)
dy = 0;
}
}

I strongly suspect that you're loading some resources (sounds, images) either by assuming that they're present as files, or you're using appropriate getResource / getResourceAsStream calls, but your resources aren't present in the jar file. We can't really tell without seeing any of your code or what's in your jar file, but you should check where you're loading the resource, and why you expect the resource to be found.
Oh, and you may have a casing issue too - when it's loading resources from the Windows file system, asking for FOO.PNG will work even if the file is called foo.png; the same is not true when loading resources from a jar file.
Of course, you should look at Resources.java line 111 and Player.java line 31 to help pin down exactly what's going wrong (e.g. which resource is failing).
EDIT: Okay, now that we've got the code, it's exactly as I first suggested. This line of code in Resource.player():
player = ImageIO.read(new File("src/resources/player.png"));
... is loading player.png expecting it to be a file on the local file system. You want something like:
player = ImageIO.read(Resource.class.getResource("/src/resources/player.png"));
It's odd to have a src folder in your jar file, by the way. If you've actually just got the image in a reources directory, you'd want:
player = ImageIO.read(Resource.class.getResource("/resources/player.png"));

Related

Intersection of Rectangles for Java (Freeze Tag)

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

Java game slows down when player moves

I'm trying to write my first game in Java. I followed some tutorials and learned how to load and update a background using a Canvas and how to load and move a player sprite. I did these two separately and they worked fine, but when I put the two together and try to move the player, the game slows down to the point that it is unplayable. This only happens when I hold down an arrow key to move the player; the game actually runs "smoothly" if I rapidly tap the arrow key. After quite a bit of testing, I'm convinced that the problem occurs when the background is redrawn each frame. Any other improvements would also be appreciated.
Code (All of it):
Game.Java:
package Game;
import Level.Level;
import Player.Player;
import Sprites.SpriteSheetLoader;
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;
public class Game extends Canvas implements Runnable {
// Set dimensions of the game.
public static final int HEIGHT = 320;
public static final int WIDTH = 480;
public static final int SCALE = 2;
public static Dimension GAME_DIM = new Dimension(WIDTH * SCALE, HEIGHT * SCALE);
private BufferedImage image = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_ARGB);
private int[] pixels = ((DataBufferInt) image.getRaster().getDataBuffer()).getData();
public SpriteSheetLoader loader;
public Screen screen;
public Level level;
public InputHandler input = new InputHandler(this);
public Player player = new Player();
private boolean running = false;
private boolean moving = true;
private int FPS = 60;
private long targetTime = 1000 / FPS;
// Set character's starting position at the center. I have no idea why I had to add the "- 50" to each value.
public int x = GAME_DIM.width / 2 - 50;
public int y = GAME_DIM.height / 2 - 50;
public int xScroll = 0;
public int yScroll = 0;
public int col = 0;
public int row = 0;
public int ticks = 0;
public int frame = 0;
public static void main(String[] args) {
Game game = new Game();
game.setPreferredSize(new Dimension(GAME_DIM));
game.setMaximumSize(new Dimension(GAME_DIM));
game.setMinimumSize(new Dimension(GAME_DIM));
JFrame frame = new JFrame("Valkyrie Game");
frame.add(game);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setResizable(true);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
game.start();
}
public void start() {
running = true;
new Thread(this).start();
}
public Game() {
}
public void init() {
loader = new SpriteSheetLoader();
screen = new Screen(WIDTH, HEIGHT);
level = new Level(16, 16);
}
public void run() {
init();
long start, elapsed, wait;
while (running) {
start = System.nanoTime();
render();
tick();
elapsed = System.nanoTime() - start;
//System.out.println("Elapsed: " + elapsed);
wait = targetTime - elapsed / 1000000;
if(wait < 0) {
wait = 5;
}
try {
Thread.sleep(wait);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public void stop() {
running = false;
}
public void tick() {
// Movement
if (input.right) {
xScroll++;
player.setAnimation(player.walkRight);
//x++;
row = 2;
ticks++;
if(ticks < 10) {
frame = 1;
} else if(ticks == 10) {
frame = 2;
} else if(ticks == 20) {
frame = 3;
} else if(ticks == 30) {
frame = 2;
} else if(ticks == 40) {
frame = 1;
} else if(ticks == 50) {
ticks = 0;
frame = 0;
}
moving = true;
} else if (input.left) {
xScroll--;
player.setAnimation(player.walkLeft);
//x--;
row = 1;
ticks++;
if(ticks < 10) {
frame = 1;
} else if(ticks == 10) {
frame = 2;
} else if(ticks == 20) {
frame = 3;
} else if(ticks == 30) {
frame = 2;
} else if(ticks == 40) {
frame = 1;
} else if(ticks == 50) {
ticks = 0;
frame = 0;
}
moving = true;
} else if (input.up) {
yScroll--;
player.setAnimation(player.walkUp);
//y--;
row = 3;
ticks++;
if(ticks < 10) {
frame = 1;
} else if(ticks == 10) {
frame = 2;
} else if(ticks == 20) {
frame = 3;
} else if(ticks == 30) {
frame = 2;
} else if(ticks == 40) {
frame = 1;
} else if(ticks == 50) {
ticks = 0;
frame = 0;
}
moving = true;
} else if (input.down) {
yScroll++;
player.setAnimation(player.walkDown);
//y++;
row = 0;
ticks++;
if(ticks < 10) {
frame = 1;
} else if(ticks == 10) {
frame = 2;
} else if(ticks == 20) {
frame = 3;
} else if(ticks == 30) {
frame = 2;
} else if(ticks == 40) {
frame = 1;
} else if(ticks == 50) {
ticks = 0;
frame = 0;
}
moving = true;
}
if (!input.down && !input.left && !input.right && !input.up) {
player.setAnimation(player.stand);
frame = 0;
ticks = 1;
moving = false;
}
//System.out.println("Tick: " + ticks);
}
public void render() {
BufferStrategy bs = getBufferStrategy();
if (bs == null) {
createBufferStrategy(3);
requestFocus();
return;
}
do {
Graphics g = bs.getDrawGraphics();
try {
for (int i = 0; i < ticks; i++) {
g.drawImage(image, 0, 0, getWidth(), getHeight(), null);
g.drawImage(player.Player(frame, row), x, y, null);
level.renderBackground(xScroll, yScroll, screen);
for (int y = 0; y < this.screen.h; y++) {
for (int x = 0; x < screen.w; x++) {
pixels[x + (y * WIDTH)] = screen.pixels[x + (y * screen.w)];
}
}
}
} finally {
g.dispose();
}
bs.show();
this.update(bs.getDrawGraphics());
} while (bs.contentsLost());
// Graphics g = bs.getDrawGraphics();
//
// g.dispose();
// bs.show();
}
}
InputHandler.Java:
package Game;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
public class InputHandler implements KeyListener {
public boolean up = false;
public boolean down = false;
public boolean left = false;
public boolean right = false;
public InputHandler(Game game) {
game.addKeyListener(this);
}
public void toggle(KeyEvent ke, boolean pressed) {
int keyCode = ke.getKeyCode();
if(keyCode == KeyEvent.VK_UP) up = pressed;
if(keyCode == KeyEvent.VK_DOWN) down = pressed;
if(keyCode == KeyEvent.VK_LEFT) left = pressed;
if(keyCode == KeyEvent.VK_RIGHT) right = pressed;
}
public void keyTyped(KeyEvent e) {
}
public void keyPressed(KeyEvent e) {
toggle(e, true);
}
public void keyReleased(KeyEvent e) {
toggle(e, false);
}
}
Screen.Java:
package Game;
import Sprites.Sprite;
public class Screen {
public int w, h;
int xOffset = 0;
int yOffset = 0;
public int[] pixels;
public Screen(int w, int h) {
this.w = w; // 480
this.h = h; // 320
pixels = new int[w * h]; // 153600
}
public void renderSprite(int xPos, int yPos, Sprite sprite) {
int height = sprite.h;
int width = sprite.w;
xPos -= xOffset;
yPos -= yOffset;
for(int y = 0; y < height; y++) {
if(yPos + y < 0 || yPos + y >= h) continue;
for(int x = 0; x < width; x++) {
if(xPos + x < 0 || xPos + x >= w) continue;
int col = sprite.pixels[x + (y * height)];
if(col != -65281 && col < 0) pixels[(x + xPos) + (y + yPos) *w]= col;
}
}
}
public void setOffs(int xOffs, int yOffs) {
xOffset = xOffs;
yOffset = yOffs;
}
}
Level.Java:
package Level;
import Game.Screen;
import Sprites.Sprite;
import Sprites.Sprites;
import Tiles.Tile;
public class Level {
int w, h;
public int[] tiles;
public Level(int w, int h) {
this.w = w;
this.h = h;
tiles = new int[w * h];
loadMap(0, 0, 0, 0);
}
public void renderBackground(int xScroll, int yScroll, Screen screen) {
int xo = xScroll >> 4;
int yo = yScroll >> 4;
int w = (screen.w + 15) >> 4;
int h = (screen.h + 15) >> 4;
screen.setOffs(xScroll, yScroll);
for(int y = yo; y <= h + yo; y++) {
for(int x = xo; x <= w + xo; x++) {
getTile(x, y).render(x, y, screen);
}
}
screen.setOffs(0, 0);
}
public Tile getTile(int x, int y) {
if(x < 0 || y < 0 || x >= w || y >= h) return Tile.rockTile;
return Tile.tiles[tiles[x + y * w]];
}
public void loadMap(int x0, int y0, int x1, int y1) {
Sprite sprite = Sprites.level[x0][y0];
for(int y = 0; y < sprite.h; y++) {
for(int x = 0; x < sprite.w; x++) {
if(sprite.pixels[x + y * sprite.h] == -9276814) {
tiles[x + x1 + (y + y1) * h] = Tile.rockTile.id;
} else {
tiles[x + x1 + (y + y1) * h] = Tile.grassTile.id;
}
}
}
}
}
Player.Java:
package Player;
import Animation.Animation;
import Sprites.Sprite;
import java.awt.image.BufferedImage;
public class Player {
// Images for each animation
private BufferedImage[] walkingLeft = {Sprite.getSprite(0, 1), Sprite.getSprite(1, 1), Sprite.getSprite(2, 1)}; // Gets the upper left images of my sprite sheet
private BufferedImage[] walkingRight = {Sprite.getSprite(0, 2), Sprite.getSprite(1, 2), Sprite.getSprite(2, 2)};
private BufferedImage[] walkingUp = {Sprite.getSprite(0, 3), Sprite.getSprite(1, 3), Sprite.getSprite(2, 3)};
private BufferedImage[] walkingDown = {Sprite.getSprite(0, 0), Sprite.getSprite(1, 0), Sprite.getSprite(2, 0)};
private BufferedImage[] standing = {Sprite.getSprite(1, 0)};
// These are animation states.
public Animation walkLeft = new Animation(walkingLeft, 10);
public Animation walkRight = new Animation(walkingRight, 10);
public Animation walkUp = new Animation(walkingUp, 10);
public Animation walkDown = new Animation(walkingDown, 10);
public Animation stand = new Animation(standing, 10);
// This is the actual animation
public Animation animation = stand;
public BufferedImage Player(int x, int y) {
BufferedImage player = Sprite.getSprite(x, y);
return player;
}
public void update() {
animation.update();
}
public void render() {
}
public void setAnimation(Animation animation) {
this.animation = animation;
}
}
Sprite.Java:
package Sprites;
import Game.Game;
import java.awt.image.BufferedImage;
import java.io.IOException;
import javax.imageio.ImageIO;
public class Sprite {
public int w, h;
public int[] pixels;
public static BufferedImage sprite = null;
public Sprite(int w, int h) {
this.w = w;
this.h = h;
pixels = new int[w * h];
}
public void clear(int color) {
for(int i = 0; i < pixels.length; i++) {
pixels[i] = color;
}
}
private static BufferedImage spriteSheet;
private static final int TILE_SIZE = 80;
public static BufferedImage loadSprite() {
try {
sprite = ImageIO.read(Game.class.getResource("/valkyrie.png"));
} catch (IOException e) {
e.printStackTrace();
}
return sprite;
}
public static BufferedImage getSprite(int xGrid, int yGrid) {
if(spriteSheet == null) {
spriteSheet = loadSprite();
}
// xGrid and yGrid refer to each individual sprite
return spriteSheet.getSubimage(xGrid * TILE_SIZE, yGrid * TILE_SIZE, TILE_SIZE, TILE_SIZE);
}
}
This is going to require double buffering. Any game with a lot going on needs double buffering.
How do you double buffer in java for a game?
Although I couldn't go through the code completely, it seems you do not do double buffering which affect performance drastically.
Try this in the relevant part of your program:
JFrame frame = new JFrame("Valkyrie Game");
frame.add(game);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setResizable(true);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
frame.setDoubleBuffered(true); //added line, rest is the same
game.start();
You really should use Timer. It will solve all your problems.
Every tick, you redraw all what you need.
And every tick, you should just check, which keys are pressed and which are not, instead of adding listeners. To keep tracking this, you always have to remember the keys pressed "before".
You can even create two Timers, one for graphic redraw and one for game logic.
Even timers can be delayed or something, the usual approach is to find out, how much time elapsed (System.nanoTime for example) and count how much of game logic you should forward to keep game always unlaggy and fluent.

Jbuttons actions within a Jpanel and Jform

I am trying to use Jpanel and Jform to load a pic and perform some actions on it,so far the picture loads, but when I click to perform the action, it doesnt do anything. in fact it goes through the click event, but what I guess about the problem is, that the repaint() maybe doesnt work properly there.
here is the code:
public class SeamCarving
{
static SeamCarving frame=new SeamCarving();
public SeamCarving() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private BufferedImage input;
BufferedImage[] toPaint;
public TestPane() {
try {
input = ImageIO.read(new File("C:\\Users\\SONY\\Desktop\\my-pic\\Fatima.jpg"));
toPaint = new BufferedImage[]{input};
toPaint = new BufferedImage[1];
} catch (IOException ex) {
ex.printStackTrace();
}
setLayout(new GridBagLayout());
JButton loadButton = new JButton("Load");
loadButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
BufferedImage out = input;
out = input;
toPaint[0] = out;
repaint();
System.out.println("Do Something Clicked");
}
});
add(loadButton);
JButton startButton = new JButton("Start");
add(startButton);
startButton.addActionListener(new ActionListener() {
BufferedImage out = input;
#Override
public void actionPerformed(ActionEvent ae) {
out = deleteVerticalSeam(out);
System.out.println("Do Something Clicked");
toPaint[0]=out;
repaint();
}
});
}
what i want is this line: out = deleteVerticalSeam(out);
but it doesnt effect the photo at all.
EDIT
If doing like below, it will work. but I want it with button and Panel
public class SeamCarving
{
public static void main(String[] args) throws IOException {
final BufferedImage input = ImageIO.read(new File(args[0]));
final BufferedImage[] toPaint = new BufferedImage[]{input};
final Frame frame = new Frame("Seams") {
#Override
public void update(Graphics g) {
final BufferedImage im = toPaint[0];
if (im != null) {
g.clearRect(0,0,getWidth(), getHeight());
g.drawImage(im,0,0,this);
}
}
};
frame.setSize(input.getWidth(), input.getHeight());
frame.setVisible(true);
BufferedImage out = input;
for(int i = 0; i < 200; i++) {
out = deleteVerticalSeam(out);
toPaint[0]=out;
frame.repaint();
}
}
and the deleteVerticalSeam
private static BufferedImage deleteVerticalSeam(BufferedImage input) {
return deleteVerticalSeam(input, findVerticalSeam(input));
}
private static BufferedImage deleteVerticalSeam(final BufferedImage input, final int[] seam) {
int w = input.getWidth(), h = input.getHeight();
final BufferedImage out = new BufferedImage(w-1,h, BufferedImage.TYPE_INT_ARGB);
for(int y = 0; y < h; y++) {
for(int x = 0; x < seam[y]; x++) {
out.setRGB(x,y,input.getRGB(x, y));
}
for(int x = seam[y]+1; x < w; x++) {
out.setRGB(x-1,y,input.getRGB(x, y));
}
}
return out;
}
private static int[] findVerticalSeam(BufferedImage input) {
final int w = input.getWidth(), h = input.getHeight();
final FloatImage intensities = FloatImage.fromBufferedImage(input);
final FloatImage energy = computeEnergy(intensities);
final FloatImage minima = FloatImage.createSameSize(energy);
//First row is equal to the energy
for(int x = 0; x < w; x++) {
minima.set(x,0, energy.get(x,0));
}
//I assume that the rightmost pixel column in the energy image is garbage
for(int y = 1; y < h; y++) {
minima.set(0,y, energy.get(0,y) + min(minima.get(0, y - 1),
minima.get(1, y - 1)));
for(int x = 1; x < w-2; x++) {
final float sum = energy.get(x,y) + min(min(minima.get(x - 1, y - 1),
minima.get(x, y - 1)),minima.get(x + 1, y - 1));
minima.set(x,y, sum);
}
minima.set(w-2,y, energy.get(w-2,y) + min(minima.get(w-2, y - 1),minima.get(w-3, y - 1)));
}
//We find the minimum seam
float minSum = Float.MAX_VALUE;
int seamTip = -1;
for(int x = 1; x < w-1; x++) {
final float v = minima.get(x, h-1);
if(v < minSum) {
minSum=v;
seamTip=x;
}
}
//Backtrace the seam
final int[] seam = new int[h];
seam[h-1]=seamTip;
for(int x = seamTip, y = h-1; y > 0; y--) {
float left = x>0?minima.get(x-1, y-1):Float.MAX_VALUE;
float up = minima.get(x, y-1);
float right = x+1<w?minima.get(x+1, y-1):Float.MAX_VALUE;
if(left < up && left < right) x=x-1;
else if(right < up && right < left) x= x+1;
seam[y-1]=x;
}
return seam;
}
floatimage
public final class FloatImage extends JFrame{
private final int width;
private final int height;
private final float[] data;
public FloatImage(int width, int height) {
this.width = width;
this.height = height;
this.data = new float[width*height];
}
public int getWidth() {
return width;
}
public int getHeight() {
return height;
}
public float get(final int x, final int y) {
if(x < 0 || x >= width) throw new IllegalArgumentException("x: " + x);
if(y < 0 || y >= height) throw new IllegalArgumentException("y: " + y);
return data[x+y*width];
}
public void set(final int x, final int y, float value) {
if(x < 0 || x >= width) throw new IllegalArgumentException("x: " + x);
if(y < 0 || y >= height) throw new IllegalArgumentException("y: " + y);
data[x+y*width] = value;
}
public static FloatImage createSameSize(final BufferedImage sample) {
return new FloatImage(sample.getWidth(), sample.getHeight());
}
public static FloatImage createSameSize(final FloatImage sample) {
return new FloatImage(sample.getWidth(), sample.getHeight());
}
public static FloatImage fromBufferedImage(final BufferedImage src) {
final int width = src.getWidth();
final int height = src.getHeight();
final FloatImage result = new FloatImage(width, height);
for(int x = 0; x < width; x++) {
for(int y = 0; y < height; y++) {
final int argb = src.getRGB(x, y);
int r = (argb >>> 16) & 0xFF;
int g = (argb >>> 8) & 0xFF;
int b = argb & 0xFF;
result.set(x,y, (r*0.3f+g*0.59f+b*0.11f)/255);
}
}
return result;
}
public BufferedImage toBufferedImage(float scale) {
final BufferedImage result = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
for(int x = 0; x < width; x++) {
for(int y = 0; y < height; y++) {
final int intensity = ((int) (get(x, y) * scale)) & 0xFF;
result.setRGB(x,y,0xFF000000 | intensity | intensity << 8 | intensity << 16);
}
}
return result;
}
}
I "think" your basic problem starts here...
startButton.addActionListener(new ActionListener() {
BufferedImage out = input;
#Override
public void actionPerformed(ActionEvent ae) {
out = deleteVerticalSeam(out);
System.out.println("Do Something Clicked");
toPaint[0]=out;
repaint();
}
});
Try removing the instance variable out...
startButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent ae) {
BufferedImage out = deleteVerticalSeam(input);
System.out.println("Do Something Clicked");
toPaint[0]=out;
repaint();
}
});
Updated
I've updated the ActionListener to work more like...
startButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent ae) {
BufferedImage out = deleteVerticalSeam(toPaint[0]);
System.out.println("Do Something Clicked");
toPaint[0] = out;
repaint();
}
});
Which feeds the last result of the operation back into itself, which gradually decreases the number of vertical pixels in the image...
Updated with working example
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import static java.lang.Math.abs;
import static java.lang.Math.min;
public class SeamCarving {
public static void main(String[] args) {
new SeamCarving();
}
public SeamCarving() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private BufferedImage input;
BufferedImage[] toPaint;
public TestPane() {
try {
input = ImageIO.read(new File("..."));
toPaint = new BufferedImage[]{input};
toPaint = new BufferedImage[1];
} catch (IOException ex) {
ex.printStackTrace();
}
setLayout(new GridBagLayout());
JButton loadButton = new JButton("Load");
loadButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
BufferedImage out = input;
toPaint[0] = input;
repaint();
System.out.println("Do Something Clicked");
}
});
add(loadButton);
JButton startButton = new JButton("Start");
add(startButton);
startButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent ae) {
BufferedImage out = deleteVerticalSeam(toPaint[0]);
System.out.println("Do Something Clicked");
toPaint[0] = out;
repaint();
}
});
}
#Override
public Dimension getPreferredSize() {
return input == null ? super.getPreferredSize() : new Dimension(input.getWidth(), input.getHeight());
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
g2d.drawImage(toPaint[0], 0, 0, this);
g2d.dispose();
}
}
private static BufferedImage deleteVerticalSeam(BufferedImage input) {
return deleteVerticalSeam(input, findVerticalSeam(input));
}
private static BufferedImage deleteVerticalSeam(final BufferedImage input, final int[] seam) {
int w = input.getWidth(), h = input.getHeight();
final BufferedImage out = new BufferedImage(w - 1, h, BufferedImage.TYPE_INT_ARGB);
for (int y = 0; y < h; y++) {
for (int x = 0; x < seam[y]; x++) {
out.setRGB(x, y, input.getRGB(x, y));
}
for (int x = seam[y] + 1; x < w; x++) {
out.setRGB(x - 1, y, input.getRGB(x, y));
}
}
return out;
}
private static int[] findVerticalSeam(BufferedImage input) {
final int w = input.getWidth(), h = input.getHeight();
final FloatImage intensities = FloatImage.fromBufferedImage(input);
final FloatImage energy = computeEnergy(intensities);
final FloatImage minima = FloatImage.createSameSize(energy);
//First row is equal to the energy
for (int x = 0; x < w; x++) {
minima.set(x, 0, energy.get(x, 0));
}
//I assume that the rightmost pixel column in the energy image is garbage
for (int y = 1; y < h; y++) {
minima.set(0, y, energy.get(0, y) + min(minima.get(0, y - 1),
minima.get(1, y - 1)));
for (int x = 1; x < w - 2; x++) {
final float sum = energy.get(x, y) + min(min(minima.get(x - 1, y - 1),
minima.get(x, y - 1)), minima.get(x + 1, y - 1));
minima.set(x, y, sum);
}
minima.set(w - 2, y, energy.get(w - 2, y) + min(minima.get(w - 2, y - 1), minima.get(w - 3, y - 1)));
}
//We find the minimum seam
float minSum = Float.MAX_VALUE;
int seamTip = -1;
for (int x = 1; x < w - 1; x++) {
final float v = minima.get(x, h - 1);
if (v < minSum) {
minSum = v;
seamTip = x;
}
}
//Backtrace the seam
final int[] seam = new int[h];
seam[h - 1] = seamTip;
for (int x = seamTip, y = h - 1; y > 0; y--) {
float left = x > 0 ? minima.get(x - 1, y - 1) : Float.MAX_VALUE;
float up = minima.get(x, y - 1);
float right = x + 1 < w ? minima.get(x + 1, y - 1) : Float.MAX_VALUE;
if (left < up && left < right) {
x = x - 1;
} else if (right < up && right < left) {
x = x + 1;
}
seam[y - 1] = x;
}
return seam;
}
private static FloatImage computeEnergy(FloatImage intensities) {
int w = intensities.getWidth(), h = intensities.getHeight();
final FloatImage energy = FloatImage.createSameSize(intensities);
for (int x = 0; x < w - 1; x++) {
for (int y = 0; y < h - 1; y++) {
//I'm aproximating the derivatives by subtraction
float e = abs(intensities.get(x, y) - intensities.get(x + 1, y))
+ abs(intensities.get(x, y) - intensities.get(x, y + 1));
energy.set(x, y, e);
}
}
return energy;
}
public static final class FloatImage {
private final int width;
private final int height;
private final float[] data;
public FloatImage(int width, int height) {
this.width = width;
this.height = height;
this.data = new float[width * height];
}
public int getWidth() {
return width;
}
public int getHeight() {
return height;
}
public float get(final int x, final int y) {
if (x < 0 || x >= width) {
throw new IllegalArgumentException("x: " + x);
}
if (y < 0 || y >= height) {
throw new IllegalArgumentException("y: " + y);
}
return data[x + y * width];
}
public void set(final int x, final int y, float value) {
if (x < 0 || x >= width) {
throw new IllegalArgumentException("x: " + x);
}
if (y < 0 || y >= height) {
throw new IllegalArgumentException("y: " + y);
}
data[x + y * width] = value;
}
public static FloatImage createSameSize(final BufferedImage sample) {
return new FloatImage(sample.getWidth(), sample.getHeight());
}
public static FloatImage createSameSize(final FloatImage sample) {
return new FloatImage(sample.getWidth(), sample.getHeight());
}
public static FloatImage fromBufferedImage(final BufferedImage src) {
final int width = src.getWidth();
final int height = src.getHeight();
final FloatImage result = new FloatImage(width, height);
for (int x = 0; x < width; x++) {
for (int y = 0; y < height; y++) {
final int argb = src.getRGB(x, y);
int r = (argb >>> 16) & 0xFF;
int g = (argb >>> 8) & 0xFF;
int b = argb & 0xFF;
result.set(x, y, (r * 0.3f + g * 0.59f + b * 0.11f) / 255);
}
}
return result;
}
public BufferedImage toBufferedImage(float scale) {
final BufferedImage result = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
for (int x = 0; x < width; x++) {
for (int y = 0; y < height; y++) {
final int intensity = ((int) (get(x, y) * scale)) & 0xFF;
result.setRGB(x, y, 0xFF000000 | intensity | intensity << 8 | intensity << 16);
}
}
return result;
}
}
}

Memory leak in java ImageIO.read()

I am utilizing ImageIO.read(). The class which is called by the main method of the original App is this:
import java.awt.*;
import javax.swing.*;
import java.io.File;
import java.awt.image.BufferedImage;
import java.awt.event.*;
import javax.swing.JPanel;
class ImageGenerator extends JPanel{
JpegReader jpeg;
public ImageGenerator(Aplicacion a){
jpeg = new JpegReader();
loadImage();
}
private void loadImage(){
String path = "C:\\image.jpg";
image = new BufferedImage(100,100, BufferedImage.TYPE_INT_RGB); //in case error
try{
image = jpeg.readImage(new File(path));
}catch(Exception e){
System.err.println(e.getMessage());
}
}
public void paint(Graphics g){
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
RenderingHints.VALUE_INTERPOLATION_BICUBIC);
g2.drawImage(image, 0, 0, 1000, 800, null);
}
}
I am using the above in conjunction with this other class JpegReader, which I actually found on StackOverflow as an answer, but I forgot the name of the author to quote him.
import java.awt.image.BufferedImage;
import javax.imageio.*;
import javax.imageio.stream.ImageInputStream;
import java.awt.color.*;
import java.awt.image.*;
import java.io.File;
import java.io.IOException;
import java.util.Iterator;
import java.util.ArrayList;
import org.apache.sanselan.Sanselan;
import org.apache.sanselan.common.byteSources.ByteSource;
import org.apache.sanselan.common.byteSources.ByteSourceFile;
import org.apache.sanselan.ImageReadException;
import org.apache.sanselan.formats.jpeg.JpegImageParser;
import org.apache.sanselan.formats.jpeg.segments.UnknownSegment;
public class JpegReader {
public static final int COLOR_TYPE_RGB = 1;
public static final int COLOR_TYPE_CMYK = 2;
public static final int COLOR_TYPE_YCCK = 3;
private int colorType = COLOR_TYPE_RGB;
private boolean hasAdobeMarker = false;
public BufferedImage readImage(File file) throws IOException, ImageReadException {
colorType = COLOR_TYPE_RGB;
hasAdobeMarker = false;
ImageInputStream stream = ImageIO.createImageInputStream(file);
Iterator<ImageReader> iter = ImageIO.getImageReaders(stream);
while (iter.hasNext()) {
ImageReader reader = iter.next();
reader.setInput(stream);
BufferedImage image;
ICC_Profile profile = null;
try {
image = reader.read(0);
} catch (IIOException e) {
System.out.println("Hello");
colorType = COLOR_TYPE_CMYK;
checkAdobeMarker(file);
profile = Sanselan.getICCProfile(file);
WritableRaster raster = (WritableRaster) reader.readRaster(0, null);
if (colorType == COLOR_TYPE_YCCK)
convertYcckToCmyk(raster);
if (hasAdobeMarker)
convertInvertedColors(raster);
image = convertCmykToRgb(raster, profile);
System.out.println("Hello");
}finally {
try {
System.out.println("facebook");
stream.close();
} catch (IOException ioex) {
//omitted.
}
}
return image;
}
return null;
}
public void checkAdobeMarker(File file) throws IOException, ImageReadException {
JpegImageParser parser = new JpegImageParser();
ByteSource byteSource = new ByteSourceFile(file);
#SuppressWarnings("rawtypes")
ArrayList segments = parser.readSegments(byteSource, new int[] { 0xffee }, true);
if (segments != null && segments.size() >= 1) {
UnknownSegment app14Segment = (UnknownSegment) segments.get(0);
byte[] data = app14Segment.bytes;
if (data.length >= 12 && data[0] == 'A' && data[1] == 'd' && data[2] == 'o' && data[3] == 'b' && data[4] == 'e')
{
hasAdobeMarker = true;
int transform = app14Segment.bytes[11] & 0xff;
if (transform == 2)
colorType = COLOR_TYPE_YCCK;
}
}
}
public static void convertYcckToCmyk(WritableRaster raster) {
int height = raster.getHeight();
int width = raster.getWidth();
int stride = width * 4;
int[] pixelRow = new int[stride];
for (int h = 0; h < height; h++) {
raster.getPixels(0, h, width, 1, pixelRow);
for (int x = 0; x < stride; x += 4) {
int y = pixelRow[x];
int cb = pixelRow[x + 1];
int cr = pixelRow[x + 2];
int c = (int) (y + 1.402 * cr - 178.956);
int m = (int) (y - 0.34414 * cb - 0.71414 * cr + 135.95984);
y = (int) (y + 1.772 * cb - 226.316);
if (c < 0) c = 0; else if (c > 255) c = 255;
if (m < 0) m = 0; else if (m > 255) m = 255;
if (y < 0) y = 0; else if (y > 255) y = 255;
pixelRow[x] = 255 - c;
pixelRow[x + 1] = 255 - m;
pixelRow[x + 2] = 255 - y;
}
raster.setPixels(0, h, width, 1, pixelRow);
}
}
public static void convertInvertedColors(WritableRaster raster) {
int height = raster.getHeight();
int width = raster.getWidth();
int stride = width * 4;
int[] pixelRow = new int[stride];
for (int h = 0; h < height; h++) {
raster.getPixels(0, h, width, 1, pixelRow);
for (int x = 0; x < stride; x++)
pixelRow[x] = 255 - pixelRow[x];
raster.setPixels(0, h, width, 1, pixelRow);
}
}
public static BufferedImage convertCmykToRgb(Raster cmykRaster, ICC_Profile cmykProfile) throws IOException {
if (cmykProfile == null)
cmykProfile = ICC_Profile.getInstance(JpegReader.class.getResourceAsStream("/ISOcoated_v2_300_eci.icc"));
if (cmykProfile.getProfileClass() != ICC_Profile.CLASS_DISPLAY) {
byte[] profileData = cmykProfile.getData();
if (profileData[ICC_Profile.icHdrRenderingIntent] == ICC_Profile.icPerceptual) {
intToBigEndian(ICC_Profile.icSigDisplayClass, profileData, ICC_Profile.icHdrDeviceClass); // Header is first
cmykProfile = ICC_Profile.getInstance(profileData);
}
}
ICC_ColorSpace cmykCS = new ICC_ColorSpace(cmykProfile);
BufferedImage rgbImage = new BufferedImage(cmykRaster.getWidth(), cmykRaster.getHeight(), BufferedImage.TYPE_INT_RGB);
WritableRaster rgbRaster = rgbImage.getRaster();
ColorSpace rgbCS = rgbImage.getColorModel().getColorSpace();
ColorConvertOp cmykToRgb = new ColorConvertOp(cmykCS, rgbCS, null);
cmykToRgb.filter(cmykRaster, rgbRaster);
return rgbImage;
}
static void intToBigEndian(int value, byte[] array, int index) {
array[index] = (byte) (value >> 24);
array[index+1] = (byte) (value >> 16);
array[index+2] = (byte) (value >> 8);
array[index+3] = (byte) (value);
}
}
I am using sanselan-0.97-incubator.jar.
If I run this program 31 times approximately, I will get a java heap space error, so I suspect I have a memory leak.
Please help me find the memory leak or suggest how to fix the issue.
Also let me know if the jar file I'm using is OKAY, or maybe it's outdated. I had some issues locating a sanselan jar file.
Thanks in advance.
I have got the same memory issue with this code (JPEGReader). After a few trials, I found that calling reader.dispose() can solve this issue.
I give the method that I have modified. Hope it is helpful to you.
public BufferedImage readImage(File file) throws IOException, ImageReadException {
colorType = COLOR_TYPE_RGB;
hasAdobeMarker = false;
ImageInputStream stream = ImageIO.createImageInputStream(file);
try{
Iterator<ImageReader> iter = ImageIO.getImageReaders(stream);
while (iter.hasNext()) {
ImageReader reader = iter.next();
reader.setInput(stream);
BufferedImage image;
ICC_Profile profile = null;
try {
image = reader.read(0);
} catch (IIOException e) {
colorType = COLOR_TYPE_CMYK;
checkAdobeMarker(file);
profile = Sanselan.getICCProfile(file);
WritableRaster raster = (WritableRaster) reader.readRaster(0, null);
if (colorType == COLOR_TYPE_YCCK)
convertYcckToCmyk(raster);
if (hasAdobeMarker)
convertInvertedColors(raster);
image = convertCmykToRgb(raster, profile);
return image;
}
finally {
reader.dispose();
}
}
return null;
}
finally {
if (stream != null){
stream.close();
}
}
}

Java (swing) paint only what's viewable on the screen

I am making a tile based platformer game in java. I render a map which is stored in a 2 dimensional array but when this array is very big my game starts to become slow. I realised that I had to only render the part of the map that is viewable, I tried to do that but i wrote very hacky code that only worked partly so I removed it. How can I do this properly? Here is my code (without the hacky stuff). Also how could I use System.nanoTime() rather than System.currentTimeMillis()?
package sexy_robot_from_another_dimension;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.TexturePaint;
import java.awt.image.BufferedImage;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Timer;
import java.util.TimerTask;
import javax.swing.JPanel;
#SuppressWarnings("serial")
public class Game extends JPanel
{
int playerX = 50;
int playerY = 50;
static boolean up = false;
static boolean down = false;
static boolean right = false;
static boolean left = false;
int playerSpeed = 1;
String[][] map;
int blockSize = 20;
int jumpLoop = 0;
int maxJumpLoop = 280;
static BufferedImage block, player;
int playerWidth = 20;
int playerHeight = 35;
int cameraX = 0;
int cameraY = 0;
long nextSecond = System.currentTimeMillis() + 1000;
int frameInLastSecond = 0;
int framesInCurrentSecond = 0;
public Game()
{
super();
try
{
map = load("/maps/map1.txt");
}
catch (IOException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
Timer timer = new Timer();
TimerTask task = new TimerTask()
{
#Override
public void run()
{
if(up)
{
if((!playerIsOnBlock(playerX, playerY).equals("0")) || (!playerIsOnBlock(playerX + (playerWidth - 1), playerY).equals("0")))
{
timeToJump();
}
}
if(down)
{
}
if(right)
{
if((playerIsLeftBlock(playerX, playerY).equals("0")) && (playerIsLeftBlock(playerX, playerY + (playerHeight/2 - 1)).equals("0")) && (playerIsLeftBlock(playerX, playerY + (playerHeight - 1)).equals("0")))
{
playerX += playerSpeed;
}
}
if(left)
{
if((playerIsRightBlock(playerX, playerY).equals("0")) && (playerIsRightBlock(playerX, playerY + (playerHeight/2 - 1)).equals("0")) && (playerIsRightBlock(playerX, playerY + (playerHeight - 1)).equals("0")))
{
playerX -= playerSpeed;
}
}
repaint();
}
};
timer.scheduleAtFixedRate(task, 0, 10);
Timer timerGrav = new Timer();
TimerTask taskGrav = new TimerTask()
{
#Override
public void run()
{
if((playerIsOnBlock(playerX, playerY).equals("0")) && (playerIsOnBlock(playerX + (playerWidth - 1), playerY).equals("0")))
{
playerY += playerSpeed;
repaint();
}
}
};
timerGrav.scheduleAtFixedRate(taskGrav, 0, 6);
}
void timeToJump()
{
if(jumpLoop == 0)
{
jumpLoop = 1;
Timer timer = new Timer();
TimerTask task = new TimerTask()
{
#Override
public void run()
{
if((playerIsBelowBlock(playerX, playerY).equals("0")) && (playerIsBelowBlock(playerX + (playerWidth - 1), playerY).equals("0")))
{
playerY -= playerSpeed;
jumpLoop++;
repaint();
}
else
{
jumpLoop = maxJumpLoop;
}
if(jumpLoop == maxJumpLoop)
{
jumpLoop = 0;
cancel();
}
}
};
timer.scheduleAtFixedRate(task, 0, 3);
}
}
public void paintComponent(Graphics g)
{
super.paintComponent(g);
Graphics2D g2 = (Graphics2D)g;
g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
long currentTime = System.currentTimeMillis();
if (currentTime > nextSecond)
{
nextSecond += 1000;
frameInLastSecond = framesInCurrentSecond;
framesInCurrentSecond = 0;
}
framesInCurrentSecond++;
g.drawString(frameInLastSecond + " fps", 10, 20);
cameraX = -playerX + getWidth()/2;
cameraY = -playerY + getHeight()/2;
g.translate(cameraX, cameraY);
for (int x = 0; x < map.length; x++)
{
for (int y = 0; y < map[0].length; y++)
{
switch(map[x][y])
{
case "0":
break;
case "1":
if(block != null)
{
TexturePaint tp0 = new TexturePaint(block, new Rectangle(0, 0, blockSize, blockSize));
g2.setPaint(tp0);
}
g.fillRect(y*blockSize, x*blockSize, 20, 20);
break;
}
}
}
g.setColor(Color.BLACK);
if(player != null)
{
TexturePaint tp0 = new TexturePaint(player, new Rectangle(playerX, playerY, playerWidth, playerHeight));
g2.setPaint(tp0);
}
g.fillRect(playerX, playerY, playerWidth, playerHeight);
g.setColor(Color.black);
g.setFont(new Font("Droid Sans Mono", Font.PLAIN, 12));
g.drawString("Sexy!", playerX - 5, playerY - 10);
}
boolean outOfMap(int x, int y)
{
y -= blockSize - 1;
x -= blockSize - 1;
if((y/blockSize <= map.length - 2) && (y/blockSize >= 0) && (x/blockSize <= map[0].length-2) && (x/blockSize >= 0))
{
return false;
}
return true;
}
String playerIsOnBlock(int x, int y)
{
y += playerHeight;
if(!outOfMap(x, y))
{
if(map[y/blockSize][x/blockSize] != "0")
{
return map[y/blockSize][x/blockSize];
}
}
return "0";
}
String playerIsBelowBlock(int x, int y)
{
y -= playerSpeed;
if(!outOfMap(x, y))
{
if(map[y/blockSize][x/blockSize] != "0")
{
return map[y/blockSize][x/blockSize];
}
}
return "0";
}
String playerIsLeftBlock(int x, int y)
{
x += playerWidth;
if(!outOfMap(x, y))
{
if(map[y/blockSize][x/blockSize] != "0")
{
return map[y/blockSize][x/blockSize];
}
}
return "0";
}
String playerIsRightBlock(int x, int y)
{
x -= playerSpeed;
if(!outOfMap(x, y))
{
if(map[y/blockSize][x/blockSize] != "0")
{
return map[y/blockSize][x/blockSize];
}
}
return "0";
}
String[][] load(String file) throws IOException
{
BufferedReader br = new BufferedReader(new InputStreamReader(getClass().getResourceAsStream(file)));
int lines = 1;
int length = br.readLine().split(" ").length;
while (br.readLine() != null) lines++;
br.close();
br = new BufferedReader(new InputStreamReader(getClass().getResourceAsStream(file)));
String[][] map = new String[lines][length];
for (int i = 0; i < lines; i++)
{
String line = br.readLine();
String[] parts = line.split(" ");
for (int y = 0; y < length; y++)
{
map[i][y] = parts[y];
}
}
br.close();
return map;
}
}
Thank you!
It seems your camera is centered on the player, then there are two ways of doing this, I like the first way, it is a bit cleaner:
1th: Create a rectangle that bounds your cameras view, and check if the map x,y is within this view, render only if true.
Rectangle cameraView = new Rectangle(playerX - getWidth() / 2, playerY - getHeight() / 2, getWidth(), getHeight());
for (int x = 0; x < map.length; x++) {
for (int y = 0; y < map[0].length; y++) {
if (!cameraView.contains(x*blockSize, y*blockSize))
continue;
switch (map[x][y]) {
case "0":
break;
case "1":
if (block != null) {
TexturePaint tp0 = new TexturePaint(block, new Rectangle(0, 0, blockSize, blockSize));
g2.setPaint(tp0);
}
g.fillRect(y * blockSize, x * blockSize, 20, 20);
break;
}
}
}
The second option is to simply calculate the distance to the center of the screen (playerX,playerY) from each map[x][y] and skip all map[x][y] that falls outside your viewing bounds, this is a bit uglier to code and I really don't recommend this, the rectangle option above should be fast enough.
Edit:
#JasonC That is true, I didn't consider for instance when an x value is definitely outside the view, it will still go into the y loop through all the y values. One can simply create a dummy variable in the x-loop and do the following check
for (int x = 0; x < map.length; x++) {
int dummyY = playerY
if(!cameraView.contains(x,dummyY))
continue;
....
//rest of code ommitted
Another optimization you can do is considering not setting a TexturePaint (expensive operation) but instead simply drawing the image of the block:
g.fillRect(y * blockSize, x * blockSize, 20, 20);
Replaced with
g.drawImage(block, y*blockSize, x*blockSize, null);
The same with the playerimage.
Set the clipping region to the visible area with Graphics.setClip(), that will prevent most rendering operations from taking effect outside that region.
For drawing operations where this isn't sufficient (perhaps you also want to avoid doing calculations or something for objects outside the clipping area), test your objects bounds against the clipping rectangle and skip the object if it doesn't intersect.
See Graphics.setClip().
A further optimization can be done by, for example, calculating the range of blocks on your map that is definitely outside of the visible area, and excluding that from your for loop (no sense testing blocks against the clipping region if you know they are outside already). Take the clipping region, transform it to map index coordinates, then you will know where in your map the visible area is and you can just iterate over that subsection of the map.

Categories