Compare commits
3
Commits
master
...
c0c88d5dbd
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c0c88d5dbd | ||
|
|
a83caf9153 | ||
|
|
d1782afe51 |
+1
-1
@@ -8,7 +8,7 @@ authors = [""]
|
|||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["development", "debug_features"]
|
default = ["development", "debug_features"]
|
||||||
development = ["bevy/dynamic_linking", "bevy/file_watcher"]
|
development = ["bevy/dynamic_linking", "bevy/file_watcher", "bevy/embedded_watcher"]
|
||||||
debug_features = ["bevy/free_camera"]
|
debug_features = ["bevy/free_camera"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ use bevy::prelude::*;
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
camera::MatchCamera, fighter::{
|
camera::MatchCamera, fighter::{
|
||||||
FighterECB, FighterFacingDirection, FighterHitboxes, FighterHitstop, FighterHitstopShake, FighterPendingRespawn, FighterPreviousFacingDirection, FighterPreviousTranslation, FighterSurfaceState, FighterTranslation, FighterVelocity, animation::FighterAnimationFrame, attack::{
|
FighterECB, FighterFacingDirection, FighterHitboxes, FighterHitstop, FighterHitstopShake, FighterInvulnerabilityState, FighterPendingRespawn, FighterPreviousFacingDirection, FighterPreviousTranslation, FighterSurfaceState, FighterTranslation, FighterVelocity, animation::FighterAnimationFrame, attack::{
|
||||||
FighterDamage, FighterKnockbackVelocity, FighterPendingHitReaction, FighterPendingHits,
|
FighterDamage, FighterKnockbackVelocity, FighterPendingHitReaction, FighterPendingHits,
|
||||||
FighterSolvedHurtboxes, FighterStaleMoveQueue,
|
FighterSolvedHurtboxes, FighterStaleMoveQueue,
|
||||||
}, baked_animation::FighterBoneMatrices, state::FighterState,
|
}, baked_animation::FighterBoneMatrices, state::FighterState,
|
||||||
@@ -47,6 +47,7 @@ struct FighterCheckpoint {
|
|||||||
bone_matrices: FighterBoneMatrices,
|
bone_matrices: FighterBoneMatrices,
|
||||||
surface: FighterSurfaceState,
|
surface: FighterSurfaceState,
|
||||||
pending_respawn: FighterPendingRespawn,
|
pending_respawn: FighterPendingRespawn,
|
||||||
|
invulnerability_state: FighterInvulnerabilityState,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn save_or_restore(world: &mut World) {
|
pub(super) fn save_or_restore(world: &mut World) {
|
||||||
@@ -149,6 +150,7 @@ pub(super) fn save_or_restore(world: &mut World) {
|
|||||||
entity.insert(saved.bone_matrices.clone());
|
entity.insert(saved.bone_matrices.clone());
|
||||||
entity.insert(saved.surface.clone());
|
entity.insert(saved.surface.clone());
|
||||||
entity.insert(saved.pending_respawn.clone());
|
entity.insert(saved.pending_respawn.clone());
|
||||||
|
entity.insert(saved.invulnerability_state.clone());
|
||||||
}
|
}
|
||||||
world.insert_resource(checkpoint.pending_hits.clone());
|
world.insert_resource(checkpoint.pending_hits.clone());
|
||||||
world.insert_resource(checkpoint.stage_collision);
|
world.insert_resource(checkpoint.stage_collision);
|
||||||
@@ -185,6 +187,7 @@ fn capture_fighter(world: &World, entity: Entity) -> Option<FighterCheckpoint> {
|
|||||||
bone_matrices: fighter.get::<FighterBoneMatrices>()?.clone(),
|
bone_matrices: fighter.get::<FighterBoneMatrices>()?.clone(),
|
||||||
surface: fighter.get::<FighterSurfaceState>()?.clone(),
|
surface: fighter.get::<FighterSurfaceState>()?.clone(),
|
||||||
pending_respawn: fighter.get::<FighterPendingRespawn>()?.clone(),
|
pending_respawn: fighter.get::<FighterPendingRespawn>()?.clone(),
|
||||||
|
invulnerability_state: fighter.get::<FighterInvulnerabilityState>()?.clone(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -44,6 +44,9 @@ pub struct FighterAttributes {
|
|||||||
pub air_dodge_duration: u32,
|
pub air_dodge_duration: u32,
|
||||||
pub air_dodge_velocity: FGi32,
|
pub air_dodge_velocity: FGi32,
|
||||||
pub air_dodge_decay: FGi32,
|
pub air_dodge_decay: FGi32,
|
||||||
|
|
||||||
|
pub air_dodge_intangible_duration: u32,
|
||||||
|
pub air_dodge_intangible_start: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FighterAttributes {
|
impl FighterAttributes {
|
||||||
|
|||||||
+18
-3
@@ -41,8 +41,8 @@ use crate::{
|
|||||||
AttackKind, FighterAttackPlugin, FighterAttackScriptAssets, FighterDamage,
|
AttackKind, FighterAttackPlugin, FighterAttackScriptAssets, FighterDamage,
|
||||||
FighterKnockbackVelocity, FighterPendingHitReaction, FighterSolvedHurtboxes,
|
FighterKnockbackVelocity, FighterPendingHitReaction, FighterSolvedHurtboxes,
|
||||||
FighterStaleMoveQueue,
|
FighterStaleMoveQueue,
|
||||||
}, baked_animation::{FighterBoneIndexMap, FighterBoneMatrices}, ecb::FighterECBBoneIndices, manifest::FighterManifest, state::{FighterState, air::AirborneStateCommon, fall::FallState}, visual::FighterAnimations,
|
}, baked_animation::{FighterBoneIndexMap, FighterBoneMatrices}, ecb::FighterECBBoneIndices, manifest::FighterManifest, state::{FighterState, air::AirborneStateCommon, fall::FallState}, visual::{FighterAnimations, FighterInvulnerabilityVisualState},
|
||||||
}, input::FighterInput, math::{int::FGi32, vec::FGVec2}, player::Player, schedule::GameplaySet, scripting::FighterAttackScript, stage::line::StageCollision,
|
}, game_settings::GameSettings, input::FighterInput, math::{int::FGi32, vec::FGVec2}, player::Player, schedule::GameplaySet, scripting::FighterAttackScript, stage::line::StageCollision,
|
||||||
};
|
};
|
||||||
use state::state_interrupt_system;
|
use state::state_interrupt_system;
|
||||||
|
|
||||||
@@ -85,6 +85,14 @@ pub struct FighterHitstop {
|
|||||||
pub remaining_frames: u32,
|
pub remaining_frames: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Component, Default, Copy, Clone, Hash, PartialEq, Eq)]
|
||||||
|
pub enum FighterInvulnerabilityState {
|
||||||
|
#[default]
|
||||||
|
Vulnerable,
|
||||||
|
Invulnerable,
|
||||||
|
Intangible
|
||||||
|
}
|
||||||
|
|
||||||
impl FighterFacingDirection {
|
impl FighterFacingDirection {
|
||||||
fn reverse(&self) -> Self {
|
fn reverse(&self) -> Self {
|
||||||
match self {
|
match self {
|
||||||
@@ -140,7 +148,9 @@ pub struct FighterPendingRespawn(bool);
|
|||||||
FighterPendingRespawn,
|
FighterPendingRespawn,
|
||||||
FighterHitstop,
|
FighterHitstop,
|
||||||
FighterKnockbackVelocity,
|
FighterKnockbackVelocity,
|
||||||
FighterTranslation
|
FighterTranslation,
|
||||||
|
FighterInvulnerabilityState,
|
||||||
|
FighterInvulnerabilityVisualState,
|
||||||
)]
|
)]
|
||||||
pub struct Fighter {
|
pub struct Fighter {
|
||||||
pub manifest: Handle<FighterManifest>,
|
pub manifest: Handle<FighterManifest>,
|
||||||
@@ -229,6 +239,8 @@ impl Plugin for FighterPlugin {
|
|||||||
.checksum_component_with_hash::<FighterPendingRespawn>()
|
.checksum_component_with_hash::<FighterPendingRespawn>()
|
||||||
.rollback_component_with_copy::<FighterHitstop>()
|
.rollback_component_with_copy::<FighterHitstop>()
|
||||||
.checksum_component_with_hash::<FighterHitstop>()
|
.checksum_component_with_hash::<FighterHitstop>()
|
||||||
|
.rollback_component_with_copy::<FighterInvulnerabilityState>()
|
||||||
|
.checksum_component_with_hash::<FighterInvulnerabilityState>()
|
||||||
.rollback_component_with_copy::<FighterKnockbackVelocity>()
|
.rollback_component_with_copy::<FighterKnockbackVelocity>()
|
||||||
.checksum_component_with_hash::<FighterKnockbackVelocity>()
|
.checksum_component_with_hash::<FighterKnockbackVelocity>()
|
||||||
.rollback_resource_with_reflect::<StageCollision>()
|
.rollback_resource_with_reflect::<StageCollision>()
|
||||||
@@ -256,6 +268,9 @@ impl Plugin for FighterPlugin {
|
|||||||
.run_if(crate::debug_tools::attack_hitboxes_enabled)
|
.run_if(crate::debug_tools::attack_hitboxes_enabled)
|
||||||
.run_if(in_state(AppState::InMatch)),
|
.run_if(in_state(AppState::InMatch)),
|
||||||
)
|
)
|
||||||
|
.add_systems(FixedPostUpdate,
|
||||||
|
visual::update_status_colors.run_if(resource_exists::<GameSettings>)
|
||||||
|
)
|
||||||
.add_systems(
|
.add_systems(
|
||||||
FixedPostUpdate,
|
FixedPostUpdate,
|
||||||
debug::hurtbox_debug.run_if(crate::debug_tools::hurtboxes_enabled),
|
debug::hurtbox_debug.run_if(crate::debug_tools::hurtboxes_enabled),
|
||||||
|
|||||||
@@ -168,6 +168,8 @@ mod tests {
|
|||||||
air_dodge_duration: 0,
|
air_dodge_duration: 0,
|
||||||
air_dodge_velocity: FGi32::ZERO,
|
air_dodge_velocity: FGi32::ZERO,
|
||||||
air_dodge_decay: FGi32::ZERO,
|
air_dodge_decay: FGi32::ZERO,
|
||||||
|
air_dodge_intangible_duration: 29,
|
||||||
|
air_dodge_intangible_start: 4,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,16 +1,13 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
fighter::{
|
fighter::{
|
||||||
animation::AnimKind,
|
FighterInvulnerabilityState, animation::AnimKind, state::{
|
||||||
state::{
|
|
||||||
CollisionContext, EnterContext, FighterState, FighterStateImpl, InterruptContext,
|
CollisionContext, EnterContext, FighterState, FighterStateImpl, InterruptContext,
|
||||||
UpdateContext,
|
UpdateContext,
|
||||||
air::{self, AirborneStateCommon},
|
air::{self, AirborneStateCommon},
|
||||||
fall::FallState,
|
fall::FallState,
|
||||||
land::LandingType,
|
land::LandingType,
|
||||||
},
|
},
|
||||||
},
|
}, input, math::vec::FGVec2,
|
||||||
input,
|
|
||||||
math::vec::FGVec2,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Debug, Clone, Hash)]
|
#[derive(Debug, Clone, Hash)]
|
||||||
@@ -32,6 +29,12 @@ impl FighterStateImpl for AirDodgeState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn update(&mut self, state_context: &mut UpdateContext) {
|
fn update(&mut self, state_context: &mut UpdateContext) {
|
||||||
|
let airdodge_intangible_end = state_context.fighter_attributes.air_dodge_intangible_start + state_context.fighter_attributes.air_dodge_intangible_duration;
|
||||||
|
if state_context.animation_frame == state_context.fighter_attributes.air_dodge_intangible_start {
|
||||||
|
*state_context.vulnerability = FighterInvulnerabilityState::Intangible;
|
||||||
|
} else if state_context.animation_frame >= airdodge_intangible_end {
|
||||||
|
*state_context.vulnerability = FighterInvulnerabilityState::Vulnerable;
|
||||||
|
}
|
||||||
state_context.velocity.0 *= state_context.fighter_attributes.air_dodge_decay;
|
state_context.velocity.0 *= state_context.fighter_attributes.air_dodge_decay;
|
||||||
|
|
||||||
air::apply_air_motion(
|
air::apply_air_motion(
|
||||||
@@ -62,6 +65,14 @@ impl FighterStateImpl for AirDodgeState {
|
|||||||
fn surface_policy(&self) -> super::SurfacePolicy {
|
fn surface_policy(&self) -> super::SurfacePolicy {
|
||||||
super::SurfacePolicy::Airborne(crate::fighter::surface::EcbLockPolicy::StartOnDetach)
|
super::SurfacePolicy::Airborne(crate::fighter::surface::EcbLockPolicy::StartOnDetach)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn on_exit(&mut self, state_context: &mut super::ExitContext) {
|
||||||
|
*state_context.vulnerability = FighterInvulnerabilityState::Vulnerable;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn name(&self) -> String {
|
||||||
|
Self::NAME.to_owned()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn check_input(state_context: &InterruptContext) -> Option<FighterState> {
|
pub fn check_input(state_context: &InterruptContext) -> Option<FighterState> {
|
||||||
|
|||||||
@@ -18,10 +18,7 @@ use crate::fighter::state::hitstun::HitstunState;
|
|||||||
use crate::fighter::surface::EcbLockPolicy;
|
use crate::fighter::surface::EcbLockPolicy;
|
||||||
use crate::fighter::visual::FighterAnimations;
|
use crate::fighter::visual::FighterAnimations;
|
||||||
use crate::fighter::{
|
use crate::fighter::{
|
||||||
Fighter, FighterECB, FighterFacingDirection, FighterHitboxes, FighterHitstop,
|
Fighter, FighterDamage, FighterECB, FighterFacingDirection, FighterHitboxes, FighterHitstop, FighterHitstopShake, FighterHitstopShakeKind, FighterHitstopShakeRole, FighterInvulnerabilityState, FighterPendingRespawn, FighterPresentationSnap, FighterPreviousTranslation, FighterSurfaceState, FighterTranslation, FighterVelocity,
|
||||||
FighterHitstopShake, FighterHitstopShakeKind, FighterHitstopShakeRole, FighterPendingRespawn,
|
|
||||||
FighterPresentationSnap, FighterPreviousTranslation, FighterSurfaceState, FighterTranslation,
|
|
||||||
FighterVelocity, FighterDamage,
|
|
||||||
};
|
};
|
||||||
use crate::game_settings::GameSettings;
|
use crate::game_settings::GameSettings;
|
||||||
use crate::input::FighterInput;
|
use crate::input::FighterInput;
|
||||||
@@ -173,6 +170,7 @@ impl EnterContext<'_> {
|
|||||||
pub struct ExitContext<'a> {
|
pub struct ExitContext<'a> {
|
||||||
pub hitboxes: &'a mut FighterHitboxes,
|
pub hitboxes: &'a mut FighterHitboxes,
|
||||||
pub surface: &'a mut FighterSurfaceState,
|
pub surface: &'a mut FighterSurfaceState,
|
||||||
|
pub vulnerability: &'a mut FighterInvulnerabilityState,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct UpdateContext<'a> {
|
pub struct UpdateContext<'a> {
|
||||||
@@ -183,6 +181,7 @@ pub struct UpdateContext<'a> {
|
|||||||
pub velocity: &'a mut FighterVelocity,
|
pub velocity: &'a mut FighterVelocity,
|
||||||
pub surface: &'a mut FighterSurfaceState,
|
pub surface: &'a mut FighterSurfaceState,
|
||||||
pub knockback_velocity: &'a mut FighterKnockbackVelocity,
|
pub knockback_velocity: &'a mut FighterKnockbackVelocity,
|
||||||
|
pub vulnerability: &'a mut FighterInvulnerabilityState,
|
||||||
pub game_settings: &'a GameSettings,
|
pub game_settings: &'a GameSettings,
|
||||||
pub animation_frame: u32,
|
pub animation_frame: u32,
|
||||||
pub fighter_attributes: &'a FighterAttributes,
|
pub fighter_attributes: &'a FighterAttributes,
|
||||||
@@ -264,6 +263,7 @@ pub struct FighterFrameQuery {
|
|||||||
pub prev_ecb: &'static FighterPreviousECB,
|
pub prev_ecb: &'static FighterPreviousECB,
|
||||||
pub facing_direction: &'static mut FighterFacingDirection,
|
pub facing_direction: &'static mut FighterFacingDirection,
|
||||||
pub animation_frame: &'static mut FighterAnimationFrame,
|
pub animation_frame: &'static mut FighterAnimationFrame,
|
||||||
|
pub vulnerability: &'static mut FighterInvulnerabilityState,
|
||||||
pub fighter: &'static Fighter,
|
pub fighter: &'static Fighter,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -329,6 +329,7 @@ impl<'w, 's> FighterFrameQueryItem<'w, 's> {
|
|||||||
ExitContext {
|
ExitContext {
|
||||||
hitboxes: &mut self.hitboxes,
|
hitboxes: &mut self.hitboxes,
|
||||||
surface: &mut self.surface,
|
surface: &mut self.surface,
|
||||||
|
vulnerability: &mut self.vulnerability,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -349,6 +350,7 @@ impl<'w, 's> FighterFrameQueryItem<'w, 's> {
|
|||||||
knockback_velocity: &mut self.knockback_velocity,
|
knockback_velocity: &mut self.knockback_velocity,
|
||||||
game_settings,
|
game_settings,
|
||||||
animation_frame: self.animation_frame.frame,
|
animation_frame: self.animation_frame.frame,
|
||||||
|
vulnerability: &mut self.vulnerability,
|
||||||
fighter_attributes: attributes,
|
fighter_attributes: attributes,
|
||||||
attack_scripts,
|
attack_scripts,
|
||||||
attack_script_assets,
|
attack_script_assets,
|
||||||
|
|||||||
+64
-1
@@ -1,4 +1,8 @@
|
|||||||
use crate::fighter::baked_animation::BakedFighterAnimations;
|
use crate::{
|
||||||
|
fighter::{FighterInvulnerabilityState, baked_animation::BakedFighterAnimations},
|
||||||
|
game_settings::GameSettings,
|
||||||
|
materials::fighter_material::{FighterMaterial, FighterMesh},
|
||||||
|
};
|
||||||
use bevy::prelude::*;
|
use bevy::prelude::*;
|
||||||
|
|
||||||
#[derive(Component, Clone)]
|
#[derive(Component, Clone)]
|
||||||
@@ -6,3 +10,62 @@ pub struct FighterAnimations {
|
|||||||
/// The single animation source for gameplay and the visual skeleton.
|
/// The single animation source for gameplay and the visual skeleton.
|
||||||
pub baked: Handle<BakedFighterAnimations>,
|
pub baked: Handle<BakedFighterAnimations>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Component, Clone, Default)]
|
||||||
|
pub struct FighterInvulnerabilityVisualState {
|
||||||
|
pub last_known_state: FighterInvulnerabilityState,
|
||||||
|
pub frames_in_state: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn update_status_colors(
|
||||||
|
mut fighters: Query<(
|
||||||
|
&FighterInvulnerabilityState,
|
||||||
|
&mut FighterInvulnerabilityVisualState,
|
||||||
|
)>,
|
||||||
|
meshes: Query<(&FighterMesh, &MeshMaterial3d<FighterMaterial>)>,
|
||||||
|
mut materials: ResMut<Assets<FighterMaterial>>,
|
||||||
|
game_settings: Res<GameSettings>,
|
||||||
|
) {
|
||||||
|
for (invuln_state, mut invuln_state_visual) in &mut fighters {
|
||||||
|
if *invuln_state != invuln_state_visual.last_known_state {
|
||||||
|
invuln_state_visual.last_known_state = *invuln_state;
|
||||||
|
invuln_state_visual.frames_in_state = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (mesh, mat) in meshes {
|
||||||
|
let (_, invuln_state_visual) = fighters
|
||||||
|
.get(mesh.fighter)
|
||||||
|
.expect("Material should have relevant fighter available");
|
||||||
|
|
||||||
|
let status_color = match invuln_state_visual.last_known_state {
|
||||||
|
FighterInvulnerabilityState::Vulnerable => bevy::color::palettes::css::WHITE.into(),
|
||||||
|
FighterInvulnerabilityState::Invulnerable => {
|
||||||
|
game_settings.fighter_common.intangible_color
|
||||||
|
}
|
||||||
|
FighterInvulnerabilityState::Intangible => {
|
||||||
|
game_settings.fighter_common.intangible_color
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let intensity = match invuln_state_visual.last_known_state {
|
||||||
|
FighterInvulnerabilityState::Vulnerable => 0.0,
|
||||||
|
FighterInvulnerabilityState::Invulnerable | FighterInvulnerabilityState::Intangible => {
|
||||||
|
let cycle_frames = invuln_state_visual.frames_in_state
|
||||||
|
% game_settings.fighter_common.intangible_pulse_duration;
|
||||||
|
1.0 - cycle_frames as f32
|
||||||
|
/ ((game_settings.fighter_common.intangible_pulse_duration) as f32)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut material = materials
|
||||||
|
.get_mut(mat.id())
|
||||||
|
.expect("Material should exist here...");
|
||||||
|
material
|
||||||
|
.extension
|
||||||
|
.update_status_color(status_color.into(), intensity);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (_, mut invuln_state_visual) in fighters {
|
||||||
|
invuln_state_visual.frames_in_state = invuln_state_visual.frames_in_state.saturating_add(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -42,6 +42,9 @@ pub struct FighterSettingsCommon {
|
|||||||
pub leave_ground_ecb_frame_lock_duration: u32,
|
pub leave_ground_ecb_frame_lock_duration: u32,
|
||||||
pub platform_pass_platform_ignore_duration_frames: u32,
|
pub platform_pass_platform_ignore_duration_frames: u32,
|
||||||
pub platform_pass_initial_downwards_velocity: FGi32,
|
pub platform_pass_initial_downwards_velocity: FGi32,
|
||||||
|
|
||||||
|
pub intangible_color: Color,
|
||||||
|
pub intangible_pulse_duration: u32,
|
||||||
}
|
}
|
||||||
#[derive(Reflect, Serialize, Deserialize, Clone)]
|
#[derive(Reflect, Serialize, Deserialize, Clone)]
|
||||||
#[reflect(opaque)]
|
#[reflect(opaque)]
|
||||||
|
|||||||
+7
-2
@@ -35,8 +35,9 @@ use ron_asset_manager::RonAssetPlugin;
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
camera::MatchCameraPlugin, fighter::manifest::FighterManifest, game_settings::GameSettings,
|
camera::MatchCameraPlugin, fighter::manifest::FighterManifest, game_settings::GameSettings,
|
||||||
match_runtime::MatchRuntimePlugin, menus::style::FGUiStyle, schedule::GameplaySchedulePlugin,
|
match_runtime::MatchRuntimePlugin, materials::ShinesparkMaterialPlugin,
|
||||||
stage::manifest::StageManifest, ui::InGameUIPlugin,
|
menus::style::FGUiStyle, schedule::GameplaySchedulePlugin, stage::manifest::StageManifest,
|
||||||
|
ui::InGameUIPlugin,
|
||||||
};
|
};
|
||||||
|
|
||||||
mod args;
|
mod args;
|
||||||
@@ -49,6 +50,7 @@ pub mod game_settings;
|
|||||||
pub mod input;
|
pub mod input;
|
||||||
pub mod match_loading;
|
pub mod match_loading;
|
||||||
pub mod match_runtime;
|
pub mod match_runtime;
|
||||||
|
pub mod materials;
|
||||||
mod math;
|
mod math;
|
||||||
pub mod menus;
|
pub mod menus;
|
||||||
pub mod netcode;
|
pub mod netcode;
|
||||||
@@ -109,6 +111,7 @@ impl Plugin for GamePlugin {
|
|||||||
// game-level content and configuration.
|
// game-level content and configuration.
|
||||||
app.init_state::<AppState>()
|
app.init_state::<AppState>()
|
||||||
.add_plugins((
|
.add_plugins((
|
||||||
|
(
|
||||||
SettingsPlugin::new("moe.eirteam.shinespark.debug_settings"),
|
SettingsPlugin::new("moe.eirteam.shinespark.debug_settings"),
|
||||||
// Brings up GGRS (and with it `GgrsSchedule`), so it goes first.
|
// Brings up GGRS (and with it `GgrsSchedule`), so it goes first.
|
||||||
netcode::FighterNetcodePlugin::default(),
|
netcode::FighterNetcodePlugin::default(),
|
||||||
@@ -125,6 +128,8 @@ impl Plugin for GamePlugin {
|
|||||||
MatchCameraPlugin,
|
MatchCameraPlugin,
|
||||||
GameAssetPlugin,
|
GameAssetPlugin,
|
||||||
InGameUIPlugin,
|
InGameUIPlugin,
|
||||||
|
),
|
||||||
|
ShinesparkMaterialPlugin,
|
||||||
))
|
))
|
||||||
.add_plugins(menus::MenuPlugin)
|
.add_plugins(menus::MenuPlugin)
|
||||||
.add_loading_state(
|
.add_loading_state(
|
||||||
|
|||||||
+3
-10
@@ -8,9 +8,7 @@ use bevy_ggrs::prelude::Session;
|
|||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
AppState,
|
AppState, args::Args, fighter::{
|
||||||
args::Args,
|
|
||||||
fighter::{
|
|
||||||
FighterId, FighterRoster,
|
FighterId, FighterRoster,
|
||||||
animation::AnimKind,
|
animation::AnimKind,
|
||||||
attack::{AttackKind, FighterAttackScriptAssets},
|
attack::{AttackKind, FighterAttackScriptAssets},
|
||||||
@@ -18,15 +16,10 @@ use crate::{
|
|||||||
manifest::{FighterManifest, FighterManifestRegistry},
|
manifest::{FighterManifest, FighterManifestRegistry},
|
||||||
spawn_fighter,
|
spawn_fighter,
|
||||||
visual::FighterAnimations,
|
visual::FighterAnimations,
|
||||||
},
|
}, input::{LocalInputAssignments, LocalInputSource, MatchInputAssignments}, match_runtime::MatchState, netcode::{
|
||||||
input::{LocalInputAssignments, LocalInputSource, MatchInputAssignments},
|
|
||||||
match_runtime::MatchState,
|
|
||||||
netcode::{
|
|
||||||
GGRSCfg,
|
GGRSCfg,
|
||||||
session::{ConnectionStatus, SessionConfig, create_session},
|
session::{ConnectionStatus, SessionConfig, create_session},
|
||||||
},
|
}, scripting::FighterAttackScript, stage::{
|
||||||
scripting::FighterAttackScript,
|
|
||||||
stage::{
|
|
||||||
self,
|
self,
|
||||||
manifest::{StageId, StageManifest, StageManifestRegistry},
|
manifest::{StageId, StageManifest, StageManifestRegistry},
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -0,0 +1,77 @@
|
|||||||
|
use bevy::{gltf::GltfMaterialName, pbr::{ExtendedMaterial, MaterialExtension}, prelude::*, render::render_resource::AsBindGroup, shader::ShaderRef, world_serialization::WorldInstanceReady};
|
||||||
|
|
||||||
|
pub type FighterMaterial = ExtendedMaterial<StandardMaterial, FighterMaterialExtension>;
|
||||||
|
|
||||||
|
#[derive(Component)]
|
||||||
|
pub struct FighterMesh {
|
||||||
|
pub fighter: Entity
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Asset, AsBindGroup, Reflect, Debug, Clone, Default)]
|
||||||
|
pub struct FighterMaterialExtension {
|
||||||
|
#[uniform(100)]
|
||||||
|
status_color: LinearRgba,
|
||||||
|
#[uniform(100)]
|
||||||
|
status_color_intensity: f32,
|
||||||
|
}
|
||||||
|
|
||||||
|
const SHADER_ASSET_PATH: &str = "embedded://shinespark/shaders/fighter.wgsl";
|
||||||
|
|
||||||
|
impl FighterMaterialExtension {
|
||||||
|
pub fn new(status_color: Color) -> Self {
|
||||||
|
Self {
|
||||||
|
status_color: status_color.into(),
|
||||||
|
status_color_intensity: 0.0,
|
||||||
|
..default()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn update_status_color(&mut self, status_color: LinearRgba, intensity: f32) {
|
||||||
|
self.status_color = status_color;
|
||||||
|
self.status_color_intensity = intensity;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MaterialExtension for FighterMaterialExtension {
|
||||||
|
fn fragment_shader() -> ShaderRef {
|
||||||
|
SHADER_ASSET_PATH.into()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn deferred_fragment_shader() -> ShaderRef {
|
||||||
|
SHADER_ASSET_PATH.into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn bind_fighter_material(
|
||||||
|
scene_ready: On<WorldInstanceReady>,
|
||||||
|
mut commands: Commands,
|
||||||
|
children: Query<&Children>,
|
||||||
|
//color_override: Query<&ColorOverride>,
|
||||||
|
mesh_materials: Query<(Entity, &MeshMaterial3d<StandardMaterial>, &GltfMaterialName)>,
|
||||||
|
mut asset_materials: ResMut<Assets<FighterMaterial>>,
|
||||||
|
original_materials: Res<Assets<StandardMaterial>>,
|
||||||
|
) {
|
||||||
|
for descendant in children.iter_descendants(scene_ready.entity) {
|
||||||
|
let Ok((entity, id, material_name)) = mesh_materials.get(descendant) else {
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
|
||||||
|
dbg!(material_name);
|
||||||
|
|
||||||
|
if !material_name.starts_with("Fighter_") {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let Some(original_material) = original_materials.get(id.id()) else {
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
|
||||||
|
commands.entity(entity).insert((MeshMaterial3d(asset_materials.add(ExtendedMaterial {
|
||||||
|
base: StandardMaterial {
|
||||||
|
// can be used in forward or deferred mode
|
||||||
|
..original_material.clone()
|
||||||
|
},
|
||||||
|
extension: FighterMaterialExtension::new(bevy::color::palettes::css::BLUE.into())
|
||||||
|
})), FighterMesh { fighter: scene_ready.entity }));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
use bevy::{
|
||||||
|
asset::embedded_asset, prelude::*,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
pub mod fighter_material;
|
||||||
|
|
||||||
|
pub struct ShinesparkMaterialPlugin;
|
||||||
|
|
||||||
|
pub fn startup_test(asset_server: Res<AssetServer>) {
|
||||||
|
let test: Handle<Shader> = asset_server.load("embedded://shinespark/shaders/fighter.wgsl");
|
||||||
|
dbg!(test);
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Plugin for ShinesparkMaterialPlugin {
|
||||||
|
fn build(&self, app: &mut App) {
|
||||||
|
let omit_prefix = "";
|
||||||
|
embedded_asset!(app, omit_prefix, "shaders/fighter.wgsl");
|
||||||
|
app.add_systems(Startup, startup_test)
|
||||||
|
.add_observer(fighter_material::bind_fighter_material)
|
||||||
|
.add_plugins(MaterialPlugin::<fighter_material::FighterMaterial>::default());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,67 @@
|
|||||||
|
#import bevy_pbr::{
|
||||||
|
pbr_fragment::pbr_input_from_standard_material,
|
||||||
|
pbr_functions::alpha_discard,
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef PREPASS_PIPELINE
|
||||||
|
#import bevy_pbr::{
|
||||||
|
prepass_io::{VertexOutput, FragmentOutput},
|
||||||
|
pbr_deferred_functions::deferred_output,
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
#import bevy_pbr::{
|
||||||
|
forward_io::{VertexOutput, FragmentOutput},
|
||||||
|
pbr_functions::{apply_pbr_lighting, main_pass_post_lighting_processing},
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct FighterExtendedMaterial {
|
||||||
|
status_color: vec4<f32>,
|
||||||
|
status_color_intensity: f32,
|
||||||
|
#ifdef SIXTEEN_BYTE_ALIGNMENT
|
||||||
|
// Web examples WebGL2 support: structs must be 16 byte aligned.
|
||||||
|
_webgl2_padding_8b: u32,
|
||||||
|
_webgl2_padding_12b: u32,
|
||||||
|
_webgl2_padding_16b: u32,
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
@group(#{MATERIAL_BIND_GROUP}) @binding(100)
|
||||||
|
var<uniform> fighter_material: FighterExtendedMaterial;
|
||||||
|
|
||||||
|
@fragment
|
||||||
|
fn fragment(
|
||||||
|
in: VertexOutput,
|
||||||
|
@builtin(front_facing) is_front: bool,
|
||||||
|
) -> FragmentOutput {
|
||||||
|
// generate a PbrInput struct from the StandardMaterial bindings
|
||||||
|
var pbr_input = pbr_input_from_standard_material(in, is_front);
|
||||||
|
|
||||||
|
// we can optionally modify the input before lighting and alpha_discard is applied
|
||||||
|
//pbr_input.material.base_color.b = pbr_input.material.base_color.r;
|
||||||
|
|
||||||
|
// alpha discard
|
||||||
|
pbr_input.material.base_color = alpha_discard(pbr_input.material, pbr_input.material.base_color);
|
||||||
|
|
||||||
|
#ifdef PREPASS_PIPELINE
|
||||||
|
// in deferred mode we can't modify anything after that, as lighting is run in a separate fullscreen shader.
|
||||||
|
let out = deferred_output(in, pbr_input);
|
||||||
|
#else
|
||||||
|
var out: FragmentOutput;
|
||||||
|
// apply lighting
|
||||||
|
out.color = apply_pbr_lighting(pbr_input);
|
||||||
|
|
||||||
|
// we can optionally modify the lit color before post-processing is applied
|
||||||
|
var quantize_steps: i32 = 2;
|
||||||
|
out.color = vec4<f32>(vec4<u32>(out.color * f32(quantize_steps))) / f32(quantize_steps);
|
||||||
|
|
||||||
|
// apply in-shader post processing (fog, alpha-premultiply, and also tonemapping, debanding if the camera is non-hdr)
|
||||||
|
// note this does not include fullscreen postprocessing effects like bloom.
|
||||||
|
out.color = main_pass_post_lighting_processing(pbr_input, out.color);
|
||||||
|
|
||||||
|
out.color = mix(out.color, fighter_material.status_color, fighter_material.status_color_intensity * 0.5);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return out;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user