Merge branch 'enemies' into 'master'

Enemies

See merge request veloren/veloren!186

Former-commit-id: f920608508868119aad286cbe45599342dc1942b
This commit is contained in:
Forest Anderson 2019-05-28 19:08:02 +00:00
commit 2fc4e9a2f8
4 changed files with 82 additions and 3 deletions

View File

@ -8,6 +8,9 @@ pub enum Agent {
target: EcsEntity,
offset: Vec2<f32>,
},
Enemy {
target: Option<EcsEntity>,
},
}
impl Component for Agent {

View File

@ -1,25 +1,31 @@
// Library
use rand::Rng;
use specs::{Entities, Join, Read, ReadStorage, System, WriteStorage};
use vek::*;
// Crate
use crate::comp::{phys::Pos, Agent, Control, Jumping};
use crate::{
comp::{phys::Pos, Agent, Attacking, Control, Jumping},
state::Time,
};
// Basic ECS AI agent system
pub struct Sys;
impl<'a> System<'a> for Sys {
type SystemData = (
Read<'a, Time>,
Entities<'a>,
WriteStorage<'a, Agent>,
ReadStorage<'a, Pos>,
WriteStorage<'a, Control>,
WriteStorage<'a, Jumping>,
WriteStorage<'a, Attacking>,
);
fn run(
&mut self,
(entities, mut agents, positions, mut controls, mut jumpings): Self::SystemData,
(time, entities, mut agents, positions, mut controls, mut jumpings, mut attackings): Self::SystemData,
) {
for (entity, agent, pos, control) in
(&entities, &mut agents, &positions, &mut controls).join()
@ -65,6 +71,45 @@ impl<'a> System<'a> for Sys {
* 10.0;
}
}
Agent::Enemy { target } => {
let choose_new = match target.map(|tgt| positions.get(tgt)).flatten() {
Some(tgt_pos) => {
let dist = Vec2::<f32>::from(tgt_pos.0 - pos.0).magnitude();
if dist < 2.0 {
control.move_dir = Vec2::zero();
if rand::random::<f32>() < 0.2 {
attackings.insert(entity, Attacking::start());
}
false
} else if dist < 60.0 {
control.move_dir =
Vec2::<f32>::from(tgt_pos.0 - pos.0).normalized() * 0.96;
false
} else {
true
}
}
None => {
control.move_dir = Vec2::one();
true
}
};
if choose_new {
let entities = (&entities, &positions)
.join()
.filter(|(_, e_pos)| {
Vec2::<f32>::from(e_pos.0 - pos.0).magnitude() < 30.0
})
.map(|(e, _)| e)
.collect::<Vec<_>>();
*target = rand::thread_rng().choose(&entities).cloned();
}
}
}
}
}

View File

@ -93,6 +93,12 @@ lazy_static! {
"/wolf : Spawn a test wolf NPC",
handle_petwolf
),
ChatCommand::new(
"enemy",
"{}",
"/enemy : Spawn a test enemy NPC",
handle_enemy
),
ChatCommand::new(
"help", "", "/help: Display this message", handle_help)
];
@ -266,6 +272,30 @@ fn handle_petwolf(server: &mut Server, entity: EcsEntity, args: String, action:
.notify(entity, ServerMsg::Chat("You have no position!".to_owned())),
}
}
fn handle_enemy(server: &mut Server, entity: EcsEntity, args: String, action: &ChatCommand) {
match server
.state
.read_component_cloned::<comp::phys::Pos>(entity)
{
Some(mut pos) => {
pos.0.x += 1.0; // Temp fix TODO: Solve NaN issue with positions of pets
server
.create_npc(
pos,
"Tobermory".to_owned(),
comp::Body::Humanoid(comp::HumanoidBody::random()),
)
.with(comp::Agent::Enemy { target: None })
.build();
server
.clients
.notify(entity, ServerMsg::Chat("Spawned enemy!".to_owned()));
}
None => server
.clients
.notify(entity, ServerMsg::Chat("You have no position!".to_owned())),
}
}
fn handle_help(server: &mut Server, entity: EcsEntity, _args: String, _action: &ChatCommand) {
for cmd in CHAT_COMMANDS.iter() {
server

View File

@ -143,12 +143,13 @@ impl Server {
.ecs_mut()
.create_entity_synced()
.with(pos)
.with(comp::Control::default())
.with(comp::phys::Vel(Vec3::zero()))
.with(comp::phys::Dir(Vec3::unit_y()))
.with(comp::Control::default())
.with(comp::AnimationInfo::default())
.with(comp::Actor::Character { name, body })
.with(comp::Stats::default())
.with(comp::phys::ForceUpdate)
}
pub fn create_player_character(