Phaser游戏制作
Game(游戏对象)
- 所属类:Phaser.Game
- this.xx.game === this
属性汇总
- config:全局配置对象;Phaser.Core.Config
- loop:主循环控制器;Phaser.Core.TimeStep
- 各类管理器实例
- canvas:游戏画布
config
type
- AUTO:Phaser引擎自主判断使用CANVAS,还是WEBGL
- CANVAS:性能低,兼容性高
- WEBGL:性能高、兼容性低
- HEADLESS:不渲染,只允许逻辑,适用于服务器端运行
scene
- 有Object、Array<Phaser.Scene>、Phaser.Scene,三种配置类型
- v3.85.PhaserJS中,默认进入config.scene数组中的第1个场景
other
- fps:配置帧率
- width、height:设置了world边界
- parent:父盒子(HTML元素)的id
- physics:有arcade(默认)、MatterJS两种引擎
loop
连续循环创建者
- requestAnimationFrame(默认):帧率等于浏览器刷新帧率
- setTimeout:需要配置config.fps.forceSetTimeout=true,帧率近似于config.fps.target
切换帧率
this.game.loop.stop()
Phaser.Core.TimeStep.call(this.game.loop,this.game,{
target:120,
forceSetTimeOut:true
})
this.game.loop.start(this.game.step.bind(this.game))
注意点
- 每一帧的时间不一定相同
- 采用setTimeout控制帧率,帧率与config.fps.target的偏差较大
Scene(场景对象)
- 所属类:Phaser.Scene
- this.xx.scene === this
- this.physics.world.scene === this
- this.physics.systems === this.sys
属性汇总
- add:简单游戏对象的工厂;Phaser.GameObjects.GameObjectFactory
- sound:声音管理器实例;Phaser.Sound.HTML5AudioSoundManager(只举1例)
- cameras:相机管理器实例;Phaser.Cameras.Scene2D.CameraManager
- tweens:简单动画管理器实例;Phaser.Tweens.TweenManager
- textures:纹理管理器实例;Phaser.Textures.TextureManager
- anims:动画管理器实例:Phaser.Animations.AnimationManager
- physics:物理对象实例;Phaser.Physics.Arcade.ArcadePhysics
- events:事件对象实例;Phaser.Events.EventEmitter
- input:输入事件对象实例;Phaser.Input.InputPlugin
- game:游戏对象实例;Phaser.Game
- load:加载对象实例;Phaser.Loader.LoaderPlugin
- time:计时器对象实例;Phaser.Time.Clock
- sys:系统对象实例;Phaser.Scenes.Systems
- scene:场景插件对象实例;Phaser.Scenes.ScenePlugin
sys
- xx.displayList:管理场景中所有需要渲染的对象
- xx.updateList:管理场景中所有需要更新的对象
scene
- xx.stop:结束当前场景
- xx.start(sceneKey, initValue):结束当前场景,并开启新场景
- xx.run:不结束当前场景,并开启新场景
physics
xx.add
- 创建复杂游戏对象的工厂
- 支持通过继承的方式定制化对象,并注册到工厂中
xx.world.enableBody(gameObject)
- 将对象添加到物理世界中
- 为对象添加body属性
xx.world.on("worldbounds",(body, 上, 下, 左, 右)=>{})
- 上、下、左、右四个参数的类型是布尔值
textures
创建纹理Texture
//方式1
this.load.image(纹理的key,图片路径)
//方式2
const myGraphics=this.add.graphics()
myGraphics.fillStyle(0xffffff)
myGraphics.fillCircle(中心点水平坐标,中心点垂直坐标,班级)
//从左上角顶点开始裁剪
myGraphics.generateTexture(纹理的key,裁剪宽度,裁剪高度)
//销毁myGraphics对象,销毁绘制的canvas,不会销毁已生成的纹理
myGraphics.destroy()
input
- keyboard:键盘对象
- mouse:鼠标对象
- on:监听鼠标事件、……
- keyboard.on:监听键盘事件、……
cameras
功能
- 场景宽度大于游戏屏幕宽度(world的宽度)时
- 相机位置要随角色位置变化,以确保玩家视觉体验
实现相机跟随角色
- 自定义水平跟随:this.cameras.main.scrollX=this.player.x-this.game.config.width/2
- 内置API跟随:this.cameras.main.startFollow(this.player)
固定定位:[GameObject].setScrollFactor(0)
anims
- 结合this.load.spritesheet/Atlas使用
- 通过图片的快速切换
- 实现角色的连贯动作
load
加载图片、JSON文件
生命周期
- init(data):接受初始化参数
- preload:加载图片资源、加载音乐资源,不同场景preload加载的资源,是可以共享的
- create:注册事件回调,绘制游戏页面
- update(time,detla):每一帧开始时,会进行一次调用
- pause:主动设置暂停后
- resume:pause暂停中恢复前
- wake:后台切换的暂停中恢复前,如浏览器标签页切换
- shutdown:类实例销毁前
- time:游戏开始到当前帧开始的时间差
- detla:上一帧开始到当前帧开始的时间差
其他常用对象
GameObjects
游戏对象的默认origin一般有两种(0,0),(0.5,0.5)
静态对象
- Graphics:图形,用法同canvas的ctx对象
- Rectangle:矩形
- Polygon:多边形
- ellipse:椭圆
- Text:文本
- Image:图片
Sprite(普通精灵)
- 创建精灵方式:new创建、工厂创建
- mySprite.destory():销毁精灵
- mySprite.setAngle(90):顺时针旋转
- mySprite.setScale():缩放
- 生命周期方法:constructor、preUpdate
ArcadeSprite
- body属性赋值
- 拥有速度、加速度、弹性、重力、碰撞检测
- mySprite.setVelocity(水平速度,垂直速度):添加速度
- mySprite.setCollideWorldBounds(true):限制在world的范围内
- mySprite.setBounce(n):设置弹跳系数(0~1)
- mySprite.disableBody():暂时禁用
- mySprite.enableBoby():重新开启
- mySprite.body.allowGravity = false:自身不受引力
- mySprite.body.onWorldBounds=true:碰撞到world边界时,能触发对应事件
Other
- 动态组:group.remove(成员child,场景this,销毁精灵?bollean)
- 静态组:staticGroup
Physics(物理对象)
- 控制游戏世界的物理规则
- 有Arcade、Matterjs两大引擎
Display(显示对象)
控制游戏对象布局、透明度、显示/隐藏、颜色、上下层级
Events(事件对象)
- 定时事件:update事件、定时器事件
- 交互事件:键盘输入、鼠标点击/滚动、触屏版滑动、手柄控制
- 碰撞事件:静态对象和动态对象都能注册碰撞事件
- 重合事件:静态对象和动态对象都能注册重合事件
- 通信事件:on注册、emit触发,用于数据通信
碰撞检测
- 物理引擎依赖速度和加速度,来计算精灵的运动路径和碰撞检测
- 直接修改物理坐标,不会触发物理引擎的碰撞检测,精灵会直接穿过物体
两种键盘按键监听方式
create(){
this.input.keyboard?.on('keydown', ({ key }: { key: string }) => {
console.log('keydown',key)
})
}
update(time: number, delta: number): void {
const keyW=this.input.keyboard?.addKey('w')
console.log('update-balls',keyW?.isDown,keyW?.isUp)
}
一直按下 "w" 键时:
- 会不断触发keydown事件
- update回调中的keyW?.isDown,一直保持为true
- 但是keydown事件触发的频率,不会和update的调用频率保持一致
- 并且keydown事件触发的频率,通常会小于update的调用频率
Math(计算工具类)
- Angle.WrapDegrees(x)<=>x%360
- DegToRad:角度转弧度
Actions(动作序列)
控制一组游戏对象的排列位置
Geom(几何图形)
- 创建几何图形描述对象
- 结合GameObjects.Graphics,才能把图形绘制到页面上
Atlas(图集)
- TexturePacker把一组图片合并成一张
- 合成的图片叫图集
- 还会额外生成一个JSON配置文件
- 配置文件记录着图集中每个图块的位置
- 配置文件记录着图集中每个图块的key
Tilemap(砖块地图)
使用方式1
- 用Tiled把图集切割成一组图块图片
- 用Tiled拖动图块图片构建砖块地图
- 导出描述砖块地图的JSON构建文件
- Phaser中导入构建文件和图集图片
- 生成图层并放入场景中

{
"compressionlevel": -1,
"height": 50,
"infinite": false,
"layers": [
{
"data": [……],
"height": 50,
"id": 1,
"name": "layer1",
"opacity": 1,
"type": "tilelayer",
"visible": true,
"width": 150,
"x": 0,
"y": 0
}
],
"nextlayerid": 2,
"nextobjectid": 1,
"orientation": "orthogonal",
"renderorder": "right-down",
"tiledversion": "1.11.0",
"tileheight": 16,
"tilesets": [
{
"columns": 8,
"firstgid": 1,
"image": "walls.png",
"imageheight": 135,
"imagewidth": 135,
"margin": 0,
"name": "wallTileset",
"spacing": 0,
"tilecount": 64,
"tileheight": 16,
"tilewidth": 16
}
],
"tilewidth": 16,
"type": "map",
"version": "1.10",
"width": 150
}
preload() {
this.load.setPath('assets');
this.load.image('wallImg','walls.png')
this.load.tilemapTiledJSON('wallMap','walls.json')
}
create() {
const map=this.make.tilemap({key:'wallMap'})
const tiles=map.addTilesetImage('wallTileset','wallImg')
map.createLayer(0,tiles,0,0)
}
使用方式2
- Phaser导入图集图片
- 用Phaser来把图集图片切割成一组图块图片
- 每个图块图片都分配从0开始的数字编号
- 用数字数组表示图层每块区域对应的图块编号
- 生成图层并放入场景中
Other
Curves(曲线)、Cameras(相机对象)、Loader(加载对象)、Input(输入对象)、Time(计时器)、Tweens(简单动画)、Animations(精灵动画)、Scenes(场景对象)、Textures(纹理对象)、Sound(声音对象)
技巧汇总
遮罩层制作
constructor(scene: Phaser.Scene, x: number, y: number, texture: string | Phaser.Textures.Texture, frame?: string | number) {
……
this.maskGraphics = this.scene.add.graphics()
this.maskGraphics.fillStyle(0x1677ff, 0.2)
this.maskGraphics.moveTo(this.x - this.width / 2, this.y - this.height / 2)
this.maskGraphics.lineTo(this.x + this.width / 2, this.y - this.height / 2)
this.maskGraphics.lineTo(this.x + this.width / 2, this.y + this.height / 2)
this.maskGraphics.lineTo(this.x - this.width / 2, this.y + this.height / 2)
this.maskGraphics.closePath()
this.maskGraphics.fill()
this.cooldownMask = this.maskGraphics.createGeometryMask()
this.setMask(this.cooldownMask)
}
protected preUpdate(time: number, delta: number): void {
super.preUpdate(time, delta)
if (this.cooldownTime > 0) {
this.cooldownTime -= delta
const progress = Phaser.Math.Clamp(1 - this.cooldownTime / this.cooldownDuration, 0, 1)
this.maskGraphics.clear()
this.maskGraphics.fillStyle(0x1677ff, 0.2)
this.maskGraphics.moveTo(this.x - this.width / 2, this.y - this.height / 2)
this.maskGraphics.lineTo(this.x + this.width / 2, this.y - this.height / 2)
this.maskGraphics.lineTo(this.x + this.width / 2, this.y + this.height / 2 - this.height * progress)
this.maskGraphics.lineTo(this.x - this.width / 2, this.y + this.height / 2 - this.height * progress)
this.maskGraphics.closePath()
this.maskGraphics.fill()
this.maskGraphics.fillStyle(0x1677ff, 0)
this.maskGraphics.moveTo(this.x - this.width / 2, this.y + this.height / 2 - this.height * progress)
this.maskGraphics.lineTo(this.x + this.width / 2, this.y + this.height / 2 - this.height * progress)
this.maskGraphics.lineTo(this.x + this.width / 2, this.y + this.height / 2)
this.maskGraphics.lineTo(this.x - this.width / 2, this.y + this.height / 2)
this.maskGraphics.closePath()
this.maskGraphics.fill()
}
}
startCooldown() {
this.cooldownTime = this.cooldownDuration
}
Tiled
语言设置

布局设置

创建地图


新增图集

创建图层

绘制图层

保存成JSON格式

TexturePacker
创建图集


保存图集

同步问题
帧同步vs状态同步
帧同步
- 服务端接收到所有客户端当前帧的操作后,广播给所有客户端
- 客户端依据接收的操作,跑出完整的游戏逻辑,实现游戏状态的更新
状态同步
- 服务端接收到所有客户端当前帧的操作后,跑出完整的游戏逻辑
- 服务端把得到的游戏状态,发送给所有客户端
- 客户端拿到游戏的状态后,更新自身当前的游戏状态
帧同步的不足(王者荣耀为例)
- 断线重连的加载速度很慢,因为要跑完所有帧的操作
- 观看王者荣耀回放时,无法进行回退
状态同步的优点
- 安全性非常高
- 断线重连非常快
- 只需创建和同步玩家视野内的角色
使用帧编号
- 服务端生成帧编号:服务端会定期生成帧编号
- 服务端发送帧编号给客户端:每当服务端生成新的帧编号时,它会将此帧编号发送给所有连接的客户端。
- 客户端接收到帧编号后处理操作:每个客户端在接收到帧编号后,会把这个编号分配给自己接下来的操作。
- 客户端将带有帧编号的操作发送给服务端:客户端在此帧编号下进行的操作会被打包,并发送回服务端。
- 服务端接收并广播操作:服务端收到客户端的操作后,会将这些操作进行处理并广播给所有客户端
帧操作的收集和存储
create(){
this.input.keyboard?.on('keydown', () => {……})
}
update(){
const keyW=this.input.keyboard?.addKey('w')
……
}
- 建议收集update方法中的操作
- 服务端存储所有帧操作
- 客户端可以缓存100帧操作
帧操作的发送
快速反应游戏
- 客户端发送帧操作时,建议逐帧发送
- 服务端发送帧操作时,建议逐帧发送
- 服务端帧编号发出后,用50~100ms收集客户端操作
慢速反应游戏
- 客户端发送帧操作时,可以批量发送
- 服务端发送帧操作时,可以批量发送
- 服务端帧编号发出后,用200~500ms收集客户端操作
帧同步重连
- 游戏渲染方式,切换为HEADLESS,减少性能消耗
- 方式一:自定义myUpdate函数,批量处理帧操作,加速得出游戏的最新状态
- 方式二:提高游戏帧率以及游戏对象的速度,加速得出游戏的最新状态
魔兽技巧
快捷键
- F1:第1个购买的长老
- F2:第2个购买的长老
- F3:第3个购买的长老
- Ctrl+1:选中的目标组成编队1
- Shit+1:把选中的目标加入编队1
- 单击1:选中编队1
- 双击1:选中编队1&&把视角切换到编队1
- Ctrl+目标A || 双击目标A:选中所有目标A
- Alt+C:把视角切换到队伍栏选中的目标
- 长按Shit:保持选中的队伍不变,可以通过鼠标 选中 或 取消选中 目标
- 长按Alt:显示所有角色的血量
- 退格:视角切到基地,合理分配建筑的位置,方便切回视角后找到
- 士兵通用:patrol-巡逻;attack-攻击;stop-停止;hold-保持原地
- 建造者通用:build-建造
- 长老通用:open-打开
- 编队1:射手队
- 编队2:前排队
- 编队3:飞鸟队 || 弩车队
- 编队4:建筑物队
- 编队5:其他队4
- 编队0:精灵
精灵快捷键
| 建筑物 |
生命之树:T(tree) 月亮泉:M(moon) 保护者:P(protector) 长者祭坛:A(alter) 猎手大厅:H(hunter) 战争古树:R(range-靶场) 知识古树:L(loremaste-精通古代传说和历史的人,大师) 风之古树:W(wind) |
| 熊德 | roar-咆哮、enhance-提高、form-变形 |
| 丛林守护者 |
缠绕的树根(Entangling Roots):快捷键为“E”,从地下召唤出树根缠绕住敌人 自然之力(Force of Nature):快捷键F,召唤出树人。 荆棘光环:快捷键R(return);让周围友军能返还伤害 宁静(Tranquility):快捷键为T。在周围创造治疗之雨 |
| 月之女祭司 |
猫头鹰:快捷键C(call);召唤一只猫头鹰 灼热之箭:快捷键R(reinforce);攻击时带有额外伤害,可以设置为自动施放 强击光环:快捷键T(toughen) 群星坠落(the stars fall):快捷键F 隐形:快捷键I(invisibility) |
| 恶魔猎手 |
法力燃烧(mana Burn) :快捷键B 献祭(loss of life):快捷键L 闪避(evasion):快捷键E 变身(transfigure):快捷键T |
一级打法
| ||
|
1队豹子满员 建战争古树+买5弩车 2队射手满员 |
二级打法
| ||
|
建生命之树(后续配10个精灵)+4射手+4守卫之树 | ||
|
生命之树2级 |
| |
三级打法
| ||
|
建生命之树(后续配10个精灵)+4射手+4守卫之树 | ||
|
生命之树2级 |
| |
|
升级生命之树 | ||
| 生命之树3级 |
| |
精灵兵种分类
| 兵工厂分类 |
人类:弓箭手、豹子、弩车、小鸟弓箭手 兽类:小鸟、奇美拉、小鹿、变身的熊德、变身的法德 |
| 位置分类 |
前排:豹子、变身的熊德 后排:弓箭手、小鹿、法德 空中:小鸟、小鸟弓箭手、奇美拉、变身的法德 |
| 一级打法 |
1队:1麋鹿11豹子 2队:10射手 3队:5弩车+1精灵 |
| 二级打法 |
全买精灵龙:需要后期补奇美拉 全买小鹿:需要后期补奇美拉 小鹿+山岭巨人:打不赢三级队伍 全买山岭巨人:不行 |
| 三级打法 |
1队:1麋鹿1老虎1刀客9小鹿 2队:4熊德 3队:3奇美拉 |
欢乐斗地主
八雀牌
基础牌型
- 两张:对子
- 三张:三相同、同色顺子
- 四张:四相同、同色顺子
- 五张:五相同、同色顺子
- 六张:六相同、同色顺子
- 七张:七相同、同色顺子
- 八张:八相同、同色顺子
胡牌类型
- 3/3/2
- 4/4
- 5/3
- 6/2
- 8
推荐组合
- 7张同色顺子
- 5n-2m
- 4n-3(n-1)
篮球
右手投球
- 右腿在前,身体下顿
- 右大臂和右小臂呈90°
- 右臂和右腿处于同一水平线
- 左手撤出,右臂举球至头顶右侧,
- 起身并伸展手臂,最后阶段三指按压篮球
- 成功进球
- 快速出手和跳投总要选一个
抢篮板
- 篮球出手,砸中篮筐
- 篮球会有很大概率再次弹起
- 篮球的落地轨迹清晰可见
- 快速挪动脚步,弹跳、伸手、抓球
抢断传球
- 观察持球者动作
- 预判传球方位
- 快速奔跑并抢断
运球过人
- 左右交换运球,同时左右不停进行移动拉开距离
- 加速从一个方向进行突破
- 选择上篮或者跳投
游泳
游泳方式
- 蛙泳∶划水+蹬腿
- 自由泳∶扒水+摆腿
- 蛙泳划水+自由泳摆腿
- 自由泳扒水+蛙泳蹬腿
- 蹬腿式仰泳
- 摆腿式仰泳
- 蹬腿式踩水
- 摆腿式踩水
- 蹬自行车式踩水
自由泳
- 右臂划水 右肩转向出水 头部右侧出水
- 右臂出水
- 右臂入水放平 左腿下蹬
- 左臂划水
- 左臂出水
- 左臂入水放平 右腿下蹬
- 左臂划水,右腿蹬水,达到力的平衡
- 右臂划水,左腿蹬水,达到力的平衡
王者自走棋
射坦辅
(狄仁杰、一个射手)+(钟馗、法坦)+(程咬金、物坦)+(张飞、蔡文姬)
坦克
(两个法坦、六个物坦)+狄仁杰
坦射
(狄仁杰、两个射手)+(两个法坦、四个物坦)
辅远法
(蔡文姬、孙膑、墨子)+六个远程法师
辅近法
(蔡文姬、孙膑、墨子)+(司马懿、芈月)+三个远法+空位
神辅射
四个神阵营+(张飞、盾山/小明)+两个射手
蜀射手
(刘关张赵、黄忠、元歌/刘禅)+(一个站桩射手、两个游击射手)
守卫军射手
(伽罗、守约、四个低价守卫军)+四个射手
神稷下射手
(后羿+两个神阵营)+四个稷下+两个射手
神射手
三个神阵营+四个游击射手
魏法师
魏阵营+(墨子、孙膑、芈月)
桑刺客
(露露、橘子、宫本/火舞)+(一个女刺+五个男刺)
魔刺客
魔阵营+五个男刺+空位
三国杀自走棋
蜀祢衡
祢衡+刘巴+其他蜀势力
吴祢衡
祢衡+凌统+2韩当+2孙浩+吕蒙/张昭/刘表/祖茂
汉祢衡(有破军积累)
祢衡、2张让、1赵忠、1破军持有者、1空位、1董承(移除消耗)。董成和赵忠的切换点在于黄色董成的属性低于场上赵忠的属性
汉祢衡(无破军积累)
张让+祢衡+赵忠+移除锦囊/吸收攻击力锦囊+吕布/(张宁+斐元绍的黄巾兵)
黄巾刘表
刘表+3刘辟+2邓艾+张宝
吴刘表
刘表+n祖茂+1韩当
魏刘表
刘表+司马懿+邓艾+曹丕+曹仁
群刘表
刘表+(诸葛+南华老仙)/(邓艾+曹丕+司马懿)/(韩当+太史慈+祖茂+凌统)/(刘辟+张宝+张宁)+韩馥
魏判定
司马懿+(3甄姬+3曹丕)/(4甄姬+2曹丕)
魏承伤
司马懿+郭嘉+曹金玉+钟会+典韦
黄巾攻击
张宝+张宁+张楚+于毒+卜巴+张燕+于吉
张宝+张楚+于毒+2卜巴+于吉
张宝+张宁+张楚+于毒+2张燕+于吉
张宝+张宁+张楚+祢衡
黄巾刷伤
张曼成+张闿+于吉+于毒+祢衡
黄巾张让
2张让+祢衡+张宁+赵忠
汉破军(前期)
刘繇+何进+王允+皇甫嵩+万年公主+何太后+董承
鲁肃特有
二级阵营:孙翎鸾+糜夫人
无限金钱
刘巴+祢衡、刘表+邓艾/诸葛亮/(韩当+祖茂)、2张让、韩当+祢衡+凌统
有限金钱
祢衡
黄巾兵的正确绑法
第一个绑定嘲讽和黄巾兵,其余人绑定黄巾兵不加嘲讽
更多推荐

所有评论(0)