Hello I am kind of new to java. I am working on a game. when the game starts a loading screen appears and the fades away that's it so far. My question is simple. Is there a way to change the image size to fit the size of the computer screen. I want it to fit all types of screen sizes and be a larger scale of the original image. Here is my Main class so far(there are other classes like player and title and play but they are irrelevant to the question:
package Main;
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.image.BufferStrategy;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
public class Comp extends Canvas implements Runnable, KeyListener {
private static final long serialVersionUID = 1L;
public boolean run = true;
public Image screen, img;
public static double dir = 5;
public static int pixelSize = 1;
public static Dimension size = new Dimension(680, 500);
public static Dimension pixel = new Dimension(size.width / pixelSize,
size.height / pixelSize);
public static int mx;
public static manager m;
public static int my;
public static int fps;
public static boolean mr;
public static boolean ml;
JFrame frame = new JFrame();
public Thread t;
public boolean splashscreen = true;
public int time = 0;
public int timer = 140;
public int btime = 0;
public int btimer = 1;
private int FPS = 5;
private long targetTime = 1000 / FPS;
public Comp() {
setPreferredSize(size);
setFocusable(true);
addKeyListener(this);
addKeyListener(new listen());
addMouseListener(new listen());
addMouseMotionListener(new listen());
addMouseWheelListener(new listen());
m = new manager();
requestFocus();
// h = new InputHandler(this);
}
public void start() {
run = true;
frame.add(this);
frame.pack();
frame.requestFocus();
frame.setTitle("In The Maze");
frame.setResizable(false);
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
frame.setIconImage(new ImageIcon("res/traps/beartrap1.png").getImage());
t = new Thread(this);
t.start();
}
public void stop() {
run = false;
}
public static void main(String[] args) {
Comp c = new Comp();
c.start();
}
public void render() {
BufferStrategy bs = this.getBufferStrategy();
if (bs == null) {
createBufferStrategy(2);
return;
}
Graphics g = bs.getDrawGraphics();
g.setColor(Color.white);
g.fillRect(0, 0, 1000, 1000);
if (!splashscreen) {
m.render(g);
}
if(splashscreen){
ImageIcon i62 = new ImageIcon("res/splashscreen.png");
img = i62.getImage();
g.drawImage(img,(int)0 ,(int)0,Comp.size.width+10,Comp.size.height + 10,null);
time++;
}
g.dispose();
bs.show();
}
public void tick() {
if(time >= timer){
time = 0;
splashscreen = false;
}
if(!splashscreen){
m.tick();
}
Keys.update();
Esentials.tick();
}
public void run() {
screen = createVolatileImage(pixel.width, pixel.height);
long start;
long elapsed;
long wait;
long currentTime = System.currentTimeMillis();
while (run) {
start = System.nanoTime();
fps++;
if(System.currentTimeMillis() - currentTime >= 1000){
// System.out.println("fps:" + fps);
currentTime = System.currentTimeMillis();
fps = 0;
}
tick();
render();
elapsed = System.nanoTime() -start;
wait = targetTime = elapsed / 1000000;
try {
Thread.sleep(wait);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public void keyTyped(KeyEvent i) {
}
public void keyPressed(KeyEvent i) {
Keys.keySet(i.getKeyCode(), true);
}
public void keyReleased(KeyEvent i) {
Keys.keySet(i.getKeyCode(), false);
}
}
Try to use Toolkit.getScreenSize()
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
double width = screenSize.getWidth();
double height = screenSize.getHeight();
For resizing the image you can use simple imgscalr library
BufferedImage scaledImage = Scalr.resize(myImage, 100);
Determining the screen size...
How to set present screensize in Java Swing?
Full-Screen Exclusive Mode API
Scaling the image...
Java: maintaining aspect ratio of JPanel background image
Quality of Image after resize very low -- Java
The Perils of Image.getScaledInstance()
I'd also discourage the use KeyListener and encourage the use of the Key Bindings API. See How to use key bindings for more details
Using the default Graphics object from the java.awt package, you can use the drawImage method with 10 parameters:
int destinationWidth = ...;
int destinationHeight = ...;
g.drawImage(originalImage, 0, 0, destinationWidth, destinationHeight, 0, 0, originalImage.getWidth(null), originalImage.getHeight(null), null);
That way your image will be scaled and painted to g. Note that simply by using as in the example provided will stretch and deform your image if the aspect ratio of your window is different from the aspect ratio of the image.
Related
My problem is, I have a game with a random generated map and it has only 30-40 fps because of the number of blocks.(You can imagine my game like a 2d minecraft).
First I search for the first tile what is in screen. Then start a loop render tile next tile... until I reach the last tile what you can see.
(I don't use any of the Java classes like graphics/graphics2d I use my own code what is an int[] with the rows of teh screen in it and when I render a tile I change the int[x+y*width] position of the screen to the correct pixel of the block)
I think logically this is the best way to render my map and i don't understend why is the low fps. I am wrong or I need to search for some other problem in my code? Or there is any better rendering method?
If I skip the rendering of the world, there is stabile 120 fps what is capped there. What can be the problem?
I know you dont use the Gaphics functions and choose to manipulate a pixel-array instead.
Try to change your game to use the Graphics object since there is no (easy and efficient) way around it. If you still choose not to do so, try to add
System.setProperty("sun.java2d.opengl", "true");
at the very begining of your code just after
public static void main(String[] args) {
I tried to do it the same way as you back when i first made simple games but you later come to realize that the built-in Graphics functions are vastly superior in performance and ease of use.
EDIT:
A short explanaition on how a basic game might use the Graphics object:
Suppose you created a JFrame. If you then add a class that extends from Canvas and add that to it. If you want to use a menu, you might even create a JPanel first and add the Canvas into the Jpanel so you can hide it more easily.
Here you have an example how we create a usable canvas:
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.image.BufferStrategy;
import javax.swing.JFrame;
public class Game extends Canvas implements Runnable{
private static final long serialVersionUID = 1L;
public static final int WIDTH = 1920;
public static final int HEIGHT = WIDTH * 9 / 16;
public static final String TITLE = "YOUR GAMES NAME";
public static final int TICKSPERS = 120;
public static final boolean ISFRAMECAPPED = false;
public static JFrame frame;
private Thread thread;
private boolean running = false;
public int frames;
public int lastFrames;
public int ticks;
public Game(){
Dimension size = new Dimension(WIDTH, HEIGHT);
setPreferredSize(size);
setMaximumSize(size);
setMinimumSize(size);
}
public void render(){
frames++;
BufferStrategy bs = getBufferStrategy();
if (bs == null){
createBufferStrategy(2);
return;
}
Graphics g = bs.getDrawGraphics();
g.setColor(new Color(79,194,232));
g.fillRect(0, 0, getWidth(), getHeight());
//Call your render funtions from here
g.setColor(Color.BLACK);
g.fillRect(120,70,35,90);
g.dispose();
bs.show();
}
public void tick(){
}
public synchronized void start(){
if(running) return;
running = true;
thread = new Thread(this, "Thread");
thread.start();
}
public synchronized void stop(){
if(!running) return;
running = false;
try {
System.exit(1);
frame.dispose();
thread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public void init(){
}
public void run() {
init();
//Tick counter variable
long lastTime = System.nanoTime();
//Nanoseconds per Tick
double nsPerTick = 1000000000D/TICKSPERS;
frames = 0;
ticks = 0;
long fpsTimer = System.currentTimeMillis();
double delta = 0;
boolean shouldRender;
while(running){
shouldRender = !ISFRAMECAPPED;
long now = System.nanoTime();
delta += (now - lastTime) / nsPerTick;
lastTime = now;
//if it should tick it does this
while(delta >= 1 ){
ticks++;
tick();
delta -= 1;
shouldRender = true;
}
if (shouldRender){
render();
}
if (fpsTimer < System.currentTimeMillis() - 1000){
System.out.println(ticks +" ticks, "+ frames+ " frames");
ticks = 0;
lastFrames = frames;
frames = 0;
fpsTimer = System.currentTimeMillis();
}
}
}
public static void main(String[] args){
Game game = new Game();
frame = new JFrame(TITLE);
frame.add(game);
frame.pack();
frame.setResizable(false);
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
game.start();
}
}
This class can be your base. Its tick method is called 120 times a second and its render method can render stuff onto the screen.
If you are not familiar with the functions of the Graphics Object i suggest reading a little about them.
You can't reach the Graphics object from the outside. You need to call the render functions from inside the games render function before the Graphics object gets disposed. Try to seperate your game logic from the render functions.
I use a slightly different architecture than what's stated above. I actually create a separate Renderer object which is basically a deferred renderer.
It's structured like this
public class App {
JFrame window;
Renderer renderer;
Engine engine; //implementation is a nested class within App
Dimension window_dimension; //stored for later use
public App() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
window = new JFrame("MyGame");
boolean full_screen = true;
window_dimension = initializeWindow(window, full_screen);
renderer = new Renderer(window_dimension);
window.add(renderer);
engine = new Engine(renderer);
engine.start();
}
});
}
}
Renderer.java :
import java.awt.*;
import java.util.concurrent.CopyOnWriteArrayList;
public class Renderer extends JPanel {
Dimension dim;
private CopyOnWriteArrayList<Drawable> drawables = new CopyOnWriteArrayList<Drawable>();
Renderer(Dimension dim) {
this.dim = dim;
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
g2d.clearRect(0, 0, getWidth(), getHeight());
for (Drawable drawable : drawables) {
drawable.paint(g2d);
}
g2d.dispose();
drawables.clear();
}
public synchronized void render() {
repaint();
}
public synchronized void submit(Drawable drawable) {
drawables.add(drawable);
}
public synchronized void submitBackground(Drawable drawable) {
drawables.add(0,drawable);
}
}
Drawable.java :
import java.awt.*;
abstract class Drawable {
protected Stroke stroke;
protected Color color, stroke_color;
public Dimension size;
public float sub_pixel_x;
public float sub_pixel_y;
public Drawable(Color color) {
setColor(color);
setStrokeColor(new Color(0));
sub_pixel_x = 0.0f;
sub_pixel_y = 0.0f;
size = new Dimension(10, 10);
}
public void setStroke(float width) {
stroke = new BasicStroke(width);
}
public void noStroke() {
stroke = null;
}
public void setColor(Color color) {
this.color = color;
}
public void setStrokeColor(Color color) {
this.stroke_color = color;
}
public void setLocation(float x, float y) {
sub_pixel_x = x;
sub_pixel_y = y;
}
protected abstract void paint(Graphics2D g2d);
}
AbstractEngine.java :
import java.awt.*;
abstract class AbstractEngine implements Runnable {
Renderer renderer;
Dimension dimension;
boolean running;
Thread thread;
public AbstractEngine(Renderer renderer) {
this.renderer = renderer;
dimension = renderer.dim;
}
public void start() {
if (running) return;
running = true;
thread = new Thread(this, "Tread");
thread.start();
}
public void stop() {
if(!running) return;
running = false;
try {
System.exit(1);
thread.join();
}
catch (InterruptedException e) {
e.printStackTrace();
}
}
public abstract void handleInput();
public abstract void update();
public abstract void render();
#Override
public void run() {
final int UPS = 120;
final int FPS = 60;
long initialTime = System.nanoTime();
final double timeU = 1000000000 / UPS;
final double timeF = 1000000000 / FPS;
double deltaU = 0, deltaF = 0;
int frames = 0, ticks = 0;
long timer = System.currentTimeMillis();
while (running) {
long currentTime = System.nanoTime();
deltaU += (currentTime - initialTime) / timeU;
deltaF += (currentTime - initialTime) / timeF;
initialTime = currentTime;
if (deltaU >= 1) {
handleInput();
update();
ticks++;
deltaU--;
}
if (deltaF >= 1) {
render();
renderer.render();
frames++;
deltaF--;
}
if (System.currentTimeMillis() - timer > 1000) {
frames = 0;
ticks = 0;
timer += 1000;
}
}
}
}
Input is handled in the extended Engine class. I have a MouseState object that holds mouse positions and button state. I then create a MouseAdapter that updates the date in MouseState and attach it to the renderer. It's a bit weird, I know, but works nicely.
My laptop's resolution is 1920x1080. I recently opened my game from another laptop with 1360x768. The JPanel changed size and half of the game was outside the screen. I understand that my game dimensions x 4 are bigger than the second laptop's resolution. But, is there a way to make it adjust to every screen? Any ideas?
package Main;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.image.BufferedImage;
import javax.swing.JPanel;
import GameState.GameStateManager;
import Handlers.Keys;
#SuppressWarnings("serial")
public class GamePanel extends JPanel implements Runnable, KeyListener {
// dimensions
public static final int WIDTH = 320;
public static final int HEIGHT = 240;
public static final int SCALE = 4;
// game thread
private Thread thread;
private boolean running;
private int FPS = 60;
private long targetTime = 1000 / FPS;
// image
private BufferedImage image;
private Graphics2D g;
// game state manager
private GameStateManager gsm;
// other
private boolean recording = false;
private int recordingCount = 0;
private boolean screenshot;
public GamePanel() {
super();
setPreferredSize(new Dimension(WIDTH * SCALE, HEIGHT * SCALE));
setFocusable(true);
requestFocus();
}
public void addNotify() {
super.addNotify();
if (thread == null) {
thread = new Thread(this);
addKeyListener(this);
thread.start();
}
}
private void init() {
image = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB);
g = (Graphics2D) image.getGraphics();
running = true;
gsm = new GameStateManager();
}
public void run() {
init();
long start;
long elapsed;
long wait;
// game loop
while (running) {
start = System.nanoTime();
update();
draw();
drawToScreen();
elapsed = System.nanoTime() - start;
wait = targetTime - elapsed / 1000000;
if (wait < 0) wait = 5;
try {
Thread.sleep(wait);
} catch (Exception e) {
e.printStackTrace();
}
}
}
private void update() {
gsm.update();
Keys.update();
}
private void draw() {
gsm.draw(g);
}
private void drawToScreen() {
Graphics g2 = getGraphics();
g2.drawImage(image, 0, 0, WIDTH * SCALE, HEIGHT * SCALE, null);
g2.dispose();
if (screenshot) {
screenshot = false;
try {
java.io.File out = new java.io.File("screenshot " + System.nanoTime() + ".gif");
javax.imageio.ImageIO.write(image, "gif", out);
} catch (Exception e) {
}
}
if (!recording)
return;
try {
java.io.File out = new java.io.File("C:\\out\\frame" + recordingCount + ".gif");
javax.imageio.ImageIO.write(image, "gif", out);
recordingCount++;
} catch (Exception e) { }
}
public void keyTyped(KeyEvent key) { }
public void keyPressed(KeyEvent key) {
if (key.isControlDown()) {
if (key.getKeyCode() == KeyEvent.VK_R) {
recording = !recording;
return;
}
if (key.getKeyCode() == KeyEvent.VK_S) {
screenshot = true;
return;
}
}
Keys.keySet(key.getKeyCode(), true);
}
public void keyReleased(KeyEvent key) {
Keys.keySet(key.getKeyCode(), false);
}
}
You should be basing the size of game on the resolution of the screen.
You can easily get the resolution by using:
System.out.println(Toolkit.getDefaultToolkit().getScreenSize());
The next issue is are you using a full screen for your game or is you game displayed in a frame. If you are using a frame with decorations, then you also need to account for the size of the title bar and borders around the frame. This information can only be accessed after the frame has been packed.
frame.pack();
System.out.println("Frame Insets : " + frame.getInsets() );
So now the size of your game board would be the size of the screen less the insets of the frame decorations.
I am trying to make a simple animated intro. I have an image I am trying to move from the bottom left of the screen to the center of the screen in a clockwise spiral motion. This is the code that I am using for now. It just moves the image upward to the center:
static ImageLoader il = new ImageLoader();
private static BufferedImage logo = il.load("/logoNew.png");
private static Image power = il.gif("http://i.stack.imgur.com/KSnus.gif");
static double y = 1024.0;
public static void render(Graphics g){
if(y>(486/2)-128){
y = y-0.25;
}
if(draw){
g.drawImage(logo,(864/2)-128,(int)y,null);
g.setColor(Color.WHITE);
g.drawImage(power,10,10,null);
}
}
The if(draw) statement is activated by something else.
How do I go about moving the image. Do I just increment the x and the y differently at different points?
** EDIT **
I didn't make it clear on the motion. Its going from the bottom left to the top left to the top right to the bottom right to the bottom center (centre) to the center (centre) of the screen
Animation is the illusion of movement over time. Normally I would use something like the Timing Framework (or Trident or Universal Tween Engine) as the base of the animation, these provide better support for things like ease-in and ease-out.
The following example just makes uses of a simple javax.swing.Timer. I use this because it's safer to use with Swing, as it allows me to update the state of the UI from within the context of the Event Dispatching Thread, but doesn't block it (preventing it from updating the screen).
The following example uses a concept of a timeline and key frames. That is, at some point in time, something must happen. The timeline then provides the means for blending between those "key" points in time.
I, personally, like to work in abstract concepts, so the timeline is simply measured in a percentage from 0-1, which allows me to provide a variable time span. This allows me to adjust the speed of the animation without the need to change anything.
As you (should) be able to see, the last two legs only need to move half the distance, so they are slower than the other three legs, so, technically, they only need half the time to complete...but I'll leave it up to you to nut out the maths for that ;)
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.Map;
import java.util.TreeMap;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Test{
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
protected static final int PLAY_TIME = 6000;
private Timeline timeline;
private long startTime;
private Point imgPoint;
private BufferedImage img;
public TestPane() {
try {
img = ImageIO.read(new File("C:/Neko.png"));
imgPoint = new Point(0, 200 - img.getHeight());
timeline = new Timeline();
timeline.add(0f, imgPoint);
timeline.add(0.2f, new Point(0, 0));
timeline.add(0.4f, new Point(200 - img.getWidth(), 0));
timeline.add(0.6f, new Point(200 - img.getWidth(), 200 - img.getHeight()));
timeline.add(0.8f, new Point(100 - (img.getWidth() / 2), 200 - img.getHeight()));
timeline.add(1f, new Point(100 - (img.getWidth() / 2), 100 - (img.getHeight() / 2)));
Timer timer = new Timer(40, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
long duration = System.currentTimeMillis() - startTime;
float progress = (float) duration / (float) PLAY_TIME;
if (progress > 1f) {
startTime = System.currentTimeMillis();
progress = 0;
((Timer) (e.getSource())).stop();
}
System.out.println(progress);
imgPoint = timeline.getPointAt(progress);
repaint();
}
});
startTime = System.currentTimeMillis();
timer.start();
} catch (IOException exp) {
exp.printStackTrace();
}
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (img != null && imgPoint != null) {
Graphics2D g2d = (Graphics2D) g.create();
g2d.drawImage(img, imgPoint.x, imgPoint.y, this);
g2d.dispose();
}
}
}
public static class Timeline {
private Map<Float, KeyFrame> mapEvents;
public Timeline() {
mapEvents = new TreeMap<>();
}
public void add(float progress, Point p) {
mapEvents.put(progress, new KeyFrame(progress, p));
}
public Point getPointAt(float progress) {
if (progress < 0) {
progress = 0;
} else if (progress > 1) {
progress = 1;
}
KeyFrame[] keyFrames = getKeyFramesBetween(progress);
float max = keyFrames[1].progress - keyFrames[0].progress;
float value = progress - keyFrames[0].progress;
float weight = value / max;
return blend(keyFrames[0].getPoint(), keyFrames[1].getPoint(), 1f - weight);
}
public KeyFrame[] getKeyFramesBetween(float progress) {
KeyFrame[] frames = new KeyFrame[2];
int startAt = 0;
Float[] keyFrames = mapEvents.keySet().toArray(new Float[mapEvents.size()]);
while (startAt < keyFrames.length && keyFrames[startAt] <= progress) {
startAt++;
}
if (startAt >= keyFrames.length) {
startAt = keyFrames.length - 1;
}
frames[0] = mapEvents.get(keyFrames[startAt - 1]);
frames[1] = mapEvents.get(keyFrames[startAt]);
return frames;
}
protected Point blend(Point start, Point end, float ratio) {
Point blend = new Point();
float ir = (float) 1.0 - ratio;
blend.x = (int) (start.x * ratio + end.x * ir);
blend.y = (int) (start.y * ratio + end.y * ir);
return blend;
}
public class KeyFrame {
private float progress;
private Point point;
public KeyFrame(float progress, Point point) {
this.progress = progress;
this.point = point;
}
public float getProgress() {
return progress;
}
public Point getPoint() {
return point;
}
}
}
}
I was trying to follow these tutorials http://zetcode.com/tutorials/javagamestutorial/animation/ and none of the three examples on that page seem to be working for me. One of them uses a swing timer, one uses the utility timer, and the last and supposedly most effective and accurate according to the page uses a thread to animate.
I will show you the one using the thread, since it is the way that I think I will be doing thing's when using animation for making games.
ThreadAnimationExample.java (in the tutorial it is called star.java but obviously that wont work)
import java.awt.EventQueue;
import javax.swing.JFrame;
public class ThreadAnimationExample extends JFrame {
public ThreadAnimationExample() {
add(new Board());
setTitle("Star");
pack();
setResizable(false);
setLocationRelativeTo(null);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
JFrame ex = new ThreadAnimationExample();
ex.setVisible(true);
}
});
}
}
Board.java (the main class)
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Toolkit;
import javax.swing.ImageIcon;
import javax.swing.JPanel;
public class Board extends JPanel
implements Runnable {
private final int B_WIDTH = 350;
private final int B_HEIGHT = 350;
private final int INITIAL_X = -40;
private final int INITIAL_Y = -40;
private final int DELAY = 25;
private Image star;
private Thread animator;
private int x, y;
public Board() {
loadImage();
initBoard();
}
private void loadImage() {
ImageIcon ii = new ImageIcon("star.png");
star = ii.getImage();
}
private void initBoard() {
setBackground(Color.BLACK);
setPreferredSize(new Dimension(B_WIDTH, B_HEIGHT));
setDoubleBuffered(true);
x = INITIAL_X;
y = INITIAL_Y;
}
#Override
public void addNotify() {
super.addNotify();
animator = new Thread(this);
animator.start();
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
drawStar(g);
}
private void drawStar(Graphics g) {
Graphics2D g2d = (Graphics2D) g;
g2d.drawImage(star, x, y, this);
Toolkit.getDefaultToolkit().sync();
g.dispose();
}
private void cycle() {
x += 1;
y += 1;
if (y > B_HEIGHT) {
y = INITIAL_Y;
x = INITIAL_X;
}
}
#Override
public void run() {
long beforeTime, timeDiff, sleep;
beforeTime = System.currentTimeMillis();
while (true) {
cycle();
repaint();
timeDiff = System.currentTimeMillis() - beforeTime;
sleep = DELAY - timeDiff;
if (sleep < 0) {
sleep = 2;
}
try {
Thread.sleep(sleep);
} catch (InterruptedException e) {
System.out.println("Interrupted: " + e.getMessage());
}
beforeTime = System.currentTimeMillis();
}
}
}
If you are using Eclipse you should create a source folder and add that image to the source folder. Then you could use this:
ImageIcon ii = new ImageIcon( getClass().getResource("/imageName.png") );
i was making a program, game in specific, so i started with basic things, but when i try to test it it drops out weird errors which doesn't appear in code, so i suppose my code is fine, but i don't know what could be causing this. :(
This is the error:
Exception in thread "main" java.lang.NullPointerException
at java.awt.image.BufferedImage.<init>(Unknown Source)
at ca.hawk.game.Game.<init>(Game.java:33)
at ca.hawk.game.Game.main(Game.java:126)
And here's the code (package):
package ca.hawk.game;
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 java.awt.image.IndexColorModel;
import javax.swing.JFrame;
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 static final int BufferedImage = 0;
private static final IndexColorModel TYPE_INT_RGB = null;
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();
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 synchronized void start() {
running = true;
new Thread(this).start();
}
private 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;
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) {
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++;
}
public void render(){
BufferStrategy bs = getBufferStrategy();
if (bs == null){
createBufferStrategy(3);
return;
}
Graphics g = bs.getDrawGraphics();
g.setColor(Color.BLACK);
g.fillRect(0, 0, getWidth(), getHeight());
g.drawImage(image, 0, 0, getWidth(), getHeight(), null);
g.dispose();
bs.show();
}
public static void main(String[] args){
new Game().start();
}
}
change :
private BufferedImage image = new BufferedImage(WIDTH, HEIGHT, BufferedImage, TYPE_INT_RGB);
to:
private BufferedImage image = new BufferedImage(WIDTH, HEIGHT, BufferedImage, BufferedImage.TYPE_INT_ARGB);
you set a varialbe TYPE_INT_RGB that is null, so when you make a buffered image it throws null pointer exception.
TYPE_INT_RGB is a public static final variable on BufferedImage. Public means you can access it in your object, static means its a class variable not an object variable and final means its ts always the same value e.g if its 10 it will always be 10.
with BufferedImage.TYPE_INT_RGB you can access it.