Added basic pets

Former-commit-id: 1ef17505ecb11acb82541349343989128b78630f
This commit is contained in:
Joshua Barretto 2019-05-11 13:43:19 +01:00
parent 5d8a03896a
commit 266101c90d
7 changed files with 90 additions and 21 deletions

View File

@ -1,16 +1,20 @@
use specs::{Component, VecStorage};
use specs::{Component, VecStorage, Entity as EcsEntity};
use vek::*;
#[derive(Copy, Clone, Debug, Serialize, Deserialize)]
#[derive(Copy, Clone, Debug)]
pub enum Agent {
Wanderer(Vec2<f32>),
Pet {
target: EcsEntity,
offset: Vec2<f32>,
},
}
impl Component for Agent {
type Storage = VecStorage<Self>;
}
#[derive(Copy, Clone, Debug, Serialize, Deserialize)]
#[derive(Copy, Clone, Debug)]
pub struct Control {
pub move_dir: Vec2<f32>,
pub jumping: bool,

View File

@ -116,6 +116,16 @@ pub struct AnimationHistory {
pub time: f64,
}
impl AnimationHistory {
pub fn new(animation: Animation) -> Self {
Self {
last: None,
current: animation,
time: 0.0,
}
}
}
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
pub enum Animation {
Idle,

View File

@ -15,13 +15,13 @@ impl<'a> System<'a> for Sys {
WriteStorage<'a, Control>,
);
fn run(&mut self, (mut agents, pos, mut controls): Self::SystemData) {
for (mut agent, pos, mut control) in (&mut agents, &pos, &mut controls).join() {
fn run(&mut self, (mut agents, positions, mut controls): Self::SystemData) {
for (mut agent, pos, mut control) in (&mut agents, &positions, &mut controls).join() {
match agent {
Agent::Wanderer(bearing) => {
*bearing += Vec2::new(
rand::random::<f32>().fract() - 0.5,
rand::random::<f32>().fract() - 0.5,
rand::random::<f32>() - 0.5,
rand::random::<f32>() - 0.5,
) * 0.1
- *bearing * 0.01
- pos.0 * 0.0002;
@ -29,7 +29,37 @@ impl<'a> System<'a> for Sys {
if bearing.magnitude_squared() != 0.0 {
control.move_dir = bearing.normalized();
}
}
},
Agent::Pet { target, offset } => {
// Run towards target
match positions.get(*target) {
Some(tgt_pos) => {
let tgt_pos = tgt_pos.0 + *offset;
// Jump with target
control.jumping = tgt_pos.z > pos.0.z + 1.0;
// Move towards the target
let dist = tgt_pos.distance(pos.0);
control.move_dir = if dist > 5.0 {
Vec2::from(tgt_pos - pos.0).normalized()
} else if dist < 1.5 && pos.0 != tgt_pos {
Vec2::from(pos.0 - tgt_pos).normalized()
} else {
Vec2::zero()
};
},
_ => control.move_dir = Vec2::zero(),
}
// Change offset occasionally
if rand::random::<f32>() < 0.003 {
*offset = Vec2::new(
rand::random::<f32>() - 0.5,
rand::random::<f32>() - 0.5,
) * 10.0;
}
},
}
}
}

View File

@ -4,7 +4,11 @@
use crate::Server;
use common::{comp, msg::ServerMsg};
use specs::{join::Join, Entity as EcsEntity};
use specs::{
Join,
Entity as EcsEntity,
Builder,
};
use vek::*;
use lazy_static::lazy_static;
@ -72,9 +76,15 @@ lazy_static! {
ChatCommand::new(
"tp",
"{}",
"/tp <alias>: Teleport to another player",
"/tp <alias> : Teleport to another player",
handle_tp
),
ChatCommand::new(
"pet",
"{}",
"/pet : Spawn a test pet NPC",
handle_pet
),
ChatCommand::new("help", "", "/help: Display this message", handle_help)
];
}
@ -179,6 +189,23 @@ fn handle_tp(server: &mut Server, entity: EcsEntity, args: String, action: &Chat
}
}
fn handle_pet(server: &mut Server, entity: EcsEntity, args: String, action: &ChatCommand) {
match server
.state
.read_component_cloned::<comp::phys::Pos>(entity)
{
Some(pos) => {
server.create_npc(comp::Character::random())
.with(comp::Control::default())
.with(comp::Agent::Pet{ target: entity, offset: Vec2::zero() })
.with(pos)
.build();
server.clients.notify(entity, ServerMsg::Chat("Pet spawned!".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

@ -82,8 +82,8 @@ impl Server {
for i in 0..4 {
this.create_npc(comp::Character::random())
.with(comp::Agent::Wanderer(Vec2::zero()))
.with(comp::Control::default())
.with(comp::Agent::Wanderer(Vec2::zero()))
.build();
}
@ -121,6 +121,7 @@ impl Server {
.with(comp::phys::Pos(Vec3::new(0.0, 0.0, 64.0)))
.with(comp::phys::Vel(Vec3::zero()))
.with(comp::phys::Dir(Vec3::unit_y()))
.with(comp::AnimationHistory::new(Animation::Idle))
.with(character)
}
@ -140,11 +141,7 @@ impl Server {
// Set initial animation
state.write_component(
entity,
comp::AnimationHistory {
last: None,
current: Animation::Idle,
time: 0.0,
},
comp::AnimationHistory::new(Animation::Idle),
);
// Tell the client his request was successful
@ -272,7 +269,7 @@ impl Server {
// (All components Sphynx tracks)
client.notify(ServerMsg::InitialSync {
ecs_state: self.state.ecs().gen_state_package(),
entity_uid: self.state.ecs().uid_from_entity(entity).unwrap().into(),
entity_uid: self.state.ecs().uid_from_entity(entity).unwrap().into(), // Can't fail
});
self.clients.add(entity, client);

View File

@ -136,7 +136,7 @@ Voxygen has logged information about the problem (including this message) to the
The information below is intended for developers and testers.
Panic Payload: {:?}
PanicInfo: {:?}", settings_clone.log.file, reason, panic_info);
PanicInfo: {}", settings_clone.log.file, reason, panic_info);
log::error!("VOXYGEN HAS PANICKED\n\n{}", msg);

View File

@ -245,9 +245,10 @@ impl FigureCache {
for (entity, &character) in (&ecs.entities(), &ecs.read_storage::<comp::Character>()).join()
{
let model = Self::get_or_create_model(models, renderer, tick, character);
let state = self.states.get(&entity).unwrap();
renderer.render_figure(&model.0, globals, &state.locals, &state.bone_consts);
if let Some(state) = self.states.get(&entity) {
let model = Self::get_or_create_model(models, renderer, tick, character);
renderer.render_figure(&model.0, globals, &state.locals, &state.bone_consts);
}
}
}
}