diff --git a/project.godot b/project.godot index 1a91257..f8b04a7 100644 --- a/project.godot +++ b/project.godot @@ -36,6 +36,8 @@ hero_2_switch_gravity=[ Object(InputEventKey,"resource_local_to_scene":false,"re ] switch_hero=[ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":39,"unicode":0,"echo":false,"script":null) ] +hero_3_unmerge=[ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":46,"unicode":0,"echo":false,"script":null) + ] [rendering] diff --git a/scenes/heroes/3.tscn b/scenes/heroes/3.tscn new file mode 100644 index 0000000..e8879c5 --- /dev/null +++ b/scenes/heroes/3.tscn @@ -0,0 +1,61 @@ +[gd_scene load_steps=3 format=2] + +[ext_resource path="res://scenes/player.tscn" type="PackedScene" id=1] +[ext_resource path="res://scripts/heroes/3.gd" type="Script" id=2] + +[node name="RigidBody" index="0" instance=ExtResource( 1 )] + +contacts_reported = 3 +contact_monitor = true +script = ExtResource( 2 ) +_sections_unfolded = [ "Angular", "Axis Lock", "Collision", "Linear", "Pause", "Transform", "Visibility", "collision" ] + +[node name="Crosshair" parent="MasterOnly" index="0"] + +text = "" + +[node name="Boosting" type="Label" parent="MasterOnly" index="2"] + +visible = false +anchor_left = 0.5 +anchor_top = 1.0 +anchor_right = 0.5 +anchor_bottom = 1.0 +margin_left = -30.0 +margin_top = -161.0 +margin_right = 30.0 +margin_bottom = -147.0 +rect_pivot_offset = Vector2( 0, 0 ) +mouse_filter = 2 +mouse_default_cursor_shape = 0 +size_flags_horizontal = 1 +size_flags_vertical = 4 +text = "Boosting!" +align = 1 +percent_visible = 1.0 +lines_skipped = 0 +max_lines_visible = -1 + +[node name="Boosted" type="Label" parent="." index="6"] + +visible = false +anchor_left = 0.5 +anchor_top = 1.0 +anchor_right = 0.5 +anchor_bottom = 1.0 +margin_left = -29.0 +margin_top = -163.0 +margin_right = 28.0 +margin_bottom = -149.0 +rect_pivot_offset = Vector2( 0, 0 ) +mouse_filter = 2 +mouse_default_cursor_shape = 0 +size_flags_horizontal = 1 +size_flags_vertical = 4 +text = "Boosted!" +align = 1 +percent_visible = 1.0 +lines_skipped = 0 +max_lines_visible = -1 + + diff --git a/scenes/player.tscn b/scenes/player.tscn index 0f36847..976ce4c 100644 --- a/scenes/player.tscn +++ b/scenes/player.tscn @@ -1,6 +1,7 @@ -[gd_scene load_steps=5 format=2] +[gd_scene load_steps=7 format=2] [ext_resource path="res://scripts/player.gd" type="Script" id=1] +[ext_resource path="res://scripts/tp_camera.gd" type="Script" id=2] [sub_resource type="CapsuleShape" id=1] @@ -12,15 +13,23 @@ height = 0.5 length = 0.3 _sections_unfolded = [ "Resource" ] -[sub_resource type="CapsuleMesh" id=3] +[sub_resource type="PrismMesh" id=3] + +left_to_right = 0.5 +size = Vector3( 0.5, 0.5, 0.5 ) +subdivide_width = 0 +subdivide_height = 0 +subdivide_depth = 0 + +[sub_resource type="CapsuleMesh" id=4] radius = 0.4 -mid_height = 0.5 +mid_height = 0.1 radial_segments = 64 rings = 8 _sections_unfolded = [ "Resource" ] -[node name="RigidBody" type="RigidBody" index="0" groups=[ +[node name="RigidBody" type="RigidBody" groups=[ "player", ]] @@ -38,7 +47,7 @@ continuous_cd = true contacts_reported = 0 contact_monitor = false sleeping = false -can_sleep = true +can_sleep = false axis_lock_linear_x = false axis_lock_linear_y = false axis_lock_linear_z = false @@ -51,6 +60,8 @@ angular_velocity = Vector3( 0, 0, 0 ) angular_damp = -1.0 script = ExtResource( 1 ) _sections_unfolded = [ "Angular", "Axis Lock", "Collision", "Linear", "Transform", "Visibility", "collision" ] +tp_camera = NodePath("TPCamera") +master_only = NodePath("MasterOnly") [node name="Body" type="CollisionShape" parent="." index="0"] @@ -82,33 +93,9 @@ _sections_unfolded = [ "Transform", "Visibility" ] transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.4, 0 ) _sections_unfolded = [ "Transform" ] -[node name="Camera" type="Camera" parent="Yaw/Pitch" index="0"] - -keep_aspect = 0 -cull_mask = 1048575 -environment = null -h_offset = 0.0 -v_offset = 0.0 -doppler_tracking = 0 -projection = 0 -current = false -fov = 70.0 -size = 1.0 -near = 0.05 -far = 100.0 -_sections_unfolded = [ "Transform", "Visibility" ] - -[node name="Ray" type="RayCast" parent="Yaw/Pitch" index="1"] +[node name="MeshInstance" type="MeshInstance" parent="Yaw/Pitch" index="0"] -enabled = true -exclude_parent = true -cast_to = Vector3( 0, 0, -100 ) -collision_mask = 1 -_sections_unfolded = [ "Transform" ] - -[node name="MeshInstance" type="MeshInstance" parent="." index="4"] - -transform = Transform( 1, 0, 0, 0, -1.62921e-07, -1, 0, 1, -1.62921e-07, 0, 0.95, 0 ) +transform = Transform( 2.65431e-14, -1.62921e-07, 1, -1, -1.62921e-07, 0, 1.62921e-07, -1, -1.62921e-07, 0, -0.0649133, -0.103671 ) layers = 1 material_override = null cast_shadow = 1 @@ -123,7 +110,7 @@ skeleton = NodePath("..") material/0 = null _sections_unfolded = [ "Transform" ] -[node name="MasterOnly" type="Node" parent="." index="5"] +[node name="MasterOnly" type="Node" parent="." index="4"] [node name="Crosshair" type="Label" parent="MasterOnly" index="0"] @@ -167,4 +154,54 @@ percent_visible = 1.0 lines_skipped = 0 max_lines_visible = -1 +[node name="TPCamera" type="Spatial" parent="." index="5"] + +transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.74343, 0 ) +script = ExtResource( 2 ) +_sections_unfolded = [ "Transform" ] +cam = NodePath("Camera") +pivot = NodePath("Pivot") + +[node name="Pivot" type="Spatial" parent="TPCamera" index="0"] + +[node name="Camera" type="Camera" parent="TPCamera" index="1"] + +keep_aspect = 1 +cull_mask = 1048575 +environment = null +h_offset = 0.0 +v_offset = 0.0 +doppler_tracking = 0 +projection = 0 +current = false +fov = 70.0 +size = 1.0 +near = 0.05 +far = 100.0 + +[node name="Ray" type="RayCast" parent="TPCamera/Camera" index="0"] + +enabled = true +exclude_parent = true +cast_to = Vector3( 0, 0, -100 ) +collision_mask = 1 +_sections_unfolded = [ "Transform" ] + +[node name="MeshInstance" type="MeshInstance" parent="." index="6"] + +transform = Transform( 1, 0, 0, 0, -1.62921e-07, -1, 0, 1, -1.62921e-07, 0, 0.787368, 0 ) +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( 4 ) +skeleton = NodePath("..") +material/0 = null +_sections_unfolded = [ "Transform" ] + diff --git a/scripts/hero_select.gd b/scripts/hero_select.gd index 749699c..03de2aa 100644 --- a/scripts/hero_select.gd +++ b/scripts/hero_select.gd @@ -4,6 +4,7 @@ const hero_names = [ "Wallriding mfer", "WallMAKING mfer", "an ATTRACTIVE mfer", + "Margarine" ] func _ready(): diff --git a/scripts/heroes/1.gd b/scripts/heroes/1.gd index daa8087..d192ecf 100644 --- a/scripts/heroes/1.gd +++ b/scripts/heroes/1.gd @@ -23,7 +23,7 @@ func _process(delta): if is_placing_wall: # Find the point we're looking at, and put the wall there var aim = get_node("Yaw/Pitch").get_global_transform().basis - var look_ray = get_node("Yaw/Pitch/Ray") + var look_ray = get_node("TPCamera/Camera/Ray") var pos = look_ray.get_collision_point() placing_wall_node.set_translation(pos) var towards = look_ray.get_collision_normal() + pos diff --git a/scripts/heroes/3.gd b/scripts/heroes/3.gd new file mode 100644 index 0000000..0978e3e --- /dev/null +++ b/scripts/heroes/3.gd @@ -0,0 +1,91 @@ +extends "res://scripts/player.gd" + +var merge_power = .1 +var merged = null + +var old_layer +var old_mask + +var allow_merge_time = 0 +var allow_merge_threshold = 0.4 + +func _ready(): + # Called every time the node is added to the scene. + # Initialization here + pass + +func _exit_tree(): + unmerge() # Checks if necessary automatically + +func _process(delta): + if is_network_master(): + allow_merge_time += delta + if not merged and allow_merge_time > allow_merge_threshold: + var cols = get_colliding_bodies() + for col in cols: + if col.is_in_group("player"): + var same_team = col.player_info.is_right_team == player_info.is_right_team + if same_team: + rpc("merge", col.get_name()) + + if merged and Input.is_action_just_pressed("hero_3_unmerge"): + rpc("unmerge") + +func control_player(state): + if !merged: + .control_player(state) + +func set_collisions(on): + if on: + collision_layer = old_layer + collision_mask = old_mask + gravity_scale = 1 + else: + old_layer = collision_layer + old_mask = collision_mask + collision_layer = 0 + collision_mask = 0 + gravity_scale = 0 + +func set_boosted_label(node, on): + if on: + var boosted_label = $Boosted.duplicate() + boosted_label.show() + node.add_child(boosted_label) + else: + var boosted_label = node.get_node("Boosted") + boosted_label.queue_free() + +func set_boosting(is_boosting): + set_collisions(!is_boosting) + visible = !is_boosting + if is_network_master(): + get_node("MasterOnly/Boosting").visible = is_boosting + get_node(tp_camera).set_enabled(!is_boosting) + +func set_boosted(node, is_boosted): + if is_network_master(): + # Assume their PoV, but no control + node.get_node(node.tp_camera).set_enabled(is_boosted) + if node.is_network_master(): + set_boosted_label(node, is_boosted) + var ratio = (1 + merge_power) + if !is_boosted: + ratio = 1/ratio # Undo the effect + node.walk_speed *= ratio + node.air_accel *= ratio + +sync func merge(node_name): + set_boosting(true) + var other = $"/root/Level/Players".get_node(node_name) + set_boosted(other, true) + merged = other + +sync func unmerge(): + if merged: + set_boosted(merged, false) + set_boosting(false) + var pos = merged.get_translation() + pos.z += 1 + set_translation(pos) + merged = null diff --git a/scripts/lobby.gd b/scripts/lobby.gd index fb5f61b..5cc285a 100644 --- a/scripts/lobby.gd +++ b/scripts/lobby.gd @@ -68,6 +68,7 @@ func _ready(): get_node("Singleplayer").connect("pressed", self, "_singleplayer_init") get_tree().connect("network_peer_connected", self, "_player_connected") + get_tree().connect("network_peer_disconnected", self, "_player_disconnected") get_tree().connect("connected_to_server", self, "_connected_ok") get_node("HeroSelect").connect("item_selected", self, "select_hero") @@ -101,6 +102,10 @@ func _server_init(): func _player_connected(id): print("Connect, my friend: " + str(id)) +func _player_disconnected(id): + if get_tree().is_network_server(): + rpc("unregister_player", id) + func _connected_ok(): rpc("register_player", get_tree().get_network_unique_id(), my_info) if "start_game" in my_info and my_info.start_game: @@ -140,6 +145,10 @@ remote func register_player(new_peer, info): if (player_info.size() == MAX_PLAYERS): start_game() +sync func unregister_player(peer): + player_info.erase(peer) + get_node("/root/Level/Players/%d" % peer).queue_free() + func select_hero(hero): rpc("set_hero", get_tree().get_network_unique_id(), hero) @@ -182,7 +191,11 @@ remote func done_preconfiguring(who): sync func pre_configure_game(level): var self_peer_id = get_tree().get_network_unique_id() - get_node("/root/Control").queue_free() + # Remove the interface so as to not fuck with things + # But we still need the lobby (Control) alive to deal with networking! + for element in get_node("/root/Control").get_children(): + element.queue_free() + var world = load("res://scenes/levels/%d.tscn" % level).instance() get_node("/root").add_child(world) diff --git a/scripts/player.gd b/scripts/player.gd index c4e3ecd..a4a0c9f 100644 --- a/scripts/player.gd +++ b/scripts/player.gd @@ -3,8 +3,6 @@ extends RigidBody var view_sensitivity = 0.25 -var yaw = 0 -var pitch = 0 # Walking speed and jumping height are defined later. var walk_speed = 0.8 # Actually acceleration; m/s/s @@ -29,19 +27,18 @@ slave var slave_transform = Basis() slave var slave_lin_v = Vector3() slave var slave_ang_v = Vector3() -func _ready(): - set_process_input(true) +export(NodePath) var tp_camera +export(NodePath) var master_only - # Capture mouse once game is started: - Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED) +func _ready(): + set_process_input(true) debug_node = get_node("/root/Level/Debug") - if is_network_master(): - get_node("Yaw/Pitch/Camera").make_current() + get_node(tp_camera).set_enabled(true) spawn() else: - remove_child(get_node("MasterOnly")) + remove_child(get_node(master_only)) func spawn(): var placement = Vector3() @@ -61,16 +58,6 @@ func spawn(): func _input(event): if is_network_master(): - - if event is InputEventMouseMotion: - yaw = fmod(yaw - event.relative.x * view_sensitivity, 360) - pitch = max(min(pitch - event.relative.y * view_sensitivity, 85), -85) - set_rotation() - - # Toggle mouse capture: - if Input.is_action_pressed("toggle_mouse_capture"): - toggle_mouse_capture() - if Input.is_action_just_pressed("switch_hero"): switch_hero_interface() # Quit the game: @@ -85,30 +72,31 @@ func toggle_mouse_capture(): Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED) view_sensitivity = 0.25 +# Update visual yaw + pitch components to match camera func set_rotation(): - get_node("Yaw").set_rotation(Vector3(0, deg2rad(yaw), 0)) - get_node("Yaw/Pitch").set_rotation(Vector3(deg2rad(pitch), 0, 0)) + get_node("Yaw").set_rotation(Vector3(0, deg2rad(get_node(tp_camera).cam_yaw), 0)) + get_node("Yaw/Pitch").set_rotation(Vector3(deg2rad(-get_node(tp_camera).cam_pitch), 0, 0)) func _integrate_forces(state): if is_network_master(): control_player(state) rpc_unreliable("set_status", get_status()) + set_rotation() slave func set_status(s): set_transform(s[0]) set_linear_velocity(s[1]) set_angular_velocity(s[2]) - yaw = s[3] - pitch = s[4] - set_rotation() # Confirm yaw + pitch changes + get_node(tp_camera).cam_yaw = s[3] + get_node(tp_camera).cam_pitch = s[4] func get_status(): return [ get_transform(), get_linear_velocity(), get_angular_velocity(), - yaw, - pitch, + get_node(tp_camera).cam_yaw, + get_node(tp_camera).cam_pitch, ] func control_player(state): diff --git a/scripts/tp_camera.gd b/scripts/tp_camera.gd new file mode 100644 index 0000000..1388a78 --- /dev/null +++ b/scripts/tp_camera.gd @@ -0,0 +1,119 @@ +# From khairul169: https://github.com/khairul169/3rdperson-godot/blob/master/assets/scripts/tpscam.gd + +extends Spatial + +var cam_pitch = 0.0; +var cam_yaw = 0.0; +var cam_cpitch = 0.0; +var cam_cyaw = 0.0; +var cam_currentradius = 2.0; +var cam_radius = 2.0; +var cam_pos = Vector3(); +var cam_ray_result = {}; +var cam_smooth_movement = true; +var cam_fov = 60.0; +var cam_view_sensitivity = 0.3; +var cam_smooth_lerp = 10; +var cam_pitch_minmax = Vector2(90, -90); + +var is_enabled = false; +var collision_exception = []; + +export(NodePath) var cam; +export(NodePath) var pivot; + +func _ready(): + cam = get_node(cam); + pivot = get_node(pivot); + + cam_fov = cam.get_fov(); + +func set_enabled(enabled): + if enabled: + Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED); + cam.make_current() + else: + Input.set_mouse_mode(Input.MOUSE_MODE_VISIBLE); + set_process(enabled); + is_enabled = enabled; + +func clear_exception(): + collision_exception.clear(); + +func add_collision_exception(node): + collision_exception.push_back(node); + +func _input(ie): + if !is_enabled: + return; + + if ie is InputEventMouseMotion: + cam_pitch = max(min(cam_pitch+(ie.relative.y*cam_view_sensitivity),cam_pitch_minmax.x),cam_pitch_minmax.y); + if cam_smooth_movement: + cam_yaw = cam_yaw-(ie.relative.x*cam_view_sensitivity); + else: + cam_yaw = fmod(cam_yaw-(ie.relative.x*cam_view_sensitivity),360); + cam_currentradius = cam_radius; + cam_update(); + + if ie is InputEventMouseButton: + if ie.pressed: + if ie.button_index == BUTTON_WHEEL_UP: + cam_radius = max(min(cam_radius-0.2,4.0),1.0); + elif ie.button_index == BUTTON_WHEEL_DOWN: + cam_radius = max(min(cam_radius+0.2,4.0),1.0); + + # Toggle mouse capture: + if Input.is_action_just_pressed("toggle_mouse_capture"): + set_enabled(!is_enabled) + +func _process(delta): + if !is_enabled: + return; + + if !cam.is_current(): + cam.make_current(); + + if cam.get_projection() == Camera.PROJECTION_PERSPECTIVE: + cam.set_perspective(lerp(cam.get_fov(), cam_fov, cam_smooth_lerp*delta), cam.get_znear(), cam.get_zfar()); + + if cam_smooth_movement: + cam_cpitch = lerp(cam_cpitch, cam_pitch, 10*delta); + cam_cyaw = lerp(cam_cyaw, cam_yaw, 10*delta); + cam_currentradius = lerp(cam_currentradius, cam_radius, 5*delta); + + cam_update(); + +func cam_update(): + cam_pos = pivot.get_global_transform().origin; + + if cam_smooth_movement: + cam_pos.x += cam_currentradius * sin(deg2rad(cam_cyaw)) * cos(deg2rad(cam_cpitch)); + cam_pos.y += cam_currentradius * sin(deg2rad(cam_cpitch)); + cam_pos.z += cam_currentradius * cos(deg2rad(cam_cyaw)) * cos(deg2rad(cam_cpitch)); + else: + cam_pos.x += cam_currentradius * sin(deg2rad(cam_yaw)) * cos(deg2rad(cam_pitch)); + cam_pos.y += cam_currentradius * sin(deg2rad(cam_pitch)); + cam_pos.z += cam_currentradius * cos(deg2rad(cam_yaw)) * cos(deg2rad(cam_pitch)); + + var pos = Vector3(); + + if cam_ray_result.size() != 0: + print("re-pos, ray found") + var a = (cam_ray_result.position-pivot.get_global_transform().origin).normalized(); + var b = pivot.get_global_transform().origin.distance_to(cam_ray_result.position); + #pos = cam_ray_result.position; + pos = pivot.get_global_transform().origin+a*max(b-0.1, 0); + else: + pos = cam_pos; + + cam.look_at_from_position(pos, pivot.get_global_transform().origin, Vector3(0,1,0)); + +func _physics_process(delta): + if !is_enabled: + return; + + var ds = get_world().get_direct_space_state(); + if ds != null: + cam_ray_result = ds.intersect_ray(pivot.get_global_transform().origin, cam_pos, collision_exception); + #print(cam_ray_result)