Compare commits
3 Commits
520d44d564
...
b53b6289bd
| Author | SHA1 | Date | |
|---|---|---|---|
| b53b6289bd | |||
| fb799acdbe | |||
| b0a0fe077a |
@ -124,6 +124,11 @@ swap_weapon_down={
|
||||
"events": [Object(InputEventMouseButton,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"button_mask":0,"position":Vector2(0, 0),"global_position":Vector2(0, 0),"factor":1.0,"button_index":5,"canceled":false,"pressed":false,"double_click":false,"script":null)
|
||||
]
|
||||
}
|
||||
punch={
|
||||
"deadzone": 0.2,
|
||||
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":70,"key_label":0,"unicode":102,"location":0,"echo":false,"script":null)
|
||||
]
|
||||
}
|
||||
|
||||
[physics]
|
||||
|
||||
|
||||
@ -19,7 +19,7 @@ font_color = Color(1, 0, 0, 1)
|
||||
outline_size = 10
|
||||
outline_color = Color(0, 0, 0, 1)
|
||||
|
||||
[node name="player" type="LocalPlayer" unique_id=863055906 node_paths=PackedStringArray("camera", "soldier_mesh", "collider", "effects", "dead_cam_target", "respawn_label", "camera_origin", "weapon_node", "pause_panel", "exit_to_lobby", "settings_panel", "scoreboard", "chatbox", "health_label")]
|
||||
[node name="player" type="LocalPlayer" unique_id=863055906 node_paths=PackedStringArray("camera", "soldier_mesh", "collider", "effects", "dead_cam_target", "respawn_label", "camera_origin", "weapon_node", "pause_panel", "exit_to_lobby", "settings_panel", "scoreboard", "chatbox", "health_label", "hit_sound")]
|
||||
look_sensitivity = 1.5
|
||||
camera = NodePath("camera_3d")
|
||||
move_speed = 5.0
|
||||
@ -36,7 +36,9 @@ settings_panel = NodePath("settings")
|
||||
scoreboard = NodePath("scoreboard")
|
||||
chatbox = NodePath("chat_box")
|
||||
health_label = NodePath("health_label")
|
||||
hit_sound = NodePath("hit_sound")
|
||||
health = 100
|
||||
punch_cooldown = 1.0
|
||||
collision_mask = 4
|
||||
|
||||
[node name="camera_3d" type="Camera3D" parent="." unique_id=1773137418]
|
||||
|
||||
@ -38,6 +38,7 @@ soldier_mesh = NodePath("soldier_m")
|
||||
collider = NodePath("collision_shape_3d")
|
||||
effects = NodePath("effects")
|
||||
health = 100
|
||||
punch_cooldown = 1.0
|
||||
spectator_camera = NodePath("spectate_root/spectate_camera")
|
||||
camera_origin = NodePath("camera_origin")
|
||||
name_label = NodePath("name_label")
|
||||
|
||||
@ -8,6 +8,8 @@ credits_container = NodePath("panel/scroll_container/v_box_container")
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
offset_right = -6.0
|
||||
offset_bottom = -21.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
|
||||
|
||||
@ -431,9 +431,6 @@ impl Game {
|
||||
}
|
||||
|
||||
pub fn change_map_selection(&mut self, map_idx: u8, emit: bool) {
|
||||
if self.selected_map_idx == map_idx {
|
||||
return;
|
||||
}
|
||||
self.selected_map_idx = map_idx;
|
||||
if let Some(map) = self.maps.get(map_idx as usize) {
|
||||
self.selected_map = Some(map);
|
||||
@ -915,6 +912,27 @@ impl Game {
|
||||
}
|
||||
}
|
||||
|
||||
// Handle shooting, either from the server of from a client
|
||||
pub fn handle_punch(
|
||||
&mut self,
|
||||
player_id: u16,
|
||||
to: Vector3,
|
||||
transform: NetTransform,
|
||||
look_up: f32,
|
||||
deal_damage: bool,
|
||||
) -> bool {
|
||||
let self_id = self.self_id.clone().unwrap_or(0);
|
||||
if let Some(player) = self.find_player_mut(player_id) {
|
||||
if player.id() != self_id {
|
||||
player.try_punch(to, transform, look_up, deal_damage)
|
||||
} else {
|
||||
false
|
||||
}
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
// Handle for when a player is killed, run both on client and server
|
||||
pub fn on_kill(&mut self, source: DamageSource, player_id: u16) {
|
||||
if let DamageSource::Player(source_player_id) = source
|
||||
@ -1155,6 +1173,24 @@ impl Player {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn try_punch(
|
||||
&mut self,
|
||||
to: Vector3,
|
||||
transform: NetTransform,
|
||||
look_up: f32,
|
||||
deal_damage: bool,
|
||||
) -> bool {
|
||||
if let Some(character) = &mut self.character {
|
||||
character
|
||||
.dyn_bind_mut()
|
||||
.apply_rotation(transform.rotation.into());
|
||||
character.dyn_bind_mut().apply_look_up(look_up);
|
||||
character.dyn_bind_mut().try_punch(to, deal_damage)
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
pub fn id(&self) -> u16 {
|
||||
self.data.id
|
||||
}
|
||||
|
||||
@ -4,14 +4,12 @@ use std::{
|
||||
};
|
||||
|
||||
use godot::{
|
||||
classes::{AudioBusLayout, AudioServer, FileAccess, file_access::ModeFlags},
|
||||
classes::{AudioServer, FileAccess, file_access::ModeFlags},
|
||||
prelude::*,
|
||||
tools::get_autoload_by_name,
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::ui::settings::Setting::MusicVolume;
|
||||
|
||||
pub const NETWORK_SINGLETON_NAME: &str = "GameSettingsGlobal";
|
||||
|
||||
pub const MASTER_BUS: &str = "Master";
|
||||
|
||||
@ -306,6 +306,7 @@ pub enum Package {
|
||||
SelfSync(SyncPackage),
|
||||
Jump(u16),
|
||||
Shoot(u16, NetVector3, NetTransform, f32),
|
||||
Punch(u16, NetVector3, NetTransform, f32),
|
||||
TakeDamage(DamageSource, u16, i32),
|
||||
Kill(DamageSource, u16),
|
||||
SpawnBall(NetTransform, NetVector3, Option<u16>),
|
||||
|
||||
@ -150,6 +150,17 @@ impl NetworkManager {
|
||||
);
|
||||
}
|
||||
}
|
||||
Package::Punch(player_id, to, transform, look_up) => {
|
||||
if let Some(game) = &mut Game::singleton() {
|
||||
game.bind_mut().handle_punch(
|
||||
player_id,
|
||||
to.into(),
|
||||
transform,
|
||||
look_up,
|
||||
false,
|
||||
);
|
||||
}
|
||||
}
|
||||
Package::TakeDamage(source_player_id, target_player_id, damage) => {
|
||||
if let Some(game) = &mut Game::singleton() {
|
||||
game.bind_mut().handle_take_damage(
|
||||
@ -360,6 +371,28 @@ impl NetworkManager {
|
||||
}
|
||||
}
|
||||
}
|
||||
Package::Punch(_, to, transform, look_up) => {
|
||||
if let Some(game) = &mut Game::singleton() {
|
||||
let player =
|
||||
game.bind().find_player_by_addr(&conn.address).cloned();
|
||||
if let Some(player) = player {
|
||||
if game.bind_mut().handle_punch(
|
||||
player.id(),
|
||||
to.into(),
|
||||
transform,
|
||||
look_up,
|
||||
true,
|
||||
) {
|
||||
peer.broadcast_reliable(Package::Punch(
|
||||
player.id(),
|
||||
to,
|
||||
transform,
|
||||
look_up,
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Package::SetTeam(player_id, team) => {
|
||||
if let Some(game) = &mut Game::singleton() {
|
||||
let self_id = game
|
||||
|
||||
@ -16,7 +16,7 @@ use crate::{
|
||||
net::{
|
||||
network_manager::{
|
||||
NetworkManager,
|
||||
Package::{self, Jump, Shoot},
|
||||
Package::{self, Jump, Punch, Shoot},
|
||||
PeerKind,
|
||||
},
|
||||
util::cast_ray,
|
||||
@ -71,6 +71,8 @@ pub struct LocalPlayer {
|
||||
hit_sound: Option<Gd<AudioStreamPlayer>>,
|
||||
#[export]
|
||||
health: i32,
|
||||
#[export]
|
||||
punch_cooldown: f64,
|
||||
|
||||
pub player_id: Option<u16>,
|
||||
|
||||
@ -89,6 +91,8 @@ pub struct LocalPlayer {
|
||||
|
||||
locked: bool,
|
||||
|
||||
punch_cd_remaining: f64,
|
||||
|
||||
base: Base<CharacterBody3D>,
|
||||
}
|
||||
|
||||
@ -159,31 +163,17 @@ impl IPlayer for LocalPlayer {
|
||||
fn apply_look_up(&mut self, _look: f32) {}
|
||||
|
||||
fn try_shoot(&mut self, to: Vector3, deal_damage: bool) -> bool {
|
||||
if self.is_dead {
|
||||
return false;
|
||||
}
|
||||
self.try_shoot_common(to, deal_damage)
|
||||
}
|
||||
|
||||
if self.drop_ball(true) {
|
||||
return true;
|
||||
}
|
||||
|
||||
let rid = self.base().get_rid();
|
||||
if let Some(mut weapon) = self.get_weapon()
|
||||
&& let Some(camera_origin) = &self.camera_origin
|
||||
{
|
||||
if weapon.dyn_bind_mut().shoot(
|
||||
rid,
|
||||
self.player_id.unwrap_or(0),
|
||||
camera_origin.get_global_position(),
|
||||
to,
|
||||
camera_origin.get_global_basis().col_b(),
|
||||
deal_damage,
|
||||
) {
|
||||
weapon.set_rotation(Vector3::RIGHT * 0.3);
|
||||
true
|
||||
} else {
|
||||
false
|
||||
fn try_punch(&mut self, to: Vector3, deal_damage: bool) -> bool {
|
||||
if self.punch_cd_remaining <= 0. {
|
||||
if let Some(weapon) = &mut self.weapon {
|
||||
weapon.set_position(Vector3::FORWARD);
|
||||
weapon.set_rotation(Vector3::UP);
|
||||
}
|
||||
self.punch_cd_remaining = self.punch_cooldown;
|
||||
self.try_punch_common(to, deal_damage)
|
||||
} else {
|
||||
false
|
||||
}
|
||||
@ -342,6 +332,7 @@ impl ICharacterBody3D for LocalPlayer {
|
||||
|
||||
fn process(&mut self, delta: f64) {
|
||||
self.time_passed += delta;
|
||||
self.punch_cd_remaining -= delta;
|
||||
|
||||
if self.is_dead {
|
||||
self.dead_for += delta;
|
||||
@ -440,10 +431,11 @@ impl ICharacterBody3D for LocalPlayer {
|
||||
let prev_weapon_pos = weapon.get_position();
|
||||
let new_y = prev_weapon_pos.y.lerp(target_y as f32, 0.2);
|
||||
let new_x = prev_weapon_pos.x.lerp(target_x as f32, 0.2);
|
||||
let new_z = prev_weapon_pos.z.lerp(0., 0.2);
|
||||
let new_weapon_pos = Vector3 {
|
||||
y: new_y,
|
||||
x: new_x,
|
||||
..prev_weapon_pos
|
||||
z: new_z,
|
||||
};
|
||||
weapon.set_position(new_weapon_pos);
|
||||
}
|
||||
@ -465,22 +457,7 @@ impl ICharacterBody3D for LocalPlayer {
|
||||
|
||||
if self.locked {
|
||||
if event.is_action_pressed("shoot") {
|
||||
let pos = if let Some(camera) = &self.camera {
|
||||
let forward = camera.get_global_basis().col_c().neg();
|
||||
match cast_ray(
|
||||
camera.get_global_position(),
|
||||
camera.get_global_position() + forward,
|
||||
&self.base().get_world_3d(),
|
||||
&Array::from_iter(vec![self.base().get_rid()]),
|
||||
) {
|
||||
Some(res) => Some(res.position),
|
||||
None => Some(camera.get_global_position() + forward * 100.),
|
||||
}
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
if let Some(pos) = pos {
|
||||
if let Some(pos) = self.raycast_from_camera() {
|
||||
if let Some(peer) = &mut NetworkManager::singleton().bind_mut().peer {
|
||||
match peer {
|
||||
PeerKind::Client(peer, addr) => {
|
||||
@ -494,7 +471,34 @@ impl ICharacterBody3D for LocalPlayer {
|
||||
PeerKind::Server(peer, _) => {
|
||||
if self.try_shoot(pos, true) {
|
||||
peer.broadcast_reliable(Shoot(
|
||||
0,
|
||||
self.player_id.unwrap_or(0),
|
||||
pos.into(),
|
||||
self.get_transform(),
|
||||
self.look_up,
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if event.is_action_pressed("punch") {
|
||||
if let Some(pos) = self.raycast_from_camera() {
|
||||
if let Some(peer) = &mut NetworkManager::singleton().bind_mut().peer {
|
||||
match peer {
|
||||
PeerKind::Client(peer, addr) => {
|
||||
if self.try_punch(pos, false) {
|
||||
peer.send_reliable(
|
||||
addr,
|
||||
Punch(0, pos.into(), self.get_transform(), self.look_up),
|
||||
);
|
||||
}
|
||||
}
|
||||
PeerKind::Server(peer, _) => {
|
||||
if self.try_punch(pos, true) {
|
||||
peer.broadcast_reliable(Punch(
|
||||
self.player_id.unwrap_or(0),
|
||||
pos.into(),
|
||||
self.get_transform(),
|
||||
self.look_up,
|
||||
@ -661,6 +665,23 @@ impl LocalPlayer {
|
||||
hit_sound.play();
|
||||
}
|
||||
}
|
||||
|
||||
fn raycast_from_camera(&self) -> Option<Vector3> {
|
||||
if let Some(camera) = &self.camera {
|
||||
let forward = camera.get_global_basis().col_c().neg();
|
||||
match cast_ray(
|
||||
camera.get_global_position(),
|
||||
camera.get_global_position() + forward,
|
||||
&self.base().get_world_3d(),
|
||||
&Array::from_iter(vec![self.base().get_rid()]),
|
||||
) {
|
||||
Some(res) => Some(res.position),
|
||||
None => Some(camera.get_global_position() + forward * 100.),
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[godot_dyn]
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
use std::ops::Neg;
|
||||
use std::{collections::HashSet, f32::consts::PI, ops::Neg};
|
||||
|
||||
use godot::{classes::ICharacterBody3D, obj::WithBaseField, prelude::*};
|
||||
use serde::{Deserialize, Serialize};
|
||||
@ -6,8 +6,14 @@ use serde::{Deserialize, Serialize};
|
||||
use crate::{
|
||||
game_manager::{Game, GameOption},
|
||||
killbox::KillboxKind,
|
||||
net::{network_manager::NetworkManager, util::NetVector3},
|
||||
player::weapon::{BallWeapon, Weapon, WeaponType},
|
||||
net::{
|
||||
network_manager::NetworkManager,
|
||||
util::{NetVector3, shotgun_ray},
|
||||
},
|
||||
player::{
|
||||
shootable::Shootable,
|
||||
weapon::{BallWeapon, Weapon, WeaponType},
|
||||
},
|
||||
};
|
||||
|
||||
pub mod ball;
|
||||
@ -40,6 +46,7 @@ pub trait IPlayer {
|
||||
fn get_transform(&self) -> NetTransform;
|
||||
fn jump(&mut self);
|
||||
fn try_shoot(&mut self, to: Vector3, deal_damage: bool) -> bool;
|
||||
fn try_punch(&mut self, to: Vector3, deal_damage: bool) -> bool;
|
||||
fn take_damage(&mut self, source_player: DamageSource, damage: i32, kill: bool);
|
||||
fn is_dead(&self) -> bool;
|
||||
fn kill(&mut self, source_player: DamageSource);
|
||||
@ -57,6 +64,8 @@ pub trait PlayerCommon {
|
||||
fn drop_ball_common(&mut self, with_velocity: bool) -> bool;
|
||||
fn get_look_dir(&self) -> Vector3;
|
||||
fn can_take_damage(&self, source: &DamageSource) -> bool;
|
||||
fn try_shoot_common(&mut self, to: Vector3, deal_damage: bool) -> bool;
|
||||
fn try_punch_common(&mut self, to: Vector3, deal_damage: bool) -> bool;
|
||||
}
|
||||
|
||||
impl<T: IPlayer + ICharacterBody3D + WithBaseField> PlayerCommon for T {
|
||||
@ -159,6 +168,82 @@ impl<T: IPlayer + ICharacterBody3D + WithBaseField> PlayerCommon for T {
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
fn try_shoot_common(&mut self, to: Vector3, deal_damage: bool) -> bool {
|
||||
if self.is_dead() {
|
||||
return false;
|
||||
}
|
||||
|
||||
if self.drop_ball(true) {
|
||||
return true;
|
||||
}
|
||||
|
||||
let rid = self.base().get_rid();
|
||||
if let Some(mut weapon) = self.get_weapon()
|
||||
&& let Some(camera_origin) = &self.get_camera_origin()
|
||||
{
|
||||
weapon.dyn_bind_mut().shoot(
|
||||
rid,
|
||||
self.get_player_id().unwrap_or(0),
|
||||
camera_origin.get_global_position(),
|
||||
to,
|
||||
camera_origin.get_basis().col_b(),
|
||||
deal_damage,
|
||||
)
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
fn try_punch_common(&mut self, to: Vector3, deal_damage: bool) -> bool {
|
||||
if self.is_dead() {
|
||||
return false;
|
||||
}
|
||||
if !deal_damage {
|
||||
return true;
|
||||
}
|
||||
|
||||
if let Some(origin) = self.get_camera_origin() {
|
||||
let rid = self.base().get_rid();
|
||||
let up = origin.get_basis().col_b();
|
||||
let results = shotgun_ray(
|
||||
origin.get_global_position(),
|
||||
to,
|
||||
up,
|
||||
&self.base().get_world_3d(),
|
||||
&Array::from_iter(vec![rid]),
|
||||
10,
|
||||
PI / 2.,
|
||||
2.,
|
||||
);
|
||||
|
||||
let mut colliders = HashSet::new();
|
||||
for result in results {
|
||||
colliders.insert(result.collider);
|
||||
}
|
||||
|
||||
for collider in colliders {
|
||||
let collider_pos = if let Ok(node) = collider.clone().try_cast::<Node3D>() {
|
||||
node.get_global_position()
|
||||
} else {
|
||||
Vector3::ZERO
|
||||
};
|
||||
|
||||
let delta = collider_pos - origin.get_global_position();
|
||||
|
||||
if let Ok(mut shootable) = collider.clone().try_dynify::<dyn Shootable>() {
|
||||
self.run_deferred(move |s| {
|
||||
shootable.dyn_bind_mut().on_shoot(
|
||||
DamageSource::Player(s.get_player_id().unwrap_or(0)),
|
||||
100,
|
||||
delta.normalized(),
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
|
||||
|
||||
@ -33,6 +33,8 @@ pub struct RemotePlayer {
|
||||
#[export]
|
||||
health: i32,
|
||||
#[export]
|
||||
punch_cooldown: f64,
|
||||
#[export]
|
||||
pub spectator_camera: Option<Gd<Camera3D>>,
|
||||
#[export]
|
||||
camera_origin: Option<Gd<Node3D>>,
|
||||
@ -52,6 +54,8 @@ pub struct RemotePlayer {
|
||||
is_dead: bool,
|
||||
dead_for: f64,
|
||||
|
||||
punch_cd_remaining: f64,
|
||||
|
||||
base: Base<CharacterBody3D>,
|
||||
}
|
||||
|
||||
@ -120,27 +124,13 @@ impl IPlayer for RemotePlayer {
|
||||
}
|
||||
|
||||
fn try_shoot(&mut self, to: Vector3, deal_damage: bool) -> bool {
|
||||
if self.is_dead {
|
||||
return false;
|
||||
}
|
||||
self.try_shoot_common(to, deal_damage)
|
||||
}
|
||||
|
||||
if self.drop_ball(true) {
|
||||
return true;
|
||||
}
|
||||
|
||||
let rid = self.base().get_rid();
|
||||
if let Some(mesh) = &mut self.soldier_mesh
|
||||
&& let Some(mut weapon) = mesh.bind().get_weapon()
|
||||
&& let Some(camera_origin) = &self.camera_origin
|
||||
{
|
||||
weapon.dyn_bind_mut().shoot(
|
||||
rid,
|
||||
self.player_id.unwrap_or(0),
|
||||
camera_origin.get_global_position(),
|
||||
to,
|
||||
camera_origin.get_basis().col_b(),
|
||||
deal_damage,
|
||||
)
|
||||
fn try_punch(&mut self, to: Vector3, deal_damage: bool) -> bool {
|
||||
if self.punch_cd_remaining <= 0. {
|
||||
self.punch_cd_remaining = self.punch_cooldown;
|
||||
self.try_punch_common(to, deal_damage)
|
||||
} else {
|
||||
false
|
||||
}
|
||||
@ -252,6 +242,8 @@ impl ICharacterBody3D for RemotePlayer {
|
||||
}
|
||||
|
||||
fn process(&mut self, delta: f64) {
|
||||
self.punch_cd_remaining -= delta;
|
||||
|
||||
if self.is_dead {
|
||||
self.dead_for += delta;
|
||||
}
|
||||
|
||||
@ -3,7 +3,7 @@ use godot::{
|
||||
prelude::*,
|
||||
};
|
||||
|
||||
use crate::credits::{Credit, CreditPerson, Credits};
|
||||
use crate::credits::{CreditPerson, Credits};
|
||||
|
||||
const CREDITS: &'static str = include_str!("../../../credits.toml");
|
||||
|
||||
|
||||
@ -2,7 +2,7 @@ use std::collections::HashMap;
|
||||
|
||||
use godot::{
|
||||
classes::{
|
||||
Control, GridContainer, IPanel, IPanelContainer, Label, LineEdit, Panel, PanelContainer,
|
||||
Control, GridContainer, IPanelContainer, Label, LineEdit, PanelContainer,
|
||||
control::SizeFlags,
|
||||
},
|
||||
prelude::*,
|
||||
|
||||
Loading…
Reference in New Issue
Block a user