昨天我们创建好了整个tile map
坏蛋Dan:rust基础学习--基于Bevy实现扫雷小游戏day2
但是并没有将它渲染到窗口里
既然是需要渲染到窗口里的,自然就少不了布局和样式设计。
我们的这个插件board_plugin
需要暴露以下的入口供自定义:
tilp map
的属性(宽、高、有多少炸弹)tile
之间的间距。tile
的大小或者根据窗口自适应大小Optional safe uncovered start zone
)这些个选项可以组合成一个资源。
那么开搞吧~
先在board_plugin/src/resources
文件夹中创建一个board_options.rs
文件
这些都是选项,其中Serialize
[2]和Deserialize
[3]这俩都来自serde
[4]
Serialize
和Deserialize
的作用是相反的,Serialize
方法用于将一个数据结构转换成任何其它数据结构。
这里为啥要用它们呢?因为这些选项是在窗口里交互的,所以得放到runtime
才行。
Vec3
[5] 一个三维的struct
:x: f32, y: f32, z: f32
。这里需要mark
下,因为对于我们这个游戏来说2d
就够了,所以需要留意下后面是怎么用的,会有什么效果。
然后我们来给这些个选项设置默认值,一般选项都是得有默认值的。
我们之前在附录里学到过一个派生属性Default
,我们可以基于这个Default
来实现默认值。
不过直接使用Default
属性的默认值是编译器固定的,在这里对于我们来说不太友好,所以我们来使用Default
这个trait
来自定义默认值
ok
,现在选项这块就基本搞定了,不说完整了,但是该有的样子都有了。
然后再把这个资源暴露出去
然后我们来使用,参考WindowDescriptor
,我们在main.rs
中进行配置,这种不算是业务逻辑,是属于环境初始化(配置)的。
注意这里如果要insert_resource
,那么你这个insert
进去的东西就得是实现Resource
这个trait
的。
接下来就是实现展示这个过程了,这属于业务逻辑相关的了,根据ECS
开发思维,这块自然就是放到system
里的。
我们回到board_plugin/src/lib.rs
文件中改动这个create_board
方法。
options
,也就是我们之前设置的选项资源debug
模式下终端打印出图)size
,也就是宽高,自适应的需要计算窗口和图的比例。这里简单的说下计算的逻辑。
我们的窗口是width: 700
和height: 800
。
min
和max
则是自适应的瓦片的最大值和最小值。
而瓦片的board
也就是整个扫雷的大小,是跟着瓦片个数来计算的,这里存的是一个元组,分别代表行多少个瓦片和列多少个瓦片,我们在main.rs
中设置的是20 * 20
。
那么整个扫雷的大小运算逻辑就是 瓦片size
* 20 * 20。
那么三组数据都已经有了,如果不是自适应,那就是fix size * 20 * 20
。
如果是自适应,计算逻辑在adaptative_tile_size
方法中。
首先是获取获取每个瓦片的宽高在这个窗口中的比值,也就是用窗口的宽/高 除以 瓦片行/列个数得到的值。接着两者选其最小的作为基础值,这样渲染就不会溢出。不过这里还需要考虑瓦片的最大最小值,如果这个比值小于瓦片最小值,那么返回瓦片最小值,同理大于时返回瓦片最大值(值必须限制在最大值最小值之间,所以称之为夹紧)。
board_size
自然就是这个比值 * 瓦片行 * 瓦片列。
Vec2
和Vec3
类似,创建的是二维的{ x: f32, y: f32 }
。
(0, 0)
,如果是自定义,那就直接拿自定义的作为初始位置。如果不是就是默认中心,中心距离左下角的距离正好就是(-board_size.x / 2, -board_size.y / 2)
这里带上负号的原因是我们是参照中心点距离(0, 0)
的位置向(0, 0)
做平移,自然就是往x, y
负方向平移。基于commands.spawn
创建一个实体
SpatialBundle
:一个bundle
,bundle
这个trait
使得实体拥有插入/移除组件的能力,它可以理解为自身带有好几个component
的实体模板,可以直接套进来使用它的component
,这个bundle
里面有几个component
:
Visibility
:控制这个实体的显隐ComputedVisibility
:通过算法计算出来这个实体是否需要隐/显示,以及是否需要被提取出来用于渲染。Transform
:它的属性有些类似css
中的transform
属性,比如translate、rotate、scale
,它是用于描述这个实体的位置。GlobalTransform
:和Transform
类似,不过它是用来描述这个实体在它所在参考系(reference frame
)里的位置。GlobalTransform
和Transform
的区别在于前者用于get
,后者用于set
,你想获取这个实体的位置,你就用GlobalTransform
,而如果是想替换或者移动这个实体,就用Transform
。
Visibility::VISIBLE
:创建一个visibility
的组件,它是visible
的。Transform::from_translation
:创建一个transform
组件,除了translation
属性不是默认值,其它都是默认值。board_position.into
:这个方法来自于Info
这个trait
。而这个trait
一般用法和From
这个trait
相反。From<a>
表示从A
变成自己B
,而Into</a><a>
则是将自己B
变成A
。来看个例子了解下怎么使用test_from
方法中我们将A
的实例a
变成了B
的实例。test_into
方法中我们也是将A
的实例a
变成了b
的实例。两者的不同点在于调用者,test_from
中调用from
方法的是B
,而test_into
中调用into
方法的是A
的实例a
。
这里有一点需要注意,不能在给B
实现From</a><a>
的同时给A
实现Into<b>
,即使理论上可行,依旧是会报错的。
扯远了,回到我们的代码中
在创建完整个扫雷的实体之后,我们插入了一个Name
的组件。这个组件有俩字段,hash
表示唯一标识符,而name
自然就是这个实体在app
中的名字。
with_children
方法接收一个闭包,这些个闭包会被传入add_children
方法中。它会为每一个闭包创建一个ChildBuilder
[6]实例,然后存入自身的commands
中。
ChildBuilder
会把当前的children
都构建到实体当中。
PushChildren
[7] 用于将children push
到当前实体的children
里面
有些绕,但是结合代码应该就比较清晰了,这里先是把PushChildren
放到了ChildBuilder
实例里面,然后这个ChildBuilder
的实例被传入spawn_children
也就是我们传入的闭包里面,执行完之后再把这个ChildBuilder
实例的push_children
也就是PushChildren
实例拿出来再放到实体的commands
里面。
所以实际上ChildBuilder
只是个临时工具而已,用来传递PushChildren
。
那么回到我们的闭包当中,它有一个参数是parent
,也就是ChildBuilder
实例。
然后我们又调用了spawn
这个方法生成一个新的实体
这个spawn
和前面的commands.spawn
不是同一个,这个是ChildBuilder
自己的。它里面调用了commands.spawn
方法创建一个实体,然后存储这个实体的id
到PushChildren
实例的children
字段里面,这个children
字段是一个vector
。
然后返回这个实体。
Background
,看名字也就知道这是我们扫雷的背景,白色,这里还做了transform
操作,为什么呢?因为这个背景的初始位置不对,是以坐标轴中心为背景中心的,所以还得往俩轴正方向迁移才行。SpriteBundle
: 前面说过bundle
可以看作是模板,里面包含了好几个组件,这个就不解释里面的东西了,看下都有啥即可。
Sprite
[8]: 同上,看下即可。
背景搞好了,该轮到我们的瓦片了,二维结构自然是双层的遍历,这里用迭代器替代for
性能会好很多, 之前学迭代器的时候也有说到过,它在编译阶段会被展开而不是for
循环处理,所以耗时少很多。
瓦片也是一个实体。
瓦片初始化状态都是gray
也就是灰色的,也就是没有被点开的时候。
splat
:创建一个矩形,这里还需要去掉padding
占的空间,也就是内边距。from_xzy
:这方法没啥好说的,就是from_transition
,但是值是vec3::new(x, y, z)
。表示三维空间偏移量。最后再把我们的Coordinates
作为组件插入到瓦片实体里。
那么现在已经是可以渲染到窗口里了。
我们来运行下
正常,不过需要过一遍侦测的所有组件,看下是否都正常。
我这里仅看了Coordinates
,因为文档里的版本过低,有些api
都已经被废弃,所以我自己摸索了好一会才完成。
现在渲染了,下一步就该轮到实现交互了。
main.rs
lib.rs
coordinates.rs
tile.rs
tile_map.rs
board_options.rs
剩下的几个就不说了,都是导入导出的mod.rs
今天我们实现了把瓦片图渲染到窗口里,但是暂时还不能交互。
编辑于 2023-02-10 14:57・IP 属地广东