File size: 10,940 Bytes
48ca417 6337ab4 fecf169 48ca417 7cbc376 48ca417 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 |
# SEPARATED
---
## Introduction
SEPARATED is a 2D platformer game where you can talk to NPCs. Most of the game is not yet implemented.
## Table of Contents
- [SEPARATED](#separated)
- [Introduction](#introduction)
- [Table of Contents](#table-of-contents)
- [Player Inputs ∆](#player-inputs-)
- [Debugging Keyboard Shortcuts](#debugging-keyboard-shortcuts)
- [TODO](#todo)
- [`filesystem_watcher` and `asset_processor`](#filesystem_watcher-and-asset_processor)
- [Rust Things 🦀](#rust-things-)
- [Run in Wolf Mode (Debug)](#run-in-wolf-mode-debug)
- [Pedantic linting](#pedantic-linting)
- [Linting on all packages, treating warnings as errors](#linting-on-all-packages-treating-warnings-as-errors)
- [Format code](#format-code)
- [Test without default features](#test-without-default-features)
- [Test with only the `bevy_ui` features](#test-with-only-the-bevy_ui-features)
- [Test with all features enabled](#test-with-all-features-enabled)
- [Test with all features enabled on nightly](#test-with-all-features-enabled-on-nightly)
- [Generate documentation with all features enabled](#generate-documentation-with-all-features-enabled)
- [`seldom_state` + `input_manager` Example](#seldom_state--input_manager-example)
## Player Inputs ∆
| Input | KeyCode | Gamepad Button/Axis |
| :----------- | :-----------------------: | :-------------------------: |
| **Run** | **Shift** | Xbox: **X** PS5: **Square** |
| **Interact** | **E** | Xbox: **B** PS5: **◯** |
| **Attack1** | **Q** | Xbox/PS5: **L1** |
| **Jump** | **Space** | Xbox: **A** PS5: **╳** |
| **Move** | **WASD** + **Arrow Keys** | **Any Axis + D-Pad** |
## Debugging Keyboard Shortcuts
| Action | KeyCode |
| :----------------------------- | :-----: |
| Toggle Physics Wireframes | F9 |
| StateInspector (**GameState**) | F10 |
| WorldInspector | F11 |
## TODO
---
- **Use WyRand instead of `thread_rng()`**
```rust
fn print_random_value(mut rng: ResMut<GlobalEntropy<WyRand>>) {
println!("Random value: {}", rng.next_u32());
}
use bevy_rand::WyRand;
use bevy_rand::prelude::{GlobalEntropy, ForkableRng};
#[derive(Component)]
struct Source;
fn setup_source(mut commands: Commands, mut global: ResMut<GlobalEntropy<WyRand>>) {
commands
.spawn((
Source,
global.fork_rng(),
));
}
```
---
```rust
if ( jumping || falling ) {
if velocity.y.abs() < jumpHangTimeThreshold {
// Increase acceleration for this duration also.
// Reduce gravity.
}
}
// If the player is moving downwards..
if velocity.y < 0 {
// Increase gravity while falling.
gravityScale *= fallGravityMultiplier;
// Cap maximum fall speed, so when falling over large distances,
// we don't accelerate to insanely high speeds.
}
```
- **Localization**
- Tool to rename all neighbours to neighbors and other britishism! There is some in `bevy_ecs_ldtk` for example.
- ⚠️ ~~Started work by integrating `bevy_device_lang`. Requires a proper system that saves this value and allows the player to change it in the game menu, and also requires starting work on localization and saving and loading settings.~~
- Use `sys-lang` crate instead!
- **`bevy_asepritesheet` + `bevy_ecs_ldtk` integration.**
- **Patrol**
- Flip sprite when turning around!
- **Movement Improvements**
- Movement animations.
- Movement particle effects.
- Coyote (Grace) Time after falling off a ledge.
- Maybe needs a raycast in front of the player? Timer needs to start before falling off a ledge.
- **Jump Improvements**
- Jumping animations.
- Jumping particle effects.
- Wall Jumping
- ~~Prevent player movement for a short duration during the wall jump.~~ Reduce run force? Maybe a lerp between the wall jump speed and running speed?
- Air Time
- Jump Height
- Increase the player's jump height the longer the jump button is being held down.
- Clamp maximum falling speed.
- Coyote Time while jumping and pressing the jump button.
- There is already some check for being in the air we just need the input part I think.
- Bonus Air Time
- Peak Control
- Fast Fall
- Increase Player's falling speed after the peak of their jump by adjusting gravity.
- **Game Feel Improvements**
This is kinda broad but always iterate over every small mechanic towards more fun.
- **AI Stuff** ⚠️ Started work
- Pass player input(s) to ai-brain so it can use it for prediction.
- Basic Timer with Action Scheduling
- Thirst ✅
- Fatigue ⚠️
- **Pathfinding** ⚠️ Started work
- Use something to copy `dxil.dll` and `dxcompiler.dll` to Windows builds.
- **YarnSpinner**
- Begin YarnSpinner integration ✅
- YarnSpinner+LDTK integration ⚠️ Started work
- **UI**
- sickle_ui
- labels ✅
- keycap/gamepad button switching ⚠️
## `filesystem_watcher` and `asset_processor`
???
## Rust Things 🦀
---
### Run in Wolf Mode (Debug)
```pwsh
cargo run --profile awoo 2>&1 | Out-String -Stream | Where-Object { $_ -notmatch "ID3D12Device::CreateCommittedResource:" -and $_ -notmatch "Live Object at" -and $_ -notmatch "LineGizmo" -and $_ -notmatch "End of Frame" -and $_ -notmatch "prepare_windows" -and $_ -notmatch "cleanup" -and $_ -notmatch "SwapChain" -and $_ -notmatch "create_view" }
```
### Pedantic linting
```bash
cargo clippy -- -W clippy::pedantic
```
### Linting on all packages, treating warnings as errors
```bash
cargo clippy --workspace --all-targets --all-features -- -D warnings
```
This command runs the `clippy` linter on all packages in the workspace, for all targets and features. The `-D warnings` option treats any warnings as errors.
### Format code
```bash
cargo fmt --all
```
This command formats the code in every package using the default formatting rules provided by `rustfmt`.
### Test without default features
```bash
cargo test --no-default-features
```
This command runs tests in the package, but disables the default features.
### Test with only the `bevy_ui` features
```bash
cargo test --no-default-features --features="bevy_ui"
```
This command runs tests with only the `bevy_ui` feature enabled.
### Test with all features enabled
```bash
cargo test --all-features
```
This command runs tests with all features enabled.
### Test with all features enabled on nightly
```bash
cargo +nightly build --all-features
```
This command builds the package with all features enabled using the nightly version of the Rust compiler. This is typically used for generating documentation on docs.rs.
### Generate documentation with all features enabled
```bash
cargo +nightly doc --all-features --no-deps
```
This command generates documentation for the package with all features enabled, without including dependencies, using the nightly version of the Rust compiler.
## `seldom_state` + `input_manager` Example
```rust
// In this game, you can move with the left and right arrow keys, and jump with space.
// `input-manager` handles the input.
use bevy::prelude::*;
use leafwing_input_manager::{ axislike::VirtualAxis, prelude::* };
use seldom_state::prelude::*;
fn main() {
App::new()
.add_plugins((DefaultPlugins, InputManagerPlugin::<Action>::default(), StateMachinePlugin))
.add_systems(Startup, init)
.add_systems(Update, (walk, fall))
.run();
}
const JUMP_VELOCITY: f32 = 500.0;
fn init(mut commands: Commands, asset_server: Res<AssetServer>) {
commands.spawn(Camera2dBundle::default());
commands.spawn((
SpriteBundle {
transform: Transform::from_xyz(500.0, 0.0, 0.0),
texture: asset_server.load("player.png"),
..default()
},
// From `input-manager`
InputManagerBundle {
input_map: InputMap::default()
.insert(Action::Move, VirtualAxis::horizontal_arrow_keys())
.insert(Action::Move, SingleAxis::symmetric(GamepadAxisType::LeftStickX, 0.0))
.insert(Action::Jump, KeyCode::Space)
.insert(Action::Jump, GamepadButtonType::South)
.build(),
..default()
},
// This state machine achieves a very rigid movement system. Consider a state machine for
// whatever parts of your player controller that involve discrete states. Like the movement
// in Castlevania and Celeste, and the attacks in a fighting game.
StateMachine::default()
// Whenever the player presses jump, jump
.trans::<Grounded, _>(just_pressed(Action::Jump), Falling {
velocity: JUMP_VELOCITY,
})
// When the player hits the ground, idle
.trans::<Falling, _>(grounded, Grounded::Idle)
// When the player is grounded, set their movement direction
.trans_builder(value_unbounded(Action::Move), |_: &Grounded, value| {
Some(match value {
value if value > 0.5 => Grounded::Right,
value if value < -0.5 => Grounded::Left,
_ => Grounded::Idle,
})
}),
Grounded::Idle,
));
}
#[derive(Actionlike, Clone, Eq, Hash, PartialEq, Reflect)]
enum Action {
Move,
Jump,
}
fn grounded(In(entity): In<Entity>, fallings: Query<(&Transform, &Falling)>) -> bool {
let (transform, falling) = fallings.get(entity).unwrap();
transform.translation.y <= 0.0 && falling.velocity <= 0.0
}
#[derive(Clone, Copy, Component, Reflect)]
#[component(storage = "SparseSet")]
enum Grounded {
Left = -1,
Idle = 0,
Right = 1,
}
#[derive(Clone, Component, Reflect)]
#[component(storage = "SparseSet")]
struct Falling {
velocity: f32,
}
const PLAYER_SPEED: f32 = 200.0;
fn walk(mut groundeds: Query<(&mut Transform, &Grounded)>, time: Res<Time>) {
for (mut transform, grounded) in &mut groundeds {
transform.translation.x += (*grounded as i32 as f32) * time.delta_seconds() * PLAYER_SPEED;
}
}
const GRAVITY: f32 = -1000.0;
fn fall(mut fallings: Query<(&mut Transform, &mut Falling)>, time: Res<Time>) {
for (mut transform, mut falling) in &mut fallings {
let dt = time.delta_seconds();
falling.velocity += dt * GRAVITY;
transform.translation.y += dt * falling.velocity;
}
}
```
|