Comments (13)
This is something I've done a little bit of work with in Bevy.
What kind of format do you think we want to use for prefabs and levels?
I tend to lean away from JSON for anything that we expect humans to write. It's quite annoying to hand-type with the rules such as no-trailing commas, and all of the extra quotes around keys.
RON seems popular in the Rust ecosystem, but I still seem to prefer YAML over RON when humans are typing it because it's easier to type out, more common as far as editor support and general ecosystem is concerned.
The biggest reason I switch to using RON for anything in a given scenario is when I need to store a HashMap that has keys that are non-strings. RON is the only format out of it, YAML, and JSON that supports non-string keys with Serde out-of-the-box.
So I would recommend YAML or RON, but YAML is my slightly preferred option.
Also, it's easy to switch later, and a conversion from one format to another can be fully automated with a simple Rust script, so it's not a big deal if we want to try one and see how it feels first.
from punchy.
I dont think we will have a scene editor at least for awhile so we will be hand typing for sure. It seems reasonable to use RON or YAML.
Currently we use a HashMap with enum variants as keys to map animation states to frames of spritesheets, which might be useful to store in a scene but I think its not super likely. We will probably have a finite number of enemies/animations which need mapped that way it will probably be better to have that defined elsewhere.
from punchy.
Yeah, this is similar to what I need to do for my own game right now, so I figure I'll help you out while getting free code review for code that's going to be put into my game in a similar way. 😄
I think enemies will look something like this in YAML:
name: Sharky
kind: enemy
stats:
life: 3
# etc...
spritesheet:
image: ../sprites/sharky.png
animation_fps: 0.12
animations:
idle: [0, 3]
running: [8, 11]
knocked_right: [40, 46]
knocked_left: [40, 46]
dying: [71, 76]
attacking: [85, 90]
I've already gotten parallax backgrounds loading from an asset.
I'm going to try strategy of having:
- A main game metadata YAML that lists the levels and the sets the player, until we have UI, a default level that will start immediately
- Level YAML files that will have the parallax background info, and the list of enemies and where they spawn
- Fighter YAML files such as "Sharky" above, that will define all of the stats for the fighters
It shouldn't take too long to set up and get a feel for whether it works well.
from punchy.
Yeah, I ended up doing that too because I needed a loading state. I'm fine resolving conflicts and fitting whatever I end up with into what you've got, but here's what I've got so far so you get an idea of what I'll probably need:
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
enum GameState {
LoadingGame,
LoadingLevel,
PlayingLevel,
}
fn main() {
let mut app = App::new();
app.insert_resource(ClearColor(Color::rgb(0.494, 0.658, 0.650)))
.insert_resource(WindowDescriptor {
title: "Fish Fight Punchy".to_string(),
scale_factor_override: Some(1.0),
..Default::default()
})
.add_event::<ThrowItemEvent>()
.add_plugins(DefaultPlugins)
.add_plugin(RapierPhysicsPlugin::<NoUserData>::pixels_per_meter(100.0))
.add_plugin(RapierDebugRenderPlugin::default())
.add_plugin(AttackPlugin)
.add_plugin(AnimationPlugin)
.add_plugin(StatePlugin)
.add_plugin(ParallaxPlugin)
.insert_resource(ParallaxResource::default())
.add_loopless_state(GameState::LoadingGame)
.add_startup_system(setup)
.add_system(load_game.run_in_state(GameState::LoadingGame))
.add_system(load_level.run_in_state(GameState::LoadingLevel))
.add_system_set(
ConditionSet::new()
.run_in_state(GameState::PlayingLevel)
.with_system(spawn_throwable_items)
.with_system(player_controller)
.with_system(player_attack)
.with_system(helper_camera_controller)
.with_system(y_sort)
.with_system(player_attack_enemy_collision)
.with_system(player_enemy_collision)
.with_system(kill_entities)
.with_system(knockback_system)
.with_system(move_direction_system)
.with_system(move_in_arc_system)
.with_system(throw_item_system)
.with_system(item_attacks_enemy_collision)
.with_system(rotate_system)
.into(),
)
.add_system_to_stage(
CoreStage::PostUpdate,
camera_follow_player.run_in_state(GameState::PlayingLevel),
)
.add_system_to_stage(CoreStage::Last, despawn_entities);
assets::register(&mut app);
// Insert the game handle
let asset_server = app.world.get_resource::<AssetServer>().unwrap();
let game_path = std::env::args()
.nth(1)
.unwrap_or("default.game.yaml".into());
debug!(%game_path, "Starting game");
let handle: Handle<Game> = asset_server.load(&game_path);
app.world.insert_resource(handle);
app.run();
}
fn load_game(
mut commands: Commands,
game_handle: Res<Handle<Game>>,
mut assets: ResMut<Assets<Game>>,
) {
if let Some(game) = assets.remove(game_handle.clone_weak()) {
debug!("Loaded game");
commands.insert_resource(game.start_level.clone());
commands.insert_resource(game);
commands.insert_resource(NextState(GameState::LoadingLevel));
} else {
trace!("Awaiting game load")
}
}
fn load_level(
level_handle: Res<Handle<Level>>,
mut commands: Commands,
mut assets: ResMut<Assets<Level>>,
mut parallax: ResMut<ParallaxResource>,
mut texture_atlases: ResMut<Assets<TextureAtlas>>,
asset_server: Res<AssetServer>,
windows: Res<Windows>,
) {
if let Some(level) = assets.remove(level_handle.clone_weak()) {
debug!("Loaded level");
let window = windows.primary();
*parallax = level.meta.parallax_background.get_resource();
parallax.despawn_layers(&mut commands);
parallax.window_size = Vec2::new(window.width(), window.height());
parallax.create_layers(&mut commands, &asset_server, &mut texture_atlases);
// TODO: Spawn players ( I'm in the middle of this )
commands.insert_resource(level);
commands.insert_resource(NextState(GameState::PlayingLevel));
} else {
trace!("Awaiting level load");
}
}
Because we are nesting the asset loading, such that game -> level -> players
, the cleanest way to do it so far has been to have a LoadingGame, LoadingLevel, and PlayingLevel
states, but you can throw whatever you need in there for the menu and that will probably happen before loading level.
from punchy.
Btw, we should also have some sort of spacial data. Something like the size of the scene so we can limit the camera and player movement.
from punchy.
Got the PR up: #22.
I also rebased on your changes @odecay so we're merged up all nice and clean. :)
from punchy.
Sounds good, you want to assign this to me, then?
from punchy.
Sure if you have bandwidth to tackle this. Do you have any thoughts about how to define enemy types and their associated resources?
from punchy.
Yeah that seems like a good approach 👍
from punchy.
@zicklag I started implementing gamestates/menu which might effect this, do you think we will want a loading state?
from punchy.
@odecay, do we want to allow hot-reloading fighter Stats
? What that means is that instead of storing a Stats
component on the fighter entities, we store a Handle<Stats>
, that can be updated at any time and hot-reloaded.
from punchy.
OK, just got all of the scene and player information spawning through YAML assets. Now I've just got to port the rest of the enemies to their YAML forms, spawn them, and open up a PR!
from punchy.
Closed by #22
from punchy.
Related Issues (20)
- New Feature: Redirect to main menu or show next steps after beating all AI on screen HOT 1
- New Feature: Ability to switch keyboard action buttons
- Implement new positional system
- Create Scripted In-Game Item
- Hit flash on damage application HOT 2
- Add ranged attack as Slinger fighter default attack.
- Implement boss bomb throwing HOT 3
- Audio system panic on using Color Picker widget in egui_inspector debugtools
- Add Big Bass bomb throwing proper AI
- Make player able to grab Big Bass bomb while fusing
- Add unique sound effects for chain attacks
- Poor performance in Firefox HOT 1
- Update to Bevy 0.9
- Document current Items for wiki HOT 1
- Adjust Slinger ranged attack to remove Knockback HOT 1
- Add a throw strength to fighters
- Health item broken HOT 1
- Boss bomb throw always has another static bomb sprite behind the animated explosion HOT 1
- Entity despawn warning, per run dependent
- Hoping Punchy Adapts to Bevy 0.13New Feature HOT 1
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from punchy.