Now About Social Code
summaryrefslogtreecommitdiff
path: root/scripts
diff options
context:
space:
mode:
authorLucas Fryzek <lucas.fryzek@fryzekconcepts.com>2024-09-17 22:02:33 +0100
committerLucas Fryzek <lucas.fryzek@fryzekconcepts.com>2024-09-17 22:02:33 +0100
commit0abec8156bd944aa883d544850ee1187219ba943 (patch)
tree55e222da361d176b0ba79611704b56e2d942a831 /scripts
Initial commit
Diffstat (limited to 'scripts')
-rw-r--r--scripts/bsp_level_generator.gd78
-rw-r--r--scripts/bullet.gd17
-rw-r--r--scripts/enemy.gd87
-rw-r--r--scripts/level_generator.gd118
-rw-r--r--scripts/player.gd76
-rw-r--r--scripts/spin_ground.gd15
6 files changed, 391 insertions, 0 deletions
diff --git a/scripts/bsp_level_generator.gd b/scripts/bsp_level_generator.gd
new file mode 100644
index 0000000..af34e0b
--- /dev/null
+++ b/scripts/bsp_level_generator.gd
@@ -0,0 +1,78 @@
+extends Node2D
+
+@export var width: int = 40
+@export var height: int = 40
+@export var min_dim: int = 5
+
+var min_room_size: int = min_dim * min_dim
+
+var rects: Array[Vector4i] = []
+
+class BSPNode:
+ var min_dims: Vector2i
+ var max_dims: Vector2i
+ var left: BSPNode
+ var right: BSPNode
+
+ func _init(p_min_dims: Vector2i, p_max_dims: Vector2i, p_left: BSPNode, p_right: BSPNode):
+ min_dims = p_min_dims
+ max_dims = p_max_dims
+ left = p_left
+ right = p_right
+
+func generate_level(axis: int, min_space: Vector2i, max_space: Vector2i, depth: int = 0) -> BSPNode:
+ var dims = max_space - min_space
+ if dims[axis] / 2 < min_dim:
+ #rects.append(Vector4i(min_space.x, min_space.y, max_space.x, max_space.y))
+ return null
+
+ var new_axis = (axis + 1) % 2
+ # 10% we stop here and just create a big room
+ if (depth > 2 and randi_range(0, 9) == 0) \
+ or dims.x * dims.y <= min_dim * min_dim \
+ or dims[new_axis] / 2 < min_dim:
+ rects.append(Vector4i(min_space.x, min_space.y, max_space.x, max_space.y))
+ return BSPNode.new(min_space, max_space, null, null)
+
+ # Calculate min and max ranges so that a split
+ # doesn't create a room that violates min dimensions
+ var min_value = min_space[axis] + min_dim
+ var max_value = max_space[axis] - min_dim
+ var split = randi_range(min_value, max_value)
+ print("Spliting axis ", axis, " at ", split)
+
+ var left_min_space = min_space
+ var left_max_space = max_space
+ left_max_space[axis] = split
+ var left = generate_level(new_axis, left_min_space, left_max_space, depth + 1)
+
+ var right_min_space = min_space
+ right_min_space[axis] = split
+ var right_max_space = max_space
+ var right = generate_level(new_axis, right_min_space, right_max_space, depth + 1)
+
+ assert((left == null and right == null) or (left != null and right != null))
+
+ if left == null and right == null:
+ rects.append(Vector4i(min_space.x, min_space.y, max_space.x, max_space.y))
+
+ return BSPNode.new(min_space, max_space, left, right)
+
+func _ready() -> void:
+ var starting_axis = randi_range(0, 1)
+ var min_space = Vector2i(0, 0)
+ var max_space = Vector2i(width, height)
+ var map = generate_level(starting_axis, min_space, max_space)
+
+func _draw():
+ var mult = 1
+ for rect in rects:
+ var pos1 = 5*Vector2i(rect.x, rect.y)
+ var pos2 = 5*Vector2i(rect.z, rect.w)
+ var dims = pos2 - pos1
+ draw_rect(Rect2(pos1, dims), mult*Color(0.01, 0.01, 0.01))
+ draw_line(pos1, Vector2i(pos1.x, pos2.y), Color(0, 1, 0))
+ draw_line(Vector2i(pos1.x, pos2.y), pos2, Color(0, 1, 0))
+ draw_line(pos2, Vector2i(pos2.x, pos1.y), Color(0, 1, 0))
+ draw_line(Vector2i(pos2.x, pos1.y), pos1, Color(0, 1, 0))
+ mult += 2
diff --git a/scripts/bullet.gd b/scripts/bullet.gd
new file mode 100644
index 0000000..93c119a
--- /dev/null
+++ b/scripts/bullet.gd
@@ -0,0 +1,17 @@
+extends Node3D
+
+var target: Vector3
+
+var bullet_speed = 100.0
+
+# Called when the node enters the scene tree for the first time.
+#func _ready() -> void:
+# pass # Replace with function body.
+
+
+# Called every frame. 'delta' is the elapsed time since the previous frame.
+func _process(delta: float) -> void:
+ position = position.move_toward(target, bullet_speed * delta)
+
+ if (target - position).length_squared() <= 2:
+ queue_free()
diff --git a/scripts/enemy.gd b/scripts/enemy.gd
new file mode 100644
index 0000000..569905f
--- /dev/null
+++ b/scripts/enemy.gd
@@ -0,0 +1,87 @@
+extends CharacterBody3D
+
+## Speed of enemy
+@export var speed: float = 2.0
+## Target for enemy to follow
+@export var target: Node3D
+
+## Whether to use gravity on enemy
+@export var gravity_enabled: bool = false
+
+var has_astar: bool = false
+var astar: AStar3D
+var tar_vec: Vector3
+var gravity : float = ProjectSettings.get_setting("physics/3d/default_gravity")
+
+var original_color: Color
+
+func _ready() -> void:
+ if gravity_enabled:
+ motion_mode = MotionMode.MOTION_MODE_GROUNDED
+
+func chase_target(delta: float) -> void:
+ var target_pos = target.position
+ var direction = (target_pos - position).normalized()
+
+ if direction:
+ velocity.x = direction.x * speed
+ velocity.z = direction.z * speed
+ else:
+ velocity.x = move_toward(velocity.x, 0, speed)
+ velocity.z = move_toward(velocity.z, 0, speed)
+
+ if not is_on_floor() and gravity_enabled:
+ velocity.y -= gravity * delta
+
+ move_and_slide()
+
+func _physics_process(delta: float) -> void:
+ if target == null:
+ return
+
+ if not has_astar:
+ # Just try to chase player directly
+ chase_target(delta)
+ return
+
+ if Input.is_action_pressed("ui_right"):
+ return
+
+ var target_pos = target.position
+ var closest_me = astar.get_closest_point(position)
+ var closest_target = astar.get_closest_point(target_pos)
+
+ var direction: Vector3
+ if closest_me == closest_target:
+ direction = (target_pos - position).normalized()
+ else:
+ var target_path = astar.get_point_path(closest_me, closest_target)
+ if len(target_path) >= 2:
+ direction = (target_path[1] - position).normalized()
+
+ if direction:
+ #velocity.x = move_toward(velocity.x, direction.x * speed, 10.0 * delta)
+ #velocity.z = move_toward(velocity.z, direction.z * speed, 10.0 * delta)
+ velocity.x = direction.x * speed
+ velocity.z = direction.z * speed
+ else:
+ velocity.x = move_toward(velocity.x, 0, speed)
+ velocity.z = move_toward(velocity.z, 0, speed)
+
+ move_and_slide()
+
+func on_hit(_hit_position: Vector3) -> void:
+ if $HitTimer.is_stopped():
+ var material: StandardMaterial3D = $MeshInstance3D.get_active_material(0)
+ original_color = material.albedo_color
+ material.albedo_color = Color(1.0, 0.0, 0.0, 1.0)
+ $HitTimer.start()
+
+func _on_level_generator_astar_created(in_astar: AStar3D) -> void:
+ astar = in_astar
+ has_astar = true
+
+func _on_hit_timer_timeout() -> void:
+ var material: StandardMaterial3D = $MeshInstance3D.get_active_material(0)
+ material.albedo_color = original_color
+ $HitTimer.stop()
diff --git a/scripts/level_generator.gd b/scripts/level_generator.gd
new file mode 100644
index 0000000..94a87dd
--- /dev/null
+++ b/scripts/level_generator.gd
@@ -0,0 +1,118 @@
+extends Node3D
+
+@export var width: int = 10
+@export var height: int = 10
+
+var room = preload("res://prefabs/round_room.tscn")
+var door = preload("res://prefabs/door.tscn")
+
+var bounds: Vector3 = Vector3.ZERO
+var astar: AStar3D
+
+signal astar_created
+
+func get_grid_index(pos: Vector2i) -> int:
+ return pos.y*height + pos.x
+
+func set_grid_index(grid: Array[int], pos: Vector2i):
+ # If the point lies outside the grid we return
+ if pos.x < 0 or pos.x >= width or pos.y < 0 or pos.y >= height:
+ return
+
+ var index = get_grid_index(pos)
+
+ # If we already set this point we exit
+ if grid[index] != 0:
+ return
+
+ grid[index] = 1
+ var new_room: Node3D = room.instantiate()
+ var mesh = new_room.find_child("MeshInstance3D")
+ # TODO can we just load and cache the bounds?
+ bounds = mesh.get_aabb().size
+ var offset_pos = Vector3(pos.x - width / 2, 0, pos.y - height / 2)
+ new_room.position = (offset_pos * bounds)
+ #print("Placing at ", pos)
+ add_child(new_room)
+
+ var next = [pos + Vector2i.UP,
+ pos + Vector2i.LEFT,
+ pos + Vector2i.DOWN,
+ pos + Vector2i.RIGHT]
+
+ for n in next:
+ var chance = randi_range(0, 1)
+ if chance == 0:
+ set_grid_index(grid, n)
+
+func place_door(grid: Array[int], pos: Vector2i):
+ var index = get_grid_index(pos)
+ if grid[index] == 0:
+ return
+
+ var next = [pos + Vector2i.UP,
+ pos + Vector2i.LEFT,
+ pos + Vector2i.DOWN,
+ pos + Vector2i.RIGHT]
+
+ var angle = -90
+ for n in next:
+ angle += 90
+ var next_index = get_grid_index(n)
+ if n.x < 0 or n.x >= width or n.y < 0 or n.y >= height or grid[next_index] == 0:
+ var new_door: Node3D = door.instantiate()
+ var offset_pos = Vector3(pos.x - width / 2, 0, pos.y - height / 2)
+ new_door.position = (offset_pos * bounds)
+ new_door.rotate_y(deg_to_rad(angle))
+ add_child(new_door)
+
+func place_doors(grid: Array[int]):
+ for y in range(0, height):
+ for x in range(0, width):
+ place_door(grid, Vector2i(x, y))
+
+func compute_astar(grid: Array[int]):
+ for y in range(0, height):
+ for x in range(0, width):
+ var pos = Vector2i(x, y)
+ var index = get_grid_index(pos)
+ if grid[index] == 0:
+ continue
+ var offset_pos = Vector3(pos.x - width / 2, 0, pos.y - height / 2)
+ astar.add_point(index, offset_pos * bounds)
+
+ for y in range(0, height):
+ for x in range(0, width):
+ var pos = Vector2i(x, y)
+ var index = get_grid_index(pos)
+ if grid[index] == 0:
+ continue
+
+ var next = [pos + Vector2i.UP,
+ pos + Vector2i.LEFT,
+ pos + Vector2i.DOWN,
+ pos + Vector2i.RIGHT]
+ for n in next:
+ var next_index = get_grid_index(n)
+ if n.x < 0 or n.x >= width or n.y < 0 or n.y >= height or grid[next_index] == 0:
+ continue
+
+ astar.connect_points(index, next_index)
+
+# Called when the node enters the scene tree for the first time.
+func _ready() -> void:
+ astar = AStar3D.new()
+ var grid: Array[int] = [0]
+ grid.resize(width*height)
+ grid.fill(0)
+
+ var middle_x: int = width / 2
+ var middle_y: int = height / 2
+
+ var pos = Vector2i(middle_x, middle_y)
+ set_grid_index(grid, pos)
+
+ place_doors(grid)
+ compute_astar(grid)
+
+ astar_created.emit(astar)
diff --git a/scripts/player.gd b/scripts/player.gd
new file mode 100644
index 0000000..e76b4d1
--- /dev/null
+++ b/scripts/player.gd
@@ -0,0 +1,76 @@
+extends Node3D
+
+@export var grapple_distance: float = 10
+@export var grapple_speed: float = 10
+@export var fire_distance: float = 100
+
+enum State {
+ NO_GRAPPLE,
+ FREE,
+ GRAPPLING
+}
+
+var current_state: State = State.FREE
+var grapple_target: Vector3 = Vector3.ZERO
+
+var bullet_inst = preload("res://prefabs/bullet.tscn")
+
+# Called when the node enters the scene tree for the first time.
+func _ready() -> void:
+ pass # Replace with function body.
+
+func do_grapple() -> void:
+ if Input.is_action_just_pressed("attack") and current_state == State.FREE:
+ var space_state = get_world_3d().direct_space_state
+
+ var starting_pos = global_position
+ var ending_pos = starting_pos + grapple_distance * -global_transform.basis.z
+ var query = PhysicsRayQueryParameters3D.create(starting_pos, ending_pos)
+ query.collision_mask = 0x2
+ var result = space_state.intersect_ray(query)
+
+ if result:
+ grapple_target = result.position + global_transform.basis.z
+ current_state = State.GRAPPLING
+
+ if Input.is_action_just_released("attack") and current_state == State.GRAPPLING:
+ current_state = State.FREE
+ grapple_target = Vector3.ZERO
+
+
+ #print("State ", current_state, " ", grapple_target)
+ if current_state == State.GRAPPLING:
+ var dir_to_target = (grapple_target - global_position).normalized()
+
+ get_parent().local_velocity = dir_to_target * grapple_speed
+
+func fire_weapon() -> void:
+ if Input.is_action_just_pressed("attack"):
+ var space_state = get_world_3d().direct_space_state
+ var starting_pos = global_position
+ var ending_pos = starting_pos + fire_distance * -global_transform.basis.z
+ var query = PhysicsRayQueryParameters3D.create(starting_pos, ending_pos)
+ var result = space_state.intersect_ray(query)
+
+ var end = ending_pos
+ if result:
+ print("Hit! ")
+ if result.collider.has_method("on_hit"):
+ result.collider.on_hit(result.position)
+ end = result.position
+ else:
+ print("Miss")
+
+ var bullet: Node3D = bullet_inst.instantiate()
+ bullet.position = starting_pos
+ bullet.target = end
+ get_tree().get_root().add_child(bullet)
+ bullet.look_at(end)
+
+func _physics_process(_delta: float) -> void:
+ do_grapple()
+ fire_weapon()
+
+# Called every frame. 'delta' is the elapsed time since the previous frame.
+func _process(_delta: float) -> void:
+ pass
diff --git a/scripts/spin_ground.gd b/scripts/spin_ground.gd
new file mode 100644
index 0000000..078a757
--- /dev/null
+++ b/scripts/spin_ground.gd
@@ -0,0 +1,15 @@
+extends Node3D
+
+@export var rotation_dir: float = 1
+@export var rotation_axis: Vector3 = Vector3.BACK
+
+# Called when the node enters the scene tree for the first time.
+func _ready() -> void:
+ #rotate_z(deg_to_rad(180))
+ pass
+
+
+# Called every frame. 'delta' is the elapsed time since the previous frame.
+func _process(delta: float) -> void:
+ rotate(rotation_axis, rotation_dir * delta);
+ pass