从视图中通知控制器已按下某个键?

时间:2016-05-27 01:34:40

标签: java model-view-controller

我正在制作游戏,我有以下主要课程

主控制器类:

public class Manager implements Runnable {
private boolean running;
private Thread thread;

private MasterRenderer window;

private PlayerCharacter player;


private Map map;

public Manager() {
    window = new MasterRenderer();
    player = new PlayerCharacter(0, 0, Entity.FACING_DOWN, "Pepe", 0, 1, 2);
    map = new Map();

}

public void initialize() {
    window.setPlayerRenderer(new PlayerRenderer(player));
    window.setMapRenderer(new MapRenderer(map));
    window.setTerrainRenderer(new TerrainRenderer(new Terrain(0, 0, Entity.FACING_DOWN, "arbol", false)));

    running = true;
    thread = new Thread(this);

    thread.start();
}

public void run() {
    long timer = System.currentTimeMillis();
    long lastTime = System.nanoTime();
    final double ns = 1000000000.0 / 60.0;
    double delta = 0;
    int frames = 0;
    int ticks = 0;
    while (running) {
        long now = System.nanoTime();
        delta += (now - lastTime) / ns;
        lastTime = now;
        while (delta >= 1) {
            tick(delta);
            ticks++;
            delta--;
            frames++;
            render();
        }
        if (System.currentTimeMillis() - timer > 1000) {
            timer += 1000;
            System.out.println("Frames: " + frames + "\tTicks: " + ticks);

            frames = ticks = 0;
        }
    }
}

public void tick(double delta) {

}

public void render() {
    window.render();
}

public static void main(String[] args) {
    Manager manager = new Manager();
    manager.initialize();
}
}

主视图类:

public class MasterRenderer extends Canvas implements KeyListener {
private static final long serialVersionUID = 1L;

public static final int WIDTH = 640;
public static final int HEIGHT = WIDTH * 3 / 4;
public static final String TITLE = "The legend of Finn";

private JFrame frame;
private BufferStrategy bs;
private Graphics g;

private PlayerRenderer playerR;
private MapRenderer mapR;
private TerrainRenderer terrainR;

public MasterRenderer() {
    setPreferredSize(new Dimension(WIDTH, HEIGHT));

    frame = new JFrame();

    addKeyListener(this);
    frame.setTitle(TITLE);
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.add(this);
    frame.setResizable(false);
    frame.pack();
    frame.setLocationRelativeTo(null);
    frame.setVisible(true);
    requestFocus();
}

public void render() {
    bs = getBufferStrategy();
    if (bs == null) {
        createBufferStrategy(3);
        return;
    }
    g = bs.getDrawGraphics();
    g.setColor(Color.BLACK);
    g.fillRect(0, 0, getWidth(), getHeight());

    playerR.render(g);
    mapR.render(g);
    terrainR.render(g);

    bs.show();
    g.dispose();
}

public void setMapRenderer(MapRenderer mapR) {
    this.mapR = mapR;
}

public void setPlayerRenderer(PlayerRenderer playerR) {
    this.playerR = playerR;
}

public void setTerrainRenderer(TerrainRenderer terrainR) {
    this.terrainR = terrainR;
}

@Override
public void keyTyped(KeyEvent e) {
}
@Override
public void keyPressed(KeyEvent e) {
    int i=e.getKeyCode();

    System.out.println("Key pressed!!");
}
@Override
public void keyReleased(KeyEvent e) {
}
}

我以这种方式组织代码,因为我试图真正坚持MVC(此外,将keyListener放在管理器类中现在是一个痛苦的屁股)。有什么简单的方法可以在MasterRenderer注册按键时通知Manager吗?

1 个答案:

答案 0 :(得分:0)

您的View中没有Control引用,也没有注册侦听器的方法,如果没有这个,我看不到视图将如何与控件通信。我看到你有两种可能的解决方案:

  1. 将Control引用传递给视图,并在想要通知状态更改时使用控件的视图调用方法,或
  2. 设置一个机制,例如SwingPropertyChangeSupport机制,它将允许控件监听状态更改。如果你走这条路,那么你必须调用支持的fireXxx(...)方法。
  3. 幸运的是,许多Swing和AWT组件已经具有上面的数字2的机制,我建议你这样做:让你的控件用你的Canvas对象注册一个PropertyChangeListener(如果它是一个JPanel更好!),然后在你的KeyListener firePropertyChange(...)方法通知控制状态更改。

    例如:

    import java.awt.Dimension;
    import java.awt.event.KeyAdapter;
    import java.awt.event.KeyEvent;
    import java.beans.PropertyChangeEvent;
    import java.beans.PropertyChangeListener;
    import javax.swing.*;    
    
    public class MyControl implements Runnable, PropertyChangeListener {
    
        public MyControl() {
            // TODO finish
        }
    
        @Override
        public void propertyChange(PropertyChangeEvent pcEvt) {
    
            // this is only one of potentially many properties that the control can listen to
            if (MyView.KEY_PRESSED.equals(pcEvt.getPropertyName())) {
                // respond to the key pressed code
                System.out.println("KeyCode is: " + pcEvt.getNewValue());
            }
        }
    
        @Override
        public void run() {
            // TODO Finish!
        }
    
        private static void createAndShowGui() {
            // create both view and control
            MyControl control = new MyControl();
            MyView view = new MyView();
    
            // now wire the control to listen to the view
            view.addPropertyChangeListener(MyView.KEY_PRESSED, control);
    
            JFrame frame = new JFrame("MyControl");
            frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
            frame.getContentPane().add(view);
            frame.pack();
            frame.setLocationByPlatform(true);
            frame.setVisible(true);
        }
    
        public static void main(String[] args) {
            SwingUtilities.invokeLater(() -> createAndShowGui());
        }
    
    
    }
    
    class MyView extends JPanel {
        // constant for PropertyChangeListener use:
        public static final String KEY_PRESSED = "key pressed";
        private static final int PREF_W = 400;
        private static final int PREF_H = PREF_W;
    
        public MyView() {
            setFocusable(true);
            requestFocusInWindow();
            addKeyListener(new MyKeyListener());
        }
    
        @Override
        public Dimension getPreferredSize() {
            if (isPreferredSizeSet()) {
                return super.getPreferredSize();
            }
            return new Dimension(PREF_W, PREF_H);
        }
    
        private class MyKeyListener extends KeyAdapter {
    
            @Override
            public void keyPressed(KeyEvent e) {
                // get the keycode pressed
                int newValue = e.getKeyCode();
    
                // ** notify any listeners that this key has been pressed **
                firePropertyChange(KEY_PRESSED, null, newValue);
            }
    
        }
    
    }