编写包含局域网通信功能和物理引擎效果的WebGL场景
一、执行效果:
1、正确配置服务并访问页面后:
SRE实战 互联网时代守护先锋,助力企业售后服务体系运筹帷幄!一键直达领取阿里云限量特价优惠。world、a、b三个用户存在于同一场景中(在实际应用时应该分别使用不同的显示设备),a、b是普通用户,在场景中用一个球体表示,world是裁判用户,不在场景中显示实体。场景中心有一副扑克牌,裁判用户能够看到牌面,而普通用户只能看到卡背。每个用户可使用WASD、空格、Shift和鼠标控制自身的移动,其位置和姿态变化能够被其他用户实时感知。
2、world用户测试物理引擎:
world用户点击鼠标左键可以向光标方向发射具有物理效果的小方块,小方块在接触到场景边界或其他物理对象时将发生碰撞。
3、抓牌同步
普通用户(这里以a为例),点击牌堆时将从牌堆抓取卡牌,其他用户将能实时围观这一动作,卡牌到达a的手中后将显示卡面。
4、出牌同步
a用户按一下Alt键切换光标控制模式,点击一张手牌,被选中的手牌将显示橙色边框,再按Alt键则准星变为橙色,在橙色准星状态下点击左键,将带有物理效果的红桃2打出(为了显示的更明显加大了卡片的反弹系数)
5、整体场景
二、服务端部署与前端访问方法:
1、从https://github.com/ljzc002/CardSimulate或https://down.51cto.com/data/2461249下载工程
2、下载安装h2数据库软件,将playground.mv.db和playground.trace.db放入h2文件夹的同级目录,复制完毕后启动数据库。这个数据库中保存了初始的用户身份信息(TB_USER)、卡牌属性信息(TB_UINTTYPE)和用户掌控卡牌信息(TB_USERUNIT)。
如我的h2数据库最外层目录为h2-2017-06-10,其内为h2文件夹的同级目录。
这个数据库的JDBC驱动类为org.h2.Driver,URL为jdbc:h2:tcp://127.0.0.1/../../playground,用户名密码均为playground。
3、首先确保系统支持64位JDK1.8。将从Github下载的代码放入已有的SpringBoot2工程,或者用IntelliJ IDEA 打开从51CTO下载的完整工程(其中前端代码并非最新,可从Github替换),等待IntelliJ IDEA根据pom.xml自动安装依赖,导入完成后的工程结构如下图:
这里我使用SpringBoot进行包管理,用Netty实现WebSocket功能,用SpringBoot的内置Tomcat处理http请求,用druid作为数据源,读者也可以考虑用其他方式实现这些功能。
4、端口配置
这里默认使用8181作为http监听端口,用2323作为WebSocket监听端口,可以在application.yml文件中修改后端监听配置,可在login.html和KingoftheHill2.html中修改前端的默认访问端口。
5、打包和启动
在playground目录下执行mvn clean package或执行package.bat将工程打包为一个jar包。
执行java -jar ./target/netty_test01.jar或startjar.bat启动刚才生成的jar包(这个jar包包括了运行所需的所有依赖,可以剪切到其他目录启动)
出现“Netty开始监听:2323”,且无报错信息说明服务启动成功。
6、在与服务器处于同一网段的设备上,用Chrome浏览器访问http://127.0.0.1:8181/HTML/login.html(IP和端口号要根据实际情况修改),打开用户登录页面。
输入用户名密码,如果之前不存在此用户则以此用户名密码新建用户,如果已存在此用户名则尝试以此密码登录。
为了方便操作,这里使用非常宽松的身份验证规则,一次登录成功后即在浏览器本地存储中建立一个不会过期的token,凭此token这个浏览器将可以不受限制的随时访问全部前后端资源,一个浏览器也可以同时存储多个用户的token,以支持一机多开。特别强调此种身份验证不适用于需要保密的场合。
这里认为本系统的用户之间相互熟悉、相互信任,且假设用户之间能够及时高效的进行线下沟通,身份验证只是为了方便多用户的合作分工而设。
需要注意的是浏览器对每个IP和端口都建立独立的本地存储,所以更换IP和端口后需要重新登录,但原用户的信息(比如控制的单位)仍然不变(保存在数据库中)。
7、导航页面:
这是一个参考时下流行的信息系统导航页结构,用原生JavaScript编写的导航页面,登录时填写的信息以window.location.hash的形式传递进来,即使关闭此导航页,用户也将一直在数据库中保持激活状态,随时可以再次连接,直到点击右上角的“退出登录”按钮,用户才会在数据库中被置为不可用。
导航菜单栏内容在Index.js的InitMenu方法中定义:
1 var arr_user = [ 2 ["测试菜单","./PAGE/chat.html","bg/pic_test","test","unique"], 3 ["WS初始化测试","./PAGE/KingoftheHill2.html","bg/pic_test","test","unique"], 4 ["在新窗口中打开","./PAGE/OpenWindow.html" 5 ,"bg/pic_test","test","unique"] 6 ];
数组中的参数分别表示菜单名、菜单对应url、菜单所属菜单组的图标、菜单所属的菜单组、这种菜单只能打开一个,在实际使用时可以考虑从数据库按用户权限进行菜单加载。
8、点击“在新窗口中打开”菜单,打开真正的WebSocket页面,这里使用world用户进行所有的物理引擎计算和动画计算,普通用户只向world提交操作请求以及渲染world的计算结果,所以在运行时需要先打开world用户的WebSocket页,再打开其他用户的WebSocket页(但登录顺序没有要求)。
在已经具有token的情况下,也可以不经过导航页,直接输入http://127.0.0.1:8181/HTML/PAGE/KingoftheHill2.html#127.0.0.1@8282@2323@world访问
三、工程结构简介
因为涉及到的代码较多,无法一一展开介绍,这里只简单说明一些目录和文件的作用,具体的运行方式可以参考我之前的博客和网上的各种资料。
1、main.java.com下是后端的SpringBoot Java代码:其中appwithmain是一个以swt技术编写的Java桌面程序,用来处理另一个项目中cnpm的包安装异常,和本项目无关。learnnetty是从网上摘抄的一些netty学习例程,和本项目无关。websocket下是与本项目有关的后端代码:
其中HttpController2下是http请求的处理方法,主要包括用户身份验证和用户登出功能。
netty中的NettyConfig、serverBootStrap、serverInitializer、WebSocketServer根据网上的教程修改而来,因为自身对SpringBoot和Netty了解有限,只是知其然不知其所以然的生搬硬套,这里的代码肯定存在各种缺陷,读者可以考虑用更合适的方式代替。
WebSocketHandler是WebSocket请求的实际处理者,它的主要工作一是根据前台发来的token和数据库信息对WebSocket请求进行身份验证,二是根据请求中type属性的不同将信息转发给不同的对象。
pojo目录中只用到了WsSession类,它负责在Java层保存一个WebSocket连接的身份信息:
1 public class WsSession { 2 public String ChannelId=""; 3 public String UserId=""; 4 public String Token=""; 5 }
这里Token是用户前后台通用的唯一标识,与数据库tb_user表的uuid字段对应;UserId是用户的显示名,它与Token可能是一对多的关系,比如“张三”用户登录后选择退出登录,则会在数据库的tb_user表中留下一条sfky(是否可用)为0的记录,当有用户再次以张三为名登录时,数据库中将有两条userid为张三但uuid各不相同的记录。
ChannelId则是这一条WebSocket连接的唯一id,考虑到未来程序功能的扩展,一个userid可能同时具有多个channelld。
MyNettyUtil里是一些辅助工具方法。
PlaygroundApplication是SpringBoot的入口类,因为不熟悉SpringBoot的各种约定,在这里手动New了一个数据源给Netty模块使用。
2、main.resources.static目录下是前端代码:
其结构和前面博客中的一些Babylon.js例程并没有太大区别,
其中HTML.PAGE下的KingoftheHill2.html是本工程的主要Babylon.js页面,其他多为各种功能的测试页面。
JS.PAGE.kh下的khws.js是新加入的js文件,包含所有处理收到的WebSocket信息的逻辑。
3、pom.xml是Maven的配置文件,其后半部分打包配置取自https://blog.csdn.net/wuqingbin/article/details/80340110,在此对原作者表示感谢。
4、本工程中的自编代码以MIT协议发布,引用的代码以其原本协议使用。
