From fc262870c41a6f7344d9a54d70d3ada63471e6ec Mon Sep 17 00:00:00 2001 From: Luna Date: Sat, 28 Apr 2018 04:10:19 -0400 Subject: [PATCH] [Hero 5] Add ability: drag enemies in a direction The impulse is fairly weak, but it has no cooldown (of course). As long as you can reliably click on them, you can keep dragging them around. This builds charge. Portal now COSTS charge, rather than gaining it, so that you bully people until you can build a portal. --- project.godot | 2 ++ scripts/hero_select.gd | 2 +- scripts/heroes/0.gd | 2 +- scripts/heroes/1_wall.gd | 4 ++-- scripts/heroes/4.gd | 3 +-- scripts/heroes/5.gd | 37 +++++++++++++++++++++++++++++++++++-- scripts/heroes/5_portal.gd | 26 ++++++++++++-------------- scripts/placeable.gd | 6 ++++-- scripts/placement.gd | 13 +++++++------ scripts/player.gd | 20 ++++++++++++++++---- 10 files changed, 81 insertions(+), 34 deletions(-) diff --git a/project.godot b/project.godot index 1c15ea6..53fc327 100644 --- a/project.godot +++ b/project.godot @@ -59,6 +59,8 @@ primary_ability=[ Object(InputEventKey,"resource_local_to_scene":false,"resource ] hero_0_boost=[ Object(InputEventMouseButton,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"button_mask":0,"position":Vector2( 0, 0 ),"global_position":Vector2( 0, 0 ),"factor":1.0,"button_index":1,"pressed":false,"doubleclick":false,"script":null) ] +primary_mouse=[ Object(InputEventMouseButton,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"button_mask":0,"position":Vector2( 0, 0 ),"global_position":Vector2( 0, 0 ),"factor":1.0,"button_index":1,"pressed":false,"doubleclick":false,"script":null) + ] [rendering] diff --git a/scripts/hero_select.gd b/scripts/hero_select.gd index 3b998d3..5fd34df 100644 --- a/scripts/hero_select.gd +++ b/scripts/hero_select.gd @@ -15,7 +15,7 @@ const hero_text = [ "LUST.\n\nYou attract nearby heroes.\n\nPress E to switch to repelling them.", "GENEROSITY.\n\nMake contact with a friend to boost their speed.\n\nPress E to separate.", "PATIENCE.\n\nHold left mouse button on an enemy to slow them down.\n\nPress E to delete someone else's building (costs charge).", - "PRIDE.\n\nClick to build portal. Click again to build its partner.\n\nYou can build multiple portal sets.", + "PRIDE.\n\nDrag on enemies to bully them around.\n\nClick to build a portal. Click again to build its partner (costs charge).", ] func _ready(): diff --git a/scripts/heroes/0.gd b/scripts/heroes/0.gd index 7a154be..db67e4b 100644 --- a/scripts/heroes/0.gd +++ b/scripts/heroes/0.gd @@ -24,7 +24,7 @@ func control_player(state): var boost_strength = 2 var boost_drain = 25 # Recall increased charge must be factored in var cost = boost_drain * state.step - if Input.is_action_pressed("primary_action") and switch_charge > cost: + if Input.is_action_pressed("hero_0_boost") and switch_charge > cost: walk_speed *= 2 air_accel *= 2 switch_charge -= cost diff --git a/scripts/heroes/1_wall.gd b/scripts/heroes/1_wall.gd index f359e33..9c87f84 100644 --- a/scripts/heroes/1_wall.gd +++ b/scripts/heroes/1_wall.gd @@ -7,7 +7,7 @@ func _process(delta): if being_touched > 0: maker_node.switch_charge += touch_charge * delta -func init(maker): +func init(maker, index): for player in get_node("/root/Level/Players").get_children(): player.connect("body_entered", self, "count_bodies", [player, 1]) @@ -27,7 +27,7 @@ func init(maker): mat.albedo_color = color get_node("MeshInstance").set_surface_material(0, mat) - .init(maker) + .init(maker, index) func count_bodies(with, player, delta): if with == self: diff --git a/scripts/heroes/4.gd b/scripts/heroes/4.gd index 77899f7..0a5a89f 100644 --- a/scripts/heroes/4.gd +++ b/scripts/heroes/4.gd @@ -29,8 +29,7 @@ func _process(delta): get_node("TPCamera").cam_smooth_movement = true if Input.is_action_just_pressed("primary_ability"): - var look_ray = get_node("TPCamera/Camera/Ray") - var looking_at = look_ray.get_collider() + var looking_at = pick() if looking_at.has_method("destroy"): if switch_charge > looking_at.destroy_cost: switch_charge -= looking_at.destroy() diff --git a/scripts/heroes/5.gd b/scripts/heroes/5.gd index ebf9d11..dc53a2d 100644 --- a/scripts/heroes/5.gd +++ b/scripts/heroes/5.gd @@ -6,6 +6,12 @@ var radius = 15 # The spaces make the bracket centered, rather than on of the dots var first_crosshair = " [..." var second_crosshair = "...] " +var no_portal_crosshair = "+" +var portal_cost = 20 + +var flicking = null +var flick_charge = 3 +var flick_strength = 4 # --- Godot overrides --- @@ -17,10 +23,30 @@ func _ready(): func _process(delta): if is_network_master(): - placement.place_input(radius) var is_second = placement.placed.size() % 2 != 0 - var crosshair = second_crosshair if is_second else first_crosshair + var portal_crosshair = second_crosshair if is_second else first_crosshair + var crosshair = no_portal_crosshair if switch_charge < portal_cost else portal_crosshair get_node("MasterOnly/Crosshair").set_text(crosshair) + if switch_charge > portal_cost or is_second: + if placement.place_input(radius, true) and is_second: + switch_charge -= portal_cost + + if Input.is_action_just_pressed("primary_mouse"): + var pick = pick_by_friendly(false) + if pick: + flicking = pick + if flicking and Input.is_action_just_released("primary_mouse"): + var aim = get_node("Yaw/Pitch").get_global_transform().basis + var forwards = -aim[2] + var distance = (flicking.translation - translation).length() + forwards *= distance + var towards = translation + forwards + var gravity = PhysicsServer.area_get_param(get_world().get_space(), PhysicsServer.AREA_PARAM_GRAVITY_VECTOR) + # Automatically account for gravity, so as to make UI more intuitive + towards -= gravity + rpc("flick", flicking.get_name(), towards) + flicking = null + switch_charge += flick_charge func _exit_tree(): ._exit_tree() @@ -31,3 +57,10 @@ func _exit_tree(): # --- Own --- +sync func flick(player_id, towards): + var who = $"/root/Level/Players".get_node(player_id) + if who.is_network_master(): + var direction = towards - who.translation + var impulse = direction.normalized() * flick_strength * who.get_mass() + who.apply_impulse(Vector3(), impulse) + diff --git a/scripts/heroes/5_portal.gd b/scripts/heroes/5_portal.gd index 92fcdaa..239e6ea 100644 --- a/scripts/heroes/5_portal.gd +++ b/scripts/heroes/5_portal.gd @@ -1,8 +1,7 @@ extends "res://scripts/placeable.gd" -var portal_charge = 15 +var portal_charge = -5 var other -var index var enemy_colors = [ Color("#d14013"), @@ -24,10 +23,8 @@ func _exit_tree(): maker_node.placement.placed.remove(index - 1) other.queue_free() -func init(maker): +func init(maker, index): - var maker_portals = maker.placement.placed - index = maker_portals.size() # No -1, because we haven't actually been added to the array yet # If index is odd, we're the second (1, 3...), if even, first (0, 4...) var second = index % 2 != 0 var is_friend = util.is_friendly(maker) @@ -40,7 +37,7 @@ func init(maker): mat.albedo_color = color get_node("MeshInstance").set_surface_material(0, mat) - .init(maker) + .init(maker, index) func place(): .place() @@ -57,12 +54,13 @@ func player_collided(with, player): func portal(player): if player.player_info.is_right_team == maker_node.player_info.is_right_team: if other: - var spawn_distance = 1.75 - # Find a sane place to spawn - # -Z is in the direction of the portal - # X is enough away from the portal to avoid infinite loop - # With both axes, gravity could never bring us to hit the portal - var to = other.to_global(Vector3(spawn_distance,0,-spawn_distance)) - player.set_translation(to) - maker_node.switch_charge += portal_charge + if maker_node.switch_charge > -portal_charge: + var spawn_distance = 1.75 + # Find a sane place to spawn + # -Z is in the direction of the portal + # X is enough away from the portal to avoid infinite loop + # With both axes, gravity could never bring us to hit the portal + var to = other.to_global(Vector3(spawn_distance,0,-spawn_distance)) + player.set_translation(to) + maker_node.switch_charge += portal_charge diff --git a/scripts/placeable.gd b/scripts/placeable.gd index a842de4..13853d0 100644 --- a/scripts/placeable.gd +++ b/scripts/placeable.gd @@ -3,12 +3,14 @@ extends StaticBody var maker_node var material var destroy_cost = 20 +var index func _ready(): get_node("CollisionShape").disabled = true -func init(maker): +func init(maker, index): maker_node = maker + self.index = index material = get_node("MeshInstance").get_surface_material(0) if not material: @@ -23,7 +25,7 @@ func place(): material.flags_transparent = false func destroy(): - queue_free() + maker_node.placement.remove_placed(index) return destroy_cost func make_last(): diff --git a/scripts/placement.gd b/scripts/placement.gd index 7ca1053..ca4a9e8 100644 --- a/scripts/placement.gd +++ b/scripts/placement.gd @@ -31,12 +31,12 @@ master func request_placed(): for node in placed: rpc_id(get_tree().get_rpc_sender_id(), "slave_place", node.transform) -func place_input(radius=-1): +func place_input(radius=-1, require_ghost=false): # 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): + if Input.is_action_just_pressed(start_action) or (confirm and not is_placing and not require_ghost): # Press button twice to cancel if is_placing: # We changed our mind, delete the placing wall @@ -52,7 +52,7 @@ func place_input(radius=-1): if pick != -1: rpc("remove_placed", pick) - if is_placing or confirm: + if is_placing: position_placement(placing_node) if radius > 0: # A radius is specified var distance = placing_node.get_translation() - player.get_translation() @@ -62,10 +62,12 @@ func place_input(radius=-1): else: placing_node.within_range() - if confirm: + if (confirm and not require_ghost) or (confirm and is_placing): # Order matters here: confirm_placement resets placing_node so we have to do anything with it first rpc("slave_place", placing_node.transform) confirm_placement(placing_node) + return true + return false func confirm_placement(node, tf=null): if tf: @@ -130,7 +132,6 @@ sync func remove_placed(index): func create(): var node = scene.instance() player.get_node("/root/Level").add_child(node) - # We have to call_deferred because we're `load`ing instead of `preload`ing. TODO: preload? - node.init(player) + node.init(player, placed.size()) return node diff --git a/scripts/player.gd b/scripts/player.gd index db01723..d375647 100644 --- a/scripts/player.gd +++ b/scripts/player.gd @@ -297,10 +297,22 @@ func quit(): # These aren't used by vanilla player, but are used by heroes in common -func pick_from(group): +func pick(): var look_ray = get_node("TPCamera/Camera/Ray") - var looking_at = look_ray.get_collider() - var result = group.find(looking_at) - return result + return look_ray.get_collider() + +func pick_from(group): + return group.find(pick()) + +func pick_player(): + var players = get_node("/root/Level/Players").get_children() + return players[pick_from(players)] + +func pick_by_friendly(pick_friendlies): + var pick = pick_player() + if (pick.player_info.is_right_team == player_info.is_right_team) == pick_friendlies: + return pick + else: + return null # =========