Skip to content

Commit

Permalink
游戏音效
Browse files Browse the repository at this point in the history
增加游戏音效
  • Loading branch information
cloudhu committed Nov 12, 2024
1 parent 850f0e5 commit 2da40a1
Show file tree
Hide file tree
Showing 30 changed files with 208 additions and 44 deletions.
18 changes: 14 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,18 +1,21 @@
# skywalker2088
吸血鬼幸存者类型游戏,宇宙科幻废土,玩家驾驶飞船在宇宙中漫游,打怪收集装备升级飞船,研究科技,探索文明的遗迹。

______
# 0. 简介
- 游戏类型:吸血鬼幸存者like
- 游戏背景:玩家是一名太空巡警,在一次巡逻任务中发现了一艘海盗船,在追捕过程中意外地被一个黑洞吸入,进入到一个宇宙遗迹中,这个宇宙的编号是2088,
为了回到自己所在的宇宙空间,玩家需要驾驶太空飞船打怪、搜集装备、研究科技、探索文明的遗迹,在这个过程中玩家逐渐揭开这个宇宙文明毁灭的
真相,他需要尽快想办法回到自己所在的宇宙,将2088的案例带给宇宙科学家们,也许他们有办法避免自己宇宙的文明走向崩坏。

______
# 1. 玩法设计
1. 能量收集:太空飞船拥有将太空矿石转化成能量的转化内核,也能吸收转化太空怪物身上的能量晶核,这些能量为飞船提供源源不断的能源供给和升级所需的能量;
2. 飞船升级:机甲类怪物的内核和部件可以作为飞船改造升级的材料,升级改造的方向主要有引擎升级(更快的移动速度)、武器升级、防御升级……升级后的飞船可以应对更加强大的怪物;
3. 科技研究:通过对文明遗迹的探索,玩家可以收集科技点,解锁科技树,使太空飞船拥有更加强大的技能,比如激光射线、引力波探测器、无人机集群、超能粒子炮……
4. 文明遗迹:随着等级提升,玩家可以探索更加高级且危险的文明遗迹,从而获取更加强大的内核,更多的能量和科技点;
5. 美术风格:太空、科幻、废土、文明遗迹。

## 1.1 操作
1. 移动:鼠标左键为飞船导航(TODO:键盘方向键和手柄摇杆支持)
2. 暂停/恢复:键盘空格键(TODO:手柄Start按键)
Expand All @@ -36,17 +39,24 @@ ______
- [x] 暂停游戏
- [x] WASM支持
- [x] 敌人AI实现

- [x] 游戏音效

## 3.2 TODO List
- [ ] 支持手柄操作输入(我喜欢用手柄玩,没有手柄可以用键鼠)
- [ ] LDTK软件编辑关卡
- [ ] 支持手柄操作输入(我喜欢用手柄玩,没有手柄可以用键鼠,考虑使用[leafwing-input-manager](https://github.com/leafwing-studios/leafwing-input-manager)插件)
- [ ] 多语言支持(先弄中英文双语,考虑使用[fluent](https://github.com/kgv/bevy_fluent)插件)
- [ ] [LDTK](https://github.com/Trouv/bevy_ecs_ldtk)软件编辑关卡
- [ ] 关卡载入
- [ ] 关卡切换
- [ ] 玩家定点和敌人随机点出生
- [ ] 利用物理引擎进行碰撞检测
- [ ] 玩家出生、护盾、爆炸、水波等精灵动画
- [ ] 游戏UI
- [ ] 游戏音效
- [ ] 游戏存档、读档、自动保存
- [ ] 本地多人模式

# 4. 开发指南
游戏引擎:[Bevy](https://bevyengine.org/)
常用命令列表:
- Rust格式化: `cargo fmt`
- clippy提交检查:`cargo clippy --locked --workspace --all-targets --all-features -- --deny warnings`
- 本地开发运行:`cargo run`
Binary file added assets/audio/music/start_menu.ogg
Binary file not shown.
Binary file added assets/audio/sound_effects/big_explosion.ogg
Binary file not shown.
Binary file added assets/audio/sound_effects/bullet_explosion.ogg
Binary file not shown.
Binary file added assets/audio/sound_effects/bullet_hit_1.ogg
Binary file not shown.
Binary file added assets/audio/sound_effects/bullet_hit_2.ogg
Binary file not shown.
Binary file added assets/audio/sound_effects/game_over.ogg
Binary file not shown.
Binary file added assets/audio/sound_effects/game_pause.ogg
Binary file not shown.
Binary file added assets/audio/sound_effects/mode_switch.ogg
Binary file not shown.
Binary file added assets/audio/sound_effects/player_fire.ogg
Binary file not shown.
Binary file added assets/audio/sound_effects/powerup_appear.ogg
Binary file not shown.
Binary file added assets/audio/sound_effects/powerup_pick.ogg
Binary file not shown.
Binary file removed assets/audio/sound_effects/step1.ogg
Binary file not shown.
Binary file removed assets/audio/sound_effects/step2.ogg
Binary file not shown.
Binary file removed assets/audio/sound_effects/step3.ogg
Binary file not shown.
Binary file removed assets/audio/sound_effects/step4.ogg
Binary file not shown.
Binary file added assets/fonts/song_GB2312.ttf
Binary file not shown.
2 changes: 1 addition & 1 deletion src/enemy/drone.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ pub fn spawn_drone(commands: &mut Commands, fonts: &Res<Fonts>, position: Vec3)
ShipBundle {
glyph: Text2dBundle {
text: Text::from_section(
"c",
"",
TextStyle {
font: fonts.primary.clone(),
font_size: 18.0,
Expand Down
2 changes: 1 addition & 1 deletion src/enemy/drone_boss.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ pub fn spawn_drone_boss(commands: &mut Commands, fonts: &Res<Fonts>, position: V
ShipBundle {
glyph: Text2dBundle {
text: Text::from_section(
"C",
"",
TextStyle {
font: fonts.primary.clone(),
font_size: 32.0,
Expand Down
2 changes: 1 addition & 1 deletion src/enemy/fighter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ pub fn spawn_fighter(commands: &mut Commands, fonts: &Res<Fonts>, position: Vec3
ShipBundle {
glyph: Text2dBundle {
text: Text::from_section(
"w",
"W",
TextStyle {
font: fonts.primary.clone(),
font_size: 18.0,
Expand Down
2 changes: 1 addition & 1 deletion src/enemy/mothership.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ pub fn spawn_mothership(commands: &mut Commands, fonts: &Res<Fonts>, position: V
ShipBundle {
glyph: Text2dBundle {
text: Text::from_section(
"@",
"",
TextStyle {
font: fonts.primary.clone(),
font_size: 60.0,
Expand Down
14 changes: 13 additions & 1 deletion src/gameplay/gamelogic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use crate::gameplay::player::IsPlayer;
use crate::gameplay::GameState;
use crate::screens::AppState;
use crate::ship::bullet::{ExplosionRender, ShouldDespawn};
use crate::ship::platform::Fonts;
use crate::ship::platform::{play_sound_effects, Fonts, SoundAssets};
use crate::util::{Colour, Math, RenderLayer};
use crate::{AppSet, CameraShake, MainCamera};
use bevy::app::App;
Expand Down Expand Up @@ -184,6 +184,7 @@ pub fn combat_system(
mut commands: Commands,
time: Res<Time>,
mut query: Query<(&mut Health, Entity), Without<ShouldDespawn>>,
sound_assets: Res<SoundAssets>,
) {
for (mut health, entity) in &mut query {
if health.health <= 0 {
Expand All @@ -200,6 +201,8 @@ pub fn combat_system(
return;
}
health.shield += 1;
//播放增加护盾的音效
play_sound_effects(&mut commands, sound_assets.shield_up.clone());
}
}
}
Expand All @@ -216,16 +219,22 @@ pub fn take_damage_events(
Option<&mut HitFlash>,
)>,
mut camera: Query<&mut CameraShake>,
sound_assets: Res<SoundAssets>,
) {
for ev in take_damage_events.read() {
if let Ok((transform, mut health, is_player, hit_flash)) = query.get_mut(ev.entity) {
health.take_damage(ev.damage.amount);

//玩家受击时带有相机抖动效果
if is_player.is_some() {
if let Ok(mut shake) = camera.get_single_mut() {
shake.trauma = ev.damage.amount.clamp(0, 5) as f32;
}
//播放玩家被击中音效
play_sound_effects(&mut commands, sound_assets.bullet_hit_1.clone());
} else {
//播放敌人被击中音效
play_sound_effects(&mut commands, sound_assets.bullet_hit_2.clone());
// Floating Text
commands.spawn((
FloatingText::default(),
Expand Down Expand Up @@ -276,6 +285,7 @@ pub fn death_system(
>,
mut game_state: ResMut<NextState<GameState>>,
mut points: ResMut<Points>,
sound_assets: Res<SoundAssets>,
) {
for (entity, drops_loot, transform, is_player, explodes, worth_points) in &mut query {
commands.entity(entity).despawn_recursive();
Expand All @@ -294,6 +304,8 @@ pub fn death_system(
}

if is_player.is_some() {
//播放失败音效
play_sound_effects(&mut commands, sound_assets.lose.clone());
game_state.set(GameState::GameOver);
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/gameplay/player.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ fn spawn_player(In(config): In<SpawnPlayer>, mut commands: Commands, player_asse
ShipBundle {
glyph: Text2dBundle {
text: Text::from_section(
"V",
"",
TextStyle {
font: player_assets.primary.clone(),
font_size: 20.0,
Expand Down
13 changes: 13 additions & 0 deletions src/gameplay/selection.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
use crate::audio::SoundEffect;
use crate::gameplay::gamelogic::PlayerLevel;
use crate::gameplay::upgrade::{PlayerUpgrades, UpgradeEvent};
use crate::gameplay::GameState;
use crate::ship::platform::Fonts;
use crate::ship::turret::TurretClass;
use crate::theme::interaction::InteractionAssets;
use crate::util::Colour;
use bevy::prelude::*;
use rand::Rng;
Expand Down Expand Up @@ -126,20 +128,31 @@ fn menu(
(Changed<Interaction>, With<Button>, With<SelectionButton>),
>,
mut upgrade_event: EventWriter<UpgradeEvent>,
interaction_assets: Res<InteractionAssets>,
mut commands: Commands,
) {
for (interaction, mut color, button) in &mut interaction_query {
let mut source = interaction_assets.press.clone();
match *interaction {
Interaction::Pressed => {
upgrade_event.send(button.0);
next_state.set(GameState::Running);
}
Interaction::Hovered => {
*color = HOVERED_BUTTON.into();
source = interaction_assets.hover.clone();
}
Interaction::None => {
*color = NORMAL_BUTTON.into();
}
}
commands.spawn((
AudioBundle {
source,
settings: PlaybackSettings::DESPAWN,
},
SoundEffect,
));
}
}

Expand Down
16 changes: 4 additions & 12 deletions src/screens/gameplay.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
use crate::gameplay::level::spawn_level as spawn_level_command;
use crate::gameplay::loot::Points;
use crate::gameplay::GameState;
use crate::ship::platform::Fonts;
use crate::theme::interaction::OnPress;
use crate::{asset_tracking::LoadResource, audio::Music, screens::AppState, theme::prelude::*};
use bevy::input::common_conditions::input_just_pressed;
Expand Down Expand Up @@ -68,20 +67,13 @@ fn return_to_title_screen(mut next_screen: ResMut<NextState<AppState>>) {
next_screen.set(AppState::Title);
}

fn setup_game_over(mut commands: Commands, fonts: Res<Fonts>, points: Res<Points>) {
fn setup_game_over(mut commands: Commands, points: Res<Points>) {
commands
.ui_root()
.insert(StateScoped(GameState::GameOver))
.with_children(|parent| {
parent.spawn(TextBundle::from_section(
format!("{} points!", points.into_inner()),
TextStyle {
font: fonts.primary.clone(),
font_size: 30.0,
color: Color::srgb(0.9, 0.9, 0.9),
},
));
parent
.with_children(|children| {
children.label(format!("{} points!", points.into_inner()));
children
.button("Return To Title")
.observe(return_title_screen);
});
Expand Down
44 changes: 42 additions & 2 deletions src/screens/title.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,31 @@
//! The title screen that appears when the game starts.
use crate::asset_tracking::LoadResource;
use crate::audio::Music;
use crate::{screens::AppState, theme::prelude::*};
use bevy::prelude::*;

use crate::{screens::AppState, theme::prelude::*};
#[derive(Resource, Asset, Reflect, Clone)]
pub struct TitleMusic {
#[dependency]
handle: Handle<AudioSource>,
entity: Option<Entity>,
}

impl FromWorld for TitleMusic {
fn from_world(world: &mut World) -> Self {
let assets = world.resource::<AssetServer>();
Self {
handle: assets.load("audio/music/start_menu.ogg"),
entity: None,
}
}
}

pub(super) fn plugin(app: &mut App) {
app.load_resource::<TitleMusic>();
app.add_systems(OnEnter(AppState::Title), spawn_title_screen);
app.add_systems(OnEnter(AppState::Title), play_title_music);
app.add_systems(OnExit(AppState::Title), stop_title_music);
}

fn spawn_title_screen(mut commands: Commands) {
Expand Down Expand Up @@ -33,3 +53,23 @@ fn enter_credits_screen(_trigger: Trigger<OnPress>, mut next_screen: ResMut<Next
fn exit_app(_trigger: Trigger<OnPress>, mut app_exit: EventWriter<AppExit>) {
app_exit.send(AppExit::Success);
}

fn play_title_music(mut commands: Commands, mut music: ResMut<TitleMusic>) {
music.entity = Some(
commands
.spawn((
AudioBundle {
source: music.handle.clone(),
settings: PlaybackSettings::LOOP,
},
Music,
))
.id(),
);
}

fn stop_title_music(mut commands: Commands, mut music: ResMut<TitleMusic>) {
if let Some(entity) = music.entity.take() {
commands.entity(entity).despawn_recursive();
}
}
9 changes: 8 additions & 1 deletion src/ship/bullet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use crate::components::common::*;
use crate::gameplay::gamelogic::{game_not_paused, Damage, TakeDamageEvent};
use crate::gameplay::physics::Collider;
use crate::screens::AppState;
use crate::ship::platform::{play_sound_effects, SoundAssets};
use crate::AppSet;
use bevy::{prelude::*, utils::HashMap};
use bevy_prototype_lyon::prelude::{GeometryBuilder, Path, Stroke};
Expand Down Expand Up @@ -209,12 +210,16 @@ fn do_aoe_damage(
}

pub fn laser_render_system(
mut commands: Commands,
mut query: Query<(&Bullet, &mut Stroke), (With<LaserRender>, With<Bullet>, With<Stroke>)>,
sound_assets: Res<SoundAssets>,
) {
for (bullet, mut stroke) in &mut query {
stroke
.color
.set_alpha(bullet.time2live.fraction_remaining());
//播放laser音效
play_sound_effects(&mut commands, sound_assets.laser1.clone());
}
}

Expand All @@ -225,10 +230,12 @@ pub fn explosion_render_system(
(&mut ExplosionRender, &mut Path, Entity, &mut Stroke),
Without<ShouldDespawn>,
>,
sound_assets: Res<SoundAssets>,
) {
for (mut explosion, mut path, entity, mut stroke) in &mut query {
explosion.ttl.tick(time.delta());

//播放爆炸音效
play_sound_effects(&mut commands, sound_assets.big_explosion.clone());
let shape = shapes::Circle {
center: explosion.origin,
radius: explosion.radius * explosion.ttl.fraction(),
Expand Down
Loading

0 comments on commit 2da40a1

Please sign in to comment.