Skip to content

Commit

Permalink
Add 3D game project, squash the creeps
Browse files Browse the repository at this point in the history
  • Loading branch information
NathanLovato committed Apr 13, 2021
1 parent 7a7816e commit 31ff416
Show file tree
Hide file tree
Showing 47 changed files with 4,989 additions and 0 deletions.
2 changes: 2 additions & 0 deletions 3d-squash-the-creeps/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
.import
logs/
34 changes: 34 additions & 0 deletions 3d-squash-the-creeps/Main.gd
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
extends Node

export(PackedScene) var mob_scene


func _ready():
randomize()
$UserInterface/Retry.hide()


func _unhandled_input(event):
if event.is_action_pressed("ui_accept") and $UserInterface/Retry.visible:
get_tree().reload_current_scene()


func _on_MobTimer_timeout():
# Create a Mob instance and add it to the scene.
var mob = mob_scene.instance()

# Choose a random location on Path2D.
var mob_spawn_location = get_node("SpawnPath/SpawnLocation")
mob_spawn_location.unit_offset = randf()

var player_position = $Player.transform.origin

add_child(mob)
# We connect the mob to the score label to update the score upon squashing a mob.
mob.connect("squashed", $UserInterface/ScoreLabel, "_on_Mob_squashed")
mob.initialize(mob_spawn_location.translation, player_position)


func _on_Player_hit():
$MobTimer.stop()
$UserInterface/Retry.show()
140 changes: 140 additions & 0 deletions 3d-squash-the-creeps/Main.tscn
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
[gd_scene load_steps=12 format=2]

[ext_resource path="res://Main.gd" type="Script" id=1]
[ext_resource path="res://Player.tscn" type="PackedScene" id=2]
[ext_resource path="res://Mob.tscn" type="PackedScene" id=3]
[ext_resource path="res://default_env.tres" type="Environment" id=4]
[ext_resource path="res://ScoreLabel.gd" type="Script" id=6]
[ext_resource path="res://ui_theme.tres" type="Theme" id=7]

[sub_resource type="BoxShape" id=1]
extents = Vector3( 30, 1, 30 )

[sub_resource type="CubeMesh" id=2]
size = Vector3( 60, 2, 60 )

[sub_resource type="CylinderMesh" id=3]

[sub_resource type="SpatialMaterial" id=4]
albedo_color = Color( 0.960784, 0.486275, 0.0313726, 1 )

[sub_resource type="Curve3D" id=5]
_data = {
"points": PoolVector3Array( 0, 0, 0, 0, 0, 0, 14, 0, -15, 0, 0, 0, 0, 0, 0, -13, 0, -15, 0, 0, 0, 0, 0, 0, -13, 0, 16, 0, 0, 0, 0, 0, 0, 14, 0, 16, 0, 0, 0, 0, 0, 0, 14, 0, -15 ),
"tilts": PoolRealArray( 0, 0, 0, 0, 0 )
}

[node name="Main" type="Node"]
script = ExtResource( 1 )
mob_scene = ExtResource( 3 )

[node name="Ground" type="StaticBody" parent="."]
transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -1, 0 )
collision_layer = 4
collision_mask = 0

[node name="CollisionShape" type="CollisionShape" parent="Ground"]
shape = SubResource( 1 )

[node name="MeshInstance" type="MeshInstance" parent="Ground"]
mesh = SubResource( 2 )
material/0 = null

[node name="DirectionalLight" type="DirectionalLight" parent="."]
transform = Transform( 0.5, -0.777049, 0.382355, 0, 0.441506, 0.897258, -0.866025, -0.448629, 0.220753, 0, 12.5592, 14.7757 )
shadow_enabled = true

[node name="Player" parent="." instance=ExtResource( 2 )]

[node name="CameraPivot" type="Position3D" parent="."]
transform = Transform( 1, 0, 0, 0, 0.707107, 0.707107, 0, -0.707107, 0.707107, 0.183514, 0, 0 )

[node name="Camera" type="Camera" parent="CameraPivot"]
transform = Transform( 1, 0, 0, 0, 1, -2.98023e-08, 0, 2.98023e-08, 1, 0, 9.53674e-07, 19 )
projection = 1
fov = 48.6
size = 19.0

[node name="Cylinders" type="Spatial" parent="."]
transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 8, 0, 0 )

[node name="MeshInstance" type="MeshInstance" parent="Cylinders"]
transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 6, 0, -15 )
mesh = SubResource( 3 )
material/0 = SubResource( 4 )

[node name="MeshInstance3" type="MeshInstance" parent="Cylinders"]
transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, -21, 0, -15 )
mesh = SubResource( 3 )
material/0 = SubResource( 4 )

[node name="MeshInstance2" type="MeshInstance" parent="Cylinders"]
transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, -21, 0, 16 )
mesh = SubResource( 3 )
material/0 = SubResource( 4 )

[node name="MeshInstance4" type="MeshInstance" parent="Cylinders"]
transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 6, 0, 16 )
mesh = SubResource( 3 )
material/0 = SubResource( 4 )

[node name="SpawnPath" type="Path" parent="."]
transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0 )
curve = SubResource( 5 )

[node name="SpawnLocation" type="PathFollow" parent="SpawnPath"]
transform = Transform( -0.491811, 0, -0.870701, 0, 1, 0, 0.870701, 0, -0.491811, -12.9746, 0, -14.9397 )
offset = 26.9729
rotation_mode = 1
cubic_interp = false
loop = false

[node name="MobTimer" type="Timer" parent="."]
wait_time = 0.5
autostart = true

[node name="UserInterface" type="Control" parent="."]
anchor_right = 1.0
anchor_bottom = 1.0
theme = ExtResource( 7 )
__meta__ = {
"_edit_use_anchors_": false
}

[node name="ScoreLabel" type="Label" parent="UserInterface"]
margin_left = 20.0226
margin_top = 16.0181
margin_right = 126.023
margin_bottom = 71.0181
custom_colors/font_color = Color( 0.2, 0.184314, 0.215686, 1 )
text = "Score: 0"
script = ExtResource( 6 )
__meta__ = {
"_edit_use_anchors_": false
}

[node name="Retry" type="ColorRect" parent="UserInterface"]
visible = false
anchor_right = 1.0
anchor_bottom = 1.0
color = Color( 0, 0, 0, 0.447059 )
__meta__ = {
"_edit_use_anchors_": false
}

[node name="Label" type="Label" parent="UserInterface/Retry"]
anchor_right = 1.0
anchor_bottom = 1.0
text = "Press Enter to retry"
align = 1
valign = 1
__meta__ = {
"_edit_use_anchors_": false,
"_editor_description_": ""
}

[node name="WorldEnvironment" type="WorldEnvironment" parent="."]
environment = ExtResource( 4 )

[connection signal="hit" from="Player" to="." method="_on_Player_hit"]
[connection signal="timeout" from="MobTimer" to="." method="_on_MobTimer_timeout"]
38 changes: 38 additions & 0 deletions 3d-squash-the-creeps/Mob.gd
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
extends KinematicBody

# Emitted when the player jumped on the mob.
signal squashed

# Minimum speed of the mob in meters per second.
export var min_speed = 10
# Maximum speed of the mob in meters per second.
export var max_speed = 18

var velocity = Vector3.ZERO


func _physics_process(_delta):
move_and_slide(velocity)


func initialize(start_position, player_position):
translation = start_position
look_at(player_position, Vector3.UP)
rotate_y(rand_range(-PI / 4, PI / 4))

var random_speed = rand_range(min_speed, max_speed)
# We calculate a forward velocity first, which represents the speed.
velocity = Vector3.FORWARD * random_speed
# We then rotate the vector based on the mob's Y rotation to move in the direction it's looking.
velocity = velocity.rotated(Vector3.UP, rotation.y)

$AnimationPlayer.playback_speed = random_speed / min_speed


func squash():
emit_signal("squashed")
queue_free()


func _on_VisibilityNotifier_screen_exited():
queue_free()
61 changes: 61 additions & 0 deletions 3d-squash-the-creeps/Mob.tscn
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
[gd_scene load_steps=5 format=2]

[ext_resource path="res://Mob.gd" type="Script" id=1]
[ext_resource path="res://art/mob.glb" type="PackedScene" id=2]

[sub_resource type="BoxShape" id=1]
extents = Vector3( 0.679112, 0.544173, 1.10029 )

[sub_resource type="Animation" id=2]
length = 1.2
loop = true
tracks/0/type = "value"
tracks/0/path = NodePath("Pivot/Character:translation")
tracks/0/interp = 1
tracks/0/loop_wrap = true
tracks/0/imported = false
tracks/0/enabled = true
tracks/0/keys = {
"times": PoolRealArray( 0.22, 0.7, 1.18 ),
"transitions": PoolRealArray( 0.435275, 2.21914, 1 ),
"update": 0,
"values": [ Vector3( 0, 0.329753, 0 ), Vector3( 0, 0.660351, 0 ), Vector3( 0, 0.349734, 0 ) ]
}
tracks/1/type = "value"
tracks/1/path = NodePath("Pivot/Character:rotation_degrees")
tracks/1/interp = 1
tracks/1/loop_wrap = true
tracks/1/imported = false
tracks/1/enabled = true
tracks/1/keys = {
"times": PoolRealArray( 0.1, 0.46, 1.18 ),
"transitions": PoolRealArray( 0.482968, 0.535887, 1 ),
"update": 0,
"values": [ Vector3( -5.0326, 0, 0 ), Vector3( 10, 0, 0 ), Vector3( -10, 0, 0 ) ]
}

[node name="Mob" type="KinematicBody" groups=[
"mob",
]]
transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.0114588, 0 )
collision_layer = 2
collision_mask = 2147483648
script = ExtResource( 1 )

[node name="Pivot" type="Spatial" parent="."]

[node name="Character" parent="Pivot" instance=ExtResource( 2 )]
transform = Transform( 1, 0, 0, 0, 0.989268, 0.146113, 0, -0.146113, 0.989268, 0, 0.34652, 0 )

[node name="CollisionShape" type="CollisionShape" parent="."]
transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.52793, 0 )
shape = SubResource( 1 )

[node name="VisibilityNotifier" type="VisibilityNotifier" parent="."]
transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.062134, 0.331645 )
aabb = AABB( -1.19986, 0.251327, -1.57098, 2.41047, 1.09305, 3.17223 )

[node name="AnimationPlayer" type="AnimationPlayer" parent="."]
autoplay = "float"
anims/float = SubResource( 2 )
[connection signal="screen_exited" from="VisibilityNotifier" to="." method="_on_VisibilityNotifier_screen_exited"]
7 changes: 7 additions & 0 deletions 3d-squash-the-creeps/MusicPlayer.tscn
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
[gd_scene load_steps=2 format=2]

[ext_resource path="res://art/House In a Forest Loop.ogg" type="AudioStream" id=1]

[node name="MusicPlayer" type="AudioStreamPlayer"]
stream = ExtResource( 1 )
autoplay = true
72 changes: 72 additions & 0 deletions 3d-squash-the-creeps/Player.gd
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
extends KinematicBody

signal hit

# How fast the player moves in meters per second.
export var speed = 14
# Vertical impulse applied to the character upon jumping in meters per second.
export var jump_impulse = 20
# Vertical impulse applied to the character upon bouncing over a mob in meters per second.
export var bounce_impulse = 16
# The downward acceleration when in the air, in meters per second per second.
export var fall_acceleration = 75

var velocity = Vector3.ZERO


func _physics_process(delta):
var direction = Vector3.ZERO
if Input.is_action_pressed("move_right"):
direction.x += 1
if Input.is_action_pressed("move_left"):
direction.x -= 1
if Input.is_action_pressed("move_back"):
direction.z += 1
if Input.is_action_pressed("move_forward"):
direction.z -= 1

if direction != Vector3.ZERO:
# In the lines below, we turn the character when moving and make the animation play faster.
direction = direction.normalized()
$Pivot.look_at(translation + direction, Vector3.UP)
$AnimationPlayer.playback_speed = 4
else:
$AnimationPlayer.playback_speed = 1

velocity.x = direction.x * speed
velocity.z = direction.z * speed

# Jumping.
if is_on_floor() and Input.is_action_just_pressed("jump"):
velocity.y += jump_impulse

# We apply gravity every frame so the character always collides with the ground when moving.
# This is necessary for the is_on_floor() function to work as a body can always detect
# the floor, walls, etc. when a collision happens the same frame.
velocity.y -= fall_acceleration * delta
velocity = move_and_slide(velocity, Vector3.UP)

# Here, we check if we landed on top of a mob and if so, we kill it and bounce.
# With move_and_slide(), Godot makes the body move sometimes multiple times in a row to
# smooth out the character's motion. So we have to loop over all collisions that may have
# happened.
# If there are no "slides" this frame, the loop below won't run.
for index in range(get_slide_count()):
var collision = get_slide_collision(index)
if collision.collider.is_in_group("mob"):
var mob = collision.collider
if Vector3.UP.dot(collision.normal) > 0.1:
mob.squash()
velocity.y = bounce_impulse

# This makes the character follow a nice arc when jumping
$Pivot.rotation.x = PI / 6 * velocity.y / jump_impulse


func die():
emit_signal("hit")
queue_free()


func _on_MobDetector_body_entered(_body):
die()
Loading

0 comments on commit 31ff416

Please sign in to comment.