概述
Godot的2D程序化植物生成是我一直想要探讨的一个内容,但是一直没有真正开动,在刚过去的中秋节假期期间,在老家无聊,在一个素描本上构思了一系列想法。本篇就基于这些自己的想法介绍一下程序化植物生成的基本思路。不一定对,不一定能实现到什么程度,但是思考、探索和总结的过程,本身可能比结果更重要。
程序所要生成的植物种类
最常见的植物包括树、花和草三种。其下又可以分为各种具体类型。
植物程序生成,就是利用参数化形式创建并绘制植物。最常见且基础的手段是分形递归。
要想很专业的生成各类植物,需要学习一点专业的《植物学》。理解包括花序类型等知识,而不是凭空捏造和想象。
Godot中的2D植物程序化生成方案
- DrawFunctionBased:也就是基于绘图函数,以及纯几何图形的
- TextureBased:依赖于Texture2D的,整体和局部采用图片按一定算法排列
- StatusBased:基于图片或图片序列的多状态切换(参照基于状态的游戏元素一文)
根据方案的不同,设计思路和算法不同。
DrawFunctionBased
基于分形和递归思路+CanvasItem
的绘图函数,可以很容易的创建和绘制分形植物。
这里又有两种思路:
- 一种是完全基于算法生成,按顺序叠加绘制完成。
- 另一种是基于曲线和节点的控制:也就是在递归算法基础上施加手动影响
分形树
这个例子是我比较迷恋分形的那段时间的一个例子:
extends Node2Dvar linesfunc _ready() -> void:lines = tree(Vector2(200,200),100)func _draw() -> void:draw_multiline(lines,Color.AQUAMARINE,1)pass# 返回树形曲线的线段 - 可以使用draw_multiline绘制和显示
func tree(start_pos:Vector2,length:float,max_fork:int =5,steps:int =5):var lines:PackedVector2Array = []if steps > 0:for i in randi_range(2,max_fork):var deg = randf_range(deg_to_rad(-60),deg_to_rad(60))var end_pos = start_pos+ Vector2.UP.rotated(deg) * lengthlines.append_array([start_pos,end_pos])lines.append_array(tree(end_pos,length/2,5,steps-1))return lines
其实关于分形树,网上有太多人用各种绘图语言和工具实现过,甚至很多特别好看。
我这里举分形树的例子,只是想说,分形和递归思路在植物生成方面的确是基础思想。
TextureBased
将植物分成多个有机组成部分,比如把树分为枝干、树叶、花和果实,每个部分指定一张图片。
然后用算法生成和绘制。
簇排列器
花或叶是按一定的秩序排列的,可以抽象出几种:用于花或叶的绘制。
排列器
- 线状:根据直线或曲线路径层叠排列
- 鱼刺状:两侧成角度排列。
- 同心环形阵列
- 多层扇形层叠
时间比较紧,没来及画示意图,先直接上了自己手绘的草图。 – 2024年9月22日14:43:38
植物分层
无论是树、花还是草,都是占有一定空间体积的,也就是有纵深,而不是二维的平面。
表示纵深最好的方法就是分层+颜色的深浅。
以树为例:
- 在枝干层的前后可以加若高层叶簇
- 每个叶簇又可以是若干层树叶,中间可以夹杂花或者果实
这样,树就立体了起来。
StatusBased
分析所需要植物的各种状态,然后绘制和分配相应的图片或图片序列。
游戏中根据需要切换状态并绘制就可以了。
植物分布器
在搞定基础植物的基础上,植物的分布也有的搞。
- 通过编写分布器,可以程序化的组合和分布各类植物。
- 可以按曲线、多边形区域等进行分布。
- 分布过程可以给予一定的位移抖动、随机缩放。而且设定多种植物的出现权重。
总结
初步设想,但可行性比较高。