有关多人网络的问题:输入

时间:2015-06-10 00:15:32

标签: java networking tcp udp

我们正在为学校制作一个六人多人游戏,我负责一个网络课程。该游戏采用了Slick 2D。在游戏中有实体(代码如下所示)

    package Game; 

import org.newdawn.slick.*;

public abstract class Entity {
    double maxHealth, health, speed, damage, width, height, locationX, locationY;
    Animation standing, walkingLeft, walkingRight, attacking, jumping, current;
    long pastTime = 0;

    public boolean isReadyToAttack(long delta) {
        if(pastTime < 2 * 500) { //multiply by 1000 to get milliseconds
            pastTime += delta;
            return false;
        }else{
            pastTime = 0;
            return true;
        }
    }

    public void setMaxHealth(double d){
        maxHealth = d;
    }
    public void setHealth(double d){
        health = d;
    }

    public void setSpeed(double x){
        speed = x;
    }

    public void setDamage(double x){
        damage = x;
    }
    public void setLocation(double x, double y){
        locationX = x;
        locationY = y;
    }
    public void setSprites(Animation s, Animation r){
        standing = s;
        walkingRight = r;
    }
    public void setCurrent(Animation a){
        current = a;
    }
    public double getMaxHealth(){
        return maxHealth;
    }
    public double getHealth(){
        return health;
    }

    public double getSpeed(){
        return speed;
    }

    public double getDamage(){
        return damage;
    }

    public double getLocationX(){
        return locationX;
    }

    public double getLocationY(){
        return locationY;
    }
    public Animation getStanding(){
        return standing;
    }
    public Animation getRight(){
        return walkingRight;
    }
    public Animation getCurrent(){
        return current;
    }
    public abstract double getAttackRange();
}

实体类也由Heroes类扩展,该类由Ares类进一步扩展。 Ares是我们游戏中的六个角色之一,当你开始游戏时,你可以从开始菜单中的六个中选择一个。

这是Hero课程:

    package Game;

import org.newdawn.slick.Animation;

public abstract class Hero extends Entity{

    static double gravity = 0.1;
    double velocity;
    int level;
    boolean disabled, grounded = true;

    public void setLevel(int i){
        level = i;
    }
    public void setVelocity(double d){
        velocity = d;
    }
    public void setDisabled(boolean b){
        disabled = b;
    }
    public void setGrounded(boolean b){
        grounded = b;
    }
    public int getLevel(){
        return level;
    }
    public double getVelocity(){
        return velocity;
    }
    public boolean getDisabled(){
        return disabled;
    }
    public boolean getGrounded(){
        return grounded;
    }
    public double getGravity(){
        return gravity;
    }

    public boolean isAlive(){
        if(getHealth() > 0)
            return true;
        return false;
    }

    public void attack(Entity gettingAttacked, Hero attacking) {
        gettingAttacked.setHealth(gettingAttacked.getHealth() - attacking.getDamage());
    }

    public boolean isReadyToRegenerate(long delta) {
        if(pastTime < 1 * 1000){
            pastTime += delta;
            return false;
        }
        else{
            pastTime = 0;
            return true;
        }
    }   

    public static void regenerate(Hero h, long delta){
        if(h.getHealth() >= 0 && h.getHealth() < h.getMaxHealth())
            if(h.isReadyToRegenerate(delta))
                h.setHealth(h.getHealth() + (h.getMaxHealth()) * 0.01);
    }
    public abstract void levelUp();
}

这是Ares类:

   package Game;

import org.newdawn.slick.Animation;
import org.newdawn.slick.SlickException;
import org.newdawn.slick.SpriteSheet;

public class Ares extends Hero {

    public Ares() throws SlickException {
        setHealth(500);
        setSpeed(0.4);
        setDamage(70);
        setLocation(850,625);
        setSprites(new Animation(new SpriteSheet("res/Ares.png", 191, 275), 200), new Animation(new SpriteSheet("res/AresWalk.png", 191, 275), 200));
    }

    public void levelUp() {
        level += 1;
        health *= 1.1;
        damage *= 1.1;
    }

    public double getAttackRange() {
        return 250;
    }

    public double maxHealth() {
        return 500;
    }

}

这是战斗代码,其中包含主要的游戏代码,代码目前尚未完成且只有动作:

 package Game;

import java.util.ArrayList;

import org.lwjgl.input.*;
import org.newdawn.slick.*;
import org.newdawn.slick.geom.Rectangle;
import org.newdawn.slick.state.*;

public class Battle extends BasicGameState {

    private ArrayList<Entity> entities = new ArrayList<Entity>();
    private Hero player;
    private Image background;
    private int midScreen, ground;

    public void init(GameContainer gc, StateBasedGame sbg) throws SlickException{
        gc.setVSync(true);
        player = new Ares();
        player.setCurrent(player.getStanding());
        entities.add(player);
        background = new Image("res/Background.png");
        midScreen = 800;
        ground = 625;
    }


    public void render(GameContainer gc, StateBasedGame sbg, Graphics g) throws SlickException{
        g.translate((float)-player.getLocationX() + midScreen, (float)-player.getLocationY() + ground);
        background.draw(0, -920);
        for(int i = 0; i < entities.size(); i++)
            entities.get(i).getCurrent().draw((float)entities.get(i).getLocationX(), (float)entities.get(i).getLocationY());
    }

    public void update(GameContainer gc, StateBasedGame sbg, int delta) throws SlickException {
            player.getCurrent().update(delta); // ensures
            Input kb = gc.getInput();

            if (kb.isKeyDown(Input.KEY_SPACE) && player.getGrounded()) {
                player.setGrounded(false);
                player.setVelocity(7);
               player.setLocation(player.getLocationX(), player.getLocationY() - player.getVelocity());
                player.setCurrent(player.getStanding());
            }
            else if (kb.isKeyDown(Input.KEY_A) && player.getLocationX() > 800) {
                player.setLocation(player.getLocationX() - player.getSpeed() * delta, player.getLocationY());
                if(player.grounded)
                    player.setCurrent(player.getRight());
            }
            else if (kb.isKeyDown(Input.KEY_D) && player.getLocationX() < 8580) {
                player.setLocation(player.getLocationX() + player.getSpeed() * delta, player.getLocationY());
                if(player.grounded)
                    player.setCurrent(player.getRight());
            }
            else
                player.setCurrent(player.getStanding());

            if (Math.abs(player.getLocationY() - ground) < .01)
                player.setGrounded(true);
            if (player.getGrounded() == false) {
                player.setVelocity(player.getVelocity() - player.getGravity());
                player.setLocation(player.getLocationX(), player.getLocationY() - player.getVelocity());
            }
            //else if (kb.isKeyDown(Input.KEY_A)) //&& (!(aresRect.intersects(turretRect))))
            //{
            //  x -= 0.3 * delta;
            //}        
            //if(kb.isKeyDown(Input.KEY_S)) 
            //  y += 0.3 * delta;
            //else if (kb.isKeyDown(Input.KEY_W)) //&& (!(aresRect.intersects(turretRect))))
            //    y -= 0.3 * delta;   
    }    

    public int getID(){
        return 1;
    }
}

我遇到的困难是创建一个服务器和客户端来获取玩家的输入,例如位置,谁选择了哪个玩家等等。我想知道如果在战斗中,当Player对象被制作时,我怎样才能获得对象的位置和其他特定属性并将它们提供给其他计算机?

到目前为止,我用网络代码得到的最远的是聊天服务器,但我很困惑如何将部分信息应用到游戏中以包括从用户那里获取输入。我看了很多关于创建多玩家网络的教程,但我仍感到困惑。至于我的经验,我有大约2年的编码经验(只有一个用Java),但这是我第一次使用网络。我尝试了UDP连接,这是我的服务器:

    package net;


import java.io.*;
import java.net.*;
import java.util.*;

import main.Game;
import packets.*;
import packets.Packet.PacketTypes;

public class GameServer extends Thread{
    private DatagramSocket socket;
    private Game game;
    private List<PlayerMP> connectedPlayers = new ArrayList <PlayerMP>();

    public GameServer(Game game){ 
        this.game = game;
        try {
            socket = new DatagramSocket(7777);
        } catch (SocketException e) {
            e.printStackTrace();
        }
    }

    public void run(){
        while(true){
            byte[] data = new byte[1024];
            DatagramPacket packet = new DatagramPacket(data, data.length);
            try {
                socket.receive(packet);
            } catch(IOException e) {
                e.printStackTrace();
            }
            parsePacket(packet.getData(), packet.getAddress(), packet.getPort());

        }
    }


    private void parsePacket(byte[] data, InetAddress address, int port) {
        String message = new String(data).trim();
        PacketTypes type = Packet.lookupPacket(message.substring(0,  2));
        Packet packet = null;
        switch(type) {
        default :
        case INVALID:
            break;
        case LOGIN:
            packet = new Packet00Login(data);
            System.out.println("[" + address.getHostAddress() + ":" + port + "] " + ((Packet00Login) packet).getUsername() + 
                    " has connected.");
            PlayerMP player = new PlayerMP(address, port);
            this.addConnection(player, ((Packet00Login)packet));
            this.connectedPlayers.add(player);
            break;
        case DISCONNECT:
            break;
        case MOVE:
            packet = new Packet02Move(data);
            System.out.println(((Packet02Move)packet).getName() +"has moved to" + ((Packet02Move)packet).getX() + "," + ((Packet02Move)packet).getY());
            this.handleMove((Packet02Move)packet);
        }

    }

    private void handleMove(Packet02Move packet) {
        if (getPlayerMP(packet.getUsername()) != null){
            int index = getPlayerMPIndex(getName());
            this.connectedPlayers.get(index).locationY = packet.getX();
            this.connectedPlayers.get(index).locationX = packet.getX();
            packet.writeData(this);

        }
    }

    public void addConnection(PlayerMP player, Packet00Login packet) {
        boolean alreadyConnected = false;
        for(PlayerMP p : this.connectedPlayers) {
            if (player.getUsername().equalsIgnoreCase(p.getUsername())) {
                if(p.ipAddress == null){
                    p.ipAddress = player.ipAddress;
                }
                if(p.port == -1) {
                    p.port = player.port;
                }
                alreadyConnected = true;
            }  else {
                sendData(packet.getData(), p.ipAddress, p.port);
                packet = new Packet00Login(p.getUsername());
                sendData(packet.getData(), player.ipAddress, player.port);
            }
            if (alreadyConnected){
                this.connectedPlayers.add(player);
                packet.writeData(this);
            }
        }
    }

    public void sendData(byte[] data, InetAddress ipAddress, int port) {
        DatagramPacket packet = new DatagramPacket(data, data.length, ipAddress, port);
        try {
            socket.send(packet);
        } catch(IOException e) {
            e.printStackTrace();
        }
    }

    public void sendDataToAllClients(byte[] data) {
        for(PlayerMP p : connectedPlayers)
            sendData(data, p.ipAddress, p.port);
    }
}

我无法弄清楚如何比使用TCP连接来回发送消息更进一步:

    import java.io.*;
import java.net.*;

public class Server {
    private static ServerSocket serverSocket;
    private static Socket socket;
    private static DataOutputStream out;
    private static Users[] user = new Users[6];
    private static DataInputStream in;

    public static void main(String[] args) throws Exception{
        System.out.println("Starting server");
        serverSocket = new ServerSocket(0);
        System.out.println("Server Started");
        while(true){
        socket = serverSocket.accept();
        for (int i = 0; i < 6; i++){
        System.out.println("Connection from: " + socket.getInetAddress());
        out = new DataOutputStream(socket.getOutputStream());
        in = new DataInputStream(socket.getInputStream());
        if (user[i] == null){
            user[i] = new Users(out, in, user);
            Thread thread = new Thread();
            thread.start();
            break;
        }
        }
        }
    }
}

class Users implements Runnable{
    private DataOutputStream out;
    private DataInputStream in;
    private Users[] user = new Users[6];
    public Users(DataOutputStream fromOut, DataInputStream goingIn, Users[] userArr){
        out = fromOut;
        in = goingIn;
        user = userArr;
    }
    public void run(){
        while(true){
            try{
                String message = in.readUTF();
                for (int i = 0; i < 6; i++){
                    if (user[i] != null)
                        user[i].out.writeUTF(message);
                }
            }catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

我想弄明白这一点。我甚至不确定从哪里开始,或者我是否走在正确的轨道上。

注意:我使用Java进行编码,并尝试使用TCP连接对此进行编码。如果您认为它可能更容易,我对UDP开放。

0 个答案:

没有答案