From 517efc9ceab4df1054495caf10f9e7e0b55f4774 Mon Sep 17 00:00:00 2001 From: Luna Date: Mon, 19 Feb 2018 00:29:59 -0500 Subject: [PATCH] Refactor hero 1 wall placement into `placement.gd` --- scenes/heroes/1_wall.tscn | 52 ++++++++++++++++++++ scenes/wall.tscn | 52 -------------------- scripts/heroes/1-wall.gd | 36 -------------- scripts/heroes/1.gd | 123 +++++++--------------------------------------- scripts/heroes/1_wall.gd | 32 ++++++++++++ scripts/placeable.gd | 21 ++++++++ scripts/placement.gd | 113 ++++++++++++++++++++++++++++++++++++++++++ scripts/player.gd | 9 ++++ 8 files changed, 244 insertions(+), 194 deletions(-) create mode 100644 scenes/heroes/1_wall.tscn delete mode 100644 scenes/wall.tscn delete mode 100644 scripts/heroes/1-wall.gd create mode 100644 scripts/heroes/1_wall.gd create mode 100644 scripts/placeable.gd create mode 100644 scripts/placement.gd diff --git a/scenes/heroes/1_wall.tscn b/scenes/heroes/1_wall.tscn new file mode 100644 index 0000000..ef4c041 --- /dev/null +++ b/scenes/heroes/1_wall.tscn @@ -0,0 +1,52 @@ +[gd_scene load_steps=4 format=2] + +[ext_resource path="res://scripts/heroes/1_wall.gd" type="Script" id=1] + +[sub_resource type="CubeMesh" id=1] + +size = Vector3( 3, 3, 0.5 ) +subdivide_width = 0 +subdivide_height = 0 +subdivide_depth = 0 + +[sub_resource type="BoxShape" id=2] + +extents = Vector3( 1.5, 1.5, 0.25 ) + +[node name="StaticBody" type="StaticBody" index="0"] + +input_ray_pickable = true +input_capture_on_drag = false +collision_layer = 1 +collision_mask = 2 +friction = 1.0 +bounce = 0.0 +constant_linear_velocity = Vector3( 0, 0, 0 ) +constant_angular_velocity = Vector3( 0, 0, 0 ) +script = ExtResource( 1 ) + +[node name="MeshInstance" type="MeshInstance" parent="." index="0"] + +transform = Transform( 1, 0, 0, 0, -1.62921e-07, -1, 0, 1, -1.62921e-07, 0, 0, -1.5 ) +layers = 1 +material_override = null +cast_shadow = 1 +extra_cull_margin = 0.0 +use_in_baked_light = false +lod_min_distance = 0.0 +lod_min_hysteresis = 0.0 +lod_max_distance = 0.0 +lod_max_hysteresis = 0.0 +mesh = SubResource( 1 ) +skeleton = NodePath("..") +material/0 = null +_sections_unfolded = [ "Transform" ] + +[node name="CollisionShape" type="CollisionShape" parent="." index="1"] + +transform = Transform( 1, 0, 0, 0, -1.62921e-07, -1, 0, 1, -1.62921e-07, 0, 0, -1.5 ) +shape = SubResource( 2 ) +disabled = true +_sections_unfolded = [ "Transform" ] + + diff --git a/scenes/wall.tscn b/scenes/wall.tscn deleted file mode 100644 index 5aadbe6..0000000 --- a/scenes/wall.tscn +++ /dev/null @@ -1,52 +0,0 @@ -[gd_scene load_steps=4 format=2] - -[ext_resource path="res://scripts/heroes/1-wall.gd" type="Script" id=1] - -[sub_resource type="CubeMesh" id=1] - -size = Vector3( 3, 3, 0.5 ) -subdivide_width = 0 -subdivide_height = 0 -subdivide_depth = 0 - -[sub_resource type="BoxShape" id=2] - -extents = Vector3( 1.5, 1.5, 0.25 ) - -[node name="StaticBody" type="StaticBody" index="0"] - -input_ray_pickable = true -input_capture_on_drag = false -collision_layer = 1 -collision_mask = 2 -friction = 1.0 -bounce = 0.0 -constant_linear_velocity = Vector3( 0, 0, 0 ) -constant_angular_velocity = Vector3( 0, 0, 0 ) -script = ExtResource( 1 ) - -[node name="MeshInstance" type="MeshInstance" parent="." index="0"] - -transform = Transform( 1, 0, 0, 0, -1.62921e-07, -1, 0, 1, -1.62921e-07, 0, 0, -1.5 ) -layers = 1 -material_override = null -cast_shadow = 1 -extra_cull_margin = 0.0 -use_in_baked_light = false -lod_min_distance = 0.0 -lod_min_hysteresis = 0.0 -lod_max_distance = 0.0 -lod_max_hysteresis = 0.0 -mesh = SubResource( 1 ) -skeleton = NodePath("..") -material/0 = null -_sections_unfolded = [ "Transform" ] - -[node name="CollisionShape" type="CollisionShape" parent="." index="1"] - -transform = Transform( 1, 0, 0, 0, -1.62921e-07, -1, 0, 1, -1.62921e-07, 0, 0, -1.5 ) -shape = SubResource( 2 ) -disabled = true -_sections_unfolded = [ "Transform" ] - - diff --git a/scripts/heroes/1-wall.gd b/scripts/heroes/1-wall.gd deleted file mode 100644 index c112da2..0000000 --- a/scripts/heroes/1-wall.gd +++ /dev/null @@ -1,36 +0,0 @@ -extends StaticBody - -var maker_node -var touch_charge = 4 -var being_touched = 0 - -func init(maker, color): - maker_node = maker - for player in get_node("/root/Level/Players").get_children(): - player.connect("body_entered", self, "count_bodies", [player, 1]) - player.connect("body_exited", self, "count_bodies", [player, -1]) - var mat = SpatialMaterial.new() - color.a = 0.5 - mat.flags_transparent = true - mat.albedo_color = color - get_node("MeshInstance").set_surface_material(0, mat) - -func place(): - # Originally, the wall is disabled to avoid weird physics - get_node("CollisionShape").disabled = false - get_node("MeshInstance").get_surface_material(0).flags_transparent = false - -func make_last(): - var mat = get_node("MeshInstance").get_surface_material(0) - mat.flags_transparent = true - mat.albedo_color.a = 0.9 - -func count_bodies(with, player, delta): - if with == self: - if player != maker_node: - being_touched += delta - -func _process(delta): - if being_touched > 0: - maker_node.switch_charge += touch_charge * delta - diff --git a/scripts/heroes/1.gd b/scripts/heroes/1.gd index 5215359..7ca94aa 100644 --- a/scripts/heroes/1.gd +++ b/scripts/heroes/1.gd @@ -1,123 +1,34 @@ extends "res://scripts/player.gd" -var walls = [] -var placing_wall_node -var is_placing_wall = false - -const max_walls = 100 +onready var placement = preload("res://scripts/placement.gd").new() # --- Godot overrides --- +func _ready(): + # connect("start_placement", self, "add_wall") + # connect("confirm_placement", self, "finalize_wall") + placement.player = self + placement.start_action = "hero_1_place_wall" + placement.confirm_action = "hero_1_confirm_wall" + placement.delete_action = "hero_1_remove_wall" + placement.scene_path = "res://scenes/heroes/1_wall.tscn" + placement.max_placed = 100 + func _process(delta): if is_network_master(): - - # We allow you to just click to place, without needing to press E - var place_wall = Input.is_action_just_pressed("hero_1_confirm_wall") - - if Input.is_action_just_pressed("hero_1_place_wall") or (place_wall and not is_placing_wall): - # Press button twice to cancel - if is_placing_wall: - # We changed our mind, delete the placing wall - placing_wall_node.queue_free() - is_placing_wall = false - else: - # Make a floating placement wall - placing_wall_node = add_wall() - is_placing_wall = true - - if Input.is_action_just_pressed("hero_1_remove_wall"): - var look_ray = get_node("TPCamera/Camera/Ray") - var removing = look_ray.get_collider() - var wall = walls.find(removing) - if wall != -1: - rpc("remove_wall", wall) - - if is_placing_wall or place_wall: - position_wall(placing_wall_node) - - if place_wall: - finalize_wall(placing_wall_node) - rpc("slave_place_wall", placing_wall_node.get_transform()) - placing_wall_node = null - is_placing_wall = false + placement.place_input() func _exit_tree(): - clear_walls() + ._exit_tree() + if placement: + placement.clear() # --- Player overrides --- func spawn(): .spawn() - clear_walls() + if placement: + placement.clear() # --- Own --- -# Find the point we're looking at, and put the wall there -func position_wall(wall): - var aim = get_node("Yaw/Pitch").get_global_transform().basis - var look_ray = get_node("TPCamera/Camera/Ray") - var pos = look_ray.get_collision_point() - wall.set_translation(pos) - var normal = look_ray.get_collision_normal() - var towards = normal + pos - var up = aim[2] # Wall should be horizontal to my view - # This helps nearly horizontal walls be easier to make flat - # We have two methods I'm deciding between - var use_method_two = true - if not use_method_two: - # Method one: only allow horizontal or vertical, based on whether the surface faces you - var wall_wall_margin = 0.75 - if normal.dot(Vector3(0,1,0)) < wall_wall_margin: - var margin = 0.8 - if up.dot(normal) > margin: # The wall is facing us - # We want flat - up = Vector3(0,1,0) - else: - # We want straight - up.y = 0 - else: - # Method two: Make y more aggressive than other dimensions - up.y = 3 * tanh(up.y) - up = up.normalized() - wall.look_at(towards, up) - -func clear_walls(): - for wall in walls: - wall.queue_free() - walls = [] - -slave func slave_place_wall(tf): - var wall = add_wall() - finalize_wall(wall, tf) - -sync func remove_wall(index): - walls[index].queue_free() - walls.remove(index) - -# Creates wall, adds to world, and returns the node -func add_wall(): - var wall = preload("res://scenes/wall.tscn").instance() - var friendly = player_info.is_right_team == master_player.player_info.is_right_team - var color = friend_color if friendly else enemy_color - get_node("/root/Level").add_child(wall) - wall.init(self, color) - return wall - -func finalize_wall(wall, tf=null): - if tf: - wall.set_transform(tf) - wall.place() - # Remember this wall, and return to non-placing state - # We need to do this even as slave, because we keep track of the count - walls.append(wall) - check_wall_count() - -func check_wall_count(): - # If we've made max_walls, remove the first we made - if walls.size() > max_walls: - walls[0].queue_free() - walls.pop_front() - # When placing, make the about-to-disappear wall translucent - if walls.size() >= max_walls: - walls[0].make_last() - diff --git a/scripts/heroes/1_wall.gd b/scripts/heroes/1_wall.gd new file mode 100644 index 0000000..a41ea4f --- /dev/null +++ b/scripts/heroes/1_wall.gd @@ -0,0 +1,32 @@ +extends "res://scripts/placeable.gd" + +var touch_charge = 4 +var being_touched = 0 + +func _process(delta): + if being_touched > 0: + maker_node.switch_charge += touch_charge * delta + +func init(maker): + + for player in get_node("/root/Level/Players").get_children(): + player.connect("body_entered", self, "count_bodies", [player, 1]) + player.connect("body_exited", self, "count_bodies", [player, -1]) + + var master_player = get_node("/root/Level/Players/%d" % get_tree().get_network_unique_id()) + var friendly = maker.player_info.is_right_team == master_player.player_info.is_right_team + var color = maker.friend_color if friendly else maker.enemy_color + + var mat = SpatialMaterial.new() + color.a = 0.5 + mat.flags_transparent = true + mat.albedo_color = color + get_node("MeshInstance").set_surface_material(0, mat) + + .init(maker) + +func count_bodies(with, player, delta): + if with == self: + if player != maker_node: + being_touched += delta + diff --git a/scripts/placeable.gd b/scripts/placeable.gd new file mode 100644 index 0000000..75d3bba --- /dev/null +++ b/scripts/placeable.gd @@ -0,0 +1,21 @@ +extends StaticBody + +var maker_node + +func init(maker): + maker_node = maker + + var mat = get_node("MeshInstance").get_surface_material(0) + mat.flags_transparent = true + mat.albedo_color.a = 0.5 + +func place(): + # Originally, the ghost is disabled to avoid weird physics + get_node("CollisionShape").disabled = false + get_node("MeshInstance").get_surface_material(0).flags_transparent = false + +func make_last(): + var mat = get_node("MeshInstance").get_surface_material(0) + mat.flags_transparent = true + mat.albedo_color.a = 0.9 + diff --git a/scripts/placement.gd b/scripts/placement.gd new file mode 100644 index 0000000..42af4df --- /dev/null +++ b/scripts/placement.gd @@ -0,0 +1,113 @@ +var player + +var is_placing = false +var placing_node +var placed = [] +var max_placed = 5 + +var start_action +var confirm_action +var delete_action + +var scene_path + +signal start_placement +signal confirm_placement + +func place_input(): + + # We allow you to just click to place, without needing to press E + var confirm = Input.is_action_just_pressed(confirm_action) + + if Input.is_action_just_pressed(start_action) or (confirm and not is_placing): + # Press button twice to cancel + if is_placing: + # We changed our mind, delete the placing wall + placing_node.queue_free() + is_placing = false + else: + # Make a floating placement wall + placing_node = create() + is_placing = true + + if Input.is_action_just_pressed(delete_action): + var pick = player.pick_from(placed) + if pick != -1: + remove_placed(pick) + + if is_placing or confirm: + call_deferred("position_placement", placing_node) + + if confirm: + call_deferred("confirm_placement", placing_node) + emit_signal("confirm_placement") + +func confirm_placement(node, tf=null): + if tf: + node.set_transform(tf) + # TODO: Is this working? Could it be done better? + node.place() + # Remember this wall, and return to non-placing state + # We need to do this even as slave, because we keep track of the count + placed.append(node) + check_count() + placing_node = null + is_placing = false + +func check_count(): + # If we've made max_walls, remove the first we made + if placed.size() > max_placed: + placed[0].queue_free() + placed.pop_front() + # When placing, make the about-to-disappear wall translucent + if placed.size() >= max_placed: + placed[0].make_last() + +# Find the point we're looking at, and put the wall there +func position_placement(node): + var aim = player.get_node("Yaw/Pitch").get_global_transform().basis + var look_ray = player.get_node("TPCamera/Camera/Ray") + var pos = look_ray.get_collision_point() + node.set_translation(pos) + var normal = look_ray.get_collision_normal() + var towards = normal + pos + var up = aim[2] # Wall should be horizontal to my view + # This helps nearly horizontal walls be easier to make flat + # We have two methods I'm deciding between + var use_method_two = true + if not use_method_two: + # Method one: only allow horizontal or vertical, based on whether the surface faces you + var on_wall_margin = 0.75 + if normal.dot(Vector3(0,1,0)) < on_wall_margin: + var margin = 0.8 + if up.dot(normal) > margin: # The wall is facing us + # We want flat + up = Vector3(0,1,0) + else: + # We want straight + up.y = 0 + else: + # Method two: Make y more aggressive than other dimensions + up.y = 3 * tanh(up.y) + up = up.normalized() + node.look_at(towards, up) + +func clear(): + for node in placed: + node.queue_free() + placed = [] + +slave func slave_place(tf): + var node = create() + confirm_placement(node, tf) + +sync func remove_placed(index): + placed[index].queue_free() + placed.remove(index) + +func create(): + var node = load(scene_path).instance() + player.get_node("/root/Level").call_deferred("add_child", node) + node.call_deferred("init", player) # TODO: Is call_deferred legal on possibly not existing node? + return node + diff --git a/scripts/player.gd b/scripts/player.gd index bfc5233..1f5ae48 100644 --- a/scripts/player.gd +++ b/scripts/player.gd @@ -293,3 +293,12 @@ func write_recording(): func quit(): get_tree().quit() +# These aren't used by vanilla player, but are used by heroes in common + +func pick_from(group): + var look_ray = get_node("TPCamera/Camera/Ray") + var looking_at = look_ray.get_collider() + var result = group.find(looking_at) + return result + +# =========