Implement punching
This commit is contained in:
parent
b0a0fe077a
commit
fb799acdbe
@ -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)
|
"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]
|
[physics]
|
||||||
|
|
||||||
|
|||||||
@ -915,6 +915,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
|
// Handle for when a player is killed, run both on client and server
|
||||||
pub fn on_kill(&mut self, source: DamageSource, player_id: u16) {
|
pub fn on_kill(&mut self, source: DamageSource, player_id: u16) {
|
||||||
if let DamageSource::Player(source_player_id) = source
|
if let DamageSource::Player(source_player_id) = source
|
||||||
@ -1155,6 +1176,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 {
|
pub fn id(&self) -> u16 {
|
||||||
self.data.id
|
self.data.id
|
||||||
}
|
}
|
||||||
|
|||||||
@ -306,6 +306,7 @@ pub enum Package {
|
|||||||
SelfSync(SyncPackage),
|
SelfSync(SyncPackage),
|
||||||
Jump(u16),
|
Jump(u16),
|
||||||
Shoot(u16, NetVector3, NetTransform, f32),
|
Shoot(u16, NetVector3, NetTransform, f32),
|
||||||
|
Punch(u16, NetVector3, NetTransform, f32),
|
||||||
TakeDamage(DamageSource, u16, i32),
|
TakeDamage(DamageSource, u16, i32),
|
||||||
Kill(DamageSource, u16),
|
Kill(DamageSource, u16),
|
||||||
SpawnBall(NetTransform, NetVector3, Option<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) => {
|
Package::TakeDamage(source_player_id, target_player_id, damage) => {
|
||||||
if let Some(game) = &mut Game::singleton() {
|
if let Some(game) = &mut Game::singleton() {
|
||||||
game.bind_mut().handle_take_damage(
|
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) => {
|
Package::SetTeam(player_id, team) => {
|
||||||
if let Some(game) = &mut Game::singleton() {
|
if let Some(game) = &mut Game::singleton() {
|
||||||
let self_id = game
|
let self_id = game
|
||||||
|
|||||||
@ -16,7 +16,7 @@ use crate::{
|
|||||||
net::{
|
net::{
|
||||||
network_manager::{
|
network_manager::{
|
||||||
NetworkManager,
|
NetworkManager,
|
||||||
Package::{self, Jump, Shoot},
|
Package::{self, Jump, Punch, Shoot},
|
||||||
PeerKind,
|
PeerKind,
|
||||||
},
|
},
|
||||||
util::cast_ray,
|
util::cast_ray,
|
||||||
@ -71,6 +71,8 @@ pub struct LocalPlayer {
|
|||||||
hit_sound: Option<Gd<AudioStreamPlayer>>,
|
hit_sound: Option<Gd<AudioStreamPlayer>>,
|
||||||
#[export]
|
#[export]
|
||||||
health: i32,
|
health: i32,
|
||||||
|
#[export]
|
||||||
|
punch_cooldown: f64,
|
||||||
|
|
||||||
pub player_id: Option<u16>,
|
pub player_id: Option<u16>,
|
||||||
|
|
||||||
@ -89,6 +91,8 @@ pub struct LocalPlayer {
|
|||||||
|
|
||||||
locked: bool,
|
locked: bool,
|
||||||
|
|
||||||
|
punch_cd_remaining: f64,
|
||||||
|
|
||||||
base: Base<CharacterBody3D>,
|
base: Base<CharacterBody3D>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -159,31 +163,13 @@ impl IPlayer for LocalPlayer {
|
|||||||
fn apply_look_up(&mut self, _look: f32) {}
|
fn apply_look_up(&mut self, _look: f32) {}
|
||||||
|
|
||||||
fn try_shoot(&mut self, to: Vector3, deal_damage: bool) -> bool {
|
fn try_shoot(&mut self, to: Vector3, deal_damage: bool) -> bool {
|
||||||
if self.is_dead {
|
self.try_shoot_common(to, deal_damage)
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.drop_ball(true) {
|
fn try_punch(&mut self, to: Vector3, deal_damage: bool) -> bool {
|
||||||
return true;
|
if self.punch_cd_remaining <= 0. {
|
||||||
}
|
self.punch_cd_remaining = self.punch_cooldown;
|
||||||
|
self.try_punch_common(to, deal_damage)
|
||||||
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
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
@ -465,22 +451,7 @@ impl ICharacterBody3D for LocalPlayer {
|
|||||||
|
|
||||||
if self.locked {
|
if self.locked {
|
||||||
if event.is_action_pressed("shoot") {
|
if event.is_action_pressed("shoot") {
|
||||||
let pos = if let Some(camera) = &self.camera {
|
if let Some(pos) = self.raycast_from_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(peer) = &mut NetworkManager::singleton().bind_mut().peer {
|
if let Some(peer) = &mut NetworkManager::singleton().bind_mut().peer {
|
||||||
match peer {
|
match peer {
|
||||||
PeerKind::Client(peer, addr) => {
|
PeerKind::Client(peer, addr) => {
|
||||||
@ -494,7 +465,34 @@ impl ICharacterBody3D for LocalPlayer {
|
|||||||
PeerKind::Server(peer, _) => {
|
PeerKind::Server(peer, _) => {
|
||||||
if self.try_shoot(pos, true) {
|
if self.try_shoot(pos, true) {
|
||||||
peer.broadcast_reliable(Shoot(
|
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(),
|
pos.into(),
|
||||||
self.get_transform(),
|
self.get_transform(),
|
||||||
self.look_up,
|
self.look_up,
|
||||||
@ -661,6 +659,23 @@ impl LocalPlayer {
|
|||||||
hit_sound.play();
|
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]
|
#[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 godot::{classes::ICharacterBody3D, obj::WithBaseField, prelude::*};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
@ -6,8 +6,14 @@ use serde::{Deserialize, Serialize};
|
|||||||
use crate::{
|
use crate::{
|
||||||
game_manager::{Game, GameOption},
|
game_manager::{Game, GameOption},
|
||||||
killbox::KillboxKind,
|
killbox::KillboxKind,
|
||||||
net::{network_manager::NetworkManager, util::NetVector3},
|
net::{
|
||||||
player::weapon::{BallWeapon, Weapon, WeaponType},
|
network_manager::NetworkManager,
|
||||||
|
util::{NetVector3, shotgun_ray},
|
||||||
|
},
|
||||||
|
player::{
|
||||||
|
shootable::Shootable,
|
||||||
|
weapon::{BallWeapon, Weapon, WeaponType},
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub mod ball;
|
pub mod ball;
|
||||||
@ -40,6 +46,7 @@ pub trait IPlayer {
|
|||||||
fn get_transform(&self) -> NetTransform;
|
fn get_transform(&self) -> NetTransform;
|
||||||
fn jump(&mut self);
|
fn jump(&mut self);
|
||||||
fn try_shoot(&mut self, to: Vector3, deal_damage: bool) -> bool;
|
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 take_damage(&mut self, source_player: DamageSource, damage: i32, kill: bool);
|
||||||
fn is_dead(&self) -> bool;
|
fn is_dead(&self) -> bool;
|
||||||
fn kill(&mut self, source_player: DamageSource);
|
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 drop_ball_common(&mut self, with_velocity: bool) -> bool;
|
||||||
fn get_look_dir(&self) -> Vector3;
|
fn get_look_dir(&self) -> Vector3;
|
||||||
fn can_take_damage(&self, source: &DamageSource) -> bool;
|
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 {
|
impl<T: IPlayer + ICharacterBody3D + WithBaseField> PlayerCommon for T {
|
||||||
@ -159,6 +168,82 @@ impl<T: IPlayer + ICharacterBody3D + WithBaseField> PlayerCommon for T {
|
|||||||
}
|
}
|
||||||
true
|
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)),
|
||||||
|
500,
|
||||||
|
delta.normalized(),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
|
#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
|
||||||
|
|||||||
@ -33,6 +33,8 @@ pub struct RemotePlayer {
|
|||||||
#[export]
|
#[export]
|
||||||
health: i32,
|
health: i32,
|
||||||
#[export]
|
#[export]
|
||||||
|
punch_cooldown: f64,
|
||||||
|
#[export]
|
||||||
pub spectator_camera: Option<Gd<Camera3D>>,
|
pub spectator_camera: Option<Gd<Camera3D>>,
|
||||||
#[export]
|
#[export]
|
||||||
camera_origin: Option<Gd<Node3D>>,
|
camera_origin: Option<Gd<Node3D>>,
|
||||||
@ -52,6 +54,8 @@ pub struct RemotePlayer {
|
|||||||
is_dead: bool,
|
is_dead: bool,
|
||||||
dead_for: f64,
|
dead_for: f64,
|
||||||
|
|
||||||
|
punch_cd_remaining: f64,
|
||||||
|
|
||||||
base: Base<CharacterBody3D>,
|
base: Base<CharacterBody3D>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -120,27 +124,13 @@ impl IPlayer for RemotePlayer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn try_shoot(&mut self, to: Vector3, deal_damage: bool) -> bool {
|
fn try_shoot(&mut self, to: Vector3, deal_damage: bool) -> bool {
|
||||||
if self.is_dead {
|
self.try_shoot_common(to, deal_damage)
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.drop_ball(true) {
|
fn try_punch(&mut self, to: Vector3, deal_damage: bool) -> bool {
|
||||||
return true;
|
if self.punch_cd_remaining <= 0. {
|
||||||
}
|
self.punch_cd_remaining = self.punch_cooldown;
|
||||||
|
self.try_punch_common(to, deal_damage)
|
||||||
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,
|
|
||||||
)
|
|
||||||
} else {
|
} else {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user