10
\$\begingroup\$

As I am relativistically new to programming and lack any sort of formal experience in the matter, I was wondering if any of you with a bit more knowledge in the subject would be willing to tell me if the following code is an acceptable way to accomplish a function binding event handler in Java 8.

I admit that the naming conventions in the following code may be slightly off-par, however, it makes sense to me as a free-spirited beginner who cares not for package.thousand_sub-packages.overly_long_class_name_and_full_essay.java.

Again, the purpose of this question is to ascertain if my solution is an acceptable one, and if it is not, what a proper one would be.

First the main class:

package TestingApp;

import JGameEngineX.JGameEngineX;
import Modes.Main_Game;
import Modes.Main_Menu;
import java.util.Random;

/**
 * @author RlonRyan
 * @name JBasicX_TestingApp
 * @version 1.0.0
 * @date Jan 9, 2012
 * @info Powered by JBasicX
 *
 */
public class JBasicX_TestingApp {

    public static JGameEngineX instance;
    public static final String[] options = {"Lambda Style!", "Javaaa!", "Spaaaaaace!", "Generic!", "Automated!", "Title goes here."};

    public static void main(String args[]) {

        if (instance != null) {
            return;
        }

        String mode = args.length >= 1 ? args[0] : "windowed";

        int fps = args.length >= 3 ? Integer.parseInt(args[2]) : 100;
        int width = args.length >= 4 ? Integer.parseInt(args[3]) : 640;
        int height = args.length >= 5 ? Integer.parseInt(args[4]) : 480;

        instance = new JGameEngineX("JBasicX Testing Application: " + options[new Random().nextInt(options.length)], mode, fps, width, height);

        instance.registerGameMode(new Main_Menu(instance));
        instance.registerGameMode(new Main_Game(instance));

        instance.init();

        instance.start("main_menu");

    }

}

Next the menu mode class:

package Modes;

import JGameEngineX.JGameEngineX;
import JGameEngineX.JGameModeX.JGameModeX;
import JIOX.JMenuX.JMenuElementX.JMenuTextElementX;
import JIOX.JMenuX.JMenuX;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.event.KeyEvent;
import java.util.Random;

/**
 *
 * @author RlonRyan
 */
public class Main_Menu extends JGameModeX {

    private JMenuX menu;

    public Main_Menu(JGameEngineX holder) {

        super("Main_Menu", holder);

    }

    @Override
    public void init() {
        menu = new JMenuX("Main Menu", 160, 120, 320, 240);
        menu.addMenuElement(new JMenuTextElementX("Start", () -> (holder.setGameMode("main_game"))));
        menu.addMenuElement(new JMenuTextElementX("Toggle Game Data", () -> (holder.toggleGameDataVisable())));
        menu.addMenuElement(new JMenuTextElementX("Randomize!", () -> (holder.setBackgroundColor(new Color(new Random().nextInt(256),new Random().nextInt(256),new Random().nextInt(256))))));
        menu.addMenuElement(new JMenuTextElementX("Reset!", () -> (holder.setBackgroundColor(Color.BLACK))));
        menu.addMenuElement(new JMenuTextElementX("Quit", () -> (System.exit(0))));
    }

    @Override
    public void registerBindings() {
        bindings.bind(KeyEvent.KEY_PRESSED, KeyEvent.VK_DOWN, (e) -> (menu.incrementHighlight()));
        bindings.bind(KeyEvent.KEY_PRESSED, KeyEvent.VK_UP, (e) -> (menu.deincrementHighlight()));
        bindings.bind(KeyEvent.KEY_PRESSED, KeyEvent.VK_ENTER, (e) -> (menu.selectMenuElement()));
        bindings.bind(KeyEvent.KEY_PRESSED, KeyEvent.VK_ESCAPE, (e) -> (System.exit(0)));
        bindings.bind(KeyEvent.KEY_PRESSED, (e) -> (System.out.println("Keypress: " + ((KeyEvent) e).getKeyChar() + " detected with lambda!")));
    }

    @Override
    public void start() {
        menu.open();
    }

    @Override
    public void update() {
        // Update...
    }

    @Override
    public void pause() {
        // Do nothing
    }

    @Override
    public void stop() {
        menu.close();
    }

    @Override
    public void paint(Graphics2D g2d) {
        menu.paint(g2d);
    }

}

Finally the binding class:

package JEventX;

import java.awt.AWTEvent;
import java.awt.event.KeyEvent;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.function.Consumer;
import javafx.util.Pair;

/**
 *
 * @author RlonRyan
 */
public class JEventBinderX {

    private final HashMap<Pair<Integer, Integer>, ArrayList<Consumer<AWTEvent>>> bindings;

    public JEventBinderX() {
    bindings = new HashMap<>();
    }

    public final void bind(int trigger, Consumer<AWTEvent> method) {
    bind(new Pair<>(trigger, 0), method);
    }

    public final void bind(int trigger, int subtrigger, Consumer<AWTEvent> method) {
    bind(new Pair<>(trigger, subtrigger), method);
    }

    public final void bind(Pair<Integer, Integer> trigger, Consumer<AWTEvent> method) {
    if (!this.bindings.containsKey(trigger)) {
        this.bindings.put(trigger, new ArrayList<>());
    }
    this.bindings.get(trigger).add(method);
    }

    public final void release(int trigger) {
    release(new Pair<>(trigger, 0));
    }

    public final void release(Pair<Integer, Integer> trigger) {
    if (this.bindings.containsKey(trigger)) {
        this.bindings.remove(trigger);
    }
    }

    public final void release(int trigger, Consumer<AWTEvent> method) {
    release(new Pair<>(trigger, 0), method);
    }

    public final void release(Pair<Integer, Integer> trigger, Consumer<AWTEvent> method) {
    if (this.bindings.containsKey(trigger)) {
        this.bindings.get(trigger).remove(method);
    }
    }

    public final void fireEvent(AWTEvent e) {
    Pair<Integer, Integer> id = null;
    if(e instanceof MouseEvent) {
        id = new Pair<>(e.getID(), ((MouseEvent)e).getButton());
    }
    else if(e instanceof KeyEvent) {
        id = new Pair<>(e.getID(), ((KeyEvent)e).getKeyCode());
    }
    if(id != null && this.bindings.containsKey(id)){
        bindings.get(id).stream().forEach((c) -> c.accept(e));
    }
    id = new Pair<>(e.getID(), 0);
    if(this.bindings.containsKey(id)) {
        bindings.get(id).stream().forEach((c) -> c.accept(e));
    }
    }

    public final void fireEvent(AWTEvent e, int subid) {
    Pair<Integer, Integer> id = new Pair<>(e.getID(), subid);
    if(this.bindings.containsKey(id)){
        bindings.get(id).stream().forEach((c) -> c.accept(e));
    }
    }

}

[Edit] And the JGameModeX class

package JGameEngineX.JGameModeX;

import JEventX.JEventBinderX;
import JGameEngineX.JGameEngineX;
import java.awt.Graphics2D;

/*
 * public static enum GAME_STATUS {
 *
 * GAME_STOPPED,
 * GAME_INTIALIZING,
 * GAME_STARTING,
 * GAME_MENU,
 * GAME_RUNNING,
 * GAME_PAUSED;
 * }
 */

/**
 *
 * @author RlonRyan
 */
public abstract class JGameModeX {

    public final String name;

    public final JEventBinderX bindings;

    public final JGameEngineX holder;

    public JGameModeX(String name, JGameEngineX holder) {
    this.name = name.toLowerCase();
    this.bindings = new JEventBinderX();
    this.holder = holder;
    }

    public abstract void init();

    public abstract void registerBindings();

    public abstract void start();

    public abstract void update();

    public abstract void paint(Graphics2D g2d);

    public abstract void pause();

    public abstract void stop();

}
\$\endgroup\$
  • \$\begingroup\$ This code really needs JGameModeX in order for some of the code to make sense. \$\endgroup\$ – rolfl May 3 '14 at 14:36
  • \$\begingroup\$ That would help, I suppose... \$\endgroup\$ – RlonRyan May 3 '14 at 17:58
3
\$\begingroup\$

Looks completely acceptable to me. If there is no reason to hold on to the lambdas in some other way, e.g. to flush or remove them, and they're not too big or complicated to distract from the current context, then I see this as much the preferred way to do it.

Short answer but, yeah, good question.

\$\endgroup\$
3
\$\begingroup\$

Why do you have this piece of code ?

if (instance != null) {
    return; 
}

In fact, why is public static JGameEngineX instance; public at all? Do you really need to expose it ? The code I was asking earlier seems to verify that instance has not been initialized by anything else but this class. If instance was private you would not need to check if it was created elsewhere since you have control over it. If you don't need the public visibility don't use it.

\$\endgroup\$
  • \$\begingroup\$ Oh, yeah, that is a bit dumb... I think I was thinking about trying to prevent multiple concurrent runs, but never got around to it, so I wound up with that. I'll make a note to remove it, thanks! \$\endgroup\$ – RlonRyan May 9 '14 at 3:34

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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