我一直在撞墙试图解决这个问题。很确定我今天丢了一些头发。
基本上,我们获得了一些工作类,并被要求在其上实施RMI。在给定的代码中有一些错误,但我修复了它们。现在我没有任何错误,而且它无法正常工作。
以下是课程:
GameClient.java
- 由我完成
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
public class GameClient extends UnicastRemoteObject implements IGUI, IGameEngine, Runnable {
IGameServer ser;
PlayerInfo player;
IGUI g;
IGameEngine ge;
public GameClient(IGameServer ss) throws RemoteException {
ser = ss;
ser.registerClient(this);
}
@Override
public void markedAsOriginalDisplayMode() throws RemoteException {
g.markedAsOriginalDisplayMode();
}
@Override
public void noMarkedDisplayMode() throws RemoteException {
g.noMarkedDisplayMode();
}
@Override
public void normalDisplayMode() throws RemoteException {
g.normalDisplayMode();
}
@Override
public void update() throws RemoteException {
g.update();
}
@Override
public void exit(int i) throws RemoteException {
g = null;
setGUI(g);
ser.setGameOver();
System.exit(i);
}
@Override
public PlayingBlock getNextBlock() throws RemoteException {
return ser.getNextBlock();
}
@Override
public PlayArea getPlayArea() throws RemoteException {
return ser.getPlayArea();
}
@Override
public String getPlayerName() throws RemoteException {
return ser.getPlayerName();
}
@Override
public int getPlayerScore() throws RemoteException {
return ser.getPlayerScore();
}
@Override
public boolean isGameOver() throws RemoteException {
return ser.isGameOver();
}
@Override
public void setGameOver() throws RemoteException {
ser.setGameOver();
}
public void setGUI(IGUI gui) {
g = gui;
}
@Override
public void setPlayer(PlayerInfo pi) {
try {
ser.setPlayer(pi);
}
catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
public void setPlayerName(String name) throws RemoteException {
ser.setPlayerName(name);
}
@Override
public void start() throws RemoteException {
ser.start();
}
@Override
public void treatEvent(int event) throws RemoteException {
ser.treatEvent(event);
}
@Override
public void run() {
String playerName = "Vasilis";
setPlayer(new PlayerInfo(playerName));
IGUI gui = new GUI(this, 20, 25);
setGUI(gui);
}
}
IGameEngine.java
import java.rmi.RemoteException;
/**
* Interface representing the logic of the game
*/
public interface IGameEngine {
public void treatEvent(int event) throws RemoteException;
public void start() throws RemoteException;
public PlayingBlock getNextBlock() throws RemoteException;
public boolean isGameOver() throws RemoteException;
public void setGameOver() throws RemoteException;
public PlayArea getPlayArea() throws RemoteException;
public int getPlayerScore() throws RemoteException;
public void setPlayerName(String name) throws RemoteException;
public void setPlayer(PlayerInfo pi);
public String getPlayerName() throws RemoteException;
public void setGUI(IGUI gui);
public void exit(int status) throws RemoteException;
}
GameEngine.java
import java.rmi.RemoteException;
import java.util.*;
class GameEngine {
private PlayArea board;
private PlayerInfo player;
private PlayingBlock activeBlock;
private PlayingBlock nextBlock;
private Timer timer;
private TimerTask pendingTask;
private int timerValue;
private float timerScaleFactor;
private int minTimerValue;
private int timerValueChangeInterval;
private int numBlocks;
private Random rng;
private IGUI gui;
private boolean gameOver;
private boolean controlsLocked;
public GameEngine(int size) {
board = new PlayArea(size);
rng = new Random(System.currentTimeMillis());
resetGame();
}
protected void resetGame() {
nextBlock = null;
board.init();
timerScaleFactor = Settings.TIMERSCALE;
minTimerValue = Settings.MINTIMER;
timerValue = Settings.INITTIMER;
timerValueChangeInterval = Settings.CHANGETIMER;
timer = new Timer();
gameOver = false;
controlsLocked = true;
if (player != null) player.reset();
}
public void setGUI(IGUI gui) {
this.gui = gui;
}
private void updateGUI() throws RemoteException {
gui.update();
}
public void setPlayer(PlayerInfo player) {
this.player = player;
}
public String getPlayerName() {
return player.getName();
}
public void setPlayerName(String name) {
player.setName(name);
}
public int getPlayerScore() {
return player.getScore();
}
public PlayArea getPlayArea() {
return board;
}
public boolean isGameOver() {
return gameOver;
}
public void setGameOver() {
this.gameOver = true;
}
public PlayingBlock getNextBlock() {
return nextBlock;
}
// --> game_engine_timer_methods
private void adjustTimerValue() {
if (++numBlocks % timerValueChangeInterval == 0) {
float nextTimerValue = (float) timerValue / timerScaleFactor;
timerValue = nextTimerValue < minTimerValue ? minTimerValue : Math.round(nextTimerValue);
}
}
private void rescheduleTimer() {
stopTimer();
final PlayingBlock block = activeBlock;
pendingTask = new TimerTask() {
public void run() {
synchronized (GameEngine.this) {
if (block.equals(activeBlock)) try {
treatEvent(GameEvent.TIMEOUT);
}
catch (RemoteException e) {
e.printStackTrace();
}
}
}
};
timer.schedule(pendingTask, timerValue);
}
// --<
// --> game_engine_start_method
public void start() throws RemoteException {
resetGame();
nextBlock = new PlayingBlock(rng.nextInt(3) + 1, Colour.randomColour(rng), PlayArea.randomSide(rng));
nextBlock();
updateGUI();
controlsLocked = false;
rescheduleTimer();
}
public void stopTimer() {
if (pendingTask != null) pendingTask.cancel();
}
public void exit(int status) {
System.exit(status);
}
// --<
// --> game_engine_nextBlock_method
private boolean nextBlock() {
int size = board.getSize();
switch (nextBlock.getSide()) {
case PlayArea.NORTHSIDE:
nextBlock.activate(new Coord(size / 2, 1).add(nextBlock.getCoG().neg()));
break;
case PlayArea.SOUTHSIDE:
nextBlock.activate(new Coord(size / 2, size - 2).add(nextBlock.getCoG().neg()));
break;
case PlayArea.EASTSIDE:
nextBlock.activate(new Coord(size - 2, size / 2).add(nextBlock.getCoG().neg()));
break;
case PlayArea.WESTSIDE:
nextBlock.activate(new Coord(1, size / 2).add(nextBlock.getCoG().neg()));
break;
default: // should never occur
break;
}
activeBlock = nextBlock;
if (board.collision(activeBlock)) return false;
else {
board.flipDraw(activeBlock);
nextBlock = new PlayingBlock(rng.nextInt(3) + 1, Colour.randomColour(rng), PlayArea.randomSide(rng));
adjustTimerValue();
return true;
}
}
// --<
// --> game_engine_movement_methods
private boolean rotate() {
return move(null);
}
private boolean slideActiveBlock() {
return move(activeBlock.getSlidingDirection());
}
private boolean move(Direction direction) {
boolean success = false;
// is the move forbidden?
if (direction != null && direction.equals(activeBlock.getSlidingDirection().getReverse())) return false;
board.flipDraw(activeBlock);
if (direction == null) activeBlock.rotate();
else activeBlock.move(direction);
if (!board.collision(activeBlock)) success = true;
else // put activeBlock back
if (direction == null) activeBlock.rotate();
else activeBlock.move(direction.getReverse());
board.flipDraw(activeBlock);
return success;
}
// --<
// --> game_engine_event_handler
synchronized public void treatEvent(int event) throws RemoteException {
if (controlsLocked || gameOver) return;
switch (event) {
case GameEvent.TIMEOUT:
if (slideActiveBlock()) {
rescheduleTimer();
updateGUI();
break;
}
else {
updateScore();
return;
}
case GameEvent.UP:
if (move(Direction.up())) updateGUI();
break;
case GameEvent.DOWN:
if (move(Direction.down())) updateGUI();
break;
case GameEvent.RIGHT:
if (move(Direction.right())) updateGUI();
break;
case GameEvent.LEFT:
if (move(Direction.left())) updateGUI();
break;
case GameEvent.ROTATE:
if (rotate()) updateGUI();
break;
case GameEvent.FLY:
pendingTask.cancel();
pendingTask = null;
while (slideActiveBlock()) ;
updateScore();
return;
default:
// should never occur
}
}
// --<
// --> game_engine_scoring_methods
private void updateScore() {
controlsLocked = true;
new Thread() {
public void run() {
int rounds = 0;
while (findSquares(++rounds)) {
// animate square
for (int i = 0; i < 4; i++) {
if (i % 2 == 0) try {
gui.markedAsOriginalDisplayMode();
}
catch (RemoteException e) {
e.printStackTrace();
}
else try {
gui.normalDisplayMode();
}
catch (RemoteException e) {
e.printStackTrace();
}
try {
updateGUI();
}
catch (RemoteException e) {
e.printStackTrace();
}
try {
Thread.sleep(150);
}
catch (InterruptedException e) {
e.printStackTrace();
exit(1);
}
}
try {
updateBoard();
}
catch (RemoteException e) {
e.printStackTrace();
}
}
if (nextBlock()) {
rescheduleTimer();
}
else {
timer.cancel();
gameOver = true;
}
try {
updateGUI(); // new block is active, display
}
catch (RemoteException e) {
e.printStackTrace();
}
controlsLocked = false; // unlock controls
}
}.start();
}
private boolean findSquares(int round) {
int roundScore = 0;
// brute force
boolean found = false;
int playSize = board.getSize();
for (int size = 3; size >= 2; size--)
for (int x = 0; x < playSize; x++)
for (int y = 0; y < playSize; y++) {
int squareColour = board.getSquareColour(x, y, size);
if (Colour.isPlayBrick(squareColour)) {
roundScore += size * size;
// player.incScore((int) Math.pow(size * size, round));
if (size == 2) {
board.mark(x, y, size);
found = true;
}
}
}
if (roundScore > 0) player.incScore((int) Math.pow(roundScore, round));
return found;
}
public void updateBoard() throws RemoteException {
Direction blockDir = activeBlock.getSlidingDirection();
Direction updateDir = blockDir.getReverse();
Coord checkBrick;
boolean falling;
int size = board.getSize();
gui.noMarkedDisplayMode();
for (int i = 0; i < size; i++) {
falling = false;
if (blockDir.equals(Direction.up())) checkBrick = new Coord(i, 0);
else if (blockDir.equals(Direction.down())) checkBrick = new Coord(i, size - 1);
else if (blockDir.equals(Direction.left())) checkBrick = new Coord(0, i);
else checkBrick = new Coord(size - 1, i);
for (int j = 0; j < size; j++) {
int brickColour = board.getBrick(checkBrick);
if (Colour.isMarked(brickColour)) {
falling = true;
board.setBrick(checkBrick, Colour.BASE);
}
else if (falling) if (Colour.isPlayBrick(brickColour)) {
board.setBrick(checkBrick, Colour.BASE);
PlayingBlock tmpBlock = new PlayingBlock(1, brickColour, PlayArea.NORTHSIDE);
// we just need any temporary block
tmpBlock.activate(checkBrick.add(blockDir.getCoordIncrement()));
while (!board.collision(tmpBlock)) {
// animate the fall
board.flipDraw(tmpBlock);
updateGUI();
try {
Thread.sleep(50);
}
catch (InterruptedException e) {
e.printStackTrace();
exit(1);
}
board.flipDraw(tmpBlock);
tmpBlock.move(blockDir);
}
tmpBlock.move(updateDir);
board.flipDraw(tmpBlock);
}
else {
break; /* stop falling, finish with this loop */
}
checkBrick = checkBrick.add(updateDir.getCoordIncrement());
}
}
gui.normalDisplayMode();
}
// --<
}
IGUI.java
/**
* The server's remote reference to a client
*
*
*/
import java.rmi.*;
public interface IGUI extends Remote {
public void update() throws RemoteException;
public void normalDisplayMode() throws RemoteException;
public void noMarkedDisplayMode() throws RemoteException;
public void markedAsOriginalDisplayMode() throws RemoteException;
}
Squares.java
import java.rmi.RemoteException;
//--> squares_class
class Squares {
public static void main(String[] args) throws RemoteException {
GameClient gc = new GameClient();
String playerName = "Quidam";
if (args.length == 1) if (args[0].length() > 15) playerName = args[0].substring(0, 15);
else playerName = args[0];
gc.setPlayer(new PlayerInfo(playerName));
IGUI gui = new GUI(gc, 20, 25);
gc.setGUI(gui);
}
}
// --<
IGameServer.java
/**
* The interface which defines what operations our server can perform for clients
*
*
*/
import java.rmi.*;
public interface IGameServer extends Remote {
public void registerClient(IGUI clientGUI) throws RemoteException;
public void treatEvent(int event) throws RemoteException;
public void start() throws RemoteException;
public PlayingBlock getNextBlock() throws RemoteException;
public boolean isGameOver() throws RemoteException;
public void setGameOver() throws RemoteException;
public PlayArea getPlayArea() throws RemoteException;
public int getPlayerScore() throws RemoteException;
public void setPlayerName(String name) throws RemoteException;
public void setPlayer(PlayerInfo pi) throws RemoteException;
public String getPlayerName() throws RemoteException;
}
这是我创建的文件GameServer.java
import java.io.IOException;
import java.io.Serializable;
import java.net.MalformedURLException;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.rmi.server.UnicastRemoteObject;
import java.util.LinkedList;
/**
* Created with IntelliJ IDEA.
* User: akay
* Date: 25/11/2013
* Time: 19:07
* To change this template use File | Settings | File Templates.
*/
public class GameServer extends UnicastRemoteObject implements IGameServer, Serializable {
LinkedList<IGUI> array;
GameEngine ge = new GameEngine(25);
public GameServer() throws RemoteException {
array = new LinkedList();
}
@Override
public PlayingBlock getNextBlock() throws RemoteException {
return ge.getNextBlock();
}
@Override
public PlayArea getPlayArea() throws RemoteException {
return ge.getPlayArea();
}
@Override
public String getPlayerName() {
return ge.getPlayerName();
}
@Override
public int getPlayerScore() {
return ge.getPlayerScore();
}
@Override
public boolean isGameOver() throws RemoteException {
return ge.isGameOver();
}
@Override
public void registerClient(IGUI clientGUI) throws RemoteException {
array.add(clientGUI);
ge.setGUI(clientGUI);
}
@Override
public void setGameOver() throws RemoteException {
ge.setGameOver();
}
@Override
public void setPlayer(PlayerInfo pi) {
ge.setPlayer(pi);
}
@Override
public void setPlayerName(String name) {
ge.setPlayerName(name);
}
@Override
public void start() throws RemoteException {
ge.start();
}
@Override
public void treatEvent(int event) throws RemoteException {
ge.treatEvent(event);
}
public static void main(String args[]) throws RemoteException {
Registry registry;
GameServer s;
final int port = Registry.REGISTRY_PORT;
if (System.getSecurityManager() == null) {
System.setSecurityManager(new java.rmi.RMISecurityManager());
}
try {
registry = LocateRegistry.createRegistry(port);
}
catch (RemoteException e) {
System.out.println("The registry couldn't be created.");
e.printStackTrace();
}
try {
s = new GameServer();
java.rmi.Naming.rebind("Server", s);
}
catch (MalformedURLException e) {
System.out.println("Bad server URI in registration.");
}
catch (RemoteException e) {
System.out.println("Couldn't bind server.");
e.printStackTrace();
}
try {
System.in.read();
}
catch (IOException e) {
}
System.exit(0);
}
}
修改了这些文件以修复错误并实施RMI。现在,应该采取的步骤如下:
GameClient
和IGUI
的{{1}}类
IGameEngine
接口。它将使用注册表找到服务器,
并接受来自GUI
的本地电话,将其转换为远程电话
调用服务器并返回任何结果。GUI
类,使其对GameEngine
的引用的类型为IGameEngine
,而不是Squares
类将启动游戏的客户端部分,现在需要创建GameClient
的实例并将其作为参考传递给GUI
到IGameEngine
GameServer
接口的IGameServer
类,并包含启动服务器和游戏引擎的main()
方法GameEngine
类,使其对GUI
的引用现在为IGUI
类型;这将是它对客户端的远程引用。由于GameEngine
现在远程调用GUI
,您需要捕获一些例外情况。这些是建议的步骤。我已经实现了除了一个之外的所有,这是第三个。
感谢任何帮助。
如果您想下载zip文件中的所有文件,请输入:http://akay.me/gameCode.zip
感谢您的任何指示。
编辑:
我编辑了我的Squares
类,通过包含以下内容从注册表中获取服务器名称:
String host = null;
Registry registry = LocateRegistry.getRegistry(host);
IGameServer s = (IGameServer) registry.lookup("Server");
GameClient gc = new GameClient(s);
正如所建议的那样。
现在我收到以下错误:
java.rmi.MarshalException: error marshalling arguments; nested exception is:
java.io.NotSerializableException: PlayerInfo
at sun.rmi.server.UnicastRef.invoke(UnicastRef.java:138)
at java.rmi.server.RemoteObjectInvocationHandler.invokeRemoteMethod(RemoteObjectInvocationHandler.java:178)
at java.rmi.server.RemoteObjectInvocationHandler.invoke(RemoteObjectInvocationHandler.java:132)
at com.sun.proxy.$Proxy0.setPlayer(Unknown Source)
at GameClient.setPlayer(GameClient.java:80)
at Squares.main(Squares.java:21)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:120)
Caused by: java.io.NotSerializableException: PlayerInfo
at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1165)
at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:329)
at sun.rmi.server.UnicastRef.marshalValue(UnicastRef.java:274)
at sun.rmi.server.UnicastRef.invoke(UnicastRef.java:133)
... 10 more
Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
at GameEngine.getPlayerName(GameEngine.java:67)
答案 0 :(得分:2)
您确实需要学习阅读错误消息。它们具有问题的精确位置,并且问题的描述也很清楚:
GameClient类中的构造函数GameClient不能应用于给定的类型; required:发现IGameServer:无参数原因:实际和正式参数列表的长度不同
那么,这是什么意思?这意味着你在没有任何参数的情况下调用new GameClient()
,而GameClient的构造函数被声明为
public GameClient(IGameServer ss) throws RemoteException {
因此,您必须将IGameServer类型的对象传递给构造函数,而不是传递任何内容。