持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第 29 天,点击查看活动详情
这是一套 张风捷特烈 出品的 Flutter&Flame
系列教程,发布于掘金社区。如果你在其他平台看到本文,可以根据对于链接移步到掘金中查看。因为文章可能会更新、修正,一切以掘金文章版本为准。本系列源码于 【toly_game】和 【pinball】 ,如果本系列对你有所帮助,希望点赞支持,本系列文章一览:
本文
)未完待续
~通过前面四篇,我们分析了 pinball
项目的整体结构,以及资源加载、主菜单、角色选择和玩法介绍等面板。最后剩下最重要的一块,就是游戏的主界面,主要包括六个部分:背景
、发射器
、轨道
、小球
、碰撞得分物
以及底部 摆动挡板
,其中最复杂的是各种碰撞体角色。
上面提及的游戏主界面构件,基本上都定义在 pinball_components
中。这也是 pinball
项目中文件最多,结构最复杂的包。
对游戏主界面的构成分析,也就是看这些构件以什么类型,如何分布在游戏场景中。下面我们就来一一介绍场景中的几个部分。
主界面最吸引人的是表面有一定的 透视感
和 深度感
,这样就形成了一个视觉上的立体空间。其实看到资源图片就会知道,这只是图片本身的效果,并非真正的 3D
模型。
如下是背景图片资源,可以看出,图片本身就是带有透视效果的。另外背景图片的边缘是比较随意的,因为它只是一个背景,在其周围会有相关的覆盖物。
对资源进行定位,很容易知道背景图的使用场景,如下是资源管理工具会生成 boardBackground
方法应用获取背景图片:
接下来继续追踪,可以看到在 board_background_sprite_component
文件中使用到了背景资源。在分析代码时,根据细微的线索去追踪有价值信息,是一件非常有趣的事。我们面对复杂的源码体系,寻找合适的切入点非常重要,没有必要一开始就硬啃核心代码处理逻辑。从周边入手,一层层剥离外围,找出线索,逐步深入,是一个很好的研究方式。
如下,就定位到了背景所对应的构件 BoardBackgroundSpriteComponent
。其中在 onLoad
方法中通过背景图片资源,为 sprite
成员赋值,并且尺寸是原图的十分之一。
紧接着,可以继续追踪 BoardBackgroundSpriteComponent
的使用场景。如下,它在 PinballGame
的 onLoad
方法中被加入到场景中:
在背景的底层,可以看到有个 ArcadeBackground
组件,它对应的就是最底层的地板。我们上一篇说过,这个地板会随着选择的角色而变化,这里就来看一下其中的原因。
另外有一个小细节,在移动端是没有地板的,整个视口都是游戏面板。毕竟移动端是竖屏的,没有空间显示更多内容。
如下所示,主要显示的内容由 ArcadeBackgroundSpriteComponent
觉得,他会监听 ArcadeBackgroundState
的变化。在新状态产出时,会更新 sprite
成员对应的图像。
可以看出,这里的地板的图片资源是定义在 CharacterTheme
中的,每个实现类都有相关的资源图片。比如下面是 android
对应的资源,这样就不难理解为什么角色的变化,会让地板图片产生变化。
接下来,最后一个问题,选择角色主题的逻辑是由 CharacterThemeCubit
完成的,产出的是 CharacterThemeState
。而这里源码是监听的是 ArcadeBackgroundState
状态,对应的是 ArcadeBackgroundCubit
,这显然是两个不同的 Bloc
。那这两者是如何产生关联的呢?也就是说选择角色时,CharacterThemeState
的变化如何通知到 ArcadeBackgroundCubit
。
以 ArcadeBackgroundCubit#onCharacterSelected
事件为线索,不难定位到:在 CharacterSelectionBehavior
中,会监听 CharacterThemeState
的变化,来触发 ArcadeBackgroundCubit
的事件,产出新的 ArcadeBackgroundState
,从而促使地板进行切换图片资,这个逻辑搭建可以梳理一下。
另外,从上面代码可以发现,小球 Ball
构件,也会受到角色主题的影响。仔细观察也不难发现,不同的角色主题,对应的小球颜色是不同的:
dash | android | sparky |
---|---|---|
| | |
通过查看 BallSpriteComponent
中逻辑的,可以知道小球构件会监听 BallState
的状态,来更新图片资源,而该资源就是定义在主题类中的。
比如 dash
主题对应的是小蓝球:
当用户选择某个角色主题,在 CharacterSelectionBehavior
中触发 onNewState
。如下红框在会寻找 Ball
对应的 BallCubit
来触发 onCharacterSelected
事件,产出新状态。从而更新小球的图片资源,这和地板的资源变化是一个道理。
在背景的上面是 Boundaries
构件:
从构件的定义中,很容易看出三个部分分别对应 boundary
文件夹中的三个图片。可以发现 pinall
项目无论是对 Flutter
中的组件,还是 Flame
中的构件,抽离分层的处理还是很细致和到位的。
通过图片资源可以看出,Boundaries
就是对背景之上的边界进行处理。比如左图的外框,中间是镂空的透明色,将背景图叠在其下,就可以遮住上面背景四周的部位。这样在视觉上就能营造出一种立体效果。
Launcher
构件主要包括三个部分:发射杆
、发射台
、轨道
。如下是三个部分的示意:
从资源中可以看出,发射台
、轨道
、挡板
这些都是独立的资源。通过在主界面上拼接,进行组合,呈现的整体视觉效果。
如下 Launcher
构件在有四个子构件, LaunchRamp
是轨道、Plunger
是发射杆、RocketSpriteComponent
是发射台。另外 Flapper
构件用于处理边界,限制小球在外壁之内,试了一下,如果把下面的 Flapper
注释掉,小球就会飞出边界之外。 对于可以运行的代码,当我们不提明白一处的作用,可以将其屏蔽掉,看一下前后的差异,从而认识某个模块的作用。
另外还有很多小的障碍物,用于碰撞后得分,这里就不一一细看了。在处理上都比较类似,可以根据资源中的图片来定位到相关的构件。
比如右侧中间的小恐龙,在游戏中会一直动,这对应的资源是 dino/animatronic
下的序列帧:
可以根据资源名称,追踪到 DashAnimatronic
构件,它是一个 SpriteAnimationComponent
。其中序列帧的资源使用的就是上面的图片:
底部可以摆动的两个挡板资源图片在 flipper
文件夹下,对应的构件是 BottomGroup
,包含左右两个_BottomGroupSide
构件。
整个游戏主界面的结构就介绍到这里,另外关于小球碰撞的相关处理,pinball
中使用的是 flame_forge2d
,我目前还没有研究,就先不分析了。下一篇,我们来看一下 Flame
中视口和相机的概念,并结合 pinball
中对相机的使用来实际体会相机的作用。那本文就到这里,明天见 ~
@张风捷特烈 2022.06.24 未允禁转
我的 公众号: 编程之王
我的 掘金主页
: 张风捷特烈我的 B站主页
: 张风捷特烈我的 github 主页
: toly1994328