3
\$\begingroup\$

I've been out of working in Java for quite some time now (almost two years), so I've been working on a fun side project just to get back into the swing of things.

Essentially, in the long term, the goal of this will to be to compile a library that can be used in to create basic platform-like 2D games.

I'm never dealt with the development of engines themselves, so I was wondering if I could get some feedback on how the engine itself actually runs. I'm also just looking for overall input - is this a well-written Java library so far?

package io.code.gm;

import java.awt.BorderLayout;
import java.awt.Canvas;
import java.awt.image.BufferedImage;
import java.awt.image.DataBufferInt;

import javax.swing.JFrame;

import io.code.gm.Input.GMInputHandler;

public abstract class GMEngine extends Canvas implements Runnable {

    private static final long serialVersionUID = 1L;

    public GMInputHandler inputHandler;

    private boolean executionStatus = false;

    private JFrame frame;
    private BufferedImage image;
    private int[] pixels;

    private int updateCount = 0;
    private int frameCount = 0;

    private int updates = 0;
    private int frames = 0;

    abstract void init();
    abstract void update();
    abstract void render();

    public GMEngine(String title, int width, int height) {
        super();

        this.frame = new JFrame(title);

        frame.setResizable(false);
        frame.setSize(width, height);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setLocationRelativeTo(null);

        frame.setLayout(new BorderLayout());
        frame.add(this, BorderLayout.CENTER);

        frame.setVisible(true);

        this.image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        this.pixels = ((DataBufferInt) image.getRaster().getDataBuffer()).getData();

        init();
    }

    public synchronized void start() {
        this.executionStatus = true;
        new Thread(this).start();
        init();
    }

    public synchronized void stop() {
        this.executionStatus = false;
    }

    /**
     * Implemented method run().
     */
    public void run() {
        long lastUpdate = System.nanoTime();
        double nanoPerUpdate = 1000000000D/60D;

        int updates = 0;
        int frames = 0;

        long timer = System.currentTimeMillis();
        double delta = 0D;

        while(executionStatus) { 
            long currentUpdate = System.nanoTime();
            delta += (currentUpdate - lastUpdate) / nanoPerUpdate;
            lastUpdate = currentUpdate;

            boolean renderStatus = false;

            while(delta >= 1) {
                updates++;
                update();
                delta -= 1;
                renderStatus = true;
            }

            if(renderStatus) {
                frames++;
                render();
            }

            if(System.currentTimeMillis() - timer >= 1000) {
                timer += 1000;

                this.updates = updates;
                this.frames = frames;

                updates = 0;
                frames = 0;
            }
        }
    }

}

A representation of implementation as a library:

package io.code.gm;

public class FakeImplementation extends GMEngine {

    private static final long serialVersionUID = 1L;

    public FakeImplementation(String title, int width, int height) {
        super(title, width, height);
    }

    public static void main(String[] args) {
        new FakeImplementation("2D Engine", 800, 500);
    }

    void init() {
        this.start();
    }

    void update() {

    }

    void render() {

    }

}
\$\endgroup\$
2
  • \$\begingroup\$ I think you should really look at this link: gafferongames.com/game-physics/fix-your-timestep It's not really an answer but I appears your code, for example, doesn't handle fluctuations in time appropriately (which is dealt with in the article under the title: "Variable delta time") \$\endgroup\$
    – Dair
    Commented Mar 28, 2016 at 3:38
  • \$\begingroup\$ @Dair actually this is really an answer... You should probably write an answer quoting that article and point out where OP has made mistakes, so that they can learn to do it better :) \$\endgroup\$
    – Vogel612
    Commented Jul 23, 2016 at 7:20

1 Answer 1

5
\$\begingroup\$

A few abstract notes about game engines and going with the times:

Choice of UI-Framework

You have chosen Swing as your UI Framework. This is a decision I frankly cannot understand. Swing has been officially deprecated in favor of JavaFX. Not only that, Swing is slow.

It's not getting easier by virtue that I know of no way to load textures in Swing. Also there's no proper integration for OpenGL (let alone any other render engine) into Swing.

These problems could easily be remedied by instead working with JavaFX, which is the new official UI framework and has acceptable, if not good integration for OpenGL through javafx.scene.canvas.Canvas

Raw AWT

Working on raw AWT to integrate free drawing with java.awt.Canvas is a royal pain and actually just a workaround for the lack of proper support in Swing. You shouldn't have to work against your UI Framework. Instead work with it and use it to your advantage. Leverage it.

Design mistakes and OOP violations

Making your GMEngine an abstract class is probably a good move. Making the stuff I need for drawing inaccessible from subclasses probably isn't.

Note that most graphics engines are expected to work on a different basis than your "Engine". This comes back to favouring Composition over Inheritance. The point I'm trying to make is that an Engine should help a programmer get work done in significantly less steps than it needed before.

It should boil down to loading Textures, positioning them and then calling something like render() repeatedly after updating the texture positions. This is simply speaking impossible with your current design, because I as "user" of your Engine have to write the code to do that myself anyways. It would've been easier for me to just write those 200-ish lines here myself, because then I have the full control over what I render and only insignificantly more work.

I think you should revisit your motivations for this class and get a clearer idea for what it should actually do to make life easier for you (and other programmers).

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.