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)
|
||||
]
|
||||
}
|
||||
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]
|
||||
|
||||
|
||||
@ -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
|
||||
pub fn on_kill(&mut self, source: DamageSource, player_id: u16) {
|
||||
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 {
|
||||
self.data.id
|
||||
}
|
||||
|
||||
@ -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,13 @@ 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. {
|
||||
self.punch_cd_remaining = self.punch_cooldown;
|
||||
self.try_punch_common(to, deal_damage)
|
||||
} else {
|
||||
false
|
||||
}
|
||||
@ -465,22 +451,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 +465,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 +659,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)),
|
||||
500,
|
||||
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
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user