forked from amethyst/evoli
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add a basic implementation of the Topplegrass creature
Refer to issue amethyst#61 Topplegrass is explained here: https://community.amethyst.rs/t/evoli-creature-designs/814/10 Any entity with the Movement component intelligently avoids obstacles. However, not all entities that can move can steer; for example, Topplegrass is moved only by the wind. Therefore, add a new component tag AvoidObstaclesTag to all entities that are supposed to steer. Add new resource Wind. Implement debug keyboard input action to change wind direction. Load initial wind direction from a config file. In order to load from file, pass the assets directory path to the loading state. Add system that spawns new Topplegrass entities. Add system that deletes Topplegrass entities when they leave the world bounds.
- Loading branch information
Showing
19 changed files
with
324 additions
and
5 deletions.
There are no files selected for viewing
Git LFS file not shown
Git LFS file not shown
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -33,5 +33,8 @@ | |
"CameraMoveBackward": [ | ||
[Key(LShift), Key(Down)] | ||
], | ||
"ChangeWindDirection": [ | ||
[Key(W)] | ||
], | ||
}, | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -47,6 +47,7 @@ Prefab ( | |
), | ||
), | ||
intelligence_tag: (), | ||
avoid_obstacles_tag: (), | ||
perception: ( | ||
range: 3.0, | ||
), | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -47,6 +47,7 @@ Prefab ( | |
), | ||
), | ||
intelligence_tag: (), | ||
avoid_obstacles_tag: (), | ||
perception: ( | ||
range: 2.5, | ||
), | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
#![enable(implicit_some)] | ||
Prefab ( | ||
entities: [ | ||
( | ||
data: ( | ||
name: ( | ||
name: "Topplegrass" | ||
), | ||
gltf: File("assets/Topplegrass.gltf", ()), | ||
despawn_when_out_of_bounds_tag: (), | ||
), | ||
), | ||
], | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
( | ||
wind: [10.0, 0.0], | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,2 @@ | ||
pub mod spatial_grid; | ||
pub mod wind; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
use amethyst::core::math::Vector2; | ||
use serde::{Deserialize, Serialize}; | ||
|
||
/// Keeps track of the wind conditions in the world. | ||
/// Currently, wind is represented by a 2D vector. | ||
#[derive(Deserialize, Serialize)] | ||
#[serde(default)] | ||
#[serde(deny_unknown_fields)] | ||
pub struct Wind { | ||
pub wind: Vector2<f32>, | ||
} | ||
|
||
impl Wind { | ||
pub fn new(x: f32, y: f32) -> Wind { | ||
Wind { | ||
wind: Vector2::new(x, y), | ||
} | ||
} | ||
} | ||
|
||
impl Default for Wind { | ||
fn default() -> Self { | ||
Wind::new(0.0, 0.0) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,4 @@ | ||
pub mod out_of_bounds; | ||
pub mod perception; | ||
pub mod topplegrass; | ||
pub mod wind_control; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
use crate::resources::world_bounds::WorldBounds; | ||
use amethyst::{core::transform::components::Transform, ecs::*}; | ||
|
||
use crate::components::creatures::DespawnWhenOutOfBoundsTag; | ||
|
||
/// Deletes any entity tagged with DespawnWhenOutOfBoundsTag if they are detected to be outside | ||
/// the world bounds. | ||
#[derive(Default)] | ||
pub struct OutOfBoundsDespawnSystem; | ||
|
||
impl<'s> System<'s> for OutOfBoundsDespawnSystem { | ||
type SystemData = ( | ||
Entities<'s>, | ||
ReadStorage<'s, Transform>, | ||
ReadStorage<'s, DespawnWhenOutOfBoundsTag>, | ||
ReadExpect<'s, WorldBounds>, | ||
); | ||
|
||
fn run(&mut self, (entities, locals, tags, bounds): Self::SystemData) { | ||
for (entity, local, _) in (&*entities, &locals, &tags).join() { | ||
let pos = local.translation(); | ||
if pos.x > bounds.right | ||
|| pos.x < bounds.left | ||
|| pos.y > bounds.top | ||
|| pos.y < bounds.bottom | ||
{ | ||
let _ = entities.delete(entity); | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,107 @@ | ||
use crate::resources::world_bounds::WorldBounds; | ||
use amethyst::{ | ||
core::{ | ||
math::{Vector2, Vector3}, | ||
timing::Time, | ||
transform::components::Transform, | ||
}, | ||
ecs::*, | ||
shrev::EventChannel, | ||
}; | ||
|
||
use rand::{thread_rng, Rng}; | ||
use std::f32; | ||
|
||
use crate::{ | ||
components::creatures::Movement, resources::wind::Wind, systems::spawner::CreatureSpawnEvent, | ||
}; | ||
|
||
/// A new topplegrass entity is spawned periodically, SPAWN_INTERVAL is the period in seconds. | ||
const SPAWN_INTERVAL: f32 = 0.5; | ||
/// The standard scaling to apply to the entity. | ||
const TOPPLEGRASS_BASE_SCALE: f32 = 0.002; | ||
/// The maximum movement speed of Topplegrass. | ||
const MAX_MOVEMENT_SPEED: f32 = 1.75; | ||
|
||
/// Periodically spawns a Topplegrass entity. | ||
#[derive(Default)] | ||
pub struct TopplegrassSpawnSystem { | ||
secs_to_next_spawn: f32, | ||
} | ||
|
||
/// Periodically schedules a Topplegrass entity to be spawned in through a CreatureSpawnEvent. | ||
impl<'s> System<'s> for TopplegrassSpawnSystem { | ||
type SystemData = ( | ||
Entities<'s>, | ||
Read<'s, LazyUpdate>, | ||
Write<'s, EventChannel<CreatureSpawnEvent>>, | ||
Read<'s, Time>, | ||
Read<'s, WorldBounds>, | ||
Read<'s, Wind>, | ||
); | ||
|
||
fn run( | ||
&mut self, | ||
(entities, lazy_update, mut spawn_events, time, world_bounds, wind): Self::SystemData, | ||
) { | ||
if self.ready_to_spawn(time.delta_seconds()) { | ||
let mut transform = Transform::default(); | ||
transform.set_scale(Vector3::new( | ||
TOPPLEGRASS_BASE_SCALE, | ||
TOPPLEGRASS_BASE_SCALE, | ||
TOPPLEGRASS_BASE_SCALE, | ||
)); | ||
transform.append_translation(Self::gen_spawn_location(&wind, &world_bounds)); | ||
let movement = Movement { | ||
velocity: Vector3::new(wind.wind.x, wind.wind.y, 0.0), | ||
max_movement_speed: MAX_MOVEMENT_SPEED, | ||
}; | ||
let entity = lazy_update | ||
.create_entity(&entities) | ||
.with(transform) | ||
.with(movement) | ||
.build(); | ||
spawn_events.single_write(CreatureSpawnEvent { | ||
creature_type: "Topplegrass".to_string(), | ||
entity, | ||
}); | ||
} | ||
} | ||
} | ||
|
||
impl TopplegrassSpawnSystem { | ||
/// Checks the time elapsed since the last spawn. If the system is ready to spawn another | ||
/// entity, the timer will be reset and this function will return true. | ||
fn ready_to_spawn(&mut self, delta_seconds: f32) -> bool { | ||
self.secs_to_next_spawn -= delta_seconds; | ||
if self.secs_to_next_spawn.is_sign_negative() { | ||
self.secs_to_next_spawn = SPAWN_INTERVAL; | ||
true | ||
} else { | ||
false | ||
} | ||
} | ||
|
||
/// Returns a Vector3<f32> representing the position in which to spawn the next entity. | ||
/// Entities will be spawned at a random point on one of the four world borders; specifically, | ||
/// the one that the wind direction is facing away from. In other words: upwind from the | ||
/// center of the world. | ||
fn gen_spawn_location(wind: &Wind, bounds: &WorldBounds) -> Vector3<f32> { | ||
let mut rng = thread_rng(); | ||
if Self::wind_towards_direction(wind.wind, Vector2::new(1.0, 0.0)) { | ||
Vector3::new(bounds.left, rng.gen_range(bounds.bottom, bounds.top), 0.5) | ||
} else if Self::wind_towards_direction(wind.wind, Vector2::new(0.0, 1.0)) { | ||
Vector3::new(rng.gen_range(bounds.left, bounds.right), bounds.bottom, 0.5) | ||
} else if Self::wind_towards_direction(wind.wind, Vector2::new(-1.0, 0.0)) { | ||
Vector3::new(bounds.right, rng.gen_range(bounds.bottom, bounds.top), 0.5) | ||
} else { | ||
Vector3::new(rng.gen_range(bounds.left, bounds.right), bounds.top, 0.5) | ||
} | ||
} | ||
|
||
/// Returns true if and only if the given wind vector is roughly in line with the given | ||
/// cardinal_direction vector, within a margin of a 1/4 PI RAD. | ||
fn wind_towards_direction(wind: Vector2<f32>, cardinal_direction: Vector2<f32>) -> bool { | ||
wind.angle(&cardinal_direction).abs() < f32::consts::FRAC_PI_4 | ||
} | ||
} |
Oops, something went wrong.