I'm new to Java and OOP programming in general so if you guys could give me dumbed down explanation I would appreciate it. I don't really understand how the Graphics object and paintComponent work in general.
The basic idea of the Simulation class is that it will do the following.
1) Create a JFrame for my animation to take place in.
2) Create a Panel (I tried using a Canvas but people told me not to do that) which fits inside my JFrame, the animation will we painted to this panel.
3) Depending on the value of 'type' (and maybe some other conditions which I have not yet coded) it will set up and paint (to the Panel) the background picture (the graphics) for the corresponding Animation.
4) After painting the background image I wan't to be able to return it to Simulation class and modify it (the background Image) in a Loop with my Simulation running on a thread (therefore creating an animation).
5) After the animation is finished I want the Simulation JFrame to close (I'm not even close to getting to this part though).
Everything I see on here just tells me to create the class InitSimGraphics and have paintComponent method within it. I want to be able to paint my lines/rectangles ect.. onto the Panel and then go on to use it again where I can modify parts of it (aka make a particle move through the screen).
What I am doing right now is clearly not working and I am really really new to this so please try to go easy on me. A different approach is probably best I think since this isn't working.
Thanks!
package comp4Pack;
import javax.swing.*;
import java.awt.*;
public class Simulation implements Runnable {
private final int pwidth = 768, pheight = 432;
private int type;
private JFrame frame;
private JPanel panel;
private boolean running = false;
private Thread thread;
/* Type means the following
*
* 0 - Kinematics
* 1 - Dynamics (Momentum)
* 2 - Vectors
* 3 - ...
*
*/
public Simulation(int type){
this.type = type;
initSimulation();
InitSimGraphics i = new InitSimGraphics();
panel.add(i);
}
private void initSimulation(){
if(type == 0){
frame = new JFrame("Kinematics Simulation");
} else if(type == 1){
frame = new JFrame("Dynamics Simulation");
} else {
frame = new JFrame("Vectors Simulation");
}
frame.setSize(pwidth, pheight);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setResizable(false);
frame.setLocationRelativeTo(null);
panel = new JPanel(new BorderLayout());
panel.setPreferredSize(new Dimension(pwidth, pheight));
panel.setMaximumSize(new Dimension(pwidth, pheight));
panel.setMinimumSize(new Dimension(pwidth, pheight));
frame.add(panel);
frame.pack();
frame.setVisible(true);
}
private void initGraphics(){
}
public void run() {
while(running){
tick();
render();
}
stop();
}
private void tick(){
}
private void render(){
}
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();
}
}
}
..
package comp4Pack;
import javax.swing.*;
import java.awt.*;
public class InitSimGraphics extends JPanel {
Graphics g;
private final int pwidth = 768, pheight = 432;
public void paintComponent(Graphics g){
super.paintComponent(g);
g.drawLine(0, 0, pwidth, pheight);
this.g = g;
}
public Graphics getGraphics(){
return g;
}
}
Related
I'm trying to write a simple program: a bouncing ball that appears and starts bouncing after you press the "Start" button on the screen. The program should be closed by pressing "X".
For some reason, it runs very slowly. The ball is blinking, and I have to wait for a long time after I press the "X" for program to close.
Here is the code:
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.*;
import java.util.*;
import javax.swing.*;
public class Bounce
{
public static void main(String[] args)
{
JFrame frame = new BounceFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.show();
}
}
class BounceFrame extends JFrame
{
public BounceFrame()
{
setSize(WIDTH, HEIGHT);
setTitle("Bounce");
Container contentPane = getContentPane();
canvas = new BallCanvas();
contentPane.add(canvas, BorderLayout.CENTER);
JPanel buttonPanel = new JPanel();
addButton(buttonPanel, "Start", new ActionListener()
{
public void actionPerformed(ActionEvent evt)
{
addBall();
}
});
contentPane.add(buttonPanel, BorderLayout.SOUTH);
}
public void addButton(Container c, String title, ActionListener listener)
{
JButton button = new JButton(title);
c.add(button);
button.addActionListener(listener);
}
public void addBall()
{
try
{
Ball b = new Ball(canvas);
canvas.add(b);
for (int i = 1; i <= 10000; i++)
{
b.move();
Thread.sleep(10);
}
}
catch (InterruptedException exception)
{
}
}
private BallCanvas canvas;
public static final int WIDTH = 300;
public static final int HEIGHT = 200;
}
class BallCanvas extends JPanel
{
public void add(Ball b)
{
balls.add(b);
}
public void paintComponent(Graphics g)
{
super.paintComponent(g);
Graphics2D g2 = (Graphics2D)g;
for (int i = 0; i < balls.size(); i++)
{
Ball b = (Ball)balls.get(i);
b.draw(g2);
}
}
private ArrayList balls = new ArrayList();
}
class Ball
{
public Ball(Component c) { canvas = c; }
public void draw(Graphics2D g2)
{
g2.fill(new Ellipse2D.Double(x, y, XSIZE, YSIZE));
}
public void move()
{
x += dx;
y += dy;
if (x < 0)
{
x = 0;
dx = -dx;
}
if (x + XSIZE >= canvas.getWidth())
{
x = canvas.getWidth() - XSIZE;
dx = -dx;
}
if (y < 0)
{
y = 0;
dy = -dy;
}
if (y + YSIZE >= canvas.getHeight())
{
y = canvas.getHeight() - YSIZE;
dy = -dy;
}
canvas.paint(canvas.getGraphics());
}
private Component canvas;
private static final int XSIZE = 15;
private static final int YSIZE = 15;
private int x = 0;
private int y = 0;
private int dx = 2;
private int dy = 2;
}
The slowness comes from two related problems, one simple and one more complex.
Problem #1: paint vs. repaint
From the
JComponent.paint docs:
Invoked by Swing to draw components.
Applications should not invoke paint directly, but should instead use the repaint method to schedule the component for redrawing.
So the canvas.paint() line at the end of Ball.move must go.
You want to call
Component.repaint
instead...
but just replacing the paint with repaint will reveal the second problem, which prevents the ball from even appearing.
Problem #2: Animating inside the ActionListener
The ideal ActionListener.actionPerformed method changes the program's state and returns as soon as possible, using lazy methods like repaint to let Swing schedule the actual work for whenever it's most convenient.
In contrast, your program does basically everything inside the actionPerformed method, including all the animation.
Solution: A Game Loop
A much more typical structure is to start a
javax.swing.Timer
when your GUI starts, and just let it run
"forever",
updating your simulation's state every tick of the clock.
public BounceFrame()
{
// Original code here.
// Then add:
new javax.swing.Timer(
10, // Your timeout from `addBall`.
new ActionListener()
{
public void actionPerformed(final ActionEvent ae)
{
canvas.moveBalls(); // See below for this method.
}
}
).start();
}
In your case, the most important
(and completely missing)
state is the
"Have we started yet?"
bit, which can be stored as a boolean in BallCanvas.
That's the class that should do all the animating, since it also owns the canvas and all the balls.
BallCanvas gains one field, isRunning:
private boolean isRunning = false; // new field
// Added generic type to `balls` --- see below.
private java.util.List<Ball> balls = new ArrayList<Ball>();
...and a setter method:
public void setRunning(boolean state)
{
this.isRunning = state;
}
Finally, BallCanvas.moveBalls is the new
"update all the things"
method called by the Timer:
public void moveBalls()
{
if (! this.isRunning)
{
return;
}
for (final Ball b : balls)
{
// Remember, `move` no longer calls `paint`... It just
// updates some numbers.
b.move();
}
// Now that the visible state has changed, ask Swing to
// schedule repainting the panel.
repaint();
}
(Note how much simpler iterating over the balls list is now that the list has a proper generic type.
The loop in paintComponent could be made just as straightforward.)
Now the BounceFrame.addBall method is easy:
public void addBall()
{
Ball b = new Ball(canvas);
canvas.add(b);
this.canvas.setRunning(true);
}
With this setup, each press of the space bar adds another ball to the simulation.
I was able to get over 100 balls bouncing around on my 2006 desktop without a hint of flicker.
Also, I could exit the application using the 'X' button or Alt-F4, neither of which responded in the original version.
If you find yourself needing more performance
(or if you just want a better understanding of how Swing painting works),
see
"Painting in AWT and Swing:
Good Painting Code Is the Key to App Performance"
by Amy Fowler.
I would suggest you to use 'Timer' class for running your gameloop.It runs infinitely and you can stop it whenever you want using timer.stop()
You can also set its speed accordingly.
I testing to implement graphics into MVC structure but Im a bit stuck. Here is what I got so far. For now I just want to get the red ball to bounce back and forth. And use the button start to start the thread and button stop to stop the thread that runs the GameLoop in the controller.
But I think Im mixing this up a bit. Would very much appreciate some feedback!
Heres what I got so far:
GameModell
suppose to controll the bouncing. If the location of the ball is under 40 px or above 80 px - multiply the locationX with -1 to make the ball change direction
GameView
Here Im putting the labels on a JFrame. I also want to display the buttons start and stop to controll the thread but I guess they are hidden by the JPanel in TheGraphics class
GameController
Starts and stops the thread with ActionListeners. Contains the GameLoop
TheGraphics
Paints the ball and controll the direction
I guess I got a lot of thing that are all wrong but this is the best I can do at the moment. Would very much apreciate some help!
Thanks!
MAIN:
public class MVCgame {
public static void main(String[] args) {
GameModel gm = new GameModel();
GameView gv = new GameView();
GameController gc = new GameController(gm, gv);
}
}
MODEL:
public class GameModel {
private int multi = 1;
public void setMulti(int locX) {
if(locX < 40 || locX > 80) {
multi = multi * -1;
}
}
public int multi() {
return multi;
}
}
VIEW:
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class GameView extends JFrame {
private JPanel jp = new JPanel();
private JButton start = new JButton("Start");
private JButton stop = new JButton("Stop");
TheGraphics gr = new TheGraphics();
public GameView() {
add(jp);
add(gr);
jp.add(start);
jp.add(stop);
setSize(250, 250);
setVisible(true);
}
public void addListener(ActionListener theListener) {
start.addActionListener(theListener);
stop.addActionListener(theListener);
}
public JButton getStart() {
return start;
}
public JButton getStop() {
return stop;
}
// GUESS I SHOULD PUT THIS IN THE VIEW???
public void paintEllipse(Graphics theG) {
Graphics2D g2d = (Graphics2D) theG;
g2d.setColor(new Color(255, 0, 0));
g2d.fillOval(0, 0, 10, 10);
}
}
CONTROLLER:
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class GameController implements Runnable {
GameView gv;
GameModel gm;
private Thread thread;
private boolean running = false;
public GameController(GameModel gm, GameView gv) {
this.gv = gv;
this.gm = gm;
gv.addListener(theListener);
start();
}
ActionListener theListener = new ActionListener() {
public void actionPerformed(ActionEvent e) {
if (e.getSource() == gv.getStart()) {
start();
System.out.println("PLAY = ");
} else if (e.getSource() == gv.getStop()) {
stop();
System.out.println("STOP = ");
}
}
};
public synchronized void start() {
thread = new Thread(this);
thread.start();
running = true;
}
public synchronized void stop() {
thread.interrupt();
running = false;
}
// GameLoop
public void run() {
long lastTime = System.nanoTime();
double amountOfTicks = 60.0;
double ns = 1000000000 / amountOfTicks;
double delta = 0;
long timer = System.currentTimeMillis();
int frames = 0;
while (running) {
long now = System.nanoTime();
delta += (now - lastTime) / ns;
lastTime = now;
while (delta >= 10) {
// tick();
delta--;
// repainting the graphics
gv.gr.drawer();
gm.setMulti(gv.gr.drawer());
System.out.println("gv.gr.drawer() = " + gv.gr.drawer() + " gm.multi() " + gm.multi());
// I want to use this value in the model to change the direction
}
if (running) {
}
frames++;
if (System.currentTimeMillis() - timer > 1000) {
timer += 1000;
System.out.println("FPS: " + frames);
frames = 0;
}
}
}
}
THE GRAPHICS:
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import javax.swing.JPanel;
public class TheGraphics extends JPanel {
private int locX = 40;
public TheGraphics() {
}
public int drawer() {
locX++;
repaint();
return locX;
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
g2d.setColor(new Color(255, 0, 0));
g2d.fillOval(locX, 30, 10, 10);
}
}
GameModell suppose to controll the bouncing. If the location of the ball is under 40 px or above 80 px - multiply the locationX with -1 to make the ball change direction
public void setMulti(int locX) {
if(locX < 40 || locX > 80) {
multi = multi * -1;
}
}
Really bad idea. You should always check position and direction (sign(speed)). Otherwise, your object might get stuck out of bounds always changing direction without moving from place forever.
Apart from this, using the MVC concept is overkill in my eyes and shouldn't be used in such a small project nor in a game. In a game, you should more or less put all three together. Of course you can, but the advantages and disadvantages of the MVC concept don't fit the needs of a game in many ways (except for the GUI, perhaps).
Your main loop might look something like this (you kind of did this already, but why is the tick() commented out in your code?):
while (running) {
update(); // Update all game objects
paint(); // Paint them all
}
Each game object will have its own update() and paint() implementation. You absolutely need to separate the logic of update and paint, even if they are in the same class. So this one:
public int drawer() {
locX++;
repaint();
return locX;
}
is an absolute no-go.
Edit: (Referring your update answer)
You are using the method location() for different purposes. According to the Java name convention, you should rename it getLocation() and setLocation() depending on the use to clarify the code.
(Even if this is not really MVC anymore, I'd let GameFrame implement ActionListener instead of specifying it as variable of GameController.)
One thing you should really change is this one:
private int locX = 0;
public void location(int loc) {
this.locX = (int) loc;
}
Basically, you are duplicating the location value every frame and create unused redundant data. Another problem is, that this might work fine for only one variable, but what if you add more than the position to your model later on? Instead TheGraphics has to render on an instance of the data model, not its values. As long you are using one GameModel
private GameModel model; // set value once at initialisation
and rendering its values in paintComponent will work fine, but if you want to add more than one GameModel (handling GameModel more like a GameObjectModel), you will need to pass it as parameter in the paint method.
public void update() {
repaint();
}
Remove it and try getting around without. A method called from one place forwarding to a different method is a bad idea most of the time, especially if it obfuscates the functionality with a different name.
gv.gr.update();
gv.gr.location(gm.location());
You are first repainting your image and then setting the location? Basically, your game runs one frame behind all the time. Swap that order.
gv.gr.location(gm.location());
gv.gr.repaint();
Will be fine (I already said about location()).
I am making a simple game project and I am having a problem when trying to create a rectangle that moves across the screen.
Here is the main class:
`public class Main extends Canvas implements Runnable {
private static final long serialVersionUID = 1L;
private JFrame frame;
boolean running = false;
Graphics g;
static int HEIGHT = 500;
static int WIDTH = HEIGHT * 16 / 9;
SoundHandler sh = new SoundHandler();
//Game state manager
private GameStateManager gsm;
public Main()
{
//window
frame = new JFrame("Game");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(this, BorderLayout.CENTER);
frame.pack();
frame.setSize(WIDTH, HEIGHT);
frame.setResizable(false);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
init();
}
void init()
{
gsm = new GameStateManager();
sh.playMusic("Undertale.wav", 1);
}
public synchronized void start(){
running = true;
new Thread(this).start();
}
public synchronized void stop(){
running = false;
}
//game loop
public void run()
{
//init time loop variables
long lastLoopTime = System.nanoTime();
final int TARGET_FPS = 60;
final long OPTIMAL_TIME = 1000000000 / TARGET_FPS;
double lastFpsTime = 0;
int fps = 0;
while(running)
{
//work out how long its been since last update
//will be used to calculate how entities should
//move this loop
long now = System.nanoTime();
long updateLength = now - lastLoopTime;
lastLoopTime = now;
double delta = updateLength / ((double)OPTIMAL_TIME);
//update frame counter
lastFpsTime += updateLength;
fps++;
//update FPS counter
if(lastFpsTime >= 1000000000)
{
System.out.println("FPS " + fps);
lastFpsTime = 0;
fps = 0;
}
//game updates
update(delta);
//draw
draw(g);
try{
Thread.sleep((lastLoopTime - System.nanoTime() + OPTIMAL_TIME)/1000000 );
}catch(InterruptedException e){
System.out.println("Error in sleep");
}
}
}
private void update(double delta)
{
//updates game state code
gsm.update(delta);
}
public void draw(Graphics g)
{
gsm.draw(g);
}`
here is the class I want to draw the rectangle with
package me.mangodragon.gamestate;
import java.awt.Graphics;
public class MainState extends GameState{
int x;
public MainState(GameStateManager gsm){
this.gsm = gsm;
}
public void init() {
}
public void update(double delta) {
x += 2 * delta;
}
public void draw(Graphics g) {
g.drawRect(x, 0, 50, 50);
g.dispose();
}
public void keyPressed(int k) {
}
public void keyReleased(int k) {
}
}
I keep getting this error:
Exception in thread "Thread-4" java.lang.NullPointerException
at me.mangodragon.gamestate.MainState.draw(MainState.java:22)
at me.mangodragon.gamestate.GameStateManager.draw(GameStateManager.java:37)
at me.mangodragon.main.Main.draw(Main.java:118)
at me.mangodragon.main.Main.run(Main.java:100)
at java.lang.Thread.run(Unknown Source)
I tried to fix it, but I could not locate the problem.
Thanks!
You never assign anything to g (Graphics). Now, before you run off and try and figure out how you might do that, I'd highly, highly recommend you get rid of this variable, it's going to cause you too many issues.
Normally, when the system wants your component to painted, it calls your paint method and passes you the Graphics context which it wants you to paint to. This approach is known as passive painting, as the paint requests come at random times, which isn't really what you want. Another issue is java.awt.Canvas isn't double buffered, which will cause flickering to occur as your component is updated.
You might want to take a look at Painting in AWT and Swing and Performing Custom Painting for more details
You could use a JPanel instead, which is double buffered, but the main reason for using java.awt.Canvas is so you can make use the BufferStrategy API. This not only provides double buffering, but also provides you with a means by which you can take direct control over the painting process (or active painting).
See BufferStrategy and BufferStrategy and BufferCapabilities for more details
You defined g as such:
Graphics g;
But never gave it a value.
This is not how you should be drawing shapes, anyways. Instead, override the paint method (inherited from Canvas) in class Main:
#Override
public void paint(Graphics2D g) {
//Drawing code goes in here. This runs whenever the Canvas is rendered.
}
Then, when you want to update it, such as in your while loop, run
this.repaint(); //note that this doesn't take arguments
If you want to use the draw(Graphics g) method in the other class, call it in paint().
public void paint(Graphics2D g) {
gsm.draw(g);
}
The problem is that you have not defined g, so it is null. And for the most part, you are never supposed to create a new Graphics object, but instead get it from somewhere.
Since you are inheriting a Canvas, this can be very easily done.
First, you should change your draw method to be like this.
private void draw() {
BufferStrategy bs = this.getBufferStrategy();
if (bs == null) {
this.createBufferStrategy(3);
return;
}
Graphics g = bs.getDrawGraphics();
// Draw your game here, using the g declared above
g.dispose();
bs.show();
}
The first few lines create something called a BufferStrategy which you can read more about here but it essentially lets Java render the next couple frames ahead of schedule so that you don't see any flickering.
From the BufferStrategy, you can get the Graphics object to draw on.
And, finally, you have to dispose of the Graphics object, and then show the Buffer so that everything you did shows on the screen.
I'm brand new to Java and have only recently learnt about object oriented programming. I'm trying to create a program which can run a simulation, the general idea is that I want a part of the screen dedicated to buttons/sliders and another part to be dedicated the the Canvas running the simulation. For now I'm not worried about the simulation itself, I'm just trying to get some graphics on the canvas (which is smaller than the JFrame).
Here is my code (I'll try to leave some explanation below it)
public class Launcher {
public static void main(String[] args){
Display display = new Display();
}
}
.
import java.awt.*;
import javax.swing.*;
public class Display {
public final int width = 1280, height = 720;
public final int cwidth = 894, cheight = 504;
public final String title = "Mechancis Simulator";
private JFrame frame;
//private JPanel panel;
private Canvas canvas;
private Simulation simulation;
public Display(){
initDisplay();
simulation = new Simulation();
}
private void initDisplay(){
frame = new JFrame(title);
frame.setSize(width, height);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setResizable(false);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
/*panel = new JPanel();
panel.setSize(width, height);
panel.setLocation(0,0); */
canvas = new Canvas();
canvas.setPreferredSize(new Dimension(cwidth, cheight));
canvas.setMaximumSize(new Dimension(cwidth, cheight));
canvas.setMinimumSize(new Dimension(cwidth, cheight));
canvas.setLocation(width - (cwidth +15), 15);
//panel.add(canvas);
frame.add(canvas);
/* Add code for buttons/sliders/boxes here */
/* Add these to panel */
}
public JFrame getFrame(){
return frame;
}
public Canvas getCanvas(){
return canvas;
}
}
.
import java.awt.Graphics;
import java.awt.image.BufferStrategy;
import java.awt.*;
import javax.swing.*;
public class Simulation extends Display implements Runnable {
private boolean running = false;
private Thread thread;
private BufferStrategy bs;
private Graphics g;
public Simulation(){
}
private void init(){
}
private void tick(){
}
private void render(){
bs = getCanvas().getBufferStrategy();
if(bs == null){
getCanvas().createBufferStrategy(3);
return;
}
g = bs.getDrawGraphics();
//Draw Here!
//End Drawing!
bs.show();
g.dispose();
}
public void run(){
init();
while(running){
tick();
render();
}
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();
}
}
}
When I run the program the window starts going crazy. I'm quite new to classes and threading so maybe that is the problem. I just want to be able to run the simulation after setting up Frame and Canvas in the Display object.
Thanks.
What you're doing basically is this:
class Display {
private final Simulation sim;
public Display() { sim = new Simulation(); }
}
class Simulation extends Display {
public Simulation() { }
}
when you create a new Display the constructor creates a new Simulation which is a Display which creates a new Simulation which is a Display which creates a new Simulation which is a Display which creates a new Simulation...*
So don't. There's no reason for your Simulation to be a display and to own another Simulation. If you want all the control in Display define a constructor that takes as an argument the Simulation it's displaying and give it a simulation when you create it:
class Display {
private final Simulation sim;
public Display(Simulation sim) { this.sim = sim; }
}
class Simulation {
}
...
Display display = new Display(new Simulation());
*I suggest you google for a tutorial on inheritance, if you wish to know more. Here's the tutorial from oracle to get you started: "You can write a subclass constructor that invokes the constructor of the superclass, either implicitly or by using the keyword super." In your code example the constructor super() is invoked implicitly.
I am very new to java. Very. Like I basically started today. I have previous programming knowledge in other languages, like c, c++, PHP, javascript, etc, but I can't figure this one out. I started watching tutorials on Youtube about how to make a video game in Java(videos from theChernoProject), but about 7 episodes in, I came across a problem, where we have our window, and we paint a black rectangle across the whole thing, and the application freezes my whole computer. Here is my code:
package com.darksun.theonetruemike.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 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();
}
}
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();
}
}
I'm using eclipse to make this project(highly against my will), and when I press the Debug button, the window appears, and my computer freezes, resulting in having to force quit the entire computer. Please help if you can, and thanks for help ahead of time!
since i have low reputation, i will post my comment as answer, try not to -rep
i copied your code to netbeans, a black console like window appears, nothing happens, but it doesnt freeze, but the JVM is using about 50% of cpu