【问题标题】:Developing a Networked Game [closed]开发网络游戏[关闭]
【发布时间】:2012-08-06 00:58:04
【问题描述】:

我是一名中级经验的程序员,我想创建一个网络游戏。我无法决定我应该为这款游戏选择哪种网络“模型”。

“模型”是指信息应该从服务器传输到客户端的方法以及实际发生处理的位置。目前,这是我正在考虑的模型:

  • 假设有四个人 - 用户、约翰、鲍勃和服务器。服务器是控制游戏的人。
  • 用户正坐在他的电脑前玩游戏。他点击鼠标。
  • John 是用户计算机上检测鼠标点击的程序。他不知道这意味着什么,但他知道他应该把它发送给 Bob。
  • Bob 在服务器端。他和约翰一样,对点击一无所知,但他知道如何与约翰沟通。他拿起鼠标点击并把它交给服务器,告诉他它来自用户。
  • 服务器是大脑。他解释鼠标点击并更改游戏中的某些内容。 每(比如)30 毫秒,服务器渲染游戏。他知道用户的摄像头指向哪里,因此他生成了应该出现在用户屏幕上的图像。
  • 服务器不知道如何将其发送给用户,因此他将其提供给 Bob。 Bob 将图像发送给 John。
  • John 将图像显示在屏幕上。

现在,这是一个 2 人游戏,所以我预计服务器在处理所有用户请求时不会出现问题。我想听听您对这个模型的反馈。好吗?如果没有,有哪些替代方案?

【问题讨论】:

  • user>john>bob>server==user>program>api>server...准确吗?玩家一号和二号是什么关系?这是他们交替充当用户(国际象棋)的顺序游戏吗?还是有两个同时访问服务器的方?你怎么描述的,听起来不像是多人系统
  • @RobotWoods 是的,这是正确的。玩家从不互相交流。他们只是将输入发送到生成输出并将其返回给每个用户的服务器。可以将其比作这样的论坛:多个客户端将他们的消息发送到服务器,服务器存储它们并将包含所有消息的 HTML 文档返回给每个用户。
  • 在我看来,您问题的措辞太不准确,无法给出有用的答案。您的大部分问题都包含一个没有意义的复杂示例“模型”。应该使用的“模型”在很大程度上取决于您尝试制作的游戏类型,并且您没有提供任何有用的信息。请尝试修改您的问题,因为我很想帮助您。

标签: java networking client


【解决方案1】:

您绝对应该阅读整个 PDF,了解帝国时代的工作原理。它完全相关,将极大地帮助您理清思路:

http://web.cs.wpi.edu/~claypool/courses/4513-B03/slides/BT01.pdf

【讨论】:

  • 帝国时代是一个 RTS,是点对点的。 OP 明确表示他正在寻找客户端服务器游戏。这是两个完全不同的东西。
  • @BlueRaja-DannyPflughoeft 该文档描述了对等网络,但也描述了它与客户端/服务器模型相比的优缺点。 “这将极大地帮助你理清思路”仍然是一个非常正确的陈述。
【解决方案2】:

如果没有全貌,我想我会构建两个 Web 服务,连接到某个数据库(很可能)。

第一个将接受一些与某些用户执行的操作相关的参数(单击坐标、时间、用户 ID 等),将这些参数保存到数据库中,并以一些状态详细信息(成功、失败等)进行响应。

另一个 API 将接受时间作为参数,并返回(以 JSON 或 XML 格式)自那时以来发生的所有活动(如在聊天程序中......这是自上次更新以来的消息) ...或者,取决于游戏构造,累积状态...例如,如果游戏由两个团队组成,将一块瓷砖从红色翻转到蓝色,则此 API 将返回瓷砖的当前状态。然后,在客户端代码中,我会处理响应以向该用户反映当前的游戏状态。

这是一些示例代码。这不会按原样自动更新,您可以设置超时以定期轮询新数据,或设置某种长轮询 (wiki)。哦,因为这是教育性的,所以没有输入验证(除了长度):

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="viewport" content="initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<title>Game</title>
<style>
html, body {margin:0;padding:0;height:100%;width:100%;}
#board {width:298px;height:298px;border:thin solid #000;position:relative;}
#puck {width:58px; height:58px; display:block; background-image:url('al.png'); background-size:contain; position:absolute; top:120px; left:120px;}
</style>
</head>

<body onload="update();">
<div id="board">
<div id="puck"></div>
</div>
<button onclick="update();">Update</button>
</body>
<script>
var x,y;
document.getElementById('board').addEventListener('click',move);

function move(e){
    a1=((window.XMLHttpRequest)?new XMLHttpRequest():new ActiveXObject("Microsoft.XMLHTTP"));
    x=(e.clientX-29);
    y=(e.clientY-29);
    a1.abort();
    a1.onreadystatechange=function()
    {
        if (a1.readyState==4&&a1.status==200){
                document.getElementById('puck').style.left = x+'px';
                document.getElementById('puck').style.top= y+'px';
        }
    }
    params='x='+x+'&y='+y;
    a1.open("POST","al_accept.php",true);
    a1.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
    a1.setRequestHeader("Content-length", params.length);
    a1.setRequestHeader("Connection", "close");
    a1.send(params);
}

function update(){
    a2=((window.XMLHttpRequest)?new XMLHttpRequest():new ActiveXObject("Microsoft.XMLHTTP"));
    a2.onreadystatechange=function()
    {
        if (a2.readyState==4&&a2.status==200){
                res=JSON.parse(a2.responseText)
                x=res.x;
                y=res.y;
                document.getElementById('puck').style.left = x+'px';
                document.getElementById('puck').style.top= y+'px';
        }
    }
    params='x='+x+'&y='+y;
    a2.open("POST","al_respond.php",true);
    a2.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
    a2.setRequestHeader("Content-length", params.length);
    a2.setRequestHeader("Connection", "close");
    a2.send(params);

}
</script>
</html>

您会看到 move 函数将数据发送到 al_accept.php 存储它(这里只是写入文件,因为每次移动都会覆盖之前的任何内容)并且 update 函数调用 al_respond.php 到检索最新数据。

al_accept.php:

<?php
$x=(strlen($_REQUEST['x'])>3)?substr($_REQUEST['x'],0,3):$_REQUEST['x'];
$y=(strlen($_REQUEST['y'])>3)?substr($_REQUEST['y'],0,3):$_REQUEST['y'];
$pos=fopen('al.txt','w');
$str='{"x":'.$x.',"y":'.$y.'}';
fwrite($pos,$str);
fclose($pos);
?>

al_respond.php:

<?php
header('content-type:application/json');
echo file_get_contents('al.txt');
?>

如果你在两台机器上打开它,你可以在一台机器上移动球,当你在另一台机器上更新时,你会看到最新的位置(反之亦然)。

【讨论】:

  • 如果您投反对票,请解释。你不同意我试图回答你认为是一个不完整的问题吗?还是不同意我的回答?
  • 我既不同意你的回答,又觉得你对不完整问题的回答只会让提问者感到困惑。您是否曾经实施过您描述的系统,或者知道它可以在其他任何地方实施?这听起来很复杂,很慢,而且没有完全解释……两个“网络服务”?某处的“api”?也许我只是不理解你......
  • 感谢您的回复。是的,我确实混合了 API 和 Web 服务,但是,是的,我已经用这个结构构建了多个(快速)系统。一个具体的例子是一个基于画布的绘图聊天程序。第一个 Web 服务接受图像、用户名和时间戳。图像被保存到服务器,它的文件名,其他参数被添加到数据库中的表中。用户可以调用另一个服务(同样,使用时间作为参数)。查询数据库以获取比传递的参数更新的所有条目,然后在客户端应用程序中使用这些字段来构建更新的聊天
  • 另外,我同意你的观点,如果问题明确询问其他方法,提出替代解决方案可能会令人困惑,但因为这是“你会怎么做”,我认为有解释空间
  • 看来您使用 PHP 的经验比使用 Java 的经验多,而且您正在应用 PHP 的核心概念,而这些概念根本不需要在 Java 中完成。使用普通的套接字编程,您的两个步骤变得繁琐且不必要。而不是client tell server to update, server write update to file / db, client2 ask server for update, server respond with file/db contents,我们可以简单地使用client send update to server, server push update to all clients,因为所有客户端都已经连接到服务器本身。永远不要强迫client2 向服务器请求更新。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-12-19
  • 1970-01-01
  • 2015-03-18
  • 2012-09-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多