New to Godot, challenging myself to make a prototype in a weekend. Am I doing things correctly? Godot 3.6

submitted by edited

I'm mostly concerned about if I'm understanding how Godot does things. I'm coming from Love2D and so messing a lot with the GUI has been a new workflow for me completely. Please disregard the absolute mess that my code is, I'm trying to get through things quickly and not necessarily cleanly. Also, I know I don't need to add 'pass' all the time, I just like the pink visual cue that my function is over, sorta like Lua lol.

```gdscript
extends Node2D

var rng:= RandomNumberGenerator.new()

onready var arrow_left: Node2D = $ArrowLeft onready var arrow_up: Node2D = $ArrowUp
onready var arrow_right: Node2D = $ArrowRight onready var score_label: Label = $Control/ScoreLabel
onready var health_label: Label = $Control/HealthLabel

var arrow:PackedScene = preload("res://Arrow.tscn")

var arrows: Array = []
var score: int = 0
var health: float = 100.0
var in_left: bool = false var in_up: bool = false
var in_right: bool = false var left_pos: float = 0.0
var up_pos: float = 0.0 var right_pos: float = 0.0
var current_left_arrow: Node2D = null
var current_up_arrow: Node2D = null
var current_right_arrow: Node2D = null

func _ready() -> void:
rng.randomize()

var window_width: float = get_viewport().size.x
var window_height: float = get_viewport().size.y
var left_arrow_pos: float = window_width * 0.3
var up_arrow_pos: float = window_width * 0.5
var right_arrow_pos: float = window_width * 0.7
var arrows_height: float = window_height * 0.9

left_pos = left_arrow_pos
up_pos = up_arrow_pos
right_pos = right_arrow_pos

arrow_left.position.x = left_arrow_pos
arrow_left.position.y = arrows_height
arrow_up.position.x = up_arrow_pos
arrow_up.position.y = arrows_height
arrow_right.position.x = right_arrow_pos
arrow_right.position.y = arrows_height
pass

func _process(delta) -> void:
score_label.text = "Score: " + str(score) health_label.text = "Health: " + str(health)

if Input.is_action_just_pressed("left") and in_left and current_left_arrow:
    increase_score()
    arrows.erase(current_left_arrow)
    current_left_arrow.queue_free()
    current_left_arrow = null
    in_left = false

if Input.is_action_just_pressed("up") and in_up and current_up_arrow:
    increase_score()
    arrows.erase(current_up_arrow)
    current_up_arrow.queue_free()
    current_up_arrow = null
    in_up = false

if Input.is_action_just_pressed("right") and in_right and current_right_arrow:
    increase_score()
    arrows.erase(current_right_arrow)
    current_right_arrow.queue_free()
    current_right_arrow = null
    in_right = false

for i in arrows.duplicate():  #supposedly safe iteration?
    i.position.y += 3
    if i.position.y > 540:
        health -= 10
        arrows.erase(i)
        i.queue_free()

if health <= 0:
    get_tree().change_scene("res://GameOver.tscn")
if score >= 5:
    get_tree().change_scene("res://ChoosePath.tscn")

pass

func _on_CreateArrowTimer_timeout() -> void:

var arrow_instance = arrow.instance()
var arrow_pos = get_rand_arrow_pos()
if arrow_pos == 1:
    arrow_instance.position.x = left_pos
elif arrow_pos == 2:
    arrow_instance.position.x = up_pos
elif arrow_pos == 3:
    arrow_instance.position.x = right_pos
arrows.append(arrow_instance)
arrow_instance.position = Vector2(arrow_instance.position.x, 0)
add_child(arrow_instance)
pass

func increase_score() -> void:
score += 1
pass

func on_LeftArea2D_area_entered(area: Area2D) -> void: if area.is_in_group("arrow"): in_left = true
current_left_arrow = area.get_parent() #get the full arrow Node2D to use for deletion pass func _on_LeftArea2D_area_exited(area: Area2D) -> void:
if area.is_in_group("arrow"):
in_left = false current_left
arrow = null
pass

func on_UpArea2D_area_entered(area: Area2D) -> void: if area.is_in_group("arrow"): in_up = true
current_up_arrow = area.get_parent() pass func _on_UpArea2D_area_exited(area: Area2D) -> void:
if area.is_in_group("arrow"):
in_up = false current_up
arrow = null
pass

func on_RightArea2D_area_entered(area: Area2D) -> void: if area.is_in_group("arrow"): in_right = true
current_right_arrow = area.get_parent() pass func _on_RightArea2D_area_exited(area: Area2D) -> void:
if area.is_in_group("arrow"):
in_right = false current_right
arrow = null
pass

func get_rand_arrow_pos() -> int: return rng.randi_range(1,3)
pass
```

I'm not sure if the way I'm doing number randomization is correct and if using duplicate() truly is the right way to remove things from the array. Is it truly deleting the node in the array? Lastly, why can't I seem to get the window size as a script-wide variable? It seems like I can only do so inside the ready function. Thanks!

edit: Code has been properly formatted, sorry!

edit2: From what I can tell this is the right way to remove objects by iterating over the array in reverse
```gdscript
for a in arrows:
a.position.y += 300 * delta

for i in range(arrows.size() - 1, -1, -1):  #iterate safely by going backwards
    var a = arrows[i]
    if a.position.y > 540:
        health -= 10
        arrows.remove(i)
        a.queue_free()

```
I split up the movement code into its own for loop and then moved the deletion code into the reverse loop.

7
28

Log in to comment

7 Comments

Im curious why did you pick 3.6 over 4.4 or 4.x?

Hey there, I wanted open gl 2 support.

I have and like to use some pretty old and low powered stuff so its nice to have that. Also, its a smaller export which I also like.
Idk, I might be being stupid here but whatever its just a quick prototype!

You can only get the window size after the window is ready, if you were on godot 4 that’d be with an @onready var but I don’t remember how to do that in 3

Oh hey, this works lol in godot 3, its just 'onready' instead of '@onready'
thanks!

Nice, glad it was easy!

You can simplify your rng by using global randomize(). Then you won't have to remember to create a new random generator, and you can generate random stuff with randi_range() instead of rng.randi_range(). That is, if you don't need several differently-seeded random generators.

Couldn't read through the whole code because of messed up formatting.

Oh, good idea. I probably won't need several differently-seeded rngs. I can't imagine in this project when I'd need that.