2016-04-28 36 views
1

我在java中制作了一个简单的球和桨多人游戏。它使用MultiCastSocket来发送和接收数据。球仅在球员系统上移动
1.球的位置由网络上的所有球员发送。所有球员都会收到这些数据,但只有p1以外的球员阅读并更新球位。现在问题在于,虽然球在p1上平稳移动,但在其他球员的系统上却不是连续运动。下面是我的代码的网络部分的代码片段: (这里myTag是玩家号码 rec是接收数据类的对象,它接收数据并存储在一个字符串中datajava多人游戏平滑网络运作

private class ScheduleTask extends TimerTask { 

    @Override 
    public void run() { 


     paddleArr[myTag].moveX(); 

     for(int i=0; i<4; i++){ 
      if(i != myTag){ 
       if(!others.contains(i)){ 
        Computer comPaddle = new Computer(paddleArr[i], ball); 
        if(paddleArr[i].isHorizontal()){comPaddle.moveSideways();} 
        else {comPaddle.move();} 
       } 
      } 
     } 
     if(myTag==0){ball.move();} 

     if(ball.getXdir()*ball.getXdir()+ball.getYdir()*ball.getYdir() >= 80){ 
      ball.setXdir(ball.getXdir()*0.67); 
      ball.setYdir(ball.getYdir()*0.67); 
     } 


     if(newgame){ 
      try { 
      socket = new MulticastSocket(4446); 
      group =InetAddress.getByName("228.6.7.8"); 
      socket.joinGroup(group); 
     } catch (IOException e) { 
      // TODO Auto-generated catch block 

      System.out.println("error"); 
     } 
      rec = new ReceiveData(socket, group, port, myTag); 
     newgame = false; 
     } 

     //System.out.println(rec.data); 

     if(bak > 10){ 
      setAllPos(rec.data.trim()); 
     } 
     bak++; 

     checkCollision(); 
     repaint(); 

     try { 
      socket = new MulticastSocket(4446); 
      group = InetAddress.getByName("228.6.7.8"); 
     } catch (IOException e) { 
      // TODO Auto-generated catch block 
      e.printStackTrace(); 
     } 
     String str = myTag+" "+(ball.getMyX())+" "+(ball.getMyY())+" "+(ball.getXdir())+" "+(ball.getYdir())+" "+(paddleArr[myTag].getMyX())+" "+(paddleArr[myTag].getMyY()); 
     buf = str.getBytes(); 
     // Create a DatagramPacket 
     DatagramPacket packet = new DatagramPacket(buf, buf.length,group, 4446); 
     // Do a send. 
     try { 
      socket.send(packet); 
     } catch (IOException e) { 
      // TODO Auto-generated catch block 
      System.out.println("send failed"); 
     } 
     // And when we have finished sending data close the socket 
     socket.close(); 

    } 
} 

public void setAllPos(String s){ 
    //System.out.println(s); 
    String[] data = s.split(" "); 
    if(myTag != 0){ 
     if(data[0].equals("0")) 
     { 
      ball.setMyX(Double.parseDouble(data[1])); 
      ball.setMyY(Double.parseDouble(data[2])); 
      ball.setXdir(Double.parseDouble(data[3])); 
      ball.setYdir(Double.parseDouble(data[4])); 
      repaint(); 
      //ball.move(); 
      //paddleBottom.setMyX(Integer.parseInt(data[5])); 
      //content.udpPosition = data[5]; 
      //System.out.println("Ball pos set"); 
     } 
    } 

回答

0

不幸的是,你不能通过应用你通过网络获得的最新职位来进行网络游戏。带宽浪费(因为您需要每帧发送至少一条消息)并且不可靠(因为网络数据包可能会有随机延迟,所以您会看到不均匀的运动)。

有解决这个问题的两个基本选项,并可以将它们合并为更好的结果:

1)保持球的地方“影子”副本代表正在发生的事情上稍微延迟版本的每个客户端上其他机器。然后,当您收到网络更新时,不是跳到新位置,而是开始在当前位置和目标位置之间进行插值,以便在短时间内到达那里。如果您在此期间收到新的更新,则开始插入新位置。这样,你就不会感觉到任何奇怪的跳跃,代价是轻微的常数滞后(可以合理地低)

2)不是只发送位置,而是发送速度(你已经这么做)。在此基础上对每台机器进行模拟运动,而不是基于位置更新。一切都将平稳,但你可能会失去同步的位置和错误将复合

正确的解决方案是复合两种解决方案。内插位置并对接收到的速度执行模拟(如果需要,也可以进行时间插值)。

你可以在这里阅读关于它背后的一些数学知识 https://en.wikipedia.org/wiki/Dead_reckoning#Dead_reckoning_for_networked_games 加上在网上查找'dead reckoning'了解更多详情。在gamasutra上应该有不少文章。

你可能也想看看 http://trac.bookofhook.com/bookofhook/trac.cgi/wiki/Quake3Networking 和QUAKE3网络协议其他来源 - 这是很好的例子,它如何能够非常有效的方式来完成与非可靠的网络(并为您介绍https://en.wikipedia.org/wiki/Lamport_timestamps隐含在此期间)

+0

非常感谢!它现在就像一种魅力:) – Sarvesh