Hey guys I'm new to Java game programming and I'm working with the Runnable interface right now. For some reason, my run() method never gets called and I'm not sure why. I've tried putting many System.out.println statements in there but they never get printed. Any help would be greatly appreciated!
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Toolkit;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import javax.swing.JPanel;
public class GamePanel extends JPanel implements Runnable
{
private final int WIDTH = 160;
private final int HEIGHT = WIDTH/12 *9;
private final int RATIO = 3;
private Thread animator;
private volatile boolean running;
private volatile boolean gameOver;
private double FPS = 60D;
private double period = 1000/FPS;
private Image dbImage;
private Graphics dbg;
public GamePanel()
{
setPreferredSize(new Dimension(WIDTH *3, HEIGHT*3));
setBackground(Color.WHITE);
setFocusable(true);
requestFocus();
terminate();
}
public void addNotify()
{
super.addNotify();
startGame();
}
public void startGame()
{
System.out.println("Thread started");
animator = new Thread();
animator.start();
}
public void stopGame()
{
System.out.println("Thread stopped");
running = false;
}
public void run()
{
long beforeTime, timeDiff, sleepTime;
beforeTime = System.currentTimeMillis();
System.out.println(beforeTime);
running = true;
while (running)
{
System.out.println("Running");
gameUpdate();
gameRender();
paintScreen();
timeDiff = System.currentTimeMillis() - beforeTime;
sleepTime = (long) period - timeDiff;
if(sleepTime <= 0)
sleepTime = 5;
try
{
Thread.sleep(sleepTime);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
beforeTime = System.currentTimeMillis();
}
System.exit(0);
}
public void gameRender()
{
if (dbImage == null)
{
dbImage = createImage(WIDTH, HEIGHT);
}
else
dbg = dbImage.getGraphics();
dbg.setColor(Color.WHITE);
dbg.fillRect(0, 0, WIDTH, HEIGHT);
}
public void paintComponent(Graphics g)
{
super.paintComponent(g);
g.drawImage(dbImage, 0, 0, null);
}
public void gameUpdate()
{
}
private void paintScreen()
{
Graphics g;
try
{
g = this.getGraphics();
if (g!= null && dbImage!= null)
g.drawImage(dbImage, 0, 0, null);
Toolkit.getDefaultToolkit().sync();
g.dispose();
}
catch (Exception e)
{
System.out.println("Error: " + e.getMessage());
}
}
public void terminate()
{
addKeyListener (new KeyAdapter()
{
public void keyPressed(KeyEvent e)
{
int keyCode = e.getKeyCode();
if (keyCode == KeyEvent.VK_ESCAPE)
{
stopGame();
}
}
});
}
}
import javax.swing.JFrame;
public class GameFrame extends JFrame
{
private final int WIDTH = 160;
private final int HEIGHT = WIDTH/12*9;
private final int RATIO = 3;
public GameFrame()
{
setTitle("User Input Game");
setSize(WIDTH*3,HEIGHT*3);
setLocationRelativeTo(null);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setResizable(false);
GamePanel mainPanel = new GamePanel();
add(mainPanel);
}
}
public class Main
{
public static void main(String[] args)
{
new GameFrame().setVisible(true);
}
}
You need to change your startGame() method:
animator = new Thread(new GamePanel());
You need to pass a Runnable (of which GamePanel is one) into the Thread constructor. The thread then runs the runnable when it starts.
You don't seem to have a main method anywhere. Either in this class or an external class you need a main method that creates an instance of GamePanel and pass it as an argument to a Thread class. Like so:
public class Test
{
public static void main(String[] args)
{
Thread t = new Thread(new GamePanel()).start();
}
}
Related
What I'm trying to do
Making a Pong game where the Y axis gets the value from my cursor according to the application
What did I tried
private void pallet() {
ycur=(int)MouseInfo.getPointerInfo().getLocation().getY();
}
This way I get the Y value according to my monitor instead of the application.
I also tried to use the MouseEvent.getY(), but I get the error when trying to call this method from the main.
private void pallet() {
ycur=(int)MouseInfo.getPointerInfo().getLocation().getY();
}
This is how my code looks like, I think the problem lies in how I'm using my main and methods but I'm not sure.
public class MyFirst extends JPanel {
public int x = 500, y = 300, border = 30;
public boolean goingDown = true;
public int ycur, cursor;
public void moveBall() {
x++;
if (goingDown == true) {
y++;
} else if (goingDown == false) {
y--;
}
if (y == getHeight() - border) {
goingDown = false;
} else if (y == 0) {
goingDown = true;
}
}
#Override
public void paint(Graphics g) {
super.paint(g);
g.fillOval(x, y, 30, 30);
g.fillRect(30, ycur, 15, 100);
}
public static void main(String[] args) throws InterruptedException {
JFrame frame = new JFrame("Pong");
frame.pack();
frame.setSize(1000, 600);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
frame.setLocationRelativeTo(null);
MyFirst game = new MyFirst();
frame.add(game);
while (true) {
game.pallet(e);
game.moveBall();
game.repaint();
Thread.sleep(10);
}
}
public void pallet(MouseEvent e) {
ycur=e.getY();
}
}
Problems with your code:
As already mentioned, you're fighting against Swing's event-driven architecture. Instead of a while true loop, use listeners, including a MouseMotionListener ot track the changes in the mouse location, and an ActionListener tied to a Swing Timer to move the ball.
Avoid using Thread.sleep(...) in Swing GUI's except with great care as this can put the entire application to sleep.
Avoid putting too much logic within the main method. This method should be short, should create the key objects, connect them, set the program in motion and that's it.
Paint with the paintComponent method, not the paint method. It results in smoother animation with its double buffering.
For example:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.*;
#SuppressWarnings("serial")
public class MoveBallTest extends JPanel{
private static final int PREF_W = 1000;
private static final int PREF_H = 600;
private static final int TIMER_DELAY = 12;
private static final int SPRITE_WIDTH = 30;
private static final Color OVAL_SPRITE_COLOR = Color.RED;
private static final Color RECT_SPRITE_COLOR = Color.BLUE;
private static final int DELTAY_Y = 1;
private boolean goingDown = true;
private Timer timer = new Timer(TIMER_DELAY, this::timerActionPerformed);
private int ovalSpriteY;
private int rectSpriteY;
public MoveBallTest() {
timer.start();
MyMouse myMouse = new MyMouse();
addMouseMotionListener(myMouse);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(OVAL_SPRITE_COLOR);
g.fillOval(SPRITE_WIDTH, ovalSpriteY, SPRITE_WIDTH, SPRITE_WIDTH);
g.setColor(RECT_SPRITE_COLOR);
g.fillRect(SPRITE_WIDTH, rectSpriteY, SPRITE_WIDTH / 2, SPRITE_WIDTH * 3);
}
#Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet()) {
return super.getPreferredSize();
}
return new Dimension(PREF_W, PREF_H);
}
public void timerActionPerformed(ActionEvent e) {
if (ovalSpriteY <= 0) {
goingDown = true;
} else if (ovalSpriteY >= getHeight() - SPRITE_WIDTH) {
goingDown = false;
}
ovalSpriteY += goingDown ? DELTAY_Y : -DELTAY_Y;
repaint();
}
private class MyMouse extends MouseAdapter {
#Override
public void mouseMoved(MouseEvent e) {
rectSpriteY = e.getY();
}
}
private static void createAndShowGui() {
JFrame frame = new JFrame("MoveBallTest");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(new MoveBallTest());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createAndShowGui());
}
}
This is my code so far, what I want to do is to add a new Object every time the mouse is moved, but the system is not even accessing the MouseEvent class after hours of thinking, I still am not able to figure the problem. Please Help!!
My main class:
package testing;
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.image.BufferStrategy;
import java.util.Random;
public class Wincall extends Canvas implements Runnable {
public static final int HEIGHT = 640, WIDTH = 1080;
private WinTest w;
private Handler handler;
private ME me = new ME(this);
public Wincall(){
handler = new Handler();
w = new WinTest(WIDTH, HEIGHT, "Test", this);
}
public synchronized void run(){
while(true){
long now = System.currentTimeMillis();
this.tick();
this.render();
long after = System.currentTimeMillis();
int tt = (int) (after-now);
if(tt>5)
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Time Taken in millisecs : " + tt);
}
}
public void tick(){
handler.tick();
}
public void render(){
BufferStrategy bs = this.getBufferStrategy();
if(bs == null)
{
this.createBufferStrategy(3);
return;
}
Graphics g = bs.getDrawGraphics();
//render
g.setColor(Color.BLACK);
g.fillRect(0 ,0 ,WIDTH, HEIGHT);
handler.render(g);
//render end
g.dispose();
bs.show();
}
public void addStuff(){
handler.addObject(new TestGO(me.getX(), me.getY(), 32, 32));
}
public static void main(String[] args){
new Wincall();
}
}
My MouseEvent class:
package testing;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionListener;
public class ME implements MouseMotionListener{
private int mx = 0, my = 0;
private Wincall game;
public ME(Wincall game){
this.game = game;
}
public void mouseDragged(MouseEvent e){}
public void mouseMoved(MouseEvent e) {
game.addStuff();
mx = e.getX();
my = e.getY();
System.out.println(mx);
System.out.println(my);
}
public int getX(){
return mx;
}
public int getY(){
return my;
}
}
My window class:
package testing;
import java.awt.Canvas;
import javax.swing.JFrame;
public class WinTest {
private static final long serialVersionUID = -369751247370351003L;
public WinTest(int h, int w, String title, Wincall game){
JFrame f = new JFrame(title);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setSize(h, w);
f.add(game);
f.setVisible(true);
f.requestFocus();
f.setResizable(false);
f.setFocusable(true);
game.addMouseMotionListener(new ME());
game.run();
}
}
Though its not clear what you are trying to do. But you need to add the MouseMotionListener to canvas not to the JFrame. Since you are adding canvas to the JFrame, it is the canvas which should capture MouseEvents. Hence, your Wintest should probably look like this :
public class WinTest extends Canvas {
private static final long serialVersionUID = -369751247370351003L;
public WinTest(int h, int w, String title, Wincall game, ME me) {
JFrame f = new JFrame(title);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setSize(h, w);
f.add(game);
f.setVisible(true);
f.requestFocus();
f.setResizable(false);
f.setFocusable(true);
// f.addMouseMotionListener(me);
game.addMouseMotionListener(me);
game.run();
}
}
Update :
Wincalll Class:
public class Wincall extends Canvas implements Runnable {
public static final int HEIGHT = 640, WIDTH = 1080;
private WinTest w;
// private Handler handler;
private ME me = new ME(this);
public Wincall() {
// handler = new Handler();
w = new WinTest(WIDTH, HEIGHT, "Test", this, me);
}
public synchronized void run() {
while (true) {
long now = System.currentTimeMillis();
this.tick();
this.render();
long after = System.currentTimeMillis();
int tt = (int) (after - now);
if (tt > 5)
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
// System.out.println("Time Taken in millisecs : " + tt);
}
}
public void tick() {
// handler.tick();
}
public void render() {
BufferStrategy bs = this.getBufferStrategy();
if (bs == null) {
this.createBufferStrategy(3);
return;
}
Graphics g = bs.getDrawGraphics();
// render
g.setColor(Color.BLACK);
g.fillRect(0, 0, WIDTH, HEIGHT);
// handler.render(g);
// render end
g.dispose();
bs.show();
}
public void addStuff() {
System.out.println("addStuff");
// handler.addObject(new TestGO(me.getX(), me.getY(), 32, 32));
}
public static void main(String[] args) {
new Wincall();
}
}
I was looking at some of my old source codes:
Try
addMouseMotionListener(me);
Instead of:
f.addMouseMotionListener(me);
import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class slide extends JFrame
{
ImageIcon[] iconArray = new ImageIcon[25];
int iconIndex = 0;
JLabel label;
JPanel panel;
slide ()
{
panel = new JPanel();
label = new JLabel();
add(panel);
setTitle("Slide Show");
panel.add(label);
for(int i = 0; i < iconArray.length; i++)
{
iconArray[i] = new ImageIcon("C:/SlideShow/slide0.jpg");
}
Timer timer = new Timer(1000, new TimerListener());
timer.start();
}
private class TimerListener implements ActionListener
{
public void actionPerformed(ActionEvent actionEvent)
{
label.setIcon(iconArray[iconIndex]);
iconIndex++ ;
if(iconIndex == 25)
iconIndex = 0;
}
}
public static void main(String[] args)
{
slide frame = new slide();
frame.setDefaultCloseOperation(EXIT_ON_CLOSE);
frame.setVisible(true);
frame.setSize(800, 600);
frame.setLocationRelativeTo(null);
}
}
Any idea how to make a slideshow to show pictures with different > > time intervals? For example 1 sec for the first picture, 200 ms for > > the next, 3 sec for the third and etc. > > > > many thanks for the help!!!
A Swing timer has at most two delays. You can set the initial delay and the interval delay.
A Thread gives you more control over how long you sleep between images.
Here's one way to develop a slide show viewer that allows you to set the delay for each image. I used 3 images from the Internet to test the viewer.
package com.ggl.testing;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.IOException;
import java.net.URL;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class Slideshow implements Runnable {
private JFrame frame;
private SSImage[] imageArray;
private SSShower showImages;
private SSViewer imageViewer;
public Slideshow() {
this.imageArray = new SSImage[3];
Image image0 = null;
Image image1 = null;
Image image2 = null;
try {
image0 = ImageIO.read(new URL(
"http://www.ericofon.com/collection/collection1.jpg"));
image1 = ImageIO
.read(new URL(
"http://magiclinks1.wikispaces.com/file/view"
+ "/collection11_lg.jpg/219833158/collection11_lg.jpg"));
image2 = ImageIO
.read(new URL(
"http://www.pokelol.com/wp-content/uploads/2011/12"
+ "/my_pokemon_collection_by_pa_paiya-d4iiuo5.jpg"));
} catch (IOException e) {
e.printStackTrace();
return;
}
imageArray[0] = new SSImage(image0, 4000L);
imageArray[1] = new SSImage(image1, 2500L);
imageArray[2] = new SSImage(image2, 1500L);
}
#Override
public void run() {
frame = new JFrame("Check Box Test");
frame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
frame.addWindowListener(new WindowAdapter() {
#Override
public void windowClosing(WindowEvent event) {
exitProcedure();
}
});
imageViewer = new SSViewer(700, 700);
frame.add(imageViewer);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
showImages = new SSShower(imageArray, imageViewer);
new Thread(showImages).start();
}
private void exitProcedure() {
showImages.setRunning(false);
frame.dispose();
System.exit(0);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Slideshow());
}
public class SSImage {
private final long delay;
private final Image image;
public SSImage(Image image, long delay) {
this.image = image;
this.delay = delay;
}
public long getDelay() {
return delay;
}
public Image getImage() {
return image;
}
}
public class SSViewer extends JPanel {
private static final long serialVersionUID = -7893539139464582702L;
private Image image;
public SSViewer(int width, int height) {
this.setPreferredSize(new Dimension(width, height));
}
public void setImage(Image image) {
this.image = image;
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(image, (this.getWidth() - image.getWidth(this)) / 2,
(this.getHeight() - image.getHeight(this)) / 2, this);
}
}
public class SSShower implements Runnable {
private int counter;
private volatile boolean running;
private SSViewer ssviewer;
private SSImage[] imageArray;
public SSShower(SSImage[] imageArray, SSViewer ssviewer) {
this.imageArray = imageArray;
this.ssviewer = ssviewer;
this.counter = 0;
this.running = true;
}
#Override
public void run() {
while (running) {
SSImage ssimage = imageArray[counter];
ssviewer.setImage(ssimage.getImage());
repaint();
sleep(ssimage.getDelay());
counter = ++counter % imageArray.length;
}
}
private void repaint() {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
ssviewer.repaint();
}
});
}
private void sleep(long delay) {
try {
Thread.sleep(delay);
} catch (InterruptedException e) {
}
}
public synchronized void setRunning(boolean running) {
this.running = running;
}
}
}
Ok, so I'm new to programming and I'm following a tutorial on Youtube to build my own game. My problem is that my screen doesn't turn red, it just stays gray. I'm sure I did something wrong but there are no errors on eclipse. Here is the code:
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 int width = 300;
public static int height = width / 16 * 9;
public static int scale = 3;
private Thread thread;
private JFrame frame;
private boolean running = false;
public Game() {
Dimension size = new Dimension(width * scale, height * scale);
setPreferredSize(size);
frame = new JFrame();
}
public synchronized void start() {
running = true;
thread = new Thread("Display");
thread.start();
}
public synchronized void stop() {
running = false;
try {
thread.join();
} catch(InterruptedException e) {
e.printStackTrace();
}
}
public void run() {
while (running) {
update();
render();
}
}
public void update() {
}
public void render() {
BufferStrategy bs = getBufferStrategy();
if (bs == null) {
createBufferStrategy(3);
return;
}
Graphics g = bs.getDrawGraphics();
g.setColor(Color.RED);
g.fillRect(0, 0, getWidth(), getHeight());
g.dispose();
bs.show();
}
public static void main(String[] args){
Game game = new Game();
game.frame.setResizable(false);
game.frame.setTitle("JJF");
game.frame.add(game);
game.frame.pack();
game.frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
game.frame.setLocationRelativeTo(null);
game.frame.setVisible(true);
game.start();
}
}
You never actually provide the Thread with something to run...
public synchronized void start() {
running = true;
// Not the reference to this...
thread = new Thread(this, "Display");
thread.start();
}
By passing this (which is an instance of your Game class which implements Runnable), the Thread will be able to call your run method
nb:
The size of your viewable area should be defined by the component, not the frame. This can be achieved by overriding the getPreferredSize method and returning the preferred viewable size you want the component to be. Otherwise, the viewable area will be the size of the frame minus it's decoration insets, which may not meet your expectations.
In your "game-loop" you should consider having a small delay between cycles to give time for the system to actually update the screen, this takes some of the pressure of the Thread
Runnable example
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.image.BufferStrategy;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JFrame;
public class Game extends Canvas implements Runnable {
private static final long serialVersionUID = 1L;
public static int width = 300;
public static int height = width / 16 * 9;
public static int scale = 3;
private Thread thread;
private JFrame frame;
private boolean running = false;
public Game() {
Dimension size = new Dimension(width * scale, height * scale);
setPreferredSize(size);
frame = new JFrame();
}
public synchronized void start() {
running = true;
thread = new Thread(this, "Display");
thread.start();
}
public synchronized void stop() {
running = false;
try {
thread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public void run() {
while (running) {
update();
render();
// try {
// Thread.sleep(40);
// } catch (InterruptedException ex) {
// }
}
}
public void update() {
}
public void render() {
BufferStrategy bs = getBufferStrategy();
if (bs == null) {
createBufferStrategy(3);
return;
}
Graphics g = bs.getDrawGraphics();
g.setColor(Color.RED);
g.fillRect(0, 0, getWidth(), getHeight());
g.dispose();
bs.show();
}
public static void main(String[] args) {
Game game = new Game();
game.frame.setResizable(false);
game.frame.setTitle("JJF");
game.frame.add(game);
game.frame.pack();
game.frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
game.frame.setLocationRelativeTo(null);
game.frame.setVisible(true);
game.start();
}
}
Why am I getting a Blank screen instead of Black when I debug or run?? I've looked everywhere and tried a lot! Please help. I'm just trying to make my screen black as I am a beginner to all of this java coding. I don't believe anything is wrong with the code as I'm not getting any errors. I'm using eclipse.
package com.techon.rain;
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 int width =300;
public static int height = width / 16 * 9;
public static int scale =3;
private JFrame frame;
private Thread thread;
private boolean running = false;
public Game() {
Dimension size = new Dimension(width*scale, height*scale);
setPreferredSize(size);
frame = new JFrame();
}
public synchronized void start() {
running = true;
thread = new Thread(this, "Display");
thread.start();
}
public synchronized void stop() {
running = false;
try {
thread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public void run() {
while(running);{
update();
render();
}
}
public void update() {
}
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.dispose();
bs.show();
}
public static void main(String[] args) {
Game game = new Game();
game.frame.setResizable(false);
game.frame.setTitle("Rain");
game.frame.add(game);
game.frame.pack();
game.frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
game.frame.setLocationRelativeTo(null);
game.frame.setVisible(true);
game.start();
}
}
replace
public void run() {
while(running);{
update();
render();
}
by
public void run() {
while(running){
update();
render();
}
due to while(running); it is not executing other stetement inside loop.