【游戏客户端】制作你玩我猜Like玩法
【游戏客户端】制作你玩我猜Like玩法
大家好,我是Lampard猿奋~~ “你画我猜”相信大家都不陌生,当初这款小游戏可谓茶余饭后必玩之选,风头一时无二。今天要和大家分享如何实现一个你玩我猜Like的玩法。
我们可以简单的把需求拆成两个个部分:1.绘图功能的实现,2.数据传输方式
本文不贴代码只讲设计思路,希望能帮助到大家~
(一)绘图功能的实现
(1)画布
要作画我们首先需要一个画布,画布我们可以在UI编辑器中用一个image控件来显示。但是需要注意两个地方:
首先就是不要用太深的颜色作为底色(你没见过黑色的画布吧,五彩斑斓的黑当我没说...), 再者就是记得画布的透明度最好设置成255,因为之后的绘制是用目标颜色和画布进行混合渲染,因此如果透明度不为255的话,渲染出来的结果可能和设定的画笔颜色会有出入
(2)rendertexture类
紧接着就是要介绍我们实现绘图逻辑的类:RenderTexture类,怎么去理解这个类呢?大家可ui把这个类当作一张白纸,我们想要实现绘制效果,首先要在白纸上画出背景颜色(画布颜色),然后再在画布颜色的基础上,继续增加各式各样我们想要绘制的图形
此时问题很多的小明就要问了:为啥不直接用UI管理器导入的Image作为真正的画布?还要搞什么白纸的概念呢?
这是因为我们要实现画笔所划过的地方与画布进行混合渲染,而RenderTexture类支持这个功能,而UI编辑器中封装好的UI类Image和Sprite是不支持的
RenderTexture类底层是调用了OpenGL的glBlendFunc的混合绘制方法,关于RenderTexture的研究我们在之前做过了。
function clsWidgetScratch:initRenderTexture()local renderTexture = cc.RenderTexture:create(self.width, self.height)self:addChild(renderTexture)renderTexture:addChild(self.drawNode)renderTexture:addChild(self.rubberImg)return renderTexture
end
如果大家想了解cocos中如何调用RenderTexture来进行混合绘制,可以看看我之前写的这一篇文章:【游戏客户端】实现刮刮乐效果
如果大家想要了解RenderTexture的底层openGL渲染逻辑,可以看看这一篇文章:glBlendFunc颜色混合
(3)画笔DrawNode
方才我们已经创建了一个Rendtexture的对象,然后把画布的颜色渲染了上去,紧接着我们只需要创造出画笔绘制的内容,然后和画布进行混合渲染就可以实现我们的绘图功能
我们知道画画是需要从点到线再到面的,因此我们可以实例化一个带颜色的DrawNode对象用来描绘画笔点下的一个点
而想要绘制出不同的颜色,只需要调整drawSolidCircle接口中的color字段即可
function clsWidgetScratch:initDrawNode()local drawNode = cc.DrawNode:create()drawNode:setVisible(true)drawNode:setBlendFunc(gl.ONE, gl.GL_ONE_MINUS_SRC_ALPHA)drawNode:setLocalZOrder(1000)drawNode:drawSolidCircle(cc.p(self.length / 2, self.length / 2), self.length / 2, 360, 10, 1, 1, self.color)return drawNode
end
(4)调整绘制的位置
有了画布和Drawnode画出来的点,我们下一步还需要做的就是监听玩家绘制的位置
首先我们要创建一个监听用的Layout置于最上层,用onTouchMove的方法监听玩家触摸的位置。紧接着把DrawNode的position设置成玩家落笔的位置,然后调用cocos中renderTexture的混合绘制方法即可
(5)橡皮擦功能
画图需求中带有了橡皮擦功能,其实聪明的朋友已经发现,所谓的橡皮擦功能。我们可以简单的把DrawNode的颜色设置为和画布的一样,就可以把之前绘制的内容给覆盖掉了
好,我们看看目前所实现的效果:
(二)数据传输方式的选择
当看到玩法效果实现出来的时候,我也和大家一样欣喜若狂,以为这个需求快要到尾声了。然鹅,困难的地方还在后面:首先这并不是一个单机玩法,它是多人实时同步的一个游戏。那就意味着你需要把绘制的内容实时同步给所有的玩家,那么问题来了,对于一幅960*640的画布,你要如何进行实时传输呢?
(1)Http协议拉取最新的图片
首先我们可以想到用类似patch的方式,每当绘制成功后就把内容以png格式上传到资源库中,然后其他猜测的玩家则用http协议去拉取最新的资源
这样的做法好处是确保绘制内容的准确性和完整性
坏处是每一次绘制内容的更新,都要去拉取一次资源,我们知道文件的IO是非常耗时的,这样当遇到性能有点卡顿的时候,更新时就会一闪一闪,这样玩家的体验上并不好
(2)RPC协议同步像素内容
那我们可不可以去同步像素的内容呢?虽然项目的每一个像素点用的都是RGBA8888的格式记录,也就是说一个像素需要32位,但我们实际只用到了8个颜色,且透明度都是255,因此我们完全可以用8个bit去映射记录每个像素的信息
但是虽然如此优化了,但每一个像素也需要用到1B的大小去记录,而我们有960*640个像素,960 * 640 / 1024,算下来我们还要用到600KB的数据去传输这个画面。
但由于处于性能压力的监控,服务端很早之前就闲置了,每次使用RPC协议,不能交互超过100KB的数据,因为如果我们需要用到这种做法,我们还得进一步优化:可以把画布分块,像场景地图那样切成小块去分开传输,总的来说也算是一种思路
这种做法好处是确保了画面的准确性,以及省去了IO的时间
坏处是需要分块请求画面内容,比较难确保每次数据传输我每一小块的内容都可以准确的获取数据和显示
(3)RPC协议同步绘制流程
其实第二种的思路已经很接近正解了,但是唯一问题就是不想采用分块的方式,想完完整整的一幅图片同步给玩家。因此我想到了第三种方法:记录玩家的绘制流程,用RPC协议同步玩家的绘制记录。
什么意思呢?首先我们把整一个画布划分成一个3*3,或者4*4像素方块组成的整体。然后我们用一个二维数组去记录这些小方块是否被绘制,绘制的颜色映射是什么。
每当玩家绘制的时候,我们就更新二维数组中该小方块的映射值,然后把这个二维数组的记录信息,以二进制数据的形式拼接在一起上传。同时参与的玩家通过RPC协议获取最新的绘制信息,然后解码成二维数组,重新根据绘制信息重新把内容“画”出来
这样我们就可以把3*3或者4*4的像素信息融合成一份,虽然会有一些锯齿感和多花了时间进行编码和解码,但是成功把数据压缩到了100K以内,且避免了IO的卡顿
local NORMAL_LENGTH = 3local i = math.floor(y / NORMAL_LENGTH)
local j = math.floor(x / NORMAL_LENGTH)
self.nodeList[i*NORMAL_LENGTH][j*NORMAL_LENGTH] = self:getEncodeNodeIndex()
(三)最后看看我们最终的效果
你画我猜玩法视频
至此你画我猜玩法的分享到此结束~~
感谢阅读,点赞,关注!!!
相关文章:

【游戏客户端】制作你玩我猜Like玩法
【游戏客户端】制作你玩我猜Like玩法 大家好,我是Lampard猿奋~~ “你画我猜”相信大家都不陌生,当初这款小游戏可谓茶余饭后必玩之选,风头一时无二。今天要和大家分享如何实现一个你玩我猜Like的玩法。 我们可以简单的把需求拆成两个个部分&…...

分页查询从接口到实现,统一对日期类型进行格式化处理
编写Service实现类编写Mapper的sql,但复杂的sql语句需要写到mapper对应的xml文件中日期类型格式化处理 /*** 扩展springmvc框架的消息转换器* param converters*/Overrideprotected void extendMessageConverters(List<HttpMessageConverter<?>> conve…...

栈和队列详解(1)
目录 一、什么是栈? 二、创建一个我们自己的栈 1.前置准备 1.1需要的三个文件 1.2结构体的创建和头文件的引用 2.接口的实现 2.1初始化栈结构体 2.2尾插(压栈) 2.3栈存放的元素个数和判断栈是否为空 2.4获取栈顶元素 2.5出栈 2.6摧毁栈 2.7测试接口 三、…...

苏州OV泛域名RSA加密算法https
RSA加密算法是一种非对称加密算法,它被广泛应用于信息安全领域。与对称加密算法不同,RSA加密算法使用了两个密钥,一个公钥和一个私钥。公钥可以公开,任何人都可以使用它加密信息,但只有私钥的持有者才能解密信息。RSA加…...

凯迪正大—微机继电保护校验仪
一、继电保护测试仪产品概述 KDJB-802继电保护测试仪是在参照电力部颁发的《微机型继电保护试验装置技术条件(讨论稿)》的基础上,听取用户意见,总结目前国内同类产品优缺点,充分使用现代的微电子技术和器件实现的一种新…...

Linux文件属性与权限管理(可读、可写、可执行)
Linux把所有文件和设备都当作文件来管理,这些文件都在根目录下,同时Linux中的文件名区分大小写。 一、文件属性 使用ls -l命令查看文件详情: 1、每行代表一个文件,每行的第一个字符代表文件类型,linux文件类型包括&am…...

Centos7.9安装lrzsz进行文件传输---Linux工作笔记059
这里咱们lrzsz命令,需要用来进行文件传输,因为如果不安装这个命令的话,那么 传输安装包什么的就不方便因为只有少数传输工具,才支持,直接拖拽的.没有的时候就可以用这个工具,用命令来传输 直接就是: sz 文件名 就可以把文件下载下来 rz 选择一个文件, 就可以把文件上传到当…...

酒吧座位全解析 小白必看
相信还有很多第一次去酒吧的朋友们还不了解吧台、散台、卡座的区分,下面我简单解说一下,如有错漏,欢迎指正!一、吧台吧台是酒吧的核心部位,走进酒吧门,首先映入眼帘的就是吧台,一排人围着吧台几…...

DAY19
题目一 空间尝试模型 一个样本做行一个样本做列 范围尝试模型 以....做分隔 dp[i][j] 为以i为左界限 以j为右界限 求这个范围内的计算值(不对 是方法数) 这& | ^ 都是双目运算符 观察一下规律 整体字符数量一定为奇数(包括运算符和数字) 对应到数组中 数组的位一定是偶数…...

Data analysis|Tableau基本介绍及可实现功能
一、基础知识介绍 (一)什么是tableau tableau 成立于 2003 年,是斯坦福大学一个计算机科学项目的成果,该项目旨在改善分析流程并让人们能够通过可视化更轻松地使用数据。Tableau可以帮助用户更好地理解和发现数据中的价值&#x…...
单元测试优化:为什么要对程序进行测试?测试有什么好处?
单元测试(Unit Testing)又称为模块测试, 是针对程序模块(软件设计的最小单位)来进行正确性检验的测试工作。 程序单元是应用的最小可测试部件。简单来说,就是测试数据的稳定性是否达到程序的预期。 我们日常开发时可能…...

自动装配在Spring Boot中的重要性及实现方式
这里写目录标题 自动装配在Spring Boot中的重要性及实现方式什么是自动装配?如何实现自动装配?如何使用自动装配自动装配的优势总结 手写自动装配的Java代码示例原理 自动装配在Spring Boot中的重要性及实现方式 Spring Boot是基于Spring框架的开源框架…...

校对软件在司法系统中的应用:加强刑事文书审查
校对软件在司法系统中的应用可以加强刑事文书审查,提高文书的准确性和可靠性。 以下是校对软件在刑事文书审查方面的应用: 1.语法和拼写检查:校对软件可以自动检查刑事文书中的语法错误和拼写错误。这包括句子结构、主谓一致、动词形式等方面…...

微信小程序上传图片和文件
1.从微信里选择图片或文件上传 使用的vant的上传组件 原生用 wx.chooseMessageFile() html <!-- 从微信上面选择文件 --><van-uploader file-list"{{ file }}" bind:after-read"afterRead" max-count"{{3}}" deletable"{{ true…...
拥抱AIGC浪潮,亚信科技将如何把握时代新增量?
去年底,由ChatGPT带起的AIGC浪潮以迅雷不及掩耳之势席卷全球。 当互联网技术的人口红利逐渐消退之际,AIGC就像打开通用人工智能大门的那把秘钥,加速开启数智化时代的到来。正如OpenAI CEO Sam Altman所言:一个全新的摩尔定律可能…...
【opencv】指定宽或高按比例缩放图片 拼接图片
指定宽或高按比例缩放图片 import cv2def resize_by_ratio(image, widthNone, heightNone, intercv2.INTER_AREA):img_new_size None(h, w) image.shape[:2] # 获得高度和宽度if width is None and height is None: # 如果输入的宽度和高度都为空return image # 直接返回原图…...

使用C#加载TOOLBLOCK
前言 因为Vpp文件类型包含了以下三种 QuickBuidJobToolBlock 不同类型的打开方式不同,需要提前知道vpp是什么类型 例如 这个TB.vpp文件是TOOLBLOCK,就不能直接在visionpro中打开(直接打开需要QuickBuid文件), 可以…...

MPAS-A原理及陆面模式的基本概念
跨尺度预测模式(The Model for Prediction Across Scales - MPAS)是由洛斯阿拉莫斯实验室和美国国家大气研究中心(NCAR)共同开发,其由3个部分组成,分别称为 MPAS-A(大气模型)、MPAS-O(海洋模型&…...
前端技术Html,Css,JavaScript,Vue3
Html 1.基本标签 <h1>最大的标题</h1> <h2> . . . </h2> <h3> . . . </h3> <h4> . . . </h4> <h5> . . . </h5> <h6>最小的标题</h6><p>这是一个段落。</p> <br> (换…...

实战项目——多功能电子时钟
一,项目要求 二,理论原理 通过按键来控制状态机的状态,在将状态值传送到各个模块进行驱动,在空闲状态下,数码管显示基础时钟,基础时钟是由7个计数器组合而成,当在ADJUST状态下可以调整时间&…...
后进先出(LIFO)详解
LIFO 是 Last In, First Out 的缩写,中文译为后进先出。这是一种数据结构的工作原则,类似于一摞盘子或一叠书本: 最后放进去的元素最先出来 -想象往筒状容器里放盘子: (1)你放进的最后一个盘子(…...

C++_核心编程_多态案例二-制作饮品
#include <iostream> #include <string> using namespace std;/*制作饮品的大致流程为:煮水 - 冲泡 - 倒入杯中 - 加入辅料 利用多态技术实现本案例,提供抽象制作饮品基类,提供子类制作咖啡和茶叶*//*基类*/ class AbstractDr…...

Flask RESTful 示例
目录 1. 环境准备2. 安装依赖3. 修改main.py4. 运行应用5. API使用示例获取所有任务获取单个任务创建新任务更新任务删除任务 中文乱码问题: 下面创建一个简单的Flask RESTful API示例。首先,我们需要创建环境,安装必要的依赖,然后…...

SCAU期末笔记 - 数据分析与数据挖掘题库解析
这门怎么题库答案不全啊日 来简单学一下子来 一、选择题(可多选) 将原始数据进行集成、变换、维度规约、数值规约是在以下哪个步骤的任务?(C) A. 频繁模式挖掘 B.分类和预测 C.数据预处理 D.数据流挖掘 A. 频繁模式挖掘:专注于发现数据中…...

高频面试之3Zookeeper
高频面试之3Zookeeper 文章目录 高频面试之3Zookeeper3.1 常用命令3.2 选举机制3.3 Zookeeper符合法则中哪两个?3.4 Zookeeper脑裂3.5 Zookeeper用来干嘛了 3.1 常用命令 ls、get、create、delete、deleteall3.2 选举机制 半数机制(过半机制࿰…...
vue3 字体颜色设置的多种方式
在Vue 3中设置字体颜色可以通过多种方式实现,这取决于你是想在组件内部直接设置,还是在CSS/SCSS/LESS等样式文件中定义。以下是几种常见的方法: 1. 内联样式 你可以直接在模板中使用style绑定来设置字体颜色。 <template><div :s…...
论文解读:交大港大上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(一)
宇树机器人多姿态起立控制强化学习框架论文解析 论文解读:交大&港大&上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(一) 论文解读:交大&港大&上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化…...
苹果AI眼镜:从“工具”到“社交姿态”的范式革命——重新定义AI交互入口的未来机会
在2025年的AI硬件浪潮中,苹果AI眼镜(Apple Glasses)正在引发一场关于“人机交互形态”的深度思考。它并非简单地替代AirPods或Apple Watch,而是开辟了一个全新的、日常可接受的AI入口。其核心价值不在于功能的堆叠,而在于如何通过形态设计打破社交壁垒,成为用户“全天佩戴…...
libfmt: 现代C++的格式化工具库介绍与酷炫功能
libfmt: 现代C的格式化工具库介绍与酷炫功能 libfmt 是一个开源的C格式化库,提供了高效、安全的文本格式化功能,是C20中引入的std::format的基础实现。它比传统的printf和iostream更安全、更灵活、性能更好。 基本介绍 主要特点 类型安全:…...

Android写一个捕获全局异常的工具类
项目开发和实际运行过程中难免会遇到异常发生,系统提供了一个可以捕获全局异常的工具Uncaughtexceptionhandler,它是Thread的子类(就是package java.lang;里线程的Thread)。本文将利用它将设备信息、报错信息以及错误的发生时间都…...