diff --git a/scenes/player.tscn b/scenes/player.tscn index 0f36847..16bb59a 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,10 +13,18 @@ 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" ] @@ -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/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/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..1212f2b --- /dev/null +++ b/scripts/tp_camera.gd @@ -0,0 +1,121 @@ +# 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); + set_process(true); + cam.make_current() + is_enabled = true; + else: + Input.set_mouse_mode(Input.MOUSE_MODE_VISIBLE); + set_process(false); + is_enabled = false; + +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)