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.
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);
Im trying to create a game in java.
At the first I've made a Jpanel and made a FPS counter and the background was white.
after that I've tried to made that when you pressing ESCAPE, the Jpanel shutting down and then I've tried to make that when you pressing Space, the Background moving to green but after that, when Im trying to start, the Jpanel moving to grey background and the FPS counter has been disappear.
this is the frame class
public class Frame extends JFrame{
public static void main(String[] args) {
new Frame();
}
public Frame(){
new JFrame();
this.setTitle("Tower Defence - By Sahar Haine");
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
this.setExtendedState(MAXIMIZED_BOTH);
this.setUndecorated(true);
this.setResizable(false);
this.setVisible(true);
Screen screen = new Screen(this);
this.add(screen);
}
this is the screen class:
public class Screen extends JPanel implements Runnable{
Thread thread = new Thread(this);
Frame frame;
private int fps = 0;
public int scene;
public Boolean running = false;
public Screen(Frame frame){
this.frame = frame;
this.frame.addKeyListener(new KeyHandller(this));
thread.start();
}
#Override
public void paintComponent(Graphics g){
g.clearRect(0, 0, this.frame.getWidth(), this.frame.getHeight());
g.drawString(fps + "", 10, 10);
if(scene == 0){
g.setColor(Color.BLUE);
}else{
}
g.setColor(Color.GREEN);
g.fillRect(0, 0, this.frame.getWidth(), this.frame.getHeight());
}
public void run() {
System.out.println("Success");
long lastFrame = System.currentTimeMillis();
int frames = 0;
running = true;
scene = 0;
while(running){
try {
repaint();
frames++;
if(System.currentTimeMillis() - 1000>= lastFrame){
fps = frames;
frames = 0;
lastFrame = System.currentTimeMillis();
}
Thread.sleep(1);
} catch (InterruptedException ex) {
Logger.getLogger(Screen.class.getName()).log(Level.SEVERE, null, ex);
}
}
System.exit(0);
}
public class KeyTyped{
public void keyESC(){
running = false;
}
public void keySPACE() {
scene = 1;
}
and this is the key handler class:
public class KeyHandler implements KeyListener{
private Screen screen;
private Screen.KeyTyped keyTyped;
public KeyHandler(Screen screen){
this.screen = screen;
this.keyTyped = this.screen.new KeyTyped();
}
public void keyTyped(KeyEvent e) {
}
public void keyPressed(KeyEvent e) {
int keyCode = e.getKeyCode();
System.out.println(e.getKeyCode());
if(keyCode == 27){
this.keyTyped.keyESC();
}
if(keyCode == 27){
this.keyTyped.keySPACE();
}
}
public void keyReleased(KeyEvent e) {
}
One issue that jumps out immediately is that you have hard coded "keyCode = 27" for both Escape and Space which is not correct. "27 - Escape" and "32 - Space". Rather than hard code the values, please use KeyEvent.VK_ESCAPE and KeyEvent.VK_SPACE as documented here, KeyEvents
EDIT 1
Also make certain that you draw the string AFTER the "Fill" or else the "Fill" will over paint the FPS string and you will not see it.
I think you have to call
super.paintComponent(g)
as the first line in your paintComponent method override.
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();
I want to, when i click the "d" button, start a timer. This is to animate a player walking. The timer doesn't start when i press the key, how do i do that?
The code I have is this:
public class Game extends JPanel implements KeyListener {
//Player variables
private BufferedImage playerStanding;
private BufferedImage playerWalking;
private BufferedImage playerFrame;
private boolean walking = false;
private final int PLAYER_HEIGHT = 100;
private final int PLAYER_WIDTH = 100;
private final int INITIAL_X = 0;
private final int INITIAL_Y = 500;
private int x = INITIAL_X;
private int y = INITIAL_Y;
//The timer I want to start on keypress-> "d"
private Timer playerAnimationTimer;
public Game() {
setPreferredSize(new Dimension(800, 800));
setBackground(Color.CYAN);
//Player
try {
playerStanding = ImageIO.read(getClass().getResource("player1.gif"));
playerWalking = ImageIO.read(getClass().getResource("player2.gif"));
playerFrame = playerStanding;
}
catch (IOException ex) {
ex.printStackTrace();
}
playerAnimationTimer = new Timer(500, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
walking = !walking;
playerFrame = walking ? playerWalking : playerStanding;
x += 10;
if (x > getWidth() - PLAYER_WIDTH) {
x = INITIAL_X;
}
repaint();
}
});
playerAnimationTimer.setRepeats(true);
}
public Dimension setPreferredSize() {
return new Dimension(800, 800);
}
#Override
public void paintComponent(Graphics graphics) {
super.paintComponent(graphics);
Graphics2D graphics2D = (Graphics2D) graphics;
if (playerFrame != null) {
graphics2D.drawImage(playerFrame, x, y, PLAYER_WIDTH, PLAYER_HEIGHT, this);
}
graphics2D.dispose();
}
#Override
public void keyTyped(KeyEvent e) {
//This doesn't work
playerAnimationTimer.start();
}
#Override
public void keyPressed(KeyEvent e) {
}
#Override
public void keyReleased(KeyEvent e) {
}
}
//The class to hold the gamepanel
public class StartGame extends JFrame implements ActionListener {
private static JButton startGame = new JButton();
StartGame() {
setDefaultCloseOperation(WindowConstants.HIDE_ON_CLOSE);
setSize(200, 100);
setVisible(true);
setBackground(Color.BLUE);
setLocationRelativeTo(null);
startGame.setText("Play!");
startGame.setSize(100, 25);
startGame.addActionListener(this);
add(startGame);
}
#Override
public void actionPerformed(ActionEvent e) {
if (e.getSource() == startGame) {
this.setVisible(false);
new GameWindow();
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new StartGame();
}
});
}
}
How could I make the timer start when I click the "d" button?
Your KeyListener doesn't work because you never add the KeyListener to anything much less to a component that has focus, which is needed for a KeyListener to work.
I suggest that you instead use Key Bindings as a cleaner safer way to capture the desired key press.
As an aside, never dispose of a Graphics object that is given to you from the JVM.
For a better answer, please edit your code to make it comply with the mcve standard. You should use no images files, and it should compile and run for us unaltered.
You could set the private Timer like you did and start it like this...
public void startTimer(){
timer.start();
timer.setRepeats(true);
}