How to add collision to randomly generated terrain (transformed sprite)

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By delphonso

In Godot 3.3.2. I’m attempting to make a Worms-like game. I found this tutorial by OptionalDev on youtube.

In this, terrain is generated by cutting the top portion of a sprite off following a random noise pattern. The collision is custom-built to say anything above that line is air, and anything below it is solid.

However, I want to make a tunnel map. I can generate maps that I like, with about 30% of the map covered in ground and 10% covered in roof and open air in between.

enter image description here

However, the collision becomes a problem. Following this tutorial - the roof would have no collision, which I obviously don’t want. You also don’t get the benefits of Godot’s native collision objects.

The tutorials I’ve seen of MeshInstance2D all suppose a Sprite that hasn’t been programmatically modified, and I’m not sure it is what I want anyway. As this is one sprite, and not several blocks, CollisionShape2D doesn’t seem like a good choice.

Of course, the goal of this will be destructible terrain.
Any guidance on where I should look next would be much appreciated.

.
EDIT:
I have managed to recreate the tutorial’s collisions on the roof as well, but I’m still wondering if there is a way to programmatically make Godot generate CollisionShape2Ds that cover the visible portions of the image.

I should also point out that the image isn’t actually cut or removed at all - merely the “open” portion is set to Color(0,0,0,0) - the Alpha being 0 is the most important part.
.

I’m using the following code - only one modification from the tutorial’s code, which is better commented.



onready var FG = $Foreground

const CLEAR = Color(0, 0, 0, 0)
var line = []

func _ready() -> void:
	randomize()
	_generate_map()

func _generate_map():
	var fg_data = FG.texture.get_data()
	fg_data.lock()
	
	var noise = OpenSimplexNoise.new()
	noise.seed = randi()
	noise.octaves = 2
	noise.period = 180
	noise.persistence = 0.8
	
	for x in range(fg_data.get_width()):
		var high = ((noise.get_noise_1d(x) + 1) * fg_data.get_height() * 0.3) + fg_data.get_height() * 0.08
		line.append(high)
		for y in range(high):
			fg_data.set_pixelv(Vector2(x, y + (high*0.3)), CLEAR)
	fg_data.unlock()
	FG.texture.set_data(fg_data)