I have just started learning java and I've been working on this code for a moving object with keyboard input. I am now trying to add in a background, but it keeps erroring with:
javax.imageio.IIOException: Can't read input file!
at javax.imageio.ImageIO.read(Unknown Source)
at game.GameLoop.run(GameLoop.java:24)
at java.lang.Thread.run(Unknown Source)
The code I have in Game.java is:
package game;
import java.applet.*;
import java.awt.*;
public class Game extends GameLoop{
public void init(){
setSize(864,480);
Thread th = new Thread(this);
th.start();
offscreen = createImage(864,480);
d = offscreen.getGraphics();
addKeyListener(this);
}
public void paint(Graphics g){
d.clearRect(0, 0, 864, 480);
d.drawImage(background, 0, 0, this);
d.drawRect(x, y, 20, 20);
g.drawImage(offscreen, 0, 0, this);
}
public void update(Graphics g){
paint(g);
}
}
And here is my GameLoop.java:
package game;
import java.applet.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
public class GameLoop extends Applet implements Runnable, KeyListener{
public int x, y;
public Image offscreen;
public Graphics d;
public boolean up, down, left, right;
public BufferedImage background;
public void run(){
x = 100;
y = 100;
try {
background = ImageIO.read(new File("background.png"));
} catch (IOException e1) {
e1.printStackTrace();
}
while(true){
x = 100;
y = 100;
while(true){
if (left == true){
x-=4;
}
if (right == true){
x+=4;
}
if (up == true){
y-=4;
}
if (down == true){
y+=4;
}
if ( x <= 0 ){
x = 0;
}
if ( y <= 0 ){
y = 0;
}
if ( x >= 843 ){
x = 843;
}
if ( y >= 460 ){
y = 459;
}
repaint();
try{
Thread.sleep(20);
} catch(InterruptedException e){
e.printStackTrace();
}
}
}
}
//#Override
public void keyPressed(KeyEvent e) {
if(e.getKeyCode() == 37){
left = true;
}
if(e.getKeyCode() == 38){
up = true;
}
if(e.getKeyCode() == 39){
right = true;
}
if(e.getKeyCode() == 40){
down = true;
}
}
//#Override
public void keyReleased(KeyEvent e) {
if(e.getKeyCode() == 37){
left = false;
}
if(e.getKeyCode() == 38){
up = false;
}
if(e.getKeyCode() == 39){
right = false;
}
if(e.getKeyCode() == 40){
down = false;
}
}
//#Override
public void keyTyped(KeyEvent e) {
}
}
Sorry about the editing I can't seem to get it all in the ``, and I will also fix the messy code, but do you guys have any ideas what is causing this error, there is a file in the src dir called background.png, it is very basic and made in MS paint, if that helps.
Thanks.
There are two places a simple, sand-boxed applet can obtain images.
Where
A loose file on the same server the applet was supplied from. E.G. This might be used for a sand-boxed 'image slideshow' where the image names are supplied in applet parameters.
A Jar on the run-time class-path of the applet. Best for resources which would not typically change (barring localized images, where it becomes more complicated). E.G. This might be used for button/menu icons, or BG images.
"background.png" strongly indicates the 2nd scenario - 'part of the app. itself'.
How to find
Both types of resources should identified by URL (do not try to establish a File as it will fail when the applet is deployed).
The way to obtain an URL for the 2nd case is something along the lines of:
URL urlToBG = this.getClass().getResource("/path/to/the/background.png");
..where /path/to/the/ might simply be /resources/ or /images/. It is the path within a Jar on the classpath, where the image can be found.
How to load
Most methods that will load a File are overloaded to accept an URL. This notably applies to ImageIO.read(URL).
While the Applet class has inbuilt methods to load images, I recommend sticking with ImageIO since it provides more comprehensive feed-back on failure.
Further tips
Tip 1
Thread.sleep(20);
Don't block the EDT (Event Dispatch Thread) - the GUI will 'freeze' when that happens. Instead of calling Thread.sleep(n) implement a Swing Timer for repeating tasks or a SwingWorker for long running tasks. See Concurrency in Swing for more details.
Tip 2
It is the third millennium, time to start using Swing instead of AWT. That would mean extending JApplet instead of Applet. Then you might shift the logic of painting into a JPanel that is double-buffered by default, and could be used in either the applet or a frame (or a window or a dialog..).
Tip 3
setSize(864,480);
The size of an applet is set in HTML, and the applet should accept whatever size it is assigned and work within that. Taking that into account, statements like:
d.clearRect(0, 0, 864, 480);
..should read more like:
d.clearRect(0, 0, getWidth(), getHeight());
#Patricia Shanahan Your comment actually helped me to solve the same problem.
I've used that code:
File here = new File(".");
try {
System.out.println(here.getCanonicalPath());
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
and from there you can figure out the correct path to use.
Related
I am trying to do a PAC-MAN clone in Java. I am using swing and awt for the GUI.
I implemented motion into my main character and it responds to keys pressed, but when the character moves the "old image" stays there. So, rather than it looking like pacman moves through the screen he leaves a trail. It is my understanding that when I use the repaint() function the image should be cleared and painted again.
This is my code:
//PACMAN CLASS
import Entities.Ghost;
import Entities.Player;
import javax.swing.*;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
public class Pacman extends JPanel implements KeyListener {
Player player = new Player("Pacman.png", 0, 0);
Ghost[] ghosts = new Ghost[4];
public Pacman(){
addKeyListener(this);
setFocusable(true);
ghosts[0] = new Ghost("Ghost_Red.png", 200, 200);
ghosts[1] = new Ghost("Ghost_Red.png", 150, 150);
ghosts[2] = new Ghost("Ghost_Red.png", 300, 100);
ghosts[3] = new Ghost("Ghost_Red.png", 50, 300);
}
public void paintComponent(Graphics g){
player.draw(g, this);
for(Ghost ghost: ghosts){
ghost.draw(g, this);
}
}
public void update() {
repaint();
}
#Override
public void keyTyped(KeyEvent e) {
}
#Override
public void keyPressed(KeyEvent e) {
if(e.getKeyCode() == KeyEvent.VK_ENTER){
new Thread( () -> {
while (true){
update();
try{
Thread.sleep(10);
}catch(InterruptedException err){
err.printStackTrace();
}
}
}).start();
}
int SPEED = 4;
if(e.getKeyCode() == KeyEvent.VK_RIGHT && player.x < (getWidth() - player.width)){
player.x += SPEED;
}
if(e.getKeyCode() == KeyEvent.VK_LEFT && player.x > 0){
player.x -= SPEED;
}
if(e.getKeyCode() == KeyEvent.VK_UP && player.y > 0){
player.y -= SPEED;
}
if(e.getKeyCode() == KeyEvent.VK_DOWN && player.y < (getHeight() - player.height)){
player.y += SPEED;
}
}
#Override
public void keyReleased(KeyEvent e) {
}
}
//MY MAIN
import javax.swing.*;
public class Main {
public static void main(String[] args) {
JFrame frame = new JFrame("Pacman");
Pacman panel = new Pacman();
frame.getContentPane().add(panel);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
frame.setSize(224*2,288*2);
frame.setResizable(false);
}
}
I followed a tutorial to get here and the guy's graphic do work properly. Thoug he is using JAva 10 and I am using Java 16
When doing custom painting, and especially when doing some "animations", it's really important to call super.paintComponent(g); as the first line in your paintComponent(...) method
This will repaint all the things you're not painting on that "frame", and thus this is what you need to do to solve your problem.
If you want to know more in detail what super.paintComponent() does, then read this answer.
So your code should end up looking like this:
public void paintComponent(Graphics g) {
super.paintComponent(g);
player.draw(g, this);
for(Ghost ghost : ghosts) {
ghost.draw(g, this);
}
//Any extra painting do it here
}
Also, this line:
frame.setVisible(true);
Should be the last one on your program
And about this line:
frame.setSize(224*2,288*2);
Better override your JPanel's getPreferredSize, and then call frame.pack() this will make your pane to have that size and then add the frame decorations, otherwise your panel will be smaller than you think it is; for more information take a look at this question and answers: Should I avoid the use of set(Preferred|Maximum|Minimum)Size methods in Java Swing?
And as a tip, don't use "magic numbers", instead declare constants as of what those 224 and 288 means and why you multiply them by 2.
And forgot to mention that when programming games, it's better to use KeyBindings rather than infinite loops (while(true)) with KeyListeners; here's an excellent answer from #HovercraftFullOfEels that shows how to do it.
There's no errors, but when I press any of the buttons, my oval/circle doesn't move at all? Can anyone help? I've been looking up and down the code for about 20 minutes seeing if I typed anything wrong or put something in the wrong place. I can't tell if this is with the way I'm moving it or my thread.
package com.badfitz66.mainpackage;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import javax.swing.JFrame;
public class Main extends JFrame implements Runnable
{
int x, y, xDirection, yDirection;
private Image dbImage;
private Graphics dbG;
Font font = new Font("Black Caps", Font.ITALIC | Font.BOLD, 30);
public void run()
{
try
{
while(true)
{
Move();
Thread.sleep(5);
}
}
catch(Exception e){
System.out.println("Error");
}
}
public void Move()
{
x += xDirection;
y += yDirection;
if (x <= 0)
x = 0;
if(x >= 500)
x = 500;
if (y <= 50)
y = 50;
if (y >= 250)
y = 250;
}
public void setXDir(int xdir)
{
xDirection = xdir;
}
public void setYDir(int ydir)
{
yDirection = ydir;
}
public class AL extends KeyAdapter
{
public void keyPressed(KeyEvent e)
{
int keyCode = e.getKeyCode();
if(keyCode == e.VK_D)
{
setXDir(+1);
}
if(keyCode == e.VK_A)
{
setXDir(-1);
}
if(keyCode == e.VK_W)
{
setYDir(-1);
}
if(keyCode == e.VK_S)
{
setYDir(+1);
}
}
public void keyReleased(KeyEvent e)
{
int keyCode = e.getKeyCode();
if(keyCode == e.VK_D)
{
setXDir(0);
}
if(keyCode == e.VK_A)
{
setXDir(0);
}
if(keyCode == e.VK_W)
{
setYDir(0);
}
if(keyCode == e.VK_S)
{
setYDir(0);
}
}
}
public Main()
{
addKeyListener(new AL());
setTitle("Java game testing");
setResizable(false);
setVisible(true);
setSize(500, 500);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBackground(Color.green);
x = 150;
y = 150;
}
public void paint(Graphics g)
{
dbImage = createImage(getWidth(),getHeight());
dbG = dbImage.getGraphics();
paintComponent(dbG);
g.drawImage(dbImage, 0, 0, this);
}
public void paintComponent(Graphics g)
{
g.setFont(font);
g.drawString("Hello world", 125, 50);
g.setColor(Color.cyan);
g.fillOval(x, y, 15, 15);
repaint();
}
public static void main(String[] args)
{
Main jg = new Main();
//Threads
Thread t1 = new Thread();
t1.start();
}
}
You never call repaint from within your Move method
Thread t1 = new Thread(); won't do much, as it will never call any runnable code, in fact it will start and terminate almost immediately, how ever...
Swing is not thread safe and you should never modify the UI or anything the UI relies on from outside the Event Dispatching Thread, this especially important, as a paint cycle could occur at any time. See Concurrency in Swing for more details
You override the paint method of a top level container (JFrame) and then break the paint chain...paint is complex series of method calls chained together to generate the final result, you should always call super.paint first, but as you probably know, JFrame is not double buffered. So instead, you should create another class that extends from JPanel and override it's paintComponent method to perform the actual painting (in fact, for the most part, it should pretty much replace the functionality that the current JFrame is doing)...Swing components are double buffered by default...
Calling repaint from within a paint method...this is bad news and this will immediately schedule another paint cycle, this becomes so fast that it consume all your CPU cycles till you computer stands still
Using KeyListener. KeyListener is notorious for having issues, in particular, it will only ever trigger a key event if the component it is registered to IS FOCUSABLE and HAS FOCUS. A JFrame is made up of the physical window, the JRootPane, which holds the content pane (and a few other components), all of which can get in the way of the frame actually getting focus. Instead, using the previously mentioned JPanel, use the key bindings API, which will allow to control the level of focus required for the key events to be triggered. See How to Use Key Bindings for more details
You should also have a look at...
Performing Custom Painting
Painting in AWT and Swing
How to use Swing Timers
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 8 years ago.
Improve this question
It's my first time trying to create a 2d game in java and I made a little 8-bit like character that I want to put in place of the rectangle that appears on screen. I can't quite understand how to get the .png image into the rectangle's place, or how I would go about making the character, in this case, the image saved to my hard drive. Thanks!
import javax.swing.*;
import java.awt.*;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
public class Keying extends JPanel {
public Rectangle character;
public int charW = 24;
public int charH = 36;
public boolean right = false;
public boolean left = false;
public boolean up = false;
public boolean down = false;
public Keying(Display f, Images i)
{
character = new Rectangle(180, 180, charW, charH);
f.addKeyListener(new KeyAdapter()
{
public void keyPressed(KeyEvent e)
{
if (e.getKeyCode() == KeyEvent.VK_D)
{
right = true;
}
if (e.getKeyCode() == KeyEvent.VK_A)
{
left = true;
}
if (e.getKeyCode() == KeyEvent.VK_S)
{
down = true;
}
if (e.getKeyCode() == KeyEvent.VK_W)
{
up = true;
}
}
public void keyReleased(KeyEvent e)
{
if (e.getKeyCode() == KeyEvent.VK_D)
{
right = false;
}
if (e.getKeyCode() == KeyEvent.VK_A)
{
left = false;
}
if (e.getKeyCode() == KeyEvent.VK_S)
{
down = false;
}
if (e.getKeyCode() == KeyEvent.VK_W)
{
up = false;
}
}
});
}
public void paintComponent(Graphics g)
{
super.paintComponent(g);
this.setBackground(Color.white);
g.setColor(Color.black);
g.fillRect(character.x, character.y, character.width, character.height);
if (right)
{
character.x += 1;
}
if (left)
{
character.x -= 1;
}
if (down)
{
character.y += 1;
}
if (up)
{
character.y -= 1;
}
repaint();
}
}
The process is relatively simple...
Start by loading the character image...
public class Keying extends JPanel {
//public Rectangle character;
private java.awt.BufferedImage character;
private java.awt.Point characterLocation;
//...
public Keying(Display f, Images i) throws IOException
{
character = javax.ImageIO.read(...);
characterLocation = new Point(0, 0);
//...
See Reading/Loading an Image for more details...
Then, you simply want to paint the character image...
#Override
protected void paintComponent(Graphics g)
{
g.drawImage(character, characterLocaiton.x, characterLocation.y, this);
Advice
Avoid KeyListener, it's prone to focus issues you really don't want to deal with. Instead use key bindings, see How to Use Key Bindings for more details
Avoid putting any logic within any of the paint routines, painting can occur at any time, many of which you don't control, this could have your character moving in directions you don't expect or faster than they should. Instead, this belongs within the main game loop which is responsible for updating the state and scheduling paint requests.
NEVER change the state of the component from within any paint method, this could cause an infinite loop of paint requests, which will consume your systems resources. Within your context, don't call setBackground (by the time you call this, the background has already been painted anyway) or repaint
This question already has answers here:
Class.getResource() returns null
(2 answers)
Closed 8 years ago.
This is my first question, I hope it's not too poorly made.
I'm definitely beginner level at java, probably lower. I'm taking most of my code from a tutorial in fact, hoping I'll learn what all the things do soon enough.
Anyway, so far, I have 3 .java files in my program, and it shows the exception to be at all 3 of them, plus one I never made.
Here's the full error:
Exception in thread "main" java.lang.NullPointerException
at javax.swing.ImageIcon.<init>(ImageIcon.java:205)
at Emilia.<init>(Emilia.java:17)
at Board.<init>(Board.java:26)
at TestGame.<init>(TestGame.java:7)
at TestGame.main(TestGame.java:18)
Here's all the code:
TestGame.java
import javax.swing.JFrame;
public class TestGame extends JFrame {
public TestGame() {
add(new Board());
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(400, 300);
setLocationRelativeTo(null);
setTitle("Project Obcasus");
setResizable(false);
setVisible(true);
}
public static void main(String[] args) {
new TestGame();
}
}
Board.java
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class Board extends JPanel implements ActionListener {
private Timer timer;
private Emilia emilia;
public Board() {
addKeyListener(new TAdapter());
setFocusable(true);
setBackground(Color.BLACK);
setDoubleBuffered(true);
emilia = new Emilia();
timer = new Timer(5, this);
timer.start();
}
public void paint(Graphics g) {
super.paint(g);
Graphics2D g2d = (Graphics2D)g;
g2d.drawImage(emilia.getImage(), emilia.getX(), emilia.getY(), this);
Toolkit.getDefaultToolkit().sync();
g.dispose();
}
public void actionPerformed(ActionEvent e) {
emilia.move();
repaint();
}
private class TAdapter extends KeyAdapter {
public void keyReleased(KeyEvent e) {
emilia.keyReleased(e);
}
public void keyPressed(KeyEvent e) {
emilia.keyPressed(e);
}
}
}
Emilia.java
import java.awt.Image;
import java.awt.event.KeyEvent;
import javax.swing.ImageIcon;
public class Emilia {
private String emilia = "emiliasprite.png";
private int dx;
private int dy;
private int x;
private int y;
private Image image;
public Emilia() {
ImageIcon ii = new ImageIcon(this.getClass().getResource(emilia));
image = ii.getImage();
x = 40;
y = 60;
}
public void move() {
x += dx;
y += dy;
}
public int getX() {
return x;
}
public int getY() {
return y;
}
public Image getImage() {
return image;
}
public void keyPressed(KeyEvent e) {
int key = e.getKeyCode();
if (key == KeyEvent.VK_A) {
dx = -1;
}
if (key == KeyEvent.VK_D) {
dx = 1;
}
if (key == KeyEvent.VK_W) {
dy = -1;
}
}
public void keyReleased(KeyEvent e) {
int key = e.getKeyCode();
if (key == KeyEvent.VK_A) {
dx = 0;
}
if (key == KeyEvent.VK_D) {
dx = 0;
}
if (key == KeyEvent.VK_W) {
dy = 0;
}
}
}
ImageIcon.java - Line 205
this(location, location.toExternalForm());
Again, I'm beginner level so if you guys could explain it as you would to a newcomer to java (or any programming language for that matter)
Thanks for any help. - Niblexis
path of .png file:
C:\Users\Damon\workspace\TestGame\Resources\Sprites\Player
The .png file is in the player folder. I tried to run the program via the run button in Eclipse. At least, I think it's the run button because it's what showed me the errors in the first place.
Looks like the problem is in this line:
ImageIcon ii = new ImageIcon(this.getClass().getResource(emilia));
which means most likely that you haven't placed your .png file in the right place for Java to find it.
Could you post the exact path of the .png file on disk?
More specifically: a null pointer in this line of ImageIcon.java:
this(location, location.toExternalForm());
would imply that the URL location is null (causing an exception in the method call .toExternalForm(). If you look at the docs for Class.getResource() you will see it says:
Returns: A URL object or null if no resource with this name is found
which implies that Java can't find the resource in question.
For us to help, you will need to describe your runtime environment (are you running your program from .class files or in a .jar? at the command-line or in a debugger in Eclipse / Netbeans?) so we can help you figure out why the resource isn't being found.
You're effectively calling Emilia.class.getResource("emiliasprite.png") with Emilia.java in the default (root) package, which means that you need to tell your IDE / build process to copy this file into the root of the classpath. (in the same directory that Emilia.class ends up) Otherwise, Java has no idea where to find it.
If you want to place the resource somewhere else, you need to change the path accordingly, as well as the mechanism that copies the resource from the source directory to the appropriate place on the classpath.
See this stackoverflow answer: Java in Eclipse: Where do I put files on the filesystem that I want to load using getResource? (e.g. images for an ImageIcon)
I recently started making a Java applet game for the java4k game contest but I'm new with applets and I have some questions about them.
I have an applet written in eclipse and I can run it in eclipse using applet viewer but how do I compile it? There doesn't seem a option for compiling applets..
..and what is a jar archive?
Thanks.
Also here's my source in case you need it:
import java.applet.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.*;
import javax.imageio.ImageIO;
public class game extends Applet implements KeyListener{
private static final long serialVersionUID = 1L;
public int x = 50,y = 50;
public boolean right, left, down, up, lt = false, rt = true;
public Image buffer;
BufferedImage img = null;
BufferedImage imgl = null;
Graphics bg;
public void init(){
try {
img = ImageIO.read(new File("C:/player.png"));
} catch (IOException e){}
try {
imgl = ImageIO.read(new File("C:/playerl.png"));
} catch (IOException e){}
addKeyListener(this);
setSize(400,200);
setBackground(Color.cyan);
Timer t = new Timer();
t.schedule(new TimerTask(){public void run(){
if (right == true){x++;}
if (left == true){x--;}
if (up == true){y--;}
if (down == true){y++;}
repaint();
}},10,10);
buffer = createImage(400,200);
bg = buffer.getGraphics();
}
public void paint(Graphics g){
bg.setColor(Color.WHITE);
//bg.clearRect(0, 0, 400, 200);
if (rt == true){
bg.drawImage(img,x,y, this);
}
if (lt == true){
bg.drawImage(imgl,x,y, this);
}
g.drawImage(buffer,0,0,this);
}
public void keyTyped(KeyEvent e){}
public void keyPressed(KeyEvent e){
if (e.getKeyCode() == 37){
left = true;
lt = true;
rt = false;
}
if (e.getKeyCode() == 39){
right = true;
rt = true;
lt = false;
}
if (e.getKeyCode() == 38){
up = true;
}
if (e.getKeyCode() == 40){
down = true;
}
}
public void keyReleased(KeyEvent e){
if (e.getKeyCode() == 37){
left = false;
}
if (e.getKeyCode() == 39){
right = false;
}
if (e.getKeyCode() == 38){
up = false;
}
if (e.getKeyCode() == 40){
down = false;
}
}
public void update(Graphics g){
paint(g);
}
}
You will need to export as a JAR file. To do this you will need to right-click the project > export.
Select Java > JAR file
In the JAR Export Dialog, select what parts you want to export (Export generated class files and resources) for your project. Probably want to specify the output folder as well. The rest of the options can be left as default and go to Finish.
You can run the JAR in a applet viewer or from a webpage in an APPLET tag, make sure to set the archive="jar file name".
In Eclipse, right click the project, click export, and export as a jar.
Then you can embed this jar in your webpage to be run as an applet, or externally with appletviewer.
There's no difference between a JAR and an Archive Jar. JAR stands for "Java ARchive".
You cant create self executive jar without main method.
Fortunately it's quite simple to do it.
You can create method called public static void main(String[] args) within your main class.
and then do something like this:
yourmainclassname yourname = new yourmainclassname(); //create new object
yourname.init(); //invoke the applet's init() method
yourname.start(); //starts the applet
// Create a window (JFrame) and make applet the content pane.
JFrame window = new JFrame("Put something here");
window.setSize(640, 480); //size in pixels
window.setContentPane(theApplet); //
window.setVisible(true);
window.setDefaultCloseOperation(javax.swing.JFrame.EXIT_ON_CLOSE);
That's all. Next you can just export project to self executive JAR.