问题概述

众所周知gamemaker是一款制作2d游戏的优秀引擎,但是落后的弱联网机制始终是一个坑。所幸在gms2中,yoyogames集团加入了TCP的联机机制,这也为gm系列引擎制作联网游戏带来了希冀。
下面用一个最简单的“红蓝球游戏”作为我们的联机用例。用例的基本描述如下:
进入游戏先选择host和join,host方以红球身份进入房间,join方以蓝球身份进入房间。双方都以WSAD为移动方式,并且双方在屏幕上需要看得到对方的球被操控移动。

代码实现

首先声明一下,如果点击host,那么给全局变量global.net赋值1,如果点击join则赋值2,表示现在玩家是以什么样的身份进入游戏。
之后host方进入一个房间,这个房间有一个obj_server,join方进入另一个房间,这个房间有一个obj_joiner。

obj_server

创建

第一行表示创建一个新的tcp连接,括号中第一个参量是tcp的写法,第二个参量是端口(自定),第三个参量是客户端数量的上限(尽量不超过1000)
sendmes表示服务器要发送的数据内容,刚开始不发送的时候先清零
timer是一个计时器,规定每5步发送一次数据

network_create_server(network_socket_tcp,250,10);
sendmes=0;
timer=5;

步事件

这里面需要介绍一下buffer。buffer是一种缓冲区,可以起到优化空间的效果,而游戏引擎里也将buffer作为发送数据的载体,因此我们定义一个新的缓冲区buf。
发送的数据sendmes赋值为红球(即host方)的x值+y值×1000,因为我这里的地图坐标上限是999,因此这样一个六位数可以把x坐标和y坐标都储存下来,最后发送一个数字就可以了。
当计时器timer减到0并且判定网络连接已经连接成功了(global.connect==1),我们开始处理发送数据的事情。(具体怎么判定网络连接成功见后文)
首先要使用buffer_create()函数申请一个buffer(类似malloc)。第一个参量是缓冲区的容量,这个可以尽量大一点;第二个参量是buffer的类型,这个可以参考下表

类型 描述
buffer_fixed A buffer of a fixed size in bytes. The size is set when the buffer is created and cannot be changed again.
buffer_grow A buffer that will grow dynamically as data is added. You create it with an initial size (which should be an approximation of the size of the data expected to be stored), and then it will expand to accept further data that overflows this initial size.
buffer_wrap A buffer where the data will wrap. When the data being added reaches the limit of the buffer size, the overwrite will be placed back at the start of the buffer, and further writing will continue from that point.
buffer_fast This is a special “stripped down” buffer that is extremely fast to read/write to. However it can only be used with buffer_u8 data types, and must be 1 byte aligned. (Information on data types and byte alignment can be found further down this page).

第三个参量是数据排列字节数,详情可见gms2中万能的F1说明,这里不再赘述。
申请完缓冲区后,便可以使用buffer_write()函数向缓冲区中写入数据。第一个参量为声明的缓冲区,第二个参量为数据类型(具体写哪个数据类型可以F1自己查),第三个便是要发送的数据内容。
写完后,使用network_send_packet()函数发送你的数据包,第一个参量是接收对象,第二个参量是写好的缓冲区,第三个参量是总尺寸,这个写buffer_get_size()是绝对没错的。
发送完后,你的缓冲区就没有意义了,因此需要用buffer_delete()函数释放空间

var buf;
sendmes=global.redx+global.redy*1000;
if(timer>0)timer-=1;
if(global.connect==1&&timer<=0)
{buf=buffer_create(10000,buffer_fixed,4);buffer_write(buf,buffer_u32,sendmes);network_send_packet(client,buf,buffer_get_size(buf));buffer_delete(buf);timer=5;
}

绘制事件

打印出getmes的内容,这里纯粹是为了方便debug。

draw_text(5,5,getmes);

Async-Networking

Async本质上就是一种需要特殊条件才能触发的步事件,例如Networking就是一种触发条件,顾名思义就是“只要连接上网络了就触发”。当客户端成功连接上这里的服务器后,我们的服务器就会进入到这里,开始处理连接成功以后的琐事。
首先,我们需要再引入一个新概念:“map”。
我们理解map为一个外交官,当两国进行交涉后,外交官将会得到很多信息,比如他国的地理位置、他国的国际代号、他国接下来想做些什么等等等等。
这时候,我们想要从外交官那里套得信息,不能简单地问:“嘿,外交官,你知道关于X国的什么信息了”,这样太笼统。正确的问法是:“嘿,外交官,X国的地理位置在哪?”“嘿,外交官,X国的国际代号是什么?”“嘿,外交官,X国现在想对我国做些什么?”
这里面map就如同外交官一样,当服务器与客户端成功连接,那么map就会身为服务器的外交官与客户端进行交涉,之后他会得到若干种信息,分别是:

信息类型 含义
type 客户端的动机(X国想做什么?)
socket 客户端的id(X国的代号是什么?)
ip 客户端的地理位置(X国的地理位置是什么?)
buffer 客户端发来的数据(X国想跟我们说什么?)

这个应该很好懂,不多赘述。接下来开始写代码:
首先我们要赋予map这个使命,让他=async_load
然后!我们可以通过ds_map_find_value(map,“type”)来获取客户端的动机(动机可以有很多,比如联网,比如发送数据,比如失去连接)
这时候把他的动机赋值给一个新变量type,然后接下来检测:如果动机是连接上了(type==network_type_connect),那么我们就让global.connect=1,此时client和ip分别运用ds_map_find_value()获取客户端的id和地址。
如果动机是接受到客户端发来的数据了,那么我们就创建一个新的缓冲区,来接受发来的缓冲区,并使用buffer_read()函数来提取缓冲区的数据,放到getmes中。之后呢,x值和y值就可以由接收到的6位数来确定了。

var map=async_load;
var type=ds_map_find_value(map,"type");
if (type==network_type_connect)
{global.connect = 1;                             //表示连接上了client=ds_map_find_value(map,"socket");         //client表示接受的客户idip=ds_map_find_value(map,"ip");
}
if (type==network_type_data)
{buffer_create(10000,buffer_fixed,4);buf=ds_map_find_value(map,"buffer");getmes=buffer_read(buf,buffer_s32);global.bluex=getmes mod 1000;global.bluey=getmes / 1000;
}

obj_joiner

对于客户端,首先我们要定义一个socket(即id),表示我们创建了一个tcp类型的接入口,然后通过network_connect()函数来连接服务器。第一个参量是刚创建的socket,第二个参量是服务器的地址,第三个参量是服务器的端口。

创建

socket=network_create_socket(network_socket_tcp);
network_connect(socket,"XXXXX",250);

步事件

这里面的内容和obj_server异曲同工(几乎一样),不再赘述

var buf;
sendmes=global.bluex+global.bluey*1000;
if(global.connect==1)
{buf=buffer_create(10000,buffer_fixed,4);buffer_write(buf,buffer_u32,sendmes);network_send_packet(server,buf,buffer_get_size(buf));buffer_delete(buf);
}

绘制事件

同上

draw_text(5,5,getmes);

Async-Networking

对于客户端而言,核心服务器永远只有一个,因此一旦连接成功,我们不需要判定type是否为network_type_connect便可以开始连接后的操作。

map=async_load;
type=ds_map_find_value(map,"type");
server=ds_map_find_value(map,"id");         //server表示服务器的id
global.connect = 1;                             //表示连接上了
if (type==network_type_data)
{buffer_create(10000,buffer_fixed,4);buf=ds_map_find_value(map,"buffer");getmes=buffer_read(buf,buffer_s32);global.redx=getmes mod 1000;global.redy=getmes / 1000;
}

之后服务器和客户端每帧都会收到一个getmes,确定完x和y后便将小球按这个坐标进行定位即可。

Gamemaker studio2经验(2)——TCP联机相关推荐

  1. Gamemaker studio2经验(3)——昼夜更替效果实现

    问题概述 在一些知名引擎(如unity,godot,cocos等)中,天空盒概念的引入使得场景中的天空丰富多彩,但是gm就吃了这个大亏.由于动态天空制作麻烦.没有对口的天空盒系统,导致很少有开发者在g ...

  2. Gamemaker studio2经验(1)——右键人物移动逻辑

    问题概述 红警.帝国时代.星际争霸--想必很多玩家都对这类即时战略游戏保有极深的感情.其中有一个较为常见的逻辑便是--左键划动选中人物,然后右键标记目标地点,使得人物向目标地点移动.这个逻辑最常见的问 ...

  3. Gamemaker studio2经验(4)——打字机效果

    问题概述 在很多游戏中--算了实在不好意思写引言了,就直说啦.如果你是UT粉,想用gm搞搞UT的同人作品但是又无从下手,那么请看过来. 对于RPG类游戏,文字交流系统是不可或缺的,但是gm的文字系统- ...

  4. ORACLE联机日志文件丢失或损坏的处理方法(转)

    经验总结: 联机日志分为当前联机日志和非当前联机日志,非当前联机日志的损坏是比较简单的,一般通过clear命令就可以解决问题. 损坏非当前联机日志: 1.启动数据库,遇到ORA-00312 or OR ...

  5. tcp丢包率_网络编程 | TCP/IP基础知识

    在2017年10月深圳 Cocos 沙龙上,有幸结识了社区中大名顶顶的Colin,Shawn在论坛上第一次看到Colin的团队用CocosCreator制作的<热血暗黑>时就被深深地震撼到 ...

  6. 计算机端口联机,网络端口之二端口传输机制

    · 每一个 TCP 联机都必须由一端(通常为 client )发起请求这个 port 通常是随机选择大于 1024 以上的 port 号来进行!其 TCP 封包会将(且只将) SYN 旗标设定起来!这 ...

  7. 高通芯片联机读取修改串码 meid ESN wifi 蓝牙 sn等参数的操作解析{二}

    上次我发了几个相关联机读写参数的帖子.很多友友询问有没有其他相关软件来解读参数的教程.今天就来个续集来解析参数读写 关于安卓机型写串码 改串码 端口开启和基带qcn等一些经验 高通联机修改IMEI等参 ...

  8. 浅谈TCP协议的端口(port)

    一:如何查看端口 1.查看所有的端口占用情况:    在windows命令行窗口下执行: C:\>netstat -ano 2.查看指定端口的占用情况C:\>netstat -aon|fi ...

  9. tcp/ip 端口号有哪些

    按端口号可分为3大类: (1)公认端口(WellKnownPorts):从0到1023,它们紧密绑定(binding)于一些服务.通常这些端口的通讯明确表明了某种服务的协议.例如:80端口实际上总是H ...

最新文章

  1. Spring BeanFactory与FactoryBean的区别及其各自的详细介绍于用法
  2. ACMNO.46 A+B问题 问题描述 输入A、B,输出A+B。(别被数值范围所局限)
  3. 使用pngquant来压缩png资源缩小apk
  4. golang切片传参
  5. where and when navigation target url is retrieved by SAP UI5 Framework
  6. 零元学Expression Blend 4 - Chapter 25 以Text相关功能就能简单做出具有设计感的登入画面...
  7. vux radio 改造为 tree 代码片段
  8. 如何查看mysql8.0的默认密码_MySQL8.0安装之后查找默认密码
  9. bzoj 3357: [Usaco2004]等差数列(DP+map)
  10. screentogif能录制声音吗_一款免费且强大的gif动画录制工具,再也不愁录动画!...
  11. php发送curl最快方式,使用PHP cURL发送短信的简单GET请求
  12. lottie库动画方案
  13. 管理学原理试题及答案
  14. 【项目管理一点通】(44) 用户测试(Alpha测试)
  15. P4 学习笔记(1)-- P4程序的构成、基本组件
  16. 数据库编程入门培训(一)
  17. java 序列化成xml文件_将Java对象序列化成JSON和XML格式
  18. 融跃教育登陆湖南卫视!揭秘融跃是个什么样机构!CFA/FRM/ACCA
  19. 启动ps时,老是出现一个提示框:不能输入剪贴板,因为意外遇到文件尾
  20. eclipse (氧气版)oxygen下载

热门文章

  1. 陶泓达:3.23黄金,原油,白银操作策略!
  2. swfkit打包swf文件步骤(图文教程)
  3. linux系统盘ssd,Linux系统下如何使用SSD固态硬盘
  4. html使背景图片毛玻璃效果,vue实现毛玻璃背景图片效果
  5. 怕抢不到演唱会门票?AI帮你做攻略!
  6. 苹果操作系统 leopard 10.5 (PC破解完全中文安装版,IBM X40安装成功)
  7. html的中性标签,HTML的figcaption标签
  8. linux脚本出错仍执行后续脚本,crontab执行脚本出错
  9. 安卓bmi项目_bmi计算器
  10. win10在运行命令输入什么可以打开设置