好了,讓我們開始與一些問題...
class www extends JFrame
首先,你應該避免覆蓋JFrame
,你不添加任何新的功能類,把自己鎖整合到一個單一的使用案例中,並存在其他難以診斷的問題。
您的課程名稱應該以大寫字母開頭。通過Code Conventions for the Java TM Programming Language閱讀,它將使人們更容易閱讀你的代碼並閱讀其他人。
下一頁...
static Maze maze = new Maze();
static Timer t;
static
是一個不好的設計的一個好兆頭。你應該避免使用它們作爲跨通信機制,你失去了他們的引用是如何改變的控制,使其難以診斷可能出現的問題
下一頁...
class DrawArea extends JPanel
{
public DrawArea (int width, int height)
{
this.setPreferredSize (new Dimension (width, height)); // size
}
public void paintComponent (Graphics g)
{
maze.show (g);
// display current state of colony
}
}
首先,你打破了油漆鏈,這可能導致繪畫工件無法結束,您必須在執行任何自定義繪畫之前調用油漆方法super
方法。詳情參見
而且Painting in AWT and Swing和Performing Custom Painting,它不是迷宮的責任油漆本身,它是由視圖來決定應如何最好地代表模型/迷宮
下一頁...
public class player extends JPanel implements ActionListener,KeyListener
{
//...
}
好的,這個班級根本就沒有用過,但它是唯一一次註冊KeyListener
。你也過於複雜的過程,因爲DrawArea
也應該負責繪製播放器和處理用戶輸入。
作爲一般的經驗法則,KeyListener
不是合適的API,原因有很多。您最好使用Key Bindings API,它可以解決KeyListener
的問題,並使其更易於更改和實現其他輸入設備。
你的代碼一般不會專注於孤立的責任,爲什麼player
被允許改變玩家的位置?
OOP的一個關鍵方面是關於隔離責任,這使得更改事物更容易,而不會對系統的其他部分造成負面影響,這也支持Model-View-Controller範例。
其基本思想是,您的模型控制數據,維護狀態並定義可以更改它的規則(並可根據需要提供事件通知)。該視圖負責渲染模型的狀態。控制器是將它粘合在一起的膠水。
通常在MVC中,模型和視圖從不與每個MVC進行通信,控制器負責充當它們之間的管道。這可以通過使用Observer Pattern直接實現(直接對控制器進行調用),或者通常使用Observer Pattern來實現,其中視圖和模型生成控制器響應的事件。
,我們需要做的是定義每個元素,每一層是會暴露給其他方,例如信息和功能的基本功能的第一件事...
public interface GameModel {
public int[][] getMaze();
public int[] getPlayerLocation();
public void setPlayerLocation(int[] location);
public void update(Set<Direction> directions);
}
public interface GameController {
public int[][] getMaze();
public int[] getPlayerLocation();
public void setDirectionPressed(Direction direction, boolean pressed);
public void start();
}
public interface GameView {
public void update();
public void setController(GameController controller);
public GameController getController();
}
這是開始的想法Composition over inheritance它允許你更好地解耦你的代碼,因爲你不依賴於類的物理實現,而只是他們的維護一個給定合同的結果。
接下來,我們定義的實現....
public class DefaultGameModel implements GameModel {
private int[][] maze
= {{1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
{1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1},
{1, 0, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1},
{1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1},
{1, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1},
{1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 0, 0, 1},
{1, 0, 1, 0, 1, 0, 0, 0, 1, 1, 1, 0, 1},
{1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1},
{1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1},
{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1}};
private int[] playerLocation = new int[]{1, 0};
@Override
public int[][] getMaze() {
return maze;
}
@Override
public int[] getPlayerLocation() {
return playerLocation;
}
@Override
public void setPlayerLocation(int[] playerLocation) {
this.playerLocation = playerLocation;
}
@Override
public void update(Set<Direction> directions) {
int[] location = getPlayerLocation();
int[][] maze = getMaze();
int x = location[0];
int y = location[1];
if (directions.contains(Direction.UP)) {
y--;
} else if (directions.contains(Direction.DOWN)) {
y++;
}
if (directions.contains(Direction.LEFT)) {
x--;
} else if (directions.contains(Direction.RIGHT)) {
x++;
}
if (x < 0) {
x = 0;
} else if (x >= maze[0].length) {
x = maze[0].length - 1;
}
if (y < 0) {
y = 0;
} else if (y >= maze.length) {
y = maze.length - 1;
}
if (maze[y][x] == 0) {
location = new int[]{x, y};
setPlayerLocation(location);
}
}
}
public class DefaultGameController implements GameController {
private GameView view;
private GameModel model;
private Timer timer;
private Set<Direction> directions;
public DefaultGameController(GameView view, GameModel model) {
this.view = view;
this.model = model;
directions = new HashSet<>(4);
view.setController(this);
}
public GameView getView() {
return view;
}
public GameModel getModel() {
return model;
}
@Override
public int[][] getMaze() {
return getModel().getMaze();
}
@Override
public int[] getPlayerLocation() {
return getModel().getPlayerLocation();
}
@Override
public void setDirectionPressed(Direction direction, boolean pressed) {
if (pressed) {
directions.add(direction);
} else {
directions.remove(direction);
}
}
@Override
public void start() {
// This isn't really required for this type of simple example, but what
// does do is demonstrates at least one possible solution for simple
// game loop
//
// Because of the basic nature of the game, it would be possible to have
// setDirectionPressed call model.update and view.update
if (timer != null && timer.isRunning()) {
timer.stop();
}
timer = new Timer(40, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
getModel().update(Collections.unmodifiableSet(directions));
getView().update();
}
});
timer.start();
}
}
public class DefaultGameView extends JPanel implements GameView {
private GameController controller;
public DefaultGameView() {
addKeyBinding("left.pressed", KeyEvent.VK_LEFT, true, new MoveAction(Direction.LEFT, true));
addKeyBinding("left.released", KeyEvent.VK_LEFT, false, new MoveAction(Direction.LEFT, false));
addKeyBinding("right.pressed", KeyEvent.VK_RIGHT, true, new MoveAction(Direction.RIGHT, true));
addKeyBinding("right.released", KeyEvent.VK_RIGHT, false, new MoveAction(Direction.RIGHT, false));
addKeyBinding("up.pressed", KeyEvent.VK_UP, true, new MoveAction(Direction.UP, true));
addKeyBinding("up.released", KeyEvent.VK_UP, false, new MoveAction(Direction.UP, false));
addKeyBinding("down.pressed", KeyEvent.VK_DOWN, true, new MoveAction(Direction.DOWN, true));
addKeyBinding("down.released", KeyEvent.VK_DOWN, false, new MoveAction(Direction.DOWN, false));
}
@Override
public void update() {
repaint();
}
@Override
public void setController(GameController controller) {
this.controller = controller;
revalidate();
repaint();
}
@Override
public GameController getController() {
return controller;
}
@Override
public Dimension getPreferredSize() {
Dimension size = new Dimension(13 * 20, 10 * 20);
GameController controller = getController();
if (controller != null) {
int[][] maze = controller.getMaze();
size.height = maze.length * 20;
size.width = maze[0].length * 20;
}
return size;
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
GameController controller = getController();
if (controller != null) {
Graphics2D g2d = (Graphics2D) g.create();
Dimension size = getPreferredSize();
int x = (getWidth() - size.width)/2;
int y = (getHeight() - size.height)/2;
int[][] maze = controller.getMaze();
for (int row = 0; row < maze.length; row++) {
int yPos = y + (row * 20);
for (int col = 0; col < maze[row].length; col++) {
int xPos = x + (col * 20);
switch (maze[row][col]) {
case 1:
g2d.setColor(Color.BLACK);
break;
default:
g2d.setColor(Color.WHITE);
break;
}
g2d.fillRect(xPos, yPos, 20, 20);
}
}
int[] playerLocation = controller.getPlayerLocation();
int xPos = x + (playerLocation[0] * 20);
int yPos = y + (playerLocation[1] * 20);
g2d.setColor(Color.RED);
g2d.fillRect(xPos, yPos, 20, 20);
g2d.dispose();
}
}
protected void addKeyBinding(String name, int virtualKey, boolean pressed, MoveAction action) {
addKeyBinding(name, KeyStroke.getKeyStroke(virtualKey, 0, !pressed), action);
}
protected void addKeyBinding(String name, KeyStroke keyStroke, MoveAction action) {
InputMap inputMap = getInputMap(WHEN_IN_FOCUSED_WINDOW);
ActionMap actionMap = getActionMap();
inputMap.put(keyStroke, name);
actionMap.put(name, action);
}
public class MoveAction extends AbstractAction {
private Direction direction;
private boolean pressed;
public MoveAction(Direction direction, boolean pressed) {
this.direction = direction;
this.pressed = pressed;
}
@Override
public void actionPerformed(ActionEvent e) {
GameController controller = getController();
if (controller != null) {
controller.setDirectionPressed(direction, pressed);
}
}
}
}
好吧,這似乎有點怪異這樣一個簡單的問題,但知道想象你想添加更多的迷宮,這是一個簡單的改變該模型。
最後,我們需要把它放在一起......
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import javax.swing.AbstractAction;
import javax.swing.ActionMap;
import javax.swing.InputMap;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.KeyStroke;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Main {
public static void main(String[] args) {
new Main();
}
public Main() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
GameModel model = new DefaultGameModel();
DefaultGameView view = new DefaultGameView();
GameController controller = new DefaultGameController(view, model);
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(view);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
controller.start();
}
});
}
public enum Direction {
UP, DOWN, LEFT, RIGHT;
}
public interface GameModel {
public int[][] getMaze();
public int[] getPlayerLocation();
public void setPlayerLocation(int[] location);
public void update(Set<Direction> directions);
}
public interface GameController {
public int[][] getMaze();
public int[] getPlayerLocation();
public void setDirectionPressed(Direction direction, boolean pressed);
public void start();
}
public interface GameView {
public void update();
public void setController(GameController controller);
public GameController getController();
}
public class DefaultGameModel implements GameModel {
private int[][] maze
= {{1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
{1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1},
{1, 0, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1},
{1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1},
{1, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1},
{1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 0, 0, 1},
{1, 0, 1, 0, 1, 0, 0, 0, 1, 1, 1, 0, 1},
{1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1},
{1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1},
{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1}};
private int[] playerLocation = new int[]{1, 0};
@Override
public int[][] getMaze() {
return maze;
}
@Override
public int[] getPlayerLocation() {
return playerLocation;
}
@Override
public void setPlayerLocation(int[] playerLocation) {
this.playerLocation = playerLocation;
}
@Override
public void update(Set<Direction> directions) {
int[] location = getPlayerLocation();
int[][] maze = getMaze();
int x = location[0];
int y = location[1];
if (directions.contains(Direction.UP)) {
y--;
} else if (directions.contains(Direction.DOWN)) {
y++;
}
if (directions.contains(Direction.LEFT)) {
x--;
} else if (directions.contains(Direction.RIGHT)) {
x++;
}
if (x < 0) {
x = 0;
} else if (x >= maze[0].length) {
x = maze[0].length - 1;
}
if (y < 0) {
y = 0;
} else if (y >= maze.length) {
y = maze.length - 1;
}
if (maze[y][x] == 0) {
location = new int[]{x, y};
setPlayerLocation(location);
}
}
}
public class DefaultGameController implements GameController {
private GameView view;
private GameModel model;
private Timer timer;
private Set<Direction> directions;
public DefaultGameController(GameView view, GameModel model) {
this.view = view;
this.model = model;
directions = new HashSet<>(4);
view.setController(this);
}
public GameView getView() {
return view;
}
public GameModel getModel() {
return model;
}
@Override
public int[][] getMaze() {
return getModel().getMaze();
}
@Override
public int[] getPlayerLocation() {
return getModel().getPlayerLocation();
}
@Override
public void setDirectionPressed(Direction direction, boolean pressed) {
if (pressed) {
directions.add(direction);
} else {
directions.remove(direction);
}
}
@Override
public void start() {
// This isn't really required for this type of simple example, but what
// does do is demonstrates at least one possible solution for simple
// game loop
//
// Because of the basic nature of the game, it would be possible to have
// setDirectionPressed call model.update and view.update
if (timer != null && timer.isRunning()) {
timer.stop();
}
timer = new Timer(40, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
getModel().update(Collections.unmodifiableSet(directions));
getView().update();
}
});
timer.start();
}
}
public class DefaultGameView extends JPanel implements GameView {
private GameController controller;
public DefaultGameView() {
addKeyBinding("left.pressed", KeyEvent.VK_LEFT, true, new MoveAction(Direction.LEFT, true));
addKeyBinding("left.released", KeyEvent.VK_LEFT, false, new MoveAction(Direction.LEFT, false));
addKeyBinding("right.pressed", KeyEvent.VK_RIGHT, true, new MoveAction(Direction.RIGHT, true));
addKeyBinding("right.released", KeyEvent.VK_RIGHT, false, new MoveAction(Direction.RIGHT, false));
addKeyBinding("up.pressed", KeyEvent.VK_UP, true, new MoveAction(Direction.UP, true));
addKeyBinding("up.released", KeyEvent.VK_UP, false, new MoveAction(Direction.UP, false));
addKeyBinding("down.pressed", KeyEvent.VK_DOWN, true, new MoveAction(Direction.DOWN, true));
addKeyBinding("down.released", KeyEvent.VK_DOWN, false, new MoveAction(Direction.DOWN, false));
}
@Override
public void update() {
repaint();
}
@Override
public void setController(GameController controller) {
this.controller = controller;
revalidate();
repaint();
}
@Override
public GameController getController() {
return controller;
}
@Override
public Dimension getPreferredSize() {
Dimension size = new Dimension(13 * 20, 10 * 20);
GameController controller = getController();
if (controller != null) {
int[][] maze = controller.getMaze();
size.height = maze.length * 20;
size.width = maze[0].length * 20;
}
return size;
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
GameController controller = getController();
if (controller != null) {
Graphics2D g2d = (Graphics2D) g.create();
Dimension size = getPreferredSize();
int x = (getWidth() - size.width)/2;
int y = (getHeight() - size.height)/2;
int[][] maze = controller.getMaze();
for (int row = 0; row < maze.length; row++) {
int yPos = y + (row * 20);
for (int col = 0; col < maze[row].length; col++) {
int xPos = x + (col * 20);
switch (maze[row][col]) {
case 1:
g2d.setColor(Color.BLACK);
break;
default:
g2d.setColor(Color.WHITE);
break;
}
g2d.fillRect(xPos, yPos, 20, 20);
}
}
int[] playerLocation = controller.getPlayerLocation();
int xPos = x + (playerLocation[0] * 20);
int yPos = y + (playerLocation[1] * 20);
g2d.setColor(Color.RED);
g2d.fillRect(xPos, yPos, 20, 20);
g2d.dispose();
}
}
protected void addKeyBinding(String name, int virtualKey, boolean pressed, MoveAction action) {
addKeyBinding(name, KeyStroke.getKeyStroke(virtualKey, 0, !pressed), action);
}
protected void addKeyBinding(String name, KeyStroke keyStroke, MoveAction action) {
InputMap inputMap = getInputMap(WHEN_IN_FOCUSED_WINDOW);
ActionMap actionMap = getActionMap();
inputMap.put(keyStroke, name);
actionMap.put(name, action);
}
public class MoveAction extends AbstractAction {
private Direction direction;
private boolean pressed;
public MoveAction(Direction direction, boolean pressed) {
this.direction = direction;
this.pressed = pressed;
}
@Override
public void actionPerformed(ActionEvent e) {
GameController controller = getController();
if (controller != null) {
controller.setDirectionPressed(direction, pressed);
}
}
}
}
}
這是一般概念的一個基本的介紹,你應該考慮探索基本OOP和博弈論
從[Swing中的併發]開始(http://docs.oracle.com/javase/tutorial/uiswing/concurrency/),[如何使用Swing定時器](http://docs.oracle.com/javase /tutorial/uiswing/misc/timer.html)和[如何使用密鑰綁定](http://docs.oracle.com/javase/tutorial/uiswing/misc/keybinding.html)。然後看看[這個答案](http://stackoverflow.com/questions/35003520/program-not-painting-screen-properly/35004777#35004777)演示了一個基本遊戲的MVC實現,使用鍵盤輸入更新遊戲模型的狀態。我們給出的任何答案基本上與上面的一樣 – MadProgrammer
@MadProgrammer:這必須是FN20,並且您已經給他這些鏈接。現在關於那座橋... –
@HovercraftFullOfEels是的,我正在考慮只是做一個快捷方式來自動填寫評論的未來問題 – MadProgrammer