i'm trying to build up a game, and i'm doing this with the help of a tutorial. My problem is, the run() method I show below is not working. I tried the sample code of the tutorial, it is exactly the same run() method and it works.
In my code, run() is never called and I don't get why.
package thisproject;
public class StartingClass extends Applet implements Runnable, KeyListener,
MouseListener {
private Builder builder;
private Image image,currentSprite, character,characterWalk, background;
private Graphics second;
private URL base;
private static Background bg1;
#Override
public void init() {
setSize(800, 400);
setBackground(Color.BLACK);
setFocusable(true);
addKeyListener(this);
Frame frame = (Frame) this.getParent().getParent();
frame.setTitle("Castle Fight");
try {
base = getDocumentBase();
} catch (Exception e) {
// TODO: handle exception
}
// Image Setups
background = getImage(base, "data/background2.png");
character = getImage(base, "data/builder.png");
currentSprite = character;
}
#Override
public void start() {
bg1 = new Background(0, 0);
builder = new Builder();
Thread thread = new Thread();
thread.start();
}
#Override
public void stop() {
// TODO Auto-generated method stub
}
#Override
public void destroy() {
// TODO Auto-generated method stub
}
#Override
public void run() {
while (true) {
System.out.println("this thing");
builder.update();
bg1.update();
repaint();
try {
Thread.sleep(17);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
#Override
public void update(Graphics g) {
if (image == null) {
image = createImage(this.getWidth(), this.getHeight());
second = image.getGraphics();
}
second.setColor(getBackground());
second.fillRect(0, 0, getWidth(), getHeight());
second.setColor(getForeground());
paint(second);
g.drawImage(image, 0, 0, this);
}
#Override
public void paint(Graphics g) {
g.drawImage(background, bg1.getBgX(), bg1.getBgY(), this);
g.drawImage(currentSprite, builder.getCenterX() - 61, builder.getCenterY() - 63, this);
}
}
}
Please, keep in mind that I took out the imports and the key events so the code didn't take much room, but I do have all the imports necessary.
Hopefully someone can give me some light on this.
You never supply the Runnable. Change
Thread thread = new Thread();
thread.start();
to
Thread thread = new Thread(this);
thread.start();
Related
Please read the latest update down below
So I am trying to make a brick breaker game and while everything works in terms of gameplay I am having trouble adding a menu system. Basically this is how my code works
public class Game extends Canvas implements Runnable{
public Graphics g;
private Menu menu;
protected Ball ball;
protected Player player;
protected BufferedImage image;
protected BufferStrategy bufferStrategy;
protected Thread thread;
protected JFrame frame;
protected volatile boolean running, gameOver;
private enum STATE{
MENU,
GAME,
ABOUT,
OPTIONS,
};
private STATE State = STATE.MENU;
public Game(){
//Set the Jframe
}
private void init()
{
image = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB);
requestFocus();
menu = new Menu();
//init everything else aswell
}
public void update()
{
//Update every moving object
}
#Override
public void run()
{
init();
long initialTime = System.nanoTime();
double timePerFrame = 1000000000/FPS;
double delta = 0;
int ticks = 0;
long timer = 0;
while (running)
{
long currentTime = System.nanoTime();
long elapsedTime = currentTime - initialTime;
delta += elapsedTime/timePerFrame;
timer += elapsedTime;
if (delta >= 1)
{
update();
delta--;
ticks++;
}
render();
initialTime = currentTime;
if (timer >= 1000000000)
{
currentFPS = ticks;
ticks = 0;
timer = 0;
}
}
stop();
}
And when I render everything that is in the STATE GAME it works just fine but when I try to add an else if statement that does menu.draw(g) it all falls apart and I just get a blank frame
Here is how I render
public void render()
{
bufferStrategy = getBufferStrategy();
if (bufferStrategy == null)
{
createBufferStrategy(3);
return;
}
g = bufferStrategy.getDrawGraphics();
g.drawImage(image, 0, 0, getWidth(), getHeight(), this);
g.setColor(BG_COLOR);
g.fillRect(0, 0, WIDTH, HEIGHT);
if(State == STATE.GAME){
player.draw(g);
ball.draw(g);
blockController.draw(g); **THESE WORK JUST FINE**
}
else if(State == STATE.MENU){
menu.draw(g); **DOES NOT WORK**
}
bufferStrategy.show();
g.dispose();
}
And my Menu class has no difference in terms of the draw method
public class Menu implements GUI
{
#Override
public void draw(Graphics g) {
g.setFont(new Font("arial", Font.BOLD, 50));
g.setColor(Color.black);
g.drawString("MENU", Game.WIDTH / 2, 100);
}
}
Any idea why this might be happening I am doing the same render litteraly but keep getting
Exception in thread "Thread-0" java.lang.ClassCastException: class sun.java2d.NullSurfaceData cannot be cast to class sun.java2d.d3d.D3DSurfaceData error or g is null error
How can I fix this?
UPDATE ----------------------------------
The menu.draw() in the render works when I remove the lines
g.setFont(new Font("arial", Font.BOLD, 50));
g.setColor(Color.black);
g.drawString("MENU", Game.WIDTH / 2, 100);
And instead add something like
g.setColor(Color.CYAN);
g.fillRect(5, 5, 200, 200);
This does work but why the setfont, setColor and drawString don't work I don't understand I wanted to add buttons aswell but they don't work either. Is it because I set the entire frame with a rectangle in the render with the line g.fillRect(0, 0, WIDTH, HEIGHT); but then can I add objects like paddle,ball,bricks but not a string or a button?
The following example seems to work fine.
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.image.BufferStrategy;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame();
frame.add(new TestPane());
frame.pack();
frame.setVisible(true);
}
});
}
public class TestPane extends Canvas {
private Thread thread;
private volatile boolean render = false;
public TestPane() {
}
#Override
public void addNotify() {
super.addNotify();
start();
}
#Override
public void removeNotify() {
super.removeNotify();
stop();
}
protected void start() {
if (thread != null) {
render = false;
try {
thread.join();
} catch (InterruptedException ex) {
}
}
render = true;
thread = new Thread(new Runnable() {
#Override
public void run() {
while (render) {
render();
try {
Thread.sleep(16);
} catch (InterruptedException ex) {
}
}
}
});
thread.start();
}
protected void stop() {
render = false;
if (thread == null) {
return;
}
try {
thread.join();
} catch (InterruptedException ex) {
}
thread = null;
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
private Menu menu = new Menu();
protected void render() {
BufferStrategy strategy = getBufferStrategy();
if (strategy == null) {
createBufferStrategy(3);
strategy = getBufferStrategy();
}
if (strategy == null) {
return;
}
do {
// The following loop ensures that the contents of the drawing buffer
// are consistent in case the underlying surface was recreated
do {
// Get a new graphics context every time through the loop
// to make sure the strategy is validated
Graphics graphics = strategy.getDrawGraphics();
graphics.setColor(Color.BLACK);
graphics.fillRect(0, 0, getWidth(), getHeight());
menu.render(graphics, getSize());
graphics.dispose();
// Repeat the rendering if the drawing buffer contents
// were restored
} while (strategy.contentsRestored());
// Display the buffer
strategy.show();
// Repeat the rendering if the drawing buffer was lost
} while (strategy.contentsLost());
}
}
public class Menu {
public void render(Graphics g, Dimension bounds) {
// This is probably going to cost you a lot of
// performance and it might be better to
// pre-create the font instead
g.setFont(new Font("Arial", Font.BOLD, 50));
g.setColor(Color.WHITE);
String text = "MENU";
FontMetrics fm = g.getFontMetrics();
g.drawString("MENU", (bounds.width - fm.stringWidth(text)) / 2, (bounds.height / 2) - fm.getAscent());
}
}
}
If you continue to have issues, continue providing a runnable example which demonstrates your issue
When i try to set value to BufferedImage called dinoImage in Dino.java in a constructor i just get a blank screen every time (second picture) because repaint() is not being called, but if i set it to null it is working just fine but without this image (first picture).
No exceptions, everything seems fine in this code, this problem appears when i try to set value to this field using static method getImage of Resource.java which uses this line of code ImageIO.read(new File(path)) and it causes that repaint() is not being called, i guess this line causes such weird behavior but i dont know how to solve it.
Main.java
public class Main {
public static void main(String[] args) {
GameWindow gameWindow = new GameWindow();
gameWindow.startGame();
}
}
GameWindow.java
public class GameWindow extends JFrame {
private GameScreen gameScreen;
public GameWindow() {
super("Runner");
setSize(1000, 500);
setVisible(true);
setResizable(false);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
gameScreen = new GameScreen();
add(gameScreen);
}
public void startGame() {
gameScreen.startThread();
}
}
GameScreen.java
public class GameScreen extends JPanel implements Runnable, KeyListener {
private Thread thread;
public static final double GRAVITY = 0.1;
public static final int GROUND_Y = 300;
private Dino dino;
public GameScreen() {
thread = new Thread(this);
dino = new Dino();
}
public void startThread() {
thread.start();
}
#Override
public void run() {
while(true) {
try {
Thread.sleep(20);
dino.updatePosition();
repaint();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
// g.clearRect(0, 0, getWidth(), getHeight());
g.setColor(Color.RED);
g.drawLine(0, GROUND_Y, getWidth(), GROUND_Y);
dino.draw(g);
}
#Override
public void keyTyped(KeyEvent e) {
}
#Override
public void keyPressed(KeyEvent e) {
System.out.println("Key Pressed");
dino.jump();
}
#Override
public void keyReleased(KeyEvent e) {
System.out.println("Key Released");
}
}
Dino.java
public class Dino {
private double x = 100;
private double y = 100;
private double speedY = 0;
private BufferedImage dinoImage;
public Dino() {
dinoImage = getImage("data/dino.png");
}
public void updatePosition() {
if(y + speedY >= GROUND_Y - 100) {
speedY = 0;
y = GROUND_Y - 100;
} else {
speedY += GRAVITY;
y += speedY;
}
}
public void jump() {
if(y == GROUND_Y - 100) {
speedY = -5;
y += speedY;
}
}
public void draw(Graphics g) {
g.setColor(Color.BLACK);
g.drawRect((int)x, (int)y, 100, 100);
g.drawImage(dinoImage, (int)x, (int)y, null);
}
}
Resource.java
public class Resource {
public static BufferedImage getImage(String path) {
BufferedImage image = null;
try {
image = ImageIO.read(new File(path));
} catch (IOException e) {
e.printStackTrace();
}
return image;
}
}
setSize(1000, 500);
setVisible(true);
setResizable(false);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
gameScreen = new GameScreen();
add(gameScreen);
Swing components need to be added to the frame BEFORE the frame is made visible. Otherwise the panel has a size of (0, 0) and there is nothing to paint.
The code should be something like:
gameScreen = new GameScreen();
add(gameScreen);
setSize(1000, 500);
setVisible(true);
Why my tick(); method being called, but not my render(); method is the question here.
So, I have a class that holds my updating and my rendering here:
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
public class MapI extends Map {
int players = 8, islands = 8;
private int dimAm, irAm, golAm, emAm;
#Override
public void tick() {
while(irAm < 48) {
tickIr();
}
while(dimAm < 4) {
tickDim();
}
}
public void tickDim() {
try {
Thread.sleep(20000);
} catch(InterruptedException e) {
e.printStackTrace();
}
dimAm += 1;
System.out.println(dimAm + " diamonds");
}
public void tickIr() {
try {
Thread.sleep(2000);
} catch(InterruptedException e) {
e.printStackTrace();
}
irAm += 1;
System.out.println(irAm + " iron");
}
#Override
public void render(Graphics g) {
g.setFont(new Font("Arial", Font.BOLD, 12));
g.setColor(Color.BLACK);
g.fillRect(30, 10, 50, 50); // dim gen(s)
g.drawString(dimAm + "", 41, 29);
g.setColor(Color.CYAN);
g.fillRect(40, 20, 30, 30);
g.setColor(Color.YELLOW);
g.fillRect(30, 100, 50, 50); // yellow base
}
}
Here's the Map class:
import java.awt.Graphics;
public abstract class Map {
protected int players, islands;
public abstract void tick();
public abstract void render(Graphics g);
}
What is happening is, when my run() method in my Game class is called, it has a while(running), and inside that loop is where I specify to render and update:
public void run(){
init();
while(running){
render();
tick();
}
stop();
}
public synchronized void start(){
if(running)
return;
running = true;
thread = new Thread(this);
thread.start();
}
public synchronized void stop(){
if(!running)
return;
running = false;
try {
thread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
With this, I should both render and update, but, as of right now, all that goes on is updates. I think that my problem might come with
#Override
public void tick() {
while(irAm < 48) {
tickIr();
}
while(dimAm < 4) {
tickDim();
}
}
, which is inside of MapI. What I think is happening is nothing else will render until none of these loops are still running, but then again, I don't know how to bypass that.
My GameAspect class that houses the render method is here:
import java.awt.Graphics;
import java.awt.image.BufferStrategy;
import blaze.game.gfx.Assets;
import blaze.game.maps.MapI;
public class GameAspect implements Runnable {
private Display display;
public int width, height;
public String title;
private boolean running = false;
private Thread thread;
private BufferStrategy bs;
private Graphics g;
private MapI map1;
public GameAspect(String title, int width, int height){
this.width = width;
this.height = height;
this.title = title;
map1 = new MapI();
}
private void init(){
display = new Display(title, width, height);
Assets.init();
}
private void tick(){
map1.tick();
}
private void render(){
bs = display.getCanvas().getBufferStrategy();
if(bs == null){
display.getCanvas().createBufferStrategy(3);
return;
}
g = bs.getDrawGraphics();
//Clear Screen
g.clearRect(0, 0, width, height);
//Draw Here!
map1.render(g);
//End Drawing!
bs.show();
g.dispose();
}
public void run(){
init();
while(running){
render();
tick();
}
stop();
}
public synchronized void start(){
if(running)
return;
running = true;
thread = new Thread(this);
thread.start();
}
public synchronized void stop(){
if(!running)
return;
running = false;
try {
thread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
I have tried numerous solutions, and I can't seem to find the issue with my code. I have checked the path names, the permissions for the files, and tried several different file names for the image. The image isn't showing up.
private Character player;
private Image image, sprite;
private URL base;
private Graphics second;
#Override
public void init() {
setSize(500,500);
setBackground(Color.white);
setFocusable(true);
addKeyListener(this);
Frame frame = (Frame)this.getParent().getParent();
frame.setTitle("Joules");
try {
base = getDocumentBase();
sprite = getImage(base,"kips.PNG");
} catch (Exception e) {
}
// sprite = getImage(base,"kips.PNG");
}
#Override
public void start() {
player = new Character();
Thread thread = new Thread(this);
thread.start();
}
#Override
public void update(Graphics g) {
if (image == null) {
image = createImage(this.getWidth(), this.getHeight());
second = image.getGraphics();
}
second.setColor(getBackground());
second.fillRect(0, 0, getWidth(), getHeight());
second.setColor(getForeground());
paint(second);
g.drawImage(image, 0, 0, this);
}
#Override
public void paint(Graphics g) {
g.drawImage(sprite,player.getCenterX(),player.getCenterY(),this);
}
#Override
public void run() {
while (true) {
repaint();
try {
Thread.sleep(34);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
Please help...
I just had this issue and found that getDocumentBase() is returning a huge path which is the base of the current applet, not the project.
Instead, I used getCodeBase() which returns "../projectName/bin/", so navigate back one folder in your relative paths in the code.
base = getCodeBase();
sprite = getImage(base,"../kips.PNG");
I've followed these tutorials and produced the following.
http://www.youtube.com/playlist?list=PL54DB126285ED0420
Main.java:
public class Main extends JFrame {
GamePanel gp;
public Main() {
gp = new GamePanel();
setSize(500, 400);
setVisible(true);
setResizable(false);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
add(gp);
}
public static void main(String[] args) {
Main m = new Main();
}
}
GamePanel.java:
public class GamePanel extends JPanel implements Runnable {
// Double Buffering Variables
private Image dbImage;
private Graphics dbg;
// JPanel Variables
static final int GWIDTH = 500, GHEIGHT = 400;
static final Dimension gameDim = new Dimension(GWIDTH, GHEIGHT);
// Game Variables
private Thread game;
private volatile boolean running = false;
public GamePanel() {
setPreferredSize(gameDim);
setBackground(Color.WHITE);
setFocusable(true);
requestFocus();
// Handle all key inputs from the user
addKeyListener(new KeyAdapter() {
#Override public void keyPressed(KeyEvent e) {}
#Override public void keyReleased(KeyEvent e) {}
#Override public void keyTyped(KeyEvent e) {}
});
}
public void run() {
while (running) {
gameUpdate();
gameRender();
paintScreen();
}
}// END run
private void gameUpdate() {
if (running && game != null) {
// update the game state
}
}
private void gameRender() {
// create the buffer
if (dbImage == null) {
dbImage = createImage(GWIDTH, GHEIGHT);
if (dbImage == null) {
System.err.println("dbImage is still null!!!");
return;
} else {
dbg = dbImage.getGraphics();
}
}
// Clear the screen
dbg.setColor(Color.WHITE);
dbg.fillRect(0, 0, GWIDTH, GHEIGHT);
// Draw the game elements
draw(dbg);
}
// draw all game content
public void draw(Graphics g) {}
private void paintScreen() {
Graphics g;
try {
g = this.getGraphics();
if (dbImage != null && g != null)
g.drawImage(dbImage, 0, 0, null);
// For Linux
Toolkit.getDefaultToolkit().sync();
g.dispose();
} catch (Exception e) {
System.err.println(e);
}
}
public void addNotify() {
super.addNotify();
startGame();
}
private void startGame() {
if (game == null || !running) {
game = new Thread(this);
game.start();
running = true;
}
}
public void stopGame() {
if (running)
running = false;
}
private void log(String s) {
System.out.println(s);
}
}
It should just print a "Hello World" string on the screen but it's not performing. I've gone over the code couple of times but couldn't see what was wrong.
So what's absent that causes it not to display the string.
Thanks.
All right. Finally just found it.
In my Main.java I'd to place the add(gp); code to the top. Because basically it was falling under.
P.S. Just mentioning again. Accidentally I erased the contents of the draw method. Silly of me. Sorry for that. It should've g.drawString("Hello World!", 100, 100); in it.
Thanks.
So what's absent that causes it not to display the string.
For starters, the "Hello World" string itself is absent.
I suggest you go over the tutorials that you referenced again as you appear to be new to Java and require more practice.