I have a simple game coming along, and am running into a problem with graphics. Before I describe the problem, I will explain the structure of the game.
-There are two timer classes: A logic timer, and a render timer. The reason there are two, is so rendering can be skipped for a few frames, and the logic will still continue (for consistency on slow computers).
-Objects can subscribe to each timer individually using the Observer pattern. An object simply needs to call LogicTimer.add(this); and implement LogicTimerObserver to be updated (similar with the render timer).
-The RenderTimer is a JFrame, and it updates by calling the draw(Graphics g); method on it's subscribers.
-Both timers are singleton objects, allowing them to be easily accessed from anywhere.
Here is the problem: Objects being rendered onto the screen will not be removed at the next frame.
I have had this happen before, and it was a fairly simple fix. But now, I have done everything the same, and problems have arisen.
Here is the RenderTimer class
Code:package timer;
import java.awt.Graphics;
import java.util.ArrayList;
import javax.swing.JPanel;
import player.Player;
import timer.interfaces.observer.RenderTimerObserver;
@SuppressWarnings("serial")
public class RenderTimer extends JPanel implements Timer {
//holds the singleton object
private static RenderTimer ref;
//list of observers
ArrayList<RenderTimerObserver> observers;
private RenderTimer() {
observers = new ArrayList<RenderTimerObserver>();
}
//return the singleton object when requested
public static RenderTimer getRenderTimer() {
if (ref == null)
// it's ok, we can call this constructor
ref = new RenderTimer();
return ref;
}
//called by main timer to render
@Override
public void advance() {
repaint();
}
//called for a repaint. calls each class wanting render updates
@Override
public void paintComponent(Graphics g) {
super.paintComponents(g);
for (RenderTimerObserver o : observers) {
o.draw(g);
}
}
//called by observers to add themselves to the list
public void addObserver(RenderTimerObserver l) {
observers.add(l);
}
//called by observers to remove themselves from the list
public void removeObserver(RenderTimerObserver l) {
observers.remove(l);
}
}
And the main class:
And an example of a class that should be rendered:Code:/*
* Order of operations:
* 1) All regular objects are created. When they request the Timer object, they receive a reference, but the Timer
* object does not initialize, because it's running variable is false;
* 2) The timer's running variable is set to true
* 3) The timer is once again requested to return it's reference, where upon it finally initializes.
*/
package main;
import javax.swing.JFrame;
import player.Player;
import timer.MainTimer;
import timer.RenderTimer;
public class Main {
public static void main(String[] args) {
System.out.println("Game Event: Application started");
initGraphics();
initializeSingletons();
}
private static void initGraphics() {
//init the draw manager
RenderTimer renderTimer;
renderTimer = RenderTimer.getRenderTimer();
//create the JPanel
JFrame f = new JFrame("2D Shooter");
//add the Drawing class to this JPanel
f.add(renderTimer);
//frame properties
f.setSize(1000,800);
f.setVisible(true);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
private static void initializeSingletons() {
//initialize regular objects
Player.getPlayer();
//set Timer's running variable to true
MainTimer.superStart();
//initialize Timer
MainTimer.getTimer();
}
}
I think the problem might be in the Main class, where the JFrame is being initialized. Maybe singletons wont work here?Code:package player;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.geom.AffineTransform;
import entity.Entity;
import timer.LogicTimer;
import timer.RenderTimer;
import timer.interfaces.observer.LogicTimerObserver;
import timer.interfaces.observer.RenderTimerObserver;
public class Player extends Entity implements LogicTimerObserver, RenderTimerObserver{
private static Player instance;
//holds timer instances
LogicTimer logicTimer;
RenderTimer renderTimer;
int goX;
int goY;
private Player()
{
//get instances
logicTimer = LogicTimer.getLogicTimer();
renderTimer = RenderTimer.getRenderTimer();
//subscribe to subjects
logicTimer.addObserver(this);
renderTimer.addObserver(this);
x = 200;
y = 200;
w = 50;
h = 20;
theta = 100;
goX = 2;
goY = 2;
}
public static Player getPlayer()
{
if (instance == null) {
// it's ok, we can call this constructor
instance = new Player();
}
return instance;
}
@Override
public void draw(Graphics g) {
// create a G2D version of g
Graphics2D g2d = (Graphics2D) g;
// antialiasing
g2d.addRenderingHints(new RenderingHints(
RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON));
// save the current transforms
AffineTransform saveXform = g2d.getTransform();
// holds transforms
AffineTransform at = new AffineTransform();
// set transforms here
at.translate(x, y);
at.rotate(theta);
// apply the transforms to the graphics object
g2d.transform(at);
// draw player
g2d.setColor(Color.RED);
g2d.fillRect(0, 0, w, h);
// reset the transforms
g2d.setTransform(saveXform);
}
@Override
public void advanceLogic() {
x += goX;
y += goY;
if (x > 1000 || x < 0) {
goX *= -1;
}
if (y > 800 || y < 0) {
goY *= -1;
}
}
}
Any help would be greatly appreciated.

