All the other questions I found seem to be related to "flicker-free" whereas I actually want a flicker...
I am trying to build a small app that shows objects blinking at a given frequency.
Below is a small workable example of what I am trying to do. Currently I flicker the object via a scheduled Task that is executed with a given frequency. Within this task I paint the object, wait for half the time and then delete it. That should give me a object that is blinking with the given frequency.
However I found that even at frequencies as low as 4Hz the blinking isn't stable anymore. I think this is due to the fact that Java does not guarantee to paint the screen when asked to but that it is allowed to pull certain paint tasks together into one. I am not sure but I think I read something like this.
My question is: How can I make a stably blinking object with frequencies up to the half the screen refreshing rate?
public class NewJFrame extends javax.swing.JFrame {
private final int FlashFreqHz = 4;
private java.util.Timer timer;
/**
* Creates new form NewJFrame
*/
public NewJFrame() {
initComponents();
startFlashing();
}
private class FlashingTask extends TimerTask{
#Override
public void run() {
int w=jPanel1.getWidth();
int h=jPanel1.getHeight();
try {
jPanel1.getGraphics().fillRect(10, 10, w/2, h/2);
Thread.sleep((1000/FlashFreqHz)/2);
jPanel1.getGraphics().clearRect(10, 10, w/2, h/2);
} catch(InterruptedException ex) {
ex.getStackTrace();
}
}
}
public void startFlashing() {
if(timer!=null) stopFlashing(); // running, must stop to get new position correct
timer = new java.util.Timer();
timer.scheduleAtFixedRate(new FlashingTask(), 0, 1000/FlashFreqHz); // 40 ms delay
}
public void stopFlashing() {
if (timer != null) {
timer.cancel();
timer = null;
jPanel1.repaint();
}
}
Just to check, here is my 'corrected' code:
import java.awt.event.ActionEvent;
import javax.swing.Timer;
import java.awt.event.ActionListener;
import javax.swing.JPanel;
import java.awt.Graphics;
public class NewJFrame extends javax.swing.JFrame implements ActionListener{
private final int FlashFreqHz = 60;
private final Timer timer;
private boolean Flash = false;
FlashFrame FlashPanel;
/**
* Creates new form NewJFrame
*/
public NewJFrame() {
initComponents();
FlashPanel = new FlashFrame();
setContentPane(FlashPanel);
timer = new Timer(1000/FlashFreqHz,this);
timer.start();
}
class FlashFrame extends JPanel {
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
if(Flash) {
g.fillRect(10, 10, getWidth()/2, getHeight()/2);
} else {
g.clearRect(10, 10, getWidth()/2, getHeight()/2);
}
}
}
#Override
public void actionPerformed(ActionEvent e) {
FlashPanel.repaint();
Flash = !Flash;
}
Does this look any better to you?
Also the question I began with remains. Although the frequency is much much more stable then with my 'sleep' method there still is some notable instability, especially at higher frequencies.
Is there anything that can be done about that?
Related
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've been taking AP Computer Science this year as a sophomore in high school and we mainly cover material like loops, classes, methods, general CS logic, and some math stuff. I am missing what I really loved about coding in the first place, making games. Now every game I have made had some sort of way to manage it whether it was using timers in visual basic or a XNA plugin for c# that setup a update method for me. The problem is I have not learned how to do this for java in my course. I've read up a little on threads and implements runnable but i'm not really sure where I'm going with it.
Class 1
import java.awt.FlowLayout;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
public class GFXScreen extends JFrame
{
/**
* #param screenHeigth
* #param screenHeigth
* #param The file name of the image. Make sure to include the extension type also
* #param The title at the top of the running screen
* #param The height of the screen
* #param The width of the screen
*/
public GFXScreen(String fileName, String screenTitle, int screenHeight, int screenWidth)
{
setLayout(new FlowLayout());
image1 = new ImageIcon(getClass().getResource(fileName));
label1 = new JLabel(image1);
this.add(label1);
//Set up JFrame
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
this.setVisible(true);
this.setTitle(screenTitle);
this.setSize(screenWidth, screenHeight);
}
/**
* #param desired amount to move picture
*/
public void updatePic(int increment)
{
//update pos
label1.setBounds(label1.bounds().x, label1.bounds().y - increment,
label1.bounds().width, label1.bounds().height);
}
private ImageIcon image1;
private JLabel label1;
}
Class 2
public class MainClass implements Runnable {
public static void main(String[] args)
{
(new Thread(new MainClass())).start();
GFXScreen gfx = new GFXScreen("pixel_man.png", "pixel_Man", 1000, 1000);
}
public void run()
{
gfx.updatePic(1);
}
}
In this instance what I want to happen is, I want a picture that starts in the top to slowly move down smoothly to the bottom. How would i do this?
Suggestions:
Again, a Swing Timer works well for simple Swing animations or simple game loops. It may not be the greatest choice for complex or rigorous tame loops as its timing is not precise.
Most game loops will not be absolutely precise with time slices
And so your game model should take this into consideration and should note absolute time slices and use that information in its physics engine or animation.
If you must use background threading, do take care that most all Swing calls are made on the Swing event thread. To do otherwise will invite pernicious infrequent and difficult to debug program-ending exceptions. For more details on this, please read Concurrency in Swing.
I avoid using null layouts, except when animating components, as this will allow my animation engine to place the component absolutely.
When posting code here for us to test, it's best to avoid code that uses local images. Either have the code use an image easily available to all as a URL or create your own image in your code (see below for a simple example).
Your compiler should be complaining to you about your using deprecated methods, such as bounds(...), and more importantly, you should heed those complaints as they're there for a reason and suggest increased risk and danger if you use them. So don't use those methods, but instead check the Java API for better substitutes.
Just my own personal pet peeve -- please indicate that you've at least read our comments. No one likes putting effort and consideration into trying to help, only to be ignored. I almost didn't post this answer because of this.
For example:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import javax.swing.AbstractAction;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
#SuppressWarnings("serial")
public class GfxPanel extends JPanel {
private static final int BI_WIDTH = 26;
private static final int BI_HEIGHT = BI_WIDTH;
private static final int GAP = 6;
private static final Point INITIAL_LOCATION = new Point(0, 0);
private static final int TIMER_DELAY = 40;
public static final int STEP = 1;
private ImageIcon image1;
private JLabel label1;
private Point labelLocation = INITIAL_LOCATION;
private int prefW;
private int prefH;
private Timer timer;
public GfxPanel(int width, int height) {
// the only time I use null layouts is for component animation.
setLayout(null);
this.prefW = width;
this.prefH = height;
// My program creates its image so you can run it without an image file
image1 = new ImageIcon(createMyImage());
label1 = new JLabel(image1);
label1.setSize(label1.getPreferredSize());
label1.setLocation(labelLocation);
this.add(label1);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(prefW, prefH);
}
public void startAnimation() {
if (timer != null && timer.isRunning()) {
timer.stop();
}
labelLocation = INITIAL_LOCATION;
timer = new Timer(TIMER_DELAY, new TimerListener());
timer.start();
}
// My program creates its image so you can run it without an image file
private Image createMyImage() {
BufferedImage bi = new BufferedImage(BI_WIDTH, BI_HEIGHT,
BufferedImage.TYPE_INT_ARGB);
Graphics2D g2 = bi.createGraphics();
g2.setColor(Color.red);
g2.fillRect(0, 0, BI_WIDTH, BI_HEIGHT);
g2.setColor(Color.blue);
int x = GAP;
int y = x;
int width = BI_WIDTH - 2 * GAP;
int height = BI_HEIGHT - 2 * GAP;
g2.fillRect(x, y, width, height);
g2.dispose();
return bi;
}
private class TimerListener implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
int x = labelLocation.x + STEP;
int y = labelLocation.y + STEP;
labelLocation = new Point(x, y);
label1.setLocation(labelLocation);
repaint();
if (x + BI_WIDTH > getWidth() || y + BI_HEIGHT > getHeight()) {
System.out.println("Stopping Timer");
((Timer) e.getSource()).stop();
}
}
}
private static void createAndShowGui() {
final GfxPanel gfxPanel = new GfxPanel(900, 750);
JButton button = new JButton(new AbstractAction("Animate") {
#Override
public void actionPerformed(ActionEvent arg0) {
gfxPanel.startAnimation();
}
});
JPanel buttonPanel = new JPanel();
buttonPanel.add(button);
JFrame frame = new JFrame("GFXScreen");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.getContentPane().add(gfxPanel);
frame.getContentPane().add(buttonPanel, BorderLayout.PAGE_END);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
What I always use is an infinite loop that calls an update method each iteration, in that method, you would do whatever was required to update the state of the game or render a GUI.
Example
public static void main(String[] args){
// Initialise game
while(true){
updateGame();
}
}
public static void updateGame(){
// Update things here.
}
What I also do ,which is a little more complex, is create and interface called IUpdateListener and have certain classes that are specialised for a certain element of the game. I would example have an InputListener, an AIListener, each handling a certain element of game updating.
public interface IUpdateListener{
public void update();
}
public class Main{
public static ArrayList<IUpdateListener> listeners = new ArrayList<IUpdateListener>();
public static void main(String[] args){
listeners.add(new InputListener());
while(true){
for(IUpdateListener listener : listeners){
listener.update();
}
}
}
}
public class InputListener implements IUpdateListener{
public void update(){
// Handle user input here etc
}
}
I have a simple physics loop that does a calculation for a time interval, waits for the interval to pass, and then renders the results on the screen. It's very simple code (even though the timing is probably wrong, but that's exactly what I'm trying to learn about) and works well when I am moving the mouse around the screen.
package physicssim;
import java.awt.Graphics;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class PhysicsSim extends JFrame {
private static class PhysicsObject {
public PhysicsObject(double x, double y, double v_x, double v_y) {
this.x = x;
this.y = y;
this.v_x = v_x;
this.v_y = v_y;
}
public double x;
public double y;
public double v_x;
public double v_y;
}
PhysicsObject particle;
boolean running = true;
DrawPane drawPane;
public PhysicsSim() {
particle = new PhysicsObject(10,10, .1, .2);
drawPane = new DrawPane(particle);
this.setSize(800,600);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setContentPane(drawPane);
this.setVisible(true);
}
private static class DrawPane extends JPanel {
PhysicsObject p;
public DrawPane(PhysicsObject p) {
this.p = p;
}
#Override
public void paint(Graphics g) {
super.paint(g); //To change body of generated methods, choose Tools | Templates.
g.fillOval((int)p.x, (int) p.y, 10, 10);
}
}
public void start() {
int FPS = 60;
long TIME_BETWEEN_FRAMES_NS = 1000000000/FPS;
// Initial draw
drawPane.repaint();
long lastDrawTime = System.nanoTime();
while(running) {
// Update physics
particle.x+=particle.v_x*(TIME_BETWEEN_FRAMES_NS*.0000001);
particle.y+=particle.v_y*(TIME_BETWEEN_FRAMES_NS*.0000001);
// While there is time until the next draw wait
while(TIME_BETWEEN_FRAMES_NS > (System.nanoTime()-lastDrawTime)) {
try {
Thread.sleep(1);
} catch (InterruptedException ex) {
Logger.getLogger(PhysicsSim.class.getName()).log(Level.SEVERE, null, ex);
}
}
drawPane.repaint();
long currentTime = System.nanoTime();
System.out.println(currentTime - lastDrawTime);
lastDrawTime = currentTime;
}
}
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
PhysicsSim sim = new PhysicsSim();
sim.start();
}
}
The last bit about printing the time difference was just a sanity check to make sure that it was in fact calling around the requested interval. The results are fairly consistent so I don't see why there should be any choppiness.
As I mentioned above, this code works great if I a moving the mouse around the screen, everything is smooth.
If I am not moving the mouse it becomes very choppy until I start moving the mouse over the application.
I assume this is something simple, but I hope that you guys can help me. Thank you.
Alright, it looks like my problem was I was drawing directly to g in paint(). After replacing with the following everything worked correctly.
#Override
public void paint(Graphics g) {
BufferedImage img = new BufferedImage(800, 600, BufferedImage.TYPE_3BYTE_BGR);
img.getGraphics().fillOval((int) p.x, (int) p.y, 10, 10);
g.drawImage(img, 0, 0, null);
}
I was considering deleting this code snippet because it's rough and shameful, but maybe it will help someone else. Happy coding.
I'm making a game with multiple asteroids going down. The goal is to dodge as many asteroids for as long as you can. I made it so that as soon as an asteroid reaches the bottom of the screen it is send back up, now i want to count every time it gets to the bottom and add it to the score.
My problem is that all the asteroids are the same class so if I use:
if(y>700){
y=-50; //
x= (int) (Math.random()*670); // To send the asteroid back up
setLocation(x,y); //
score++; // To add up the score
System.out.println(score); // To print the score
Every asteroid adds op his own amount of times it has reached the bottom, but I want to know how many asteroids have reached the bottom in total. So I figured I have to get the score out of the asteroid class and add it up in an other class but I don't know how.
This is the code of the asteroid class:
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JPanel;
import javax.swing.Timer;
public class Astroid extends JPanel implements ActionListener
{
public int yVelocity = 1;
public int x = (int) (Math.random()*650), y = (int) (Math.random()*-1000);
public Timer timer;
private int score;
public Astroid(int x,int y)
{
this.setLocation(x, y);
this.setSize(25, 25);
this.setBackground(Color.WHITE);
this.setVisible(true);
}
{
this.timer = null;
this.timer = new Timer(10,new ActionListener(){
#Override
public void actionPerformed(ActionEvent arg0)
{
setLocation(x,(y+=yVelocity));
timer.setDelay(10);
repaint();
if(y>700){
y=-50;
x= (int) (Math.random()*670);
setLocation(x,y);
score++;
System.out.println(score);
}
}
});
timer.start();
}
}
This is the code of the class that creates the asteroids:
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.Timer;
import java.util.TimerTask;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class SterTest extends JFrame implements ActionListener
{
public int a;
public SterTest()
{
this.setSize(700, 700);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setLocationRelativeTo(null);
final JPanel p = new JPanel();
p.setBackground(Color.BLACK);
p.setLayout(null);
for(a=0;a<3;a++) {
Astroid astroid = new Astroid(1,1);
p.add(astroid);
} //Creates 3 asteroids to start with
Timer timer = new Timer();
timer.scheduleAtFixedRate(new TimerTask() {
#Override
public void run() {
Astroid astroid2 = new Astroid(1,1);
p.add(astroid2);
a++;
System.out.println("Het aantal asteroids in game is:"+a);
}
}, 5000, 5000); // creates a new asteroid every 5 seconds or so
this.add(p);
this.setVisible(true);
}
Keeping track of the score probably isn't the job of the Asteroid class, so that variable would be best kept in a more central class. Then you can add an instance of the central class to each asteroid, and call a method to increment the score. Something like this:
public class ScoreKeeper {
private AtomicInteger score;
public void incrementScore (int points) {
score.getAndAdd (points);
}
public int getScore () {
return score.get ();
}
}
In you class SterTest you would create a single instance of ScoreKeeper and pass it to each new Astroid instance you create.
public class Astroid {
private ScoreKeeper scoreKeeper;
public Astroid(int x,int y, ScoreKeeper scoreKeeper) {
//... existing code ...
this.scoreKeeper = scoreKeeper;
}
// ... when you want to increment the score, do this:
scoreKeeper.incrementScore (1);
}
Note: There are better and more OO approaches to this. This answer is that fastest route to working code from your current solution.
Declare score as static.
private static int score
This will give you a single copy of that variable.
However
I see you have some threads. In this case you're going to need a little bit of synchronization to keep score consistent.
I recommend adding
private static final Object scoreLock
to your fields. And replace score++ with
synchronized(scoreLock)
{
Asteroid.score++;
}
If you're not interested in keeping score of an individual asteroid than there is no reason to add a score variable to that class. The score should be maintained at a higher level, perhaps in your SterTest() class. When you detect an asteroid has made it to the bottom, just increment that score. I don't want to tell you how to design your program, but the most obvious way would be to just have actionPerformed return the score.
Create an AsteroidListener interface. Maybe like this:
public interface AsteroidListener {
public void impact(Asteroid asteroid);
}
Make your SterTest class implement this interface. Add a new parameter to your Asteroid constructor, for the listener.
public Asteroid(int x, int y, AsteroidListener listener) { }
When you need to call the listener to notify it that there was an impact:
listener.impact(this);
Tally up the score in your SterTest class.
Use the Java Observer/Observable pattern:
public class Score extends Observable {
private AtomicInteger counter = new AtomicInteger();
public void increment() {
setChanged();
notifyObservers(Integer.valueOf(counter.incrementAndGet()));
}
}
This class is added to Astroid :
public Astroid(Score score, int x,int y) {
// ...
#Override
public void actionPerformed(ActionEvent event) {
// ...
score.increment();
}
}
StarTest implements the Observer interface:
public class StarTest implements Observer {
// ...
#Override
public void update(Observable o, Object arg) {
Integer count = (Inter)arg;
// do something with the score
}
}
You connect Observer and Observable as follows:
StarTest starTest = new StarTest();
Score score = new Score();
score.addObserver(starTest);
Astroid astroid = new Astroid(score, x, y);
I was doing a tutorial online because I wanted to make a 2d side scroller, and I got this exact error. I have googled it but came up with nothing. I tried looking for a typo and it looks clean, its not giving me an error anywere else in the code. I do not know where to start. If you could explaing to me what the error is and how i fix it then that would be amazing.
package Main;
import GameState.GameStateManager;
import javax.swing.JPanel;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.image.BufferedImage;
public class GamePanel extends JPanel implements Runnable, KeyListener{
public static final int WIDTH = 320;
public static final int HIGHT = 240;
public static final int SCALE = 2;
//game thread
private Thread thread;
private boolean running;
private int FPS = 60;
private long targetTime = 1000/FPS;
//image
private BufferedImage image;
private Graphics2D g;
//game state manager
private GameStateManager gsm;
public GamePanel(){
super();
setPreferredSize(new Dimension(WIDTH * SCALE, HEIGHT * SCALE));
setFocusable(true);
requestFocus();
}
public void addNotify(){
super.addNotify();
if (thread == null) {
thread = new Thread(this);
addKeyListener(this);
thread.start();
}
}
private void init() {
image = new BufferedImage(WIDTH, HIGHT, BufferedImage.TYPE_INT_RGB);
g = (Graphics2D) image.getGraphics();
running = true;
gsm = new GameStateManager();
}
public void run(){
init();
long start, elapsed, wait;
//game loop
while(running) {
start = System.nanoTime();
update();
draw();
drawToScreen();
elapsed = System.nanoTime() - start;
wait = targetTime - elapsed / 1000000;
try
{
Thread.sleep(wait);
}
catch(Exception e)
{
e.printStackTrace();
}//end of try catch
}
}
private void update()
{
gsm.update();
}
private void draw()
{
gsm.draw(g);
}
private void drawToScreen()
{
Graphics g2 = getGraphics();
g2.drawImage(image, 0, 0, null);
g2.dispose();
}
public void KeyPressed(KeyEvent key)
{
gsm.keyPressed(key.getKeyCode());
}
public void KeyReleased(KeyEvent key)
{
gsm.keyReleased(key.getKeyCode());
}
}
The compiler error message tells you exactly what's wrong: your class implements the KeyListener interface but does not implement all the necessary methods of the interface. Solution: be sure to implement all the necessary methods as per the KeyListener API. Also be sure to use the #Override annotation to make sure that your overrides are correct.
Having said that, I'm going to recommend that you not use KeyListeners for most key board input with Swing applications, that it is a low-level listener and should be avoided in favor of higher level constructs such as key bindings. Also, Swing GUI's should avoid use of update(...) method overrides as that is more of an AWT construct.
Your KeyReleased(KeyEvent key) method must start with small letter 'k' like keyReleased(KeyEvent key). Java is case sensitive.
You may also required to override other methods of KeyListener interface.
Also add #Override annotation (as suggested by #Hovercraft Full Of Eels) to the method when you want to override a super method. That way IDE's will give you hint's while coding.