Portal Rider Devlog 3 : hazards
hazards ⚠️
so the orginal PR that was being built in unity 🤢🤮🤧
had a lot of hazards that were being implemented. I will be implementing these same hazards in the new version 💪🏾 to stay oragnised I make a scene for each hazard.
Initially I wanted to just use the source files. but before we get into how I actually solved this part of the game. It was time to test.
the test
ok so essentially started off making a placeholder hazard
which consisted of :
RigidBody3DRayCast3DMeshInstance3Dusing aCapsuleMeshCollisionShape3Dwith aCapsuleShape
next a Group called Hazard was added to the RigidBody3D as well hazard.gd :
extends RigidBody3D
@onready var ray: RayCast3D = $RayCast3D
var group:String = "Level"
var function:String = "destroyHazard"
func _ready():
apply_central_force(Vector3(0,0,-420))
func _on_body_entered(body: Node) -> void:
#print("this body should be " + body.name)
if "Deleter" in body.get_groups():
get_tree().call_group(group, function)
queue_free()
this is a basic version of the script but eventually I will probably add something like this
func _process(delta):
if ray.is_colliding():
pass
#kill player and reset game
#queue_free()
so i can fully make use of the RayCast3D which will probably kill | reduce health off the player…haven’t decieded yet. but for now i’ll simply focusing on deleting any spawned hazards with a couple of invisible CSGBox3Ds with a group called Deleter on it. so when my hazard collides with one it then calls another function one i haven’t actually used before
get_tree().call_group()

ngl this 🤯x💯 frfr… i’ll probably use this more in the future
with this setup i would eventually be able to use this to test the next part
spawning hazards
back in the portal scene where like i said, EVERYTHING IS HAPPENING HERE❗ my root node has a couple functions that deal with hazards.
first thing is to refernce the hazard scene we just setup
@onready var hazard = preload("res://test/hazard.tscn")
then we have a function that will spawn a hazard at a random position on the map

doing it this way allows to have a lot of different spawn points there is also a timer that starts when all spawned items have been deleted.
spawn function
func spawnHazard():
for i in range(hazards.get(current_level, 1)):
var h = hazard.instantiate()
print("Hazard spawning")
# check the ammount of children within $SpawnHolder
var spawn_length = $SpawnHolder.get_child_count() - 1
#print(spawn_length)
# make a random number within that range
var rand_num = rand.randi_range(0, spawn_length)
print("Random number: ", rand_num)
# randomly use number to select a spawn location
var spawn_position = $SpawnHolder.get_child(rand_num).position
#print(spawn_position)
# add a hazard as a child of the level and set it's position
h.position = spawn_position
print(h.position)
add_child(h)
await get_tree().create_timer(1.0).timeout
print("i'm finished spawning hazards for this wave")
oh yeah remember our hazard.gd that has that cool way to call a function on another node via group name ❓ WELL I DO ❗❗❗ this is what the function destroyHazard() looks like:
func destroyHazard():
print("Hazard destroyed")
destroyed_hazards += 1
if destroyed_hazards == hazards.get(current_level, 1):
$InBetweenWaves.start()
print($InBetweenWaves.time_left)
destroyed_hazards = 0
as you can see i’m starting the timer in my hierarchy when the current wave of hazards have all been destroyed.
after i got spawning down it was time to use
the source files

by simply taking my test hazard scene and using it as a scene template i simply changed the CollisionShape3D according to cover the various hazard shapes. once i’ve made all of the hazards (there could be more who knows might add the SPICEX logo) it was time to make a couple changes to my spawning solution.
@onready var hazard_paths = [
"res://gameplay/hazards/badge.tscn",
"res://gameplay/hazards/beer.tscn",
"res://gameplay/hazards/coffee.tscn",
"res://gameplay/hazards/fishbone.tscn",
"res://gameplay/hazards/flamingo.tscn",
"res://gameplay/hazards/gold_palm.tscn",
"res://gameplay/hazards/grenade.tscn",
"res://gameplay/hazards/hat.tscn",
"res://gameplay/hazards/hockey_stick.tscn",
"res://gameplay/hazards/ninja_star.tscn"
]
this array of hazard paths stores the location of the hazards we just created. now i tried using "res://assets/models/FBX/hazards/Beer.fbx" as the path but because Beer.fbx isn’t setup with a RigidBody3D and all of the other setup from the test hazard it doesn’t move when it’s spawned on RUNTIME.
now that we have a neat reference for all these hazards, now it’s time to pick on randomly and then spawn it instead of our test hazard.
@onready var rand = RandomNumberGenerator.new()
func get_random_hazard():
var random_index = rand.randi_range(0, hazard_paths.size() - 1)
var random_hazard = load(hazard_paths[random_index])
return random_hazard
i added this bit of logic to randomly pic an object to load from the array then in my spawnHazard() function i can replace
hazard.instantiate() to get_random_hazard().instantiate()
and BAM we have the original assets that psybergames studios curated with the help of cubedrop back to life in this ressurection.