Hello there! I'm a complete newcomer, having just a few months of experience with Python and a few weeks of experience with Godot, so I'm pretty sure there's gotta be a better way to do this that I haven't figured out yet, and after a whole day of trying, I decided to check with the experts.
I'm trying to build a relatively simple puzzle game. The first step for what I'm trying to achieve is procedurally generating an image composed of triangular shapes. I made a scene for those (because they needed collision detection for later), then tried to write a script that would instance one at a time, in such a way that every new triangle is always touching at least one of the previous triangles' faces.
Problem is, since I'm still not used to vector math, the style guide, best practices and so on, my code started to grow too complicated for my own good, and I can't shake the feeling that there's probably an easier way to go about this. Anyways, this is what I have on my Main node:
extends Node2D
export var _difficulty := 2
var _size = _difficulty * 4
var _triangles = {}
var _triangle_number = 0
func _ready():
randomize()
while _triangle_number < _size:
add_empty_triangle()
_triangle_number += 1
func add_empty_triangle():
var _scene = load("res://EmptyTriangle.tscn")
var _empty_triangle = _scene.instance()
var _occupied_side := 3
if not _triangles:
_empty_triangle.rotation_degrees += get_random_angle()
add_child(_empty_triangle)
else:
var _chosen_triangle = _triangles.keys()[randi() % _triangles.size()]
var _triangle_object = _triangles[_chosen_triangle][0]
var _available_sides = _triangles[_chosen_triangle][1]
var _previous_angle = _triangle_object.get_rotation_degrees()
var _previous_position = _triangle_object.get_global_position()
var _side = choose_sides(_available_sides)
var _new_position := Vector2()
#Attach to base
if _side == 0:
_new_position = attach_to_base(_previous_position, _previous_angle)
_available_sides.erase(0)
_occupied_side = 0
#Attach to left side
elif _side == 1:
_new_position = attach_to_left_side(_previous_position, _previous_angle)
_available_sides.erase(1)
_occupied_side = 1
#Attach to right side
elif _side == 2:
_new_position = attach_to_right_side(_previous_position, _previous_angle)
_available_sides.erase(2)
_occupied_side = 2
if not _available_sides:
_triangles.erase(_triangles[_chosen_triangle])
_empty_triangle.rotation_degrees = new_angle(_previous_angle)
_empty_triangle.global_position = _new_position
add_child(_empty_triangle)
_triangles[_triangle_number] = [_empty_triangle, [0, 1, 2]]
if _occupied_side < 3:
_triangles[_triangle_number][1].erase(_occupied_side)
func get_random_angle():
var _degrees = [0.0, 90.0, 180.0, 270.0]
var _angle = _degrees[randi() % _degrees.size()]
return _angle
func choose_sides(_available_sides):
if _available_sides.size() > 1:
var _side = _available_sides[randi() % _available_sides.size()]
return _side
return _available_sides[0]
func new_angle(_previous_angle):
if _previous_angle in [180.0, 270.0]:
return _previous_angle - 180.0
return _previous_angle + 180.0
func attach_to_base(_previous_position, _previous_angle):
var _new_position := Vector2()
if _previous_angle == 0.0:
_new_position = Vector2(_previous_position.x, _previous_position.y + 32)
elif _previous_angle == 180.0:
_new_position = Vector2(_previous_position.x, _previous_position.y - 32)
elif _previous_angle == 90.0:
_new_position = Vector2(_previous_position.x - 32, _previous_position.y)
elif _previous_angle == 270.0:
_new_position = Vector2(_previous_position.x + 32, _previous_position.y)
return _new_position
func attach_to_left_side(_previous_position, _previous_angle):
var _new_position := Vector2()
if _previous_angle == 0.0:
_new_position = Vector2(_previous_position.x - 36, _previous_position.y)
elif _previous_angle == 180.0:
_new_position = Vector2(_previous_position.x + 36, _previous_position.y)
elif _previous_angle == 90.0:
_new_position = Vector2(_previous_position.x, _previous_position.y - 36)
elif _previous_angle == 270.0:
_new_position = Vector2(_previous_position.x, _previous_position.y + 36)
return _new_position
func attach_to_right_side(_previous_position, _previous_angle):
var _new_position := Vector2()
if _previous_angle == 0.0:
_new_position = Vector2(_previous_position.x + 36, _previous_position.y)
elif _previous_angle == 180.0:
_new_position = Vector2(_previous_position.x - 36, _previous_position.y)
elif _previous_angle == 90.0:
_new_position = Vector2(_previous_position.x, _previous_position.y + 36)
elif _previous_angle == 270.0:
_new_position = Vector2(_previous_position.x, _previous_position.y - 36)
return _new_position
When I play the scene, it often works, but sometimes the debugger will tell me "Invalid get index '0' (on base: 'Array')" and point at the choose_sides function. If I understand it correctly, this means that, in this case, _available_sides is an empty array; I thought I addressed this problem in lines 50-51 (inside add_empty_triangle), but clearly I did something wrong.
So I really want to know, if someone'll indulge me:
- What exactly is causing this error;
- What other mistakes I made (I'm sure they're there somewhere...);
- What would be a better way to go about this.
Thanks a lot for your attention!