Xylem is a game prototype made with FLOSS softwares including Godot, Blender and Krita.

Concept
In Xylem, you embody a botanist explorator whose purpose is to gather new plant species.
The first concept was drawn on a sketchbook then brought in Krita for digital painting.


Character

The character was modeled and rigged in Blender quite easily.
I made different animations (run, idle, throw something...) that I can export from the non linear animation editor (NLA) in Blender.
This is useful when importing different animations in Godot and assemble them using the Animation Tree.

Environment
I wanted to have a low-poly environment with solid colors so that the game is very graphical and the character detaches from the background in the final game.
The goal was to have multiple period of the day:


Game programming

In order for the game to be more interesting, I implemented a L-System class that can generate random trees based on defined rules.
The concept behind L-Systems is that you have a starting string, let's say "FX" and you also have rules :
# axiom
FX
# rules
X -> F[X]FF[XF]
Then each time, you take the input string and replace all occurences of the pattern by each rules :
# Step 1
FX
# Step 2
FF[X]FF[XF]
# Step 3
FF[F[X]FF[XF]]FF[F[X]FF[XF]F]
# Step 4
FF[F[F[X]FF[XF]]FF[F[X]FF[XF]F]]FF[F[F[X]FF[XF]]FF[F[X]FF[XF]F]F]
# And so on...
Each letter or symbol (F, X, +, -, ...) define the behavior when constructing the tree.
For example "F" means go forward, "+" means turn left, "-" turn right. And since it's in 3d, we add other symbols for different rotation on each axis.
The code is written in GDScript which is a scripting language similar to Python for the Godot game engine.
We have a LSystem and a Rule class like this :
class LSystem:
var state: String
var rules = []
var angle
class Rule:
var pattern: String
var replace: String
The process is as follows, we generate random rules with different depth and transforms:
Pattern "X" -> "F^F-F[FFF][-FF-FF[F[FF]]]"
Pattern "X" -> "-F+F[-F-FF^F]F-F+F+F-F-FF[+F]"
Pattern "X" -> "FF[^FF&F+F[&FF^F]]&F[-FF[F]]"
Pattern "X" -> "X-FFFFF"
Then for each rules in the LSystem, we replace all occurrences of the pattern by the according string:
func step() -> String:
for rule in rules:
state = state.replace(rule.pattern, rule.replace)
return state
We then iterate over the final string and construct the tree with mesh parts by keeping track of the current transform stack.
func generate_mesh(initial: Transform) -> ArrayMesh:
# Creating the mesh
var mesh: ArrayMesh = ArrayMesh.new()
# The stack is storing the transforms
var stack = [initial]
# We iterate through the string
for op in state:
match(op):
# Move forward
"F":
# X + rot
"+":
# X- rot
"-":
# Y+ rot
"<":
# ...
return mesh

Fractals are an amazing tool to create random variation. You can even animate them by changing the scale to get a growing effect:
