Reputation: 349
i am exercising some OOP with java.
I just want to write a game with some graphic objects but i want to structure it with some classes.
The overall layout should look like this:
MainClass -> new MainPanel(extends JPanel)->new StartWindow(extends abstract GameWindow which contains the gameloop)
This way i should be able to create StartWindow, Level1Window, Level2Window and so on. My StartWindow should now Draw the Layout for the first level. The StartWindow will create other objects(Player, Enemy and so on) which will later be responsible for drawing themself.
So i want to create something like "every object is responsible to draw itself"
I hope i could make clear how this should work. Problem is, i cant figure out how to delegate down this task.
My Code looks like this at the moment:
public class MainClass extends JFrame implements ActionListener {
//..... other stuff
public MainClass () {
MainPanel mainPanel = new MainPanel();
}
//.... other stuff
}
class MainPanel extends JPanel {
private GameWindow currentWindow;
public MainPanel () {
currentWindow = new StartWindow(this);
}
public void paintComponent(Graphics g) {
g.drawRect (10, 10, 200, 200); // <-- can see on the window
}
}
abstract class GameWindow {
// contains game loop and update functions and so on
}
public class StartWindow extends GameWindow {
GamePanel _parentWindow;
public StartWindow(GamePanel parentWindow) {
super();
_parentWindow = parentWindow;
}
public void paintComponent(Graphics g) {
//Does not work
g.drawRect (20, 20, 100, 100);
}
}
the "_parentWindow" contains the MainPanel, so i should have all the information that is needed to draw on its Panel, i just cant figure out how to do it.
Edit: Minimum example thats working:
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class MainClass extends JFrame implements ActionListener {
public static void main(String[] args)
{
System.out.println("Program Window1");
MainClass glt = new MainClass();
glt.setVisible(true);
}
//..... other stuff
public MainClass () {
super("Fixed Timestep Game Loop Test");
Container cp = getContentPane();
cp.setLayout(new BorderLayout());
JPanel p = new JPanel();
p.setLayout(new GridLayout(1,2));
System.out.println("Program Window2");
MainPanel gamePanel= new MainPanel();
cp.add(gamePanel, BorderLayout.CENTER);
cp.add(p, BorderLayout.SOUTH);
setSize(500, 500);
}
//.... other stuff
@Override
public void actionPerformed(ActionEvent arg0) {
// TODO Auto-generated method stub
}
}
class MainPanel extends JPanel {
private GameWindow currentWindow;
public MainPanel () {
currentWindow = new StartWindow(this);
}
public void paintComponent(Graphics g) {
g.drawRect (0, 0, 200, 200); // <-- can see on the window
}
}
abstract class GameWindow {
// contains game loop and update functions and so on
}
class StartWindow extends GameWindow {
MainPanel _parentWindow;
public StartWindow(MainPanel parentWindow) {
super();
_parentWindow = parentWindow;
}
public void paintComponent(Graphics g) {
//Does not work
g.drawRect (20, 20, 100, 100);
}
}
Upvotes: 3
Views: 1175
Reputation: 285405
I would draw the sprites in your main drawing JComponent, e.g.,
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class MainClass extends JFrame implements ActionListener {
public static void main(String[] args) {
System.out.println("Program Window1");
MainClass glt = new MainClass();
glt.setVisible(true);
}
// ..... other stuff
public MainClass() {
super("Fixed Timestep Game Loop Test");
setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
Container cp = getContentPane();
cp.setLayout(new BorderLayout());
JPanel p = new JPanel();
p.setLayout(new GridLayout(1, 2));
System.out.println("Program Window2");
MainPanel gamePanel = new MainPanel();
cp.add(gamePanel, BorderLayout.CENTER);
cp.add(p, BorderLayout.SOUTH);
setSize(500, 500);
}
// .... other stuff
@Override
public void actionPerformed(ActionEvent arg0) {
// TODO Auto-generated method stub
}
}
class MainPanel extends JPanel {
private GameWindow currentWindow;
public MainPanel() {
currentWindow = new StartWindow(this);
}
// public void paintComponent(Graphics g) {
// g.drawRect(0, 0, 200, 200); // <-- can see on the window
// }
// this should be protected, not public and should call super method
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawRect(0, 0, 200, 200); // <-- can see on the window
currentWindow.draw(g);
}
}
interface Drawable {
void draw(Graphics g);
}
abstract class GameWindow implements Drawable {
// contains game loop and update functions and so on
}
class StartWindow extends GameWindow {
MainPanel _parentWindow;
public StartWindow(MainPanel parentWindow) {
super();
_parentWindow = parentWindow;
}
@Override
public void draw(Graphics g) {
g.setColor(Color.red);
g.drawRect(20, 20, 100, 100);
}
}
but again, I reiterate that the game loop should not be inherited but rather its reference should be passed. Extension via composition rather than inheritance.
Or perhaps even better, have your model classes implement an interface, something like:
public interface Tickable {
void tick(int deltaTime);
}
Then a collection such as a List<Tickable>
is held by the main model, and every time the game loop ticks, it iterates through the list calling tick(...)
on each item in the List.
Upvotes: 2
Reputation: 66
Try something like this inside the paintComponent method of your MainPanel class.
public void paintComponent(Graphics g) {
g.drawRect (10, 10, 200, 200); // <-- can see on the window
Graphics2D g2d = (Graphics2D) g.create();
((StartWindow) currentWindow).paintComponent(g2d);
g2d.dispose();
}
Upvotes: 2