3D tutorial with brownian-ish motion enemies

This commit is contained in:
MartinOpat 2025-11-16 19:53:24 +01:00
parent 9628fff680
commit f848935717
9 changed files with 169 additions and 3 deletions

View File

@ -0,0 +1,15 @@
extends Node
@export var mob_scene: PackedScene
func _on_mob_timer_timeout() -> void:
var mob = mob_scene.instantiate()
var mob_spawn_location = get_node("SpawnPath/SpawnLocation")
mob_spawn_location.progress_ratio = randf()
var player_position = $Player.position
mob.initialize(mob_spawn_location.position, player_position)
add_child(mob)

View File

@ -0,0 +1 @@
uid://cfb7xo35cn5fo

View File

@ -1,6 +1,8 @@
[gd_scene load_steps=4 format=3 uid="uid://2wap0283yk0r"] [gd_scene load_steps=9 format=3 uid="uid://2wap0283yk0r"]
[ext_resource type="Script" uid="uid://cfb7xo35cn5fo" path="res://main.gd" id="1_0xm2m"]
[ext_resource type="PackedScene" uid="uid://ceuu150fmggvr" path="res://player.tscn" id="1_ig7tw"] [ext_resource type="PackedScene" uid="uid://ceuu150fmggvr" path="res://player.tscn" id="1_ig7tw"]
[ext_resource type="PackedScene" uid="uid://defdm2qdva75q" path="res://mob.tscn" id="2_h2yge"]
[sub_resource type="BoxShape3D" id="BoxShape3D_7dm0k"] [sub_resource type="BoxShape3D" id="BoxShape3D_7dm0k"]
size = Vector3(60, 2, 60) size = Vector3(60, 2, 60)
@ -8,10 +10,28 @@ size = Vector3(60, 2, 60)
[sub_resource type="BoxMesh" id="BoxMesh_ig7tw"] [sub_resource type="BoxMesh" id="BoxMesh_ig7tw"]
size = Vector3(60, 2, 60) size = Vector3(60, 2, 60)
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_ig7tw"]
albedo_color = Color(0.48985153, 0.33837724, 0.8704828, 1)
[sub_resource type="CylinderMesh" id="CylinderMesh_ig7tw"]
material = SubResource("StandardMaterial3D_ig7tw")
[sub_resource type="Curve3D" id="Curve3D_ig7tw"]
closed = true
_data = {
"points": PackedVector3Array(0, 0, 0, 0, 0, 0, -13.082657, 0, 14.897789, 0, 0, 0, 0, 0, 0, 14.178589, 0, 15.103276, 0, 0, 0, 0, 0, 0, 14.178589, 0, -15.240269, 0, 0, 0, 0, 0, 0, -13.01416, 0, -15.171773),
"tilts": PackedFloat32Array(0, 0, 0, 0)
}
point_count = 4
[node name="Main" type="Node"] [node name="Main" type="Node"]
script = ExtResource("1_0xm2m")
mob_scene = ExtResource("2_h2yge")
[node name="Ground" type="StaticBody3D" parent="."] [node name="Ground" type="StaticBody3D" parent="."]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -1, 0) transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -1, 0)
collision_layer = 4
collision_mask = 0
[node name="CollisionShape3D" type="CollisionShape3D" parent="Ground"] [node name="CollisionShape3D" type="CollisionShape3D" parent="Ground"]
shape = SubResource("BoxShape3D_7dm0k") shape = SubResource("BoxShape3D_7dm0k")
@ -20,7 +40,7 @@ shape = SubResource("BoxShape3D_7dm0k")
mesh = SubResource("BoxMesh_ig7tw") mesh = SubResource("BoxMesh_ig7tw")
[node name="DirectionalLight3D" type="DirectionalLight3D" parent="."] [node name="DirectionalLight3D" type="DirectionalLight3D" parent="."]
transform = Transform3D(1, 0, 0, 0, -0.50000006, 0.8660254, 0, -0.8660254, -0.50000006, 0, 15, 0) transform = Transform3D(1, 0, 0, 0, 0.8660254, 0.5, 0, -0.5, 0.8660254, 0, 15, 5)
shadow_enabled = true shadow_enabled = true
[node name="Player" parent="." instance=ExtResource("1_ig7tw")] [node name="Player" parent="." instance=ExtResource("1_ig7tw")]
@ -32,3 +52,32 @@ transform = Transform3D(1, 0, 0, 0, 0.70710677, 0.70710677, 0, -0.70710677, 0.70
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 19) transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 19)
projection = 1 projection = 1
size = 19.0 size = 19.0
[node name="Cyllinders" type="Node3D" parent="."]
[node name="MeshInstance3D" type="MeshInstance3D" parent="Cyllinders"]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -13, 0, -15)
mesh = SubResource("CylinderMesh_ig7tw")
[node name="MeshInstance3D2" type="MeshInstance3D" parent="Cyllinders"]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -13, 0, 15)
mesh = SubResource("CylinderMesh_ig7tw")
[node name="MeshInstance3D3" type="MeshInstance3D" parent="Cyllinders"]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 14, 0, -15)
mesh = SubResource("CylinderMesh_ig7tw")
[node name="MeshInstance3D4" type="MeshInstance3D" parent="Cyllinders"]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 14, 0, 15)
mesh = SubResource("CylinderMesh_ig7tw")
[node name="SpawnPath" type="Path3D" parent="."]
curve = SubResource("Curve3D_ig7tw")
[node name="SpawnLocation" type="PathFollow3D" parent="SpawnPath"]
transform = Transform3D(-0.007537449, 0, -0.9999705, 0, 1, 0, 0.9999705, 0, -0.007537449, -13.082657, 0, 14.897789)
[node name="MobTimer" type="Timer" parent="."]
autostart = true
[connection signal="timeout" from="MobTimer" to="." method="_on_mob_timer_timeout"]

View File

@ -0,0 +1,40 @@
extends CharacterBody3D
signal squashed
@export var min_speed = 10
@export var max_speed = 18
# In code timer for brownian motion
var T: float = 0.5
var Tinit: float = 1.0
var dt: float = 0.05
var t: float = 0.0
func _physics_process(_delta):
if t > T and Tinit < 0:
t = 0
set_new_velocity()
t += dt
Tinit -= dt
move_and_slide()
func initialize(start_position, player_position):
look_at_from_position(start_position, player_position, Vector3.UP)
set_new_velocity()
func set_new_velocity() -> void:
rotate_y(randf_range(-PI / 4, PI / 4))
var random_speed = randi_range(min_speed, max_speed)
velocity = Vector3.FORWARD * random_speed
velocity = velocity.rotated(Vector3.UP, rotation.y)
func _on_visible_on_screen_notifier_3d_screen_exited() -> void:
queue_free()
func squash():
squashed.emit()
queue_free()

View File

@ -0,0 +1 @@
uid://c5wp01kn08qxe

View File

@ -0,0 +1,27 @@
[gd_scene load_steps=4 format=3 uid="uid://defdm2qdva75q"]
[ext_resource type="PackedScene" uid="uid://bicorb7we351t" path="res://art/mob.glb" id="1_dy6sc"]
[ext_resource type="Script" uid="uid://c5wp01kn08qxe" path="res://mob.gd" id="1_nokgg"]
[sub_resource type="BoxShape3D" id="BoxShape3D_nokgg"]
size = Vector3(1.9155884, 0.7798462, 1.6226807)
[node name="Mob" type="CharacterBody3D" groups=["mob"]]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.22412324, 0)
collision_layer = 2
collision_mask = 0
script = ExtResource("1_nokgg")
[node name="Pivot" type="Node3D" parent="."]
[node name="Character" parent="Pivot" instance=ExtResource("1_dy6sc")]
[node name="CollisionShape3D" type="CollisionShape3D" parent="."]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.020843506, 0.4449278, 0.06854248)
shape = SubResource("BoxShape3D_nokgg")
[node name="VisibleOnScreenNotifier3D" type="VisibleOnScreenNotifier3D" parent="."]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.007541895, 0.34551716, 0.3237151)
aabb = AABB(-1.1488216, -0.65816104, -1.7166415, 2.2976432, 1.2323378, 3.433283)
[connection signal="screen_exited" from="VisibleOnScreenNotifier3D" to="." method="_on_visible_on_screen_notifier_3d_screen_exited"]

View File

@ -2,7 +2,8 @@ extends CharacterBody3D
@export var speed = 14 @export var speed = 14
@export var fall_acc = 75 @export var fall_acc = 75
@export var jump_impulse = 40 @export var jump_impulse = 50
@export var bounce_impulse = 40
var target_vel = Vector3.ZERO var target_vel = Vector3.ZERO
@ -35,5 +36,22 @@ func _physics_process(delta: float) -> void:
if is_on_floor() and Input.is_action_just_pressed("jump"): if is_on_floor() and Input.is_action_just_pressed("jump"):
target_vel.y = jump_impulse target_vel.y = jump_impulse
# Iterate through all collisions that occurred this frame
for index in range(get_slide_collision_count()):
var collision = get_slide_collision(index)
# Avoid calling collision again after deleting
if collision.get_collider() == null:
continue
if collision.get_collider().is_in_group("mob"):
var mob = collision.get_collider()
# hitting it from above.
if Vector3.UP.dot(collision.get_normal()) > 0.1:
mob.squash()
if !is_on_floor(): # TODO: This does not seem to work here
target_vel.y = bounce_impulse
break
velocity = target_vel velocity = target_vel
move_and_slide() move_and_slide()

View File

@ -7,11 +7,14 @@
radius = 1.0 radius = 1.0
[node name="Player" type="CharacterBody3D"] [node name="Player" type="CharacterBody3D"]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.3503281, 0)
collision_mask = 6
script = ExtResource("1_onrkg") script = ExtResource("1_onrkg")
[node name="Pivot" type="Node3D" parent="."] [node name="Pivot" type="Node3D" parent="."]
[node name="Character" parent="Pivot" instance=ExtResource("1_4flbx")] [node name="Character" parent="Pivot" instance=ExtResource("1_4flbx")]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.1, 0)
[node name="CollisionShape3D" type="CollisionShape3D" parent="."] [node name="CollisionShape3D" type="CollisionShape3D" parent="."]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0) transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0)

View File

@ -12,9 +12,15 @@ config_version=5
config/name="Squash the Creeps (3D)" config/name="Squash the Creeps (3D)"
config/description="In this game, your goal is to chase and kick out the creeps!" config/description="In this game, your goal is to chase and kick out the creeps!"
run/main_scene="uid://2wap0283yk0r"
config/features=PackedStringArray("4.5") config/features=PackedStringArray("4.5")
config/icon="res://icon.webp" config/icon="res://icon.webp"
[display]
window/size/viewport_width=720
window/size/viewport_height=540
[filesystem] [filesystem]
import/blender/enabled=false import/blender/enabled=false
@ -51,6 +57,12 @@ jump={
] ]
} }
[layer_names]
3d_physics/layer_1="players"
3d_physics/layer_2="enemies"
3d_physics/layer_3="world"
[rendering] [rendering]
anti_aliasing/quality/msaa_3d=2 anti_aliasing/quality/msaa_3d=2