因此,在我正在制作的游戏中,我正在尝试通过套接字发送类型为Troop的类型列表和Tower类型的ArrayList,其中类Troop和Tower都具有缓冲图像。游戏以60 fps运行,每次在updateConnection()方法中通过服务器和客户端之间的两个ArrayLists发送。当我拿出Troop类和服务器和客户端类时,我成功地能够通过ArrayLists发送,但是我得到一个错误,说当Troop在游戏中运行时不可消毒。下面我包括了Troop类,服务器和客户端类,运行测试发送和接收的两个类,以及Game类中的方法updateConnection():
public class Server{
private ObjectOutputStream output;
private ObjectInputStream input;
private ServerSocket server;
private Socket connection;
JTextArea t;
JFrame f;
//constructor
public Server(){
f = new JFrame();
f.getContentPane().setPreferredSize(new Dimension(300, 300));
f.pack();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setLocationRelativeTo(null);
t = new JTextArea();
f.add(t, BorderLayout.CENTER);
f.setVisible(true);
try{
server = new ServerSocket(8790, 10); //8798 is a dummy port for testing, this can be changed. The 100 is the maximum people waiting to connect.
try{
//Trying to connect and have conversation
waitForConnection();
setupStreams();
}catch(EOFException eofException){
//t.append("Connection was terminated");
}
} catch (IOException ioException){
ioException.printStackTrace();
}
}
//wait for connection, then display connection information
private void waitForConnection() throws IOException{
t.append(" Waiting for someone to connect...");
connection = server.accept();
t.append(" Now connected to " + connection.getInetAddress().getHostName());
}
//get stream to send and receive data
private void setupStreams() throws IOException{
output = new ObjectOutputStream(connection.getOutputStream());
output.flush();
input = new ObjectInputStream(connection.getInputStream());
t.append(" Streams are now setup ");
f.setVisible(false);
f.dispose();
}
// input.readObject();
public void closeConnection(){
//t.append(" Closing Connections... ");
try{
output.close(); //Closes the output path to the client
input.close(); //Closes the input path to the server, from the client.
connection.close(); //Closes the connection between you can the client
}catch(IOException ioException){
ioException.printStackTrace();
}
}
public ObjectOutputStream getOutput(){
return output;
}
public ObjectInputStream getInput(){
return input;
}
public void sendObjects(Object obj){
try {
output.writeObject(obj);
output.flush();
output.reset();
} catch (IOException e) {
e.printStackTrace();
}
}
public Object receiveObjects(){
try{
return input.readObject();
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
return null;
}
}
}
public class Client extends JFrame{
private static final long serialVersionUID = 1L;
private ObjectOutputStream output;
private ObjectInputStream input;
private String serverIP;
private Socket connection;
JTextArea t;
JFrame f;
//constructor
public Client(String host){
serverIP = host;
f = new JFrame();
f.getContentPane().setPreferredSize(new Dimension(300, 300));
f.pack();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setLocationRelativeTo(null);
t = new JTextArea();
f.add(t, BorderLayout.CENTER);
f.setVisible(true);
try{
connectToServer();
setupStreams();
}catch(EOFException eofException){
//t.append("Connection was terminated");
}catch(IOException ioException){
ioException.printStackTrace();
}
}
public Client(){
serverIP = "127.0.0.1";
f = new JFrame();
f.getContentPane().setPreferredSize(new Dimension(300, 300));
f.pack();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setLocationRelativeTo(null);
t = new JTextArea();
f.add(t, BorderLayout.CENTER);
f.setVisible(true);
try{
connectToServer();
setupStreams();
}catch(EOFException eofException){
//t.append("Connection was terminated");
}catch(IOException ioException){
ioException.printStackTrace();
}
}
//connect to server
private void connectToServer() throws IOException{
t.append("Attempting connection...");
connection = new Socket(InetAddress.getByName(serverIP), 8790);
t.append("Connection Established! Connected to: " + connection.getInetAddress().getHostName());
}
//set up streams
private void setupStreams() throws IOException{
output = new ObjectOutputStream(connection.getOutputStream());
output.flush();
input = new ObjectInputStream(connection.getInputStream());
t.append(" The streams are now set up!");
f.setVisible(false);
f.dispose();
}
//Close connection
public void closeConnection(){
//t.append(" Closing the connection!");
try{
output.close();
input.close();
connection.close();
}catch(IOException ioException){
ioException.printStackTrace();
}
}
public ObjectOutputStream getOutput(){
return output;
}
public ObjectInputStream getInput(){
return input;
}
public void sendObjects(Object obj){
try {
output.writeObject(obj);
output.flush();
output.reset();
} catch (IOException e) {
e.printStackTrace();
}
}
public Object receiveObjects(){
try{
return input.readObject();
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
return null;
}
}
}
public class Troop implements Serializable{
private int x;
private int y;
private int health;
private int movSpeed;
private int movSpeedx;
private int movSpeedy;
private int cost;
private long deployCoolDown;
private int level;
private transient BufferedImage image;
private int size = 16;
private Handler handler;
/**
*
* @param x
* @param y
* @param level
* @param health
* @param movSpeed
* @param movSpeedx
* @param movSpeedy
* @param cost
* @param deployCoolDown
* @param image
*
*/
public Troop(int x, int y, int level, int health, int movSpeed, int movSpeedx, int movSpeedy, int cost, long deployCoolDown, BufferedImage image, Handler handler){
this.x = x;
this.y = y;
this.level = level;
this.health = health;
this.movSpeed = movSpeed;
this.movSpeedx = -movSpeed;
this.movSpeedy = movSpeedy;
this.cost = cost;
this.deployCoolDown = deployCoolDown;
this.image = image;
this.handler = handler;
}
public void update(){
Move();
if(health <= 0){
handler.getTroops().remove(this);
}
}
public void checkX(){
int z = 0;
int tempMovSpeed = movSpeed;
if(tempMovSpeed> 0){ //moving down
int ty = (int) (y + tempMovSpeed + size + size/2) / Tile.TILE_WIDTH;
if(!collisionWithTile((int) (x) / Tile.TILE_HEIGHT,ty) &&
!collisionWithTile((int) (x + size) / Tile.TILE_HEIGHT,ty) &&
!collisionWithTile((int) (x + size/2) / Tile.TILE_HEIGHT,ty)){
z = 1;
}else{
//System.out.println("collision moving down");
}
}
tempMovSpeed = -movSpeed;
if(tempMovSpeed < 0){ // up
int ty = (int) (y + tempMovSpeed - size/2) / Tile.TILE_WIDTH;
if(!collisionWithTile((int) (x) / Tile.TILE_HEIGHT,ty) &&
!collisionWithTile((int) (x + size) / Tile.TILE_HEIGHT,ty) &&
!collisionWithTile((int) (x + size/2) / Tile.TILE_HEIGHT,ty)){
if(z == 1){
z = 3;
}
else{
z = 2;
}
}else{
//System.out.println("collision moving up");
}
}
//System.out.println(z);
if(z == 0){
//System.out.println("dead end?");
}
else if(z == 1){
movSpeedy = movSpeed;
}
else if(z == 2){
movSpeedy = -movSpeed;
}
else if(z == 3){
Random r = new Random();
int q = r.nextInt(2);
if(q == 0){
movSpeedy = movSpeed;
}
else{
movSpeedy = -movSpeed;
}
}
}
public void checkY(){
int z = 0;
int tempMovSpeed = movSpeed;
int tx = (int) (x + tempMovSpeed + size + size/2) / Tile.TILE_WIDTH;
if(!collisionWithTile(tx, (int) (y) / Tile.TILE_HEIGHT) &&
!collisionWithTile(tx, (int) (y + size) / Tile.TILE_HEIGHT) &&
!collisionWithTile(tx, (int) (y + size/2) / Tile.TILE_HEIGHT)){
z = 1;
}
tempMovSpeed = -movSpeed;
tx = (int) (x + tempMovSpeed - size/2) / Tile.TILE_WIDTH;
if(!collisionWithTile(tx, (int) (y) / Tile.TILE_HEIGHT) &&
!collisionWithTile(tx, (int) (y + size) / Tile.TILE_HEIGHT) &&
!collisionWithTile(tx, (int) (y + size/2) / Tile.TILE_HEIGHT)){
if(z != 1){
z = 2;
}
else{
z = 3;
}
}
if(z == 0){
//System.out.println("dead end");
}
else if(z == 1){
movSpeedx = movSpeed;
}
else if(z == 2){
movSpeedx = -movSpeed;
}
else{
Random r = new Random();
int q = r.nextInt(1);
if(q == 0){
movSpeedx = movSpeed;
}
else{
movSpeedx = -movSpeed;
}
}
}
protected boolean collisionWithTile(int x, int y){
return !handler.getWorlds().get(handler.getGame().getLevel()).getTile(x, y).isPath();
}
public void render(Graphics g){
g.setColor(Color.GREEN);
g.fillRect(x, y, size, size);
}
public void Move(){
if(movSpeedx > 0){ //moving right
int tx = (int) (x + movSpeedx + size + size/2) / Tile.TILE_WIDTH;
if(!collisionWithTile(tx, (int) (y) / Tile.TILE_HEIGHT) &&
!collisionWithTile(tx, (int) (y + size) / Tile.TILE_HEIGHT) &&
!collisionWithTile(tx, (int) (y + size/2) / Tile.TILE_HEIGHT)){
x += movSpeedx;
}else{
x = tx * Tile.TILE_WIDTH - 3 * size /2;
checkX();
movSpeedx = 0;
}
}
else if(movSpeedx < 0){ // left
int tx = (int) (x + movSpeedx - size/2) / Tile.TILE_WIDTH;
if(!collisionWithTile(tx, (int) (y) / Tile.TILE_HEIGHT) &&
!collisionWithTile(tx, (int) (y + size) / Tile.TILE_HEIGHT) &&
!collisionWithTile(tx, (int) (y + size/2) / Tile.TILE_HEIGHT)){
x += movSpeedx;
}else{
x = tx * Tile.TILE_WIDTH + Tile.TILE_WIDTH + size/2;
checkX();
movSpeedx = 0;
}
}
if(movSpeedy > 0){ //moving down
int ty = (int) (y + movSpeedy + size + size/2) / Tile.TILE_WIDTH;
if(!collisionWithTile((int) (x) / Tile.TILE_HEIGHT, ty) &&
!collisionWithTile((int) (x + size) / Tile.TILE_HEIGHT, ty) &&
!collisionWithTile((int) (x + size/2) / Tile.TILE_HEIGHT, ty)){
y += movSpeedy;
}else{
//System.out.println("collision");
y = ty * Tile.TILE_WIDTH - 3 * size /2;
movSpeedy = 0;
checkY();
}
}
else if(movSpeedy < 0){ // up
int ty = (int) (y + movSpeedy - size/2) / Tile.TILE_WIDTH;
if(!collisionWithTile((int) (x) / Tile.TILE_HEIGHT, ty) &&
!collisionWithTile((int) (x + size) / Tile.TILE_HEIGHT, ty) &&
!collisionWithTile((int) (x + size/2) / Tile.TILE_HEIGHT, ty)){
y += movSpeedy;
}else{
y = ty * Tile.TILE_WIDTH + Tile.TILE_WIDTH + size/2;
movSpeedy = 0;
checkY();
}
}
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
public int getSize(){
return size;
}
public int getMovSpeed() {
return movSpeed;
}
public void setMovSpeed(int movSpeed) {
this.movSpeed = movSpeed;
}
public int getHealth() {
return health;
}
public void changeHealth(int health) {
this.health += health;
}
public int getCost() {
return cost;
}
public void setCost(int cost) {
this.cost = cost;
}
public long getDeployCoolDown() {
return deployCoolDown;
}
public void setDeployCoolDown(int deployCoolDown) {
this.deployCoolDown = deployCoolDown;
}
private void writeObject(ObjectOutputStream out)throws IOException{
out.defaultWriteObject();
}
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException{
in.defaultReadObject();
}
}
来自Game的方法(每秒调用60次):
private void updateConnection(){
if(isClientActive()){
if(player.getType() == 0){
client.sendObjects(towers);
System.out.println("sent towers: " + towers.size());
}else{
client.sendObjects(troops);
System.out.println("sent troops: " + troops.size());
}
ArrayList<Object> obj = (ArrayList<Object>)client.receiveObjects();
System.out.println("obj: " +obj.size());
if(obj != null && obj.size() > 0){
if (obj.get(0) instanceof Troop) {
mendTroops(obj);
}else if(obj.get(0) instanceof Troop){
mendTowers(obj);
}
}
}else if(isServerActive()){
if(player.getType() == 0){
server.sendObjects(towers);
System.out.println("sent towers: " + towers.size());
}else{
server.sendObjects(troops);
System.out.println("sent troops: " + troops.size());
}
ArrayList<Object> obj = (ArrayList<Object>)server.receiveObjects();
System.out.println("obj: " +obj.size());
if(obj != null && obj.size() > 0){
if (obj.get(0) instanceof Troop) {
mendTroops(obj);
}else if(obj.get(0) instanceof Troop){
mendTowers(obj);
}
}
}
}
以下是我调用服务器,客户端和部队类的两种主要方法:
public static void main(String[] args){
Server s = new Server();
ArrayList<Troop> troopsArray = new ArrayList<Troop>();
troopsArray.add(new Goblin(1,1,1));
troopsArray.add(new Goblin(2,2,2));
s.sendObject(troopsArray);
}
public static void main(String[] args){
Client c = new Client();
while(true){
ArrayList<Troop> troop2 = (ArrayList<Troop>)c.receiveObjects();
JOptionPane.showMessageDialog(null, troop2.get(1).getX());
}
}
以下是请求的Handler代码:
public class Handler implements Serializable{
private Game game;
private transient Player player;
private transient ArrayList<Tower> towers;
private transient ArrayList<Troop> troops;
private transient Screen screen;
private transient Frame frame;
private transient Menu menu;
private ArrayList<Worlds> worlds;
public Handler(Game game, Player player, ArrayList<Tower> towers, ArrayList<Troop> troops, Screen screen, Frame frame, Menu menu, ArrayList<Worlds> worlds){
this.game = game;
this.player = player;
this.towers = towers;
this.troops = troops;
this.screen = screen;
this.frame = frame;
this.menu = menu;
this.worlds = worlds;
}
public Server getServer(){
return game.getServer();
}
public Client getClient(){
return game.getClient();
}
public ArrayList<Worlds> getWorlds() {
return worlds;
}
public Game getGame() {
return game;
}
public Player getPlayer() {
return player;
}
public ArrayList<Tower> getTowers() {
return towers;
}
public ArrayList<Troop> getTroops() {
return troops;
}
public Screen getScreen() {
return screen;
}
public Frame getFrame() {
return frame;
}
public Menu getMenu() {
return menu;
}
public boolean towerCollisionWithTile(int x, int y){
return worlds.get(game.getLevel()).getTile(x, y).isTowerNotPlaceable();
}
}
世界级:
public class Worlds implements Serializable{
private int width = 40;
private int height = 20; //in tiles
private int spawnX, spawnY;
private int[][] tiles;
public Worlds(String path){
loadWorld(path);
}
public Tile getTile(int x, int y){
if(x < 0 || y < 0 || x >= width || y >= height)
return Tile.grassTile;
Tile t = Tile.tiles[tiles[x][y]];
if(t == null)
return Tile.grassTile;
return t;
}
public void render(Graphics g){
for(int y = 0; y < height; y++){
for(int x = 0; x < width; x++){
getTile(x, y).render(g, (int) (x * Tile.TILE_WIDTH),
(int) (y* Tile.TILE_HEIGHT));
}
}
}
private void loadWorld(String path){
String file = Utils.loadFileAsString(path);
String [] tokens = file.split("\\s");
tiles = new int[width][height];
for(int y = 0; y < height; y++){
for(int x = 0; x < width; x++){
tiles[x][y] = Utils.parseInt(tokens[(x + y * width)]);
}
}
}
}
很抱歉,如果我发布了太多代码,但我宁愿有点太多,还不够。如果需要,我可以发布错误控制台的内容。我很感激帮助。
答案 0 :(得分:0)
处理程序似乎是this,不可序列化。你需要像BufferedImage一样使它成为瞬态。
答案 1 :(得分:0)
归功于Ian和CConard96。问题是,虽然我试图发送的类是可序列化的,但它所引用的引用却没有。为了减少我通过套接字发送的内容(从而简化它以便更少需要可序列化)我能够通过使用静态引用来解决问题,从而消除它们(非序列化类)被写入的ObjectOutputStream。
虽然瞬态可以起作用,但在这种情况下并不理想。它将导致发送的对象具有对瞬态的任何空引用。因此Handler变量以及缓冲的Image需要以不同的方式传递。