【飞行棋】多人游戏-微信小程序开发流程详解
可曾记得小时候玩过的飞行棋游戏,是90后的都有玩过吧,现在重温一下,这是一个可以二到四个人参与的游戏,通过投骰子走棋,一开始靠运气,后面还靠自己选择,谁抢占先机才能赢,还可以和小伙伴们一起玩,狭路相逢勇者胜,可谓趣味多多。
文章目录
- 创建小程序
- 开始页面
- 游戏页面
- 游戏逻辑
- 画棋盘
- 画棋子
- 投骰子
- 游戏规则
- 1. 投骰子
- 2. 移动棋子
- 3. 选择棋子
- 测试游戏
- 关于项目
创建小程序
打开电脑上的微信开发工具,如下图所示,新建一个小程序项目

例如,项目名称为
flying-chess,依次选择
- 小程序
- 不使用云服务
- 使用JavaScript - 基础模板
开始页面
新建的项目中,系统有自动创建的第一个页面,文件在/pages/index/index.wxml,就在这里添加布局,
考虑到游戏可视情况选择几人玩,要在布局里添加表单组件,让用户选择,
然后点击开始游戏即可,显示结果如下图所示

在对应的
index.js逻辑文件里,添加开始游戏按钮点击事件,
在事件方法里写上代码调用系统的API如下,可打开游戏页面:
wx.navigateTo({ url:"/pages/game/game", ... })还需要把用户选择的数据传过去;
游戏页面
接下来,新建一个文件夹game,建一个游戏页面,文件名都是game,
在文件/pages/game/game.wxml中,添加游戏页面的布局,代码如下
<view class="game-panel"><image class="canvas" src="{{bgImg}}" /><view class="float-panel id{{index}} {{index==current ? 'active' : ''}}" wx:for="{{toasts}}" wx:key="index"><view class="title"><text>{{item}}</text></view></view><canvas class="canvas" id="canv" type="2d" disable-scroll="true" bindtouchstart="onTouchStart"></canvas>
</view>
<!-- 这里显示游戏底部的布局 --></view>
</view>
游戏页面上只用了一个
canvas画布组件,一个背景图片,一个float-panel类的视图层显示数据,都是层层叠放显示的
游戏逻辑
就在game.js文件里写游戏逻辑,当页面加载渲染完成时,系统会调用其中的方法onReady(),就在这里开始写,先获取canvas组件的数据,
画棋盘
实现画棋盘的逻辑并不复杂的,可以这么做,先用canvas绘制好网格,然后在对应的格子上绘制各种图案就可以,
就像平时用电脑办公的表格制作软件Excel,单元格可以合并的,如下图所示,

画棋盘的代码放在项目里的一个
/utils/game-map.js文件中,作为模块来用
需要用模块的时候,用import导入一下这个模块文件,看如下代码
import GameMap from '../../utils/game-map.js';Page({/*** 页面的初始数据*/data: {bgImg: '',//显示背景图片isAnimaging: false,//是否在动画中isNewAir: false,//是否再加棋子(派新飞机)toasts: ['x4', 'x4', 'x4', 'x4'],//飞机场显示的信息current: 0,//允许哪个玩家操作,默认第一个玩家(1号)currentColor: 'none',//设置游戏地图底部的控件背景颜色isSelectMode: false,//如果一个玩家派出多个棋子,会进入选择棋子状态isEndGame: false,//是否结束游戏},/*** 生命周期函数--监听页面初次渲染完成*/onReady() {//获取canvas组件的数据wx.createSelectorQuery().select('#canv').fields({size: true,node: true}, res => {//...省略了//这里设置canvas组件的节点和绘制APIthis.canvasData = {canvas: res.node,context: res.node.getContext('2d')};//获取底部控件对象 组件 将用来操作this.ctrlPanel = this.selectComponent('#ctrl-panel');//初始化棋盘this.initChessPanel();//...省略了}).exec()},
从上面代码看出来了,调用方法initChessPanel()就可以绘制游戏地图,来看看怎么实现的呢
//设置初始游戏数据
const initGameData = {bgColor: '#55A3FF',//棋盘背景色preCurrentUid: -1,//上一个玩家id,-1表示没有
};
//用不同的四个颜色分别表示四个玩家的棋子
const initUserList = ['#E60116', '#FFC700', '#0277A8', '#08983F'].map((color, i) => {return {chessColor: color,//棋子颜色isJoin: this.joinUsers.indexOf(i) >= 0,//是否加入};
});
//这里调用模块文件game-map.js的GameMap地图对象,把上面的配置数据传入即可
const map = new GameMap(this.canvasData, initUserList, initGameData);
//调用地图对象的绘制地图上所有格子的方法,格子就是棋子的位置,生成图片数据
let bgImg = map.drawMapGrids();
let current = this.data.current;
//设置好地图数据,将来用到
this.gameData = map.gameData;
//更新显示到页面
this.setData({bgImg,//把地图显示到背景中currentColor: this.gameData.userlist[current].chessColor,gameToast: `请${current + 1}号玩家点击投骰子`
});
//省略了...
棋盘上各种颜色都是可以替换的,例如到了晚上,背景就显示漆黑的夜空;
其中GameMap是一个游戏地图对象,在模块文件中有实现绘制地图,能给出坐标,
想想生活中用到的地图导航,作用一样的,
其中的joinUsers是从开始页面传来的数据,表示有哪些玩家加入游戏
把画好的棋盘生成一个图片数据,设置到背景图片组件中显示,
画出来后,效果如下图

画棋子
地图有了,再把所有棋子画出来,
开始玩的时候,棋子都是放在飞机场上的,每个玩家都有四个棋子,
在调用方法initChessPanel()里面继续写,代码如下,
//给地图设置棋子上的图像,就是飞机图片
map.setChessImg('/static/fly.png',()=>{//设置好,就可以绘制棋子了this.redraw();
});
然后调用方法redraw()去绘制所有棋子,代码如下
const { canvas, context: ctx } = this.canvasData;//canvas组件的数据
const { grids, userlist, size, chessImg } = this.gameData;//游戏的数据
const r = size / 2;//棋子半径
const { toasts } = this.data;//显示游戏状态的数据
//因为这是重绘方法 使用前先清空画布
ctx.clearRect(0, 0, canvas.width, canvas.height);
//把参与的玩家的棋子全部画出来
userlist.forEach((user, uid) => {let chesses = [];//记录可以绘制的棋子user.chesses.forEach((chess, i) => {//这里判断一下棋子的状态,如没有隐藏,且棋子有指向棋盘上的坐标,就可以加到记录中if (chess.isHide!=true && chess.gridIndex >= 0) {//...省略了继续判断逻辑}});//绘制棋子的chesses.forEach((chess, i) => {let g = grids[chess.gridIndex];//...省略了//绘制棋子的方法this.drawChessAtLocation(user, g);//判断棋子的数量,这是在同一个坐标上被叠放的棋子if (chess.count > 1) {let p = {//...};//给棋子画上数量标记ctx.fillText('' + chess.count, p.left, p.top);}});//判断这个玩家是否加入游戏if (user.isJoin) {//绘制玩家飞机场上的棋子user.chesses.forEach(chess => {if (chess.gridIndex < 0) {ctx.drawImage(chessImg, chess.left - r, chess.top - r, size, size);}});//更新玩家的信息toasts[uid] = `${uid + 1}号玩家`;} else {toasts[uid] = ``;}
});
//更新显示
this.setData({toasts
})
其中用到了方法
drawChessAtLocation(user, g),这是实现在地图上画棋子的,只传入参数用户数据和格子坐标
把所有棋子画出来后, 效果图如下

投骰子
由于绘制投骰子动画会变得复杂,需要写很多代码,不如做一下布局,这样好弄点,省了不少代码吧,
就用控件组件来代替投骰子,控件组件放在棋盘的底部,在文件/pages/game/game.wxml中加上如下布局代码
<view><block wx:if="{{isEndGame}}"><text>{{gameToast}}</text></block><block wx:else><ctrl-panel id="ctrl-panel" isGameEnd="{{isGameEnd}}" isDisabled="{{isAnimaging || isSelectMode}}" bindstart="onClickStart" bgColor="{{currentColor}}"><text>{{gameToast}}</text></ctrl-panel></block><view>
这个组件ctrl-panel是放在别处的,也是自定义组件,需要的时候可以拿来直接用,用这个来选择操作再好不过了,
看看控件在游戏页面的布局显示效果,如下图

这控件不仅仅是用来投骰子哦,还有一些细节待发现
游戏规则
接下来,写到游戏规则了,实现过程会复杂一些,
再理清一下思路,想想应该怎么做才合适呢,
飞行棋的游戏规则大致是这样的,没有玩过的可以了解一下:
- 棋子是顺时针方向走的,目的是走到自己颜色对应的飞机升降点;
- 若投骰子投到6点,可以选择再拿一个棋子(派一个新飞机),然后再投骰子一次,让新飞机走;
- 若走到自己对应颜色的一格,可以选择再走4步;
- 若走到有连接线的一格,可以选择直接飞行,到对面的相同颜色一格;
- 选择直接飞行时,如果中间的格子有遇到对手的棋子,就打回飞机场;
- 棋子走到一格子上有自己的棋子,是可以叠放的,
- 若是走到对手的棋子上就打回,如对手有叠放棋子,自己和对手的棋子就全部打回;
- 棋子走到升降点中间最接近的一格子上就算游戏胜利;
按照飞行棋的游戏规则,实现游戏逻辑,觉得难不难呢,可以分三步实现,能把难度降低,
1. 投骰子
要移动棋子前,先投骰子,这部分靠运气,通过概率分配实现,
投骰子的逻辑在组件ctrl-panel中有实现,代码如下
// 取1~6之间的随机数
let num = Math.floor(Math.random()*6)+1;
可见
Math的一些函数有经常用到
投完骰子后,组件ctrl-panel会传来事件,调用一个方法onClickStart(e),
是写到game.js里面的,代码如下,
const { stepNum } = e.detail;
//这里记录一下步数
this.stepNum = stepNum;
//记录玩家在棋盘中的所有棋子id
let indexes = [];
//...省略了
//定义走下一步的方法
let next = () => {//判断有没有派过新飞机,以及棋子有2个以上,让玩家先选择棋子再走if (this.isNewAir != true && indexes.length > 1) {this.setData({isSelectMode: true,//设置选择棋子状态gameToast: `请${current + 1}号玩家选择棋子`});return;}//开始动画 看出棋子移动效果this.startAnimation(false, () => {//动画结束会执行到这里,判断一下是否派过新飞机了,重置一下状态if (this.isNewAir) this.isNewAir = false;});
};
//获取步数后,判断是否是6点,是的话,让用户选择是否再拿一个棋子(派新飞机)
if (stepNum == 6 && this.isNewAir != true && indexes.length > 0) {if (user.chessIndex >= 0) {//...省略了}//下一步next();return;
}
//没有就继续,下一步
next();
2. 移动棋子
获取步数后,就可以移动棋子了,调用的方法startAnimation(used, callback),
需要通过动画实现棋子一步一步走的效果,代码如下
const { current } = this.data;//表示当前的玩家id
const { grids, size, userlist } = this.gameData;//游戏数据
this.gameData.preCurrentUid = current;//记录到上一个
//省略了...
//获取步数
let num = this.stepNum;
//动画结束方法
let end = (index) => {//走完棋子,动画也就结束了,调用此方法处理一下this.endAnimation(chess, index, used, callback);
};
//下一步移动方法
let next = (i) => {//省略了...//棋子位置变了,重新画个棋子this.drawChess(user, d);//如果步数没走完,继续调用下一步方法setTimeout(() => next(i + 1), StepTimeMs);
};
//获取棋子在地图中指定位置上的格子数据
let d = grids[chess.gridIndex];
//判断是否到了自己开始升降的位置,nodes是升降点的地图数据
if (d.nodes && d.nodes[0].grid.cid == current) {//省略了...this.takeGridChess(user, () => {this.enterNextNode(user, chess, d.nodes, num, chess.nodeIndex);});return;
};
//调用带走的棋子方法
this.takeGridChess(user, () => next(1));
调用移动棋子的方法参数used, callback分别是是否使用过,动画结束时会回调,
其中方法takeGridChess()就是把正在移动的棋子拿走,然后重新绘制整个棋子,实现动画效果,
方法enterNextNode()就是在进入升降航道路线时才调用的
还有,动画结束需要处理的方法是endAnimation(chessi, index, used, callback),
这实现了棋子到目标格子上做出反应处理的逻辑,代码如下
const { current } = this.data;
const { userlist, grids, size } = this.gameData;
const user = userlist[current];
const chess = user.chesses[user.chessIndex];
const gridIndex = chess.gridIndex;
let end = () => {//...省略了//处理结束,更新一下显示数据this.setData({isAnimaging: false,gameToast: `请${uid + 1}号玩家点击投骰子`});//重新绘制所有棋子this.redraw();//需要结束回调时 就回调if (callback instanceof Function) callback();
};
switch (gridIndex) {case 6:case 19://...{//执行到这里,说明是走到可以直线飞行的格子上,调用控件组件让玩家选择要不要直线飞行this.ctrlPanel.showSelectAirAtLineModal(res => {if (!res.confirm) {//没选择直线飞,就继续判断this.isBeatBackChess(gridIndex,current);end();return;}let i = 0;//直线飞行动画const next = () => {//...省略了i++;if(i>10) {//...省略了this.isBeatBackChess(chess.gridIndex, current, gridIndex + 6);end();return;}//...省略了setTimeout(next, 100);//0.1s移动一次}; this.takeGridChess(user, next);});return;}default:{//...省略了//调用判断是否碰到对方的棋子方法this.isBeatBackChess(chess.gridIndex, current);}
}
end();
3. 选择棋子
只有当玩家的飞机场里至少有两个都出发了,才是可以选择棋子的,
在game.js里写,是canvas组件绑定是触摸事件方法onTouchStart(e),选择棋子的代码如下
if (this.data.isEndGame) return;//游戏结束时,不处理操作
const touch = e.touches[0];
const { userlist, grids, size } = this.gameData;
const { current, isSelectMode } = this.data;
// 获取正在操作的玩家数据
let user = userlist[current];
let chessIndex = user.chesses.findIndex((c, i) => {//...省略了
});
//判断是否选择到棋子
if (chessIndex >= 0) {//更新玩家选择的棋子user.chessIndex = chessIndex;//判断是否是选择状态,若是的话,就开始走棋动画if (isSelectMode) {this.startAnimation();}
}
测试游戏
就讲到这里,篇幅有限,上面都有讲了重点的,还有几个方法就不讲了,
可以看看项目源码,直接运行,看到有感觉,里面代码并不多,可以参考学习一下,
最后看一下飞行棋小程序的运行效果图,怎么样,可以吧

若想一起玩的人数不够4个,在开始页面上是可以选择人数的

关于项目
如果要看项目源码 请点这里看,在资源一栏下可以找到飞行棋的源码,放心下载,感谢支持!
如果是在手机上看会有可能找不到资源一栏,就在电脑浏览器上看,
喜欢的话,点个赞收藏吧,遇到什么不明白的地方请主动留言,作者看到会回复。
相关文章:
【飞行棋】多人游戏-微信小程序开发流程详解
可曾记得小时候玩过的飞行棋游戏,是90后的都有玩过吧,现在重温一下,这是一个可以二到四个人参与的游戏,通过投骰子走棋,一开始靠运气,后面还靠自己选择,谁抢占先机才能赢,还可以和小…...
力扣 146. LRU 缓存
一、题目描述 请你设计并实现一个满足LRU(最近最少使用)缓存约束的数据结构。 实现 LRUCache 类: LRUCache(int capacity) 以正整数作为容量 capacity 初始化LRU缓存。int get(int key) 如果关键字 key 存在于缓存中,则返回关键…...
关于Oracle SCN的最大阈值
SCN每秒增长的速度跟Oracle的版本有关,在Oracle 11.2.0.2之前是每秒允许最大增长16384,在Oracle 11.2.0.2之后是默认每秒允许增长32768,这个值跟新增的隐含参数_max_reasonable_scn_rate有关,如下所示: NAME …...
Linux多路转接之poll
文章目录 一、poll的认识二、编写poll方案服务器三、poll方案多路转接的总结 一、poll的认识 多路转接技术是在不断更新进步的,一开始多路转接采用的是select方案,但是select方案存在的缺点比较多,所以在此基础上改进,产生了poll…...
Webpack打包流程
轻松了解Webpack 打包流程 Webpack是一个现代的JavaScript应用程序的静态模块打包器。它将多个JavaScript文件打包成一个或多个静态资源文件,以便在浏览器中加载。Webpack将应用程序视为一个依赖项图,其中包括应用程序的所有模块,然后通过该…...
React事件委托
React 事件委托(Event Delegation)是一种优化事件处理的技术,它通过将事件监听器添加到父级元素(而不是子元素)来实现。当事件触发时,事件会向上冒泡到父元素,然后在父元素上调用事件处理函数。…...
Notion——构建个人知识库
前言 使用Notion快三年了,它All in one的理念在使用以后确实深有体会,一直想找一个契机将这个软件分享给大家,这款笔记软件在网上已经有很多的教程了,所以在这里我主要想分享框架方面的内容给大家,特别对于学生党、研究…...
ModuleNotFoundError: No module named ‘Multiscaledeformableattention‘
在实现DINO Detection方法时,我们可能会遇到以上问题。因为在DeformableAttention模块,为了加速,需要自己去编译这个模块。 如果你的环境变量中能够找到cuda路径,使用正确的torch版本和cuda版本的话,这个问题很容易解…...
【数据结构】链表(C语言实现)
创作不易,本篇文章如果帮助到了你,还请点赞 关注支持一下♡>𖥦<)!! 主页专栏有更多知识,如有疑问欢迎大家指正讨论,共同进步! 🔥c语言系列专栏:c语言之路重点知识整合 &#x…...
【2023程序员必看】大数据行业分析
1、政策重点扶持,市场前景广阔 2014年,大数据首次写入政府工作报告,大数据逐渐成为各级政府关注的热点。 2015年9月,国务院发布《促进大数据发展的行动纲要》,大数据正式上升至国家战略层面,十九大报告提…...
通达信SCTR强势股选股公式,根据六个技术指标打分
SCTR指标(StockCharts Technical Rank)的思路来源于著名技术分析师约翰墨菲,该指标根据长、中、短三个周期的六个关键技术指标对股票进行打分,根据得分对一组股票进行排名,从而可以识别出强势股。 与其他技术指标一样,SCTR的设计…...
SpringBoot+Token+Redis+Lua+自动续签极简分布式锁Token登录方案
前言 用SpringBoot做一个项目,都要写登录注册之类的方案 使用Cookie或Session的话,它是有状态的,不符合现代的技术 使用Security或者Shiro框架实现起来比较复杂,一般项目无需用那么复杂 使用JWT它虽然是无状态的,也可…...
多模态:MiniGPT-4
多模态:MiniGPT-4 IntroductionMethodlimitation参考 Introduction GPT-4具有很好的多模态能力,但是不开源。大模型最近发展的也十分迅速,大模型的涌现能力可以很好的迁移到各类任务,于是作者猜想这种能力可不可以应用到多模态模…...
5年时间里,自动化测试于我带来的意义,希望你也能早点知道
摘要:在我有限的软件测试经历里,曾有一段专职的自动化测试经历。 接触自动化 那时第一次上手自动化测试,团队里用的是Python,接口自动化测试的框架是requestsExcelJenkins,APP自动化测试的框架是Appium。 整个公司当…...
【MyBaits】SpringBoot整合MyBatis之动态SQL
目录 一、背景 二、if标签 三、trim标签 四、where标签 五、set标签 六、foreach标签 一、背景 如果我们要执行的SQL语句中不确定有哪些参数,此时我们如果使用传统的就必须列举所有的可能通过判断分支来解决这种问题,显示这是十分繁琐的。在Spring…...
涅槃重生,BitKeep如何闯出千万用户新起点
在全球,BitKeep钱包现在已经有超过千万用户在使用。 当我得知这个数据的时候,有些惊讶,也有点意料之中。关注BitKeep这几年,真心看得出这家公司的发展之迅速。还记得2018年他们推出第一个版本时,小而美,简洁…...
绝地求生 压枪python版
仅做学习交流,非盈利,侵联删(狗头保命) 一、概述 1.1 效果 总的来说,这种方式是通过图像识别来完成的,不侵入游戏,不读取内存,安全不被检测。 1.2 前置知识 游戏中有各种不同的枪械&#x…...
麒麟操作V10SP1系统systemd目标单元
通过命令列出当前系统中所有可用的 systemd 目标单元。 用于被控制系统启动时运行哪些服务和进程,以及系统在运行过程中的行为。 rootkylin:~# systemctl list-units --typetargetUNIT LOAD ACTIVE SUB DESCRIPTION basic.target…...
python基于LBP+SVM开发构建基于fer2013数据集的人脸表情识别模型是种什么体验,让结果告诉你...
本身LBPSVM是比较经典的技术路线用来做图像识别、目标检测,没有什么特殊的地方 fer2013数据集在我之前的博文中也有详细的实践过,如下: 《fer2013人脸表情数据实践》 系统地基于CNN开发实现 《Python实现将人脸表情数据集fer2013转化为图像…...
antd——实现不分页的表格前端排序功能——基础积累
最近在写后台管理系统时,遇到一个需求,就是给表格中的某些字段添加排序功能。注意该表格是不分页的,因此排序可以只通过前端处理。 如下图所示: 在antd官网上是有关于表格排序的功能的。 对某一列数据进行排序,通过…...
Python爬虫实战:研究MechanicalSoup库相关技术
一、MechanicalSoup 库概述 1.1 库简介 MechanicalSoup 是一个 Python 库,专为自动化交互网站而设计。它结合了 requests 的 HTTP 请求能力和 BeautifulSoup 的 HTML 解析能力,提供了直观的 API,让我们可以像人类用户一样浏览网页、填写表单和提交请求。 1.2 主要功能特点…...
C++:std::is_convertible
C++标志库中提供is_convertible,可以测试一种类型是否可以转换为另一只类型: template <class From, class To> struct is_convertible; 使用举例: #include <iostream> #include <string>using namespace std;struct A { }; struct B : A { };int main…...
FFmpeg 低延迟同屏方案
引言 在实时互动需求激增的当下,无论是在线教育中的师生同屏演示、远程办公的屏幕共享协作,还是游戏直播的画面实时传输,低延迟同屏已成为保障用户体验的核心指标。FFmpeg 作为一款功能强大的多媒体框架,凭借其灵活的编解码、数据…...
基于Flask实现的医疗保险欺诈识别监测模型
基于Flask实现的医疗保险欺诈识别监测模型 项目截图 项目简介 社会医疗保险是国家通过立法形式强制实施,由雇主和个人按一定比例缴纳保险费,建立社会医疗保险基金,支付雇员医疗费用的一种医疗保险制度, 它是促进社会文明和进步的…...
蓝牙 BLE 扫描面试题大全(2):进阶面试题与实战演练
前文覆盖了 BLE 扫描的基础概念与经典问题蓝牙 BLE 扫描面试题大全(1):从基础到实战的深度解析-CSDN博客,但实际面试中,企业更关注候选人对复杂场景的应对能力(如多设备并发扫描、低功耗与高发现率的平衡)和前沿技术的…...
使用Matplotlib创建炫酷的3D散点图:数据可视化的新维度
文章目录 基础实现代码代码解析进阶技巧1. 自定义点的大小和颜色2. 添加图例和样式美化3. 真实数据应用示例实用技巧与注意事项完整示例(带样式)应用场景在数据科学和可视化领域,三维图形能为我们提供更丰富的数据洞察。本文将手把手教你如何使用Python的Matplotlib库创建引…...
使用Spring AI和MCP协议构建图片搜索服务
目录 使用Spring AI和MCP协议构建图片搜索服务 引言 技术栈概览 项目架构设计 架构图 服务端开发 1. 创建Spring Boot项目 2. 实现图片搜索工具 3. 配置传输模式 Stdio模式(本地调用) SSE模式(远程调用) 4. 注册工具提…...
Windows安装Miniconda
一、下载 https://www.anaconda.com/download/success 二、安装 三、配置镜像源 Anaconda/Miniconda pip 配置清华镜像源_anaconda配置清华源-CSDN博客 四、常用操作命令 Anaconda/Miniconda 基本操作命令_miniconda创建环境命令-CSDN博客...
Qt 事件处理中 return 的深入解析
Qt 事件处理中 return 的深入解析 在 Qt 事件处理中,return 语句的使用是另一个关键概念,它与 event->accept()/event->ignore() 密切相关但作用不同。让我们详细分析一下它们之间的关系和工作原理。 核心区别:不同层级的事件处理 方…...
【Linux】Linux安装并配置RabbitMQ
目录 1. 安装 Erlang 2. 安装 RabbitMQ 2.1.添加 RabbitMQ 仓库 2.2.安装 RabbitMQ 3.配置 3.1.启动和管理服务 4. 访问管理界面 5.安装问题 6.修改密码 7.修改端口 7.1.找到文件 7.2.修改文件 1. 安装 Erlang 由于 RabbitMQ 是用 Erlang 编写的,需要先安…...
