Entity attack
- implemented - changed param of a fn of trait Behavior
This commit is contained in:
@@ -104,7 +104,7 @@ impl Default for Config {
|
|||||||
floors: 0..255,
|
floors: 0..255,
|
||||||
name: "Basic enemy".to_string(),
|
name: "Basic enemy".to_string(),
|
||||||
behavior: Box::new(RandomMovement::new()),
|
behavior: Box::new(RandomMovement::new()),
|
||||||
health: 30,
|
health: 10,
|
||||||
attack: 10,
|
attack: 10,
|
||||||
priority: 1,
|
priority: 1,
|
||||||
}],
|
}],
|
||||||
|
|||||||
@@ -3,8 +3,7 @@ use super::{
|
|||||||
floor::{Floor, FloorView},
|
floor::{Floor, FloorView},
|
||||||
};
|
};
|
||||||
use dyn_clone::{clone_trait_object, DynClone};
|
use dyn_clone::{clone_trait_object, DynClone};
|
||||||
use rand::{Rng, SeedableRng};
|
use rand::Rng;
|
||||||
use rand_pcg::Pcg32;
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::{collections::VecDeque, fmt::Display, mem};
|
use std::{collections::VecDeque, fmt::Display, mem};
|
||||||
|
|
||||||
@@ -57,7 +56,7 @@ impl Direction {
|
|||||||
/// Restituisce una direzione casuale a partire da un generatore.\
|
/// Restituisce una direzione casuale a partire da un generatore.\
|
||||||
/// La direzione viene generata con una distribuzione uniforme, ovvero non
|
/// La direzione viene generata con una distribuzione uniforme, ovvero non
|
||||||
/// c'è una direzione preferita o con più probabilità.
|
/// c'è una direzione preferita o con più probabilità.
|
||||||
pub fn random(rng: &mut Pcg32) -> Self {
|
pub fn random(rng: &mut impl Rng) -> Self {
|
||||||
match rng.gen_range(0..5) {
|
match rng.gen_range(0..5) {
|
||||||
0 => Direction::Up,
|
0 => Direction::Up,
|
||||||
1 => Direction::Down,
|
1 => Direction::Down,
|
||||||
@@ -130,7 +129,7 @@ impl Entity {
|
|||||||
/// Permette di vedere tutti gli effetti che in questo momento sono applicati all'entità.\
|
/// Permette di vedere tutti gli effetti che in questo momento sono applicati all'entità.\
|
||||||
/// Gli effetti qui elencati sono in uno stato di attesa prima di essere effettivamente
|
/// Gli effetti qui elencati sono in uno stato di attesa prima di essere effettivamente
|
||||||
/// applicati tremite la funzione update.
|
/// applicati tremite la funzione update.
|
||||||
pub fn get_effects(& self) -> impl Iterator<Item = &Box<dyn Effect>> {
|
pub fn get_effects(&self) -> impl Iterator<Item = &Box<dyn Effect>> {
|
||||||
self.effects.iter()
|
self.effects.iter()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -220,8 +219,12 @@ impl Entity {
|
|||||||
}
|
}
|
||||||
/// prende una decisione e applica l'azione da fare
|
/// prende una decisione e applica l'azione da fare
|
||||||
/// L'azione compiuta viene restituita, altrimenti None
|
/// L'azione compiuta viene restituita, altrimenti None
|
||||||
fn compute_action(&mut self, behavior: &mut Box<dyn Behavior>, floor: &mut Floor) -> Option<Action> {
|
fn compute_action(
|
||||||
let action = behavior.get_next_action()?;
|
&mut self,
|
||||||
|
behavior: &mut Box<dyn Behavior>,
|
||||||
|
floor: &mut Floor,
|
||||||
|
) -> Option<Action> {
|
||||||
|
let action = behavior.get_next_action(self)?;
|
||||||
let action = match self.buffer {
|
let action = match self.buffer {
|
||||||
Action::DoNothing => action,
|
Action::DoNothing => action,
|
||||||
_ => mem::replace(&mut self.buffer, Action::DoNothing),
|
_ => mem::replace(&mut self.buffer, Action::DoNothing),
|
||||||
@@ -255,7 +258,7 @@ impl Display for Entity {
|
|||||||
#[derive(Clone, Default, Debug, Deserialize, Serialize)]
|
#[derive(Clone, Default, Debug, Deserialize, Serialize)]
|
||||||
pub enum Action {
|
pub enum Action {
|
||||||
Move(Direction),
|
Move(Direction),
|
||||||
//Attack(Direction),
|
Attack(Direction),
|
||||||
#[default]
|
#[default]
|
||||||
DoNothing,
|
DoNothing,
|
||||||
}
|
}
|
||||||
@@ -277,6 +280,14 @@ impl Action {
|
|||||||
let cell = floor.get_cell_mut(&entity.position);
|
let cell = floor.get_cell_mut(&entity.position);
|
||||||
cell.entity_over(entity);
|
cell.entity_over(entity);
|
||||||
}
|
}
|
||||||
|
Action::Attack(direction) => {
|
||||||
|
let mut pos = entity.position;
|
||||||
|
direction.move_from(&mut pos);
|
||||||
|
|
||||||
|
if let Some(other) = floor.get_entity_at(&pos) {
|
||||||
|
other.apply_damage(entity.attack);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -308,14 +319,14 @@ pub trait Behavior: DynClone + core::fmt::Debug {
|
|||||||
/// in modo che possa eventualmente fare ulteriori calcoli.\
|
/// in modo che possa eventualmente fare ulteriori calcoli.\
|
||||||
/// Non è necessario implementarla.
|
/// Non è necessario implementarla.
|
||||||
fn on_death(&mut self, _view: FloorView) {}
|
fn on_death(&mut self, _view: FloorView) {}
|
||||||
/// Genera una azione che poi verrà usata per l'entità associata.\
|
/// Genera un'azione che poi verrà usata per l'entità associata.\
|
||||||
/// L'azione può essere generata in qualunque modo: casuale, sempre la stessa,
|
/// L'azione può essere generata in qualunque modo: casuale, sempre la stessa,
|
||||||
/// tramite interazione con console, o tramite una connessione ad un client.\
|
/// tramite interazione con console, o tramite una connessione ad un client.\
|
||||||
/// \
|
/// \
|
||||||
/// Nel caso in cui venga restituito None come valore, l'entità verrà rimossa dal gioco.\
|
/// Nel caso in cui venga restituito None come valore, l'entità verrà rimossa dal gioco.\
|
||||||
/// Questo viene fatto in modo che si possa avere una possibilità di rimozione del giocatore,
|
/// Questo viene fatto in modo che si possa avere una possibilità di rimozione del giocatore,
|
||||||
/// ma anche una possibilità che alcune entità rare possano sparire.
|
/// ma anche una possibilità che alcune entità rare possano sparire.
|
||||||
fn get_next_action(&mut self) -> Option<Action>;
|
fn get_next_action(&mut self, entity: &Entity) -> Option<Action>;
|
||||||
}
|
}
|
||||||
clone_trait_object!(Behavior);
|
clone_trait_object!(Behavior);
|
||||||
|
|
||||||
@@ -325,7 +336,7 @@ clone_trait_object!(Behavior);
|
|||||||
pub struct Immovable;
|
pub struct Immovable;
|
||||||
#[typetag::serde]
|
#[typetag::serde]
|
||||||
impl Behavior for Immovable {
|
impl Behavior for Immovable {
|
||||||
fn get_next_action(&mut self) -> Option<Action> {
|
fn get_next_action(&mut self, _entity: &Entity) -> Option<Action> {
|
||||||
Some(Action::DoNothing)
|
Some(Action::DoNothing)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -335,27 +346,26 @@ impl Behavior for Immovable {
|
|||||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||||
pub struct RandomMovement {
|
pub struct RandomMovement {
|
||||||
action: Action,
|
action: Action,
|
||||||
rng: Pcg32,
|
|
||||||
}
|
}
|
||||||
impl RandomMovement {
|
impl RandomMovement {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
let action = Action::default();
|
||||||
action: Action::DoNothing,
|
Self { action }
|
||||||
rng: Pcg32::seed_from_u64(0),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[typetag::serde]
|
#[typetag::serde]
|
||||||
impl Behavior for RandomMovement {
|
impl Behavior for RandomMovement {
|
||||||
fn update(&mut self, view: FloorView) {
|
fn update(&mut self, view: FloorView) {
|
||||||
let dir = Direction::random(&mut self.rng);
|
|
||||||
let mut pos = view.entity.position.clone();
|
let mut pos = view.entity.position.clone();
|
||||||
|
let mut rng = rand::rngs::ThreadRng::default();
|
||||||
|
let dir = Direction::random(&mut rng);
|
||||||
|
|
||||||
dir.move_from(&mut pos);
|
dir.move_from(&mut pos);
|
||||||
if let Cell::Empty = view.floor.get_cell(&pos) {
|
if let Cell::Empty = view.floor.get_cell(&pos) {
|
||||||
self.action = Action::Move(dir);
|
self.action = Action::Move(dir);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn get_next_action(&mut self) -> Option<Action> {
|
fn get_next_action(&mut self, _entity: &Entity) -> Option<Action> {
|
||||||
Some(mem::take(&mut self.action))
|
Some(mem::take(&mut self.action))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -105,6 +105,25 @@ impl Floor {
|
|||||||
.expect("Entrance of the floor should be inside the grid!")
|
.expect("Entrance of the floor should be inside the grid!")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Permette di prendere l'entità o il giocatore che si trova alla posizione indicata.\
|
||||||
|
/// Nel caso in cui non ci sia nessuna entità nella posizione, allora
|
||||||
|
/// verrà ritornato None.
|
||||||
|
pub fn get_entity_at(&mut self, position: &Position) -> Option<&mut Entity> {
|
||||||
|
let entity = self
|
||||||
|
.entities
|
||||||
|
.iter_mut()
|
||||||
|
.filter(|e| e.position == *position)
|
||||||
|
.next();
|
||||||
|
if let None = entity {
|
||||||
|
self.players
|
||||||
|
.iter_mut()
|
||||||
|
.filter(|e| e.position == *position)
|
||||||
|
.next()
|
||||||
|
} else {
|
||||||
|
entity
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Ritorna un eventuale giocatore che si trova sopra la cella di uscita del piano.\
|
/// Ritorna un eventuale giocatore che si trova sopra la cella di uscita del piano.\
|
||||||
/// Nel caso in cui non ci siano giocatori sopra, questo metodo ritornerà None.
|
/// Nel caso in cui non ci siano giocatori sopra, questo metodo ritornerà None.
|
||||||
pub fn get_player_at_exit(&mut self) -> Option<Entity> {
|
pub fn get_player_at_exit(&mut self) -> Option<Entity> {
|
||||||
@@ -132,7 +151,12 @@ impl Floor {
|
|||||||
pub fn update_players(&mut self) {
|
pub fn update_players(&mut self) {
|
||||||
for _ in 0..self.players.len() {
|
for _ in 0..self.players.len() {
|
||||||
let player = self.players.pop_front().unwrap();
|
let player = self.players.pop_front().unwrap();
|
||||||
if let Some(player) = player.update(self) {
|
let previous = player.position;
|
||||||
|
|
||||||
|
if let Some(mut player) = player.update(self) {
|
||||||
|
if self.collisions(&player.position) > 0 {
|
||||||
|
player.position = previous;
|
||||||
|
}
|
||||||
self.players.push_back(player);
|
self.players.push_back(player);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -142,7 +166,12 @@ impl Floor {
|
|||||||
pub fn update_entities(&mut self) {
|
pub fn update_entities(&mut self) {
|
||||||
for _ in 0..self.entities.len() {
|
for _ in 0..self.entities.len() {
|
||||||
let entity = self.entities.pop_front().unwrap();
|
let entity = self.entities.pop_front().unwrap();
|
||||||
if let Some(entity) = entity.update(self) {
|
let previous = entity.position;
|
||||||
|
|
||||||
|
if let Some(mut entity) = entity.update(self) {
|
||||||
|
if self.collisions(&entity.position) > 0 {
|
||||||
|
entity.position = previous;
|
||||||
|
}
|
||||||
self.entities.push_back(entity);
|
self.entities.push_back(entity);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -159,7 +159,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// todo!() docs
|
/// todo!() docs
|
||||||
pub fn vec_get_sample<'a, T>(vec: &Vec<(f32, &'a T)>, rng: &mut Pcg32) -> &'a T {
|
pub fn vec_get_sample<'a, T>(vec: &Vec<(f32, &'a T)>, rng: &mut impl Rng) -> &'a T {
|
||||||
let sample = rng.gen_range(0.0..1.0);
|
let sample = rng.gen_range(0.0..1.0);
|
||||||
vec.iter().filter(|(p, _)| *p >= sample).next().unwrap().1
|
vec.iter().filter(|(p, _)| *p >= sample).next().unwrap().1
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -76,9 +76,9 @@ pub fn box_of(
|
|||||||
let correction = if 2 * len + title.len() < size { 1 } else { 0 };
|
let correction = if 2 * len + title.len() < size { 1 } else { 0 };
|
||||||
|
|
||||||
std::iter::once("╔".to_string())
|
std::iter::once("╔".to_string())
|
||||||
.chain(std::iter::repeat("═".to_string()).take(len + 1))
|
.chain(std::iter::repeat("═".to_string()).take(len + 1))
|
||||||
.chain(std::iter::once(title))
|
.chain(std::iter::once(title))
|
||||||
.chain(std::iter::repeat("═".to_string()).take(len + 1 + correction))
|
.chain(std::iter::repeat("═".to_string()).take(len + 1 + correction))
|
||||||
.chain(std::iter::once("╗\n".to_string()))
|
.chain(std::iter::once("╗\n".to_string()))
|
||||||
.chain(iter.map(|string| {
|
.chain(iter.map(|string| {
|
||||||
std::iter::once("║ ".to_string())
|
std::iter::once("║ ".to_string())
|
||||||
@@ -164,18 +164,34 @@ impl Behavior for ConsoleInput {
|
|||||||
fn on_death(&mut self, floor: FloorView) {
|
fn on_death(&mut self, floor: FloorView) {
|
||||||
self.print_floor(floor, "YOU DIED!".to_string());
|
self.print_floor(floor, "YOU DIED!".to_string());
|
||||||
}
|
}
|
||||||
fn get_next_action(&mut self) -> Option<Action> {
|
fn get_next_action(&mut self, entity: &Entity) -> Option<Action> {
|
||||||
|
let prompt = "Insert your action [? for help]: ";
|
||||||
let mut term = console::Term::stdout();
|
let mut term = console::Term::stdout();
|
||||||
let _ = term.write("Insert your action [wasd or space for nothing]: ".as_bytes());
|
let _ = term.write(prompt.as_bytes());
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
if let Ok(ch) = term.read_char() {
|
if let Ok(ch) = term.read_char() {
|
||||||
match ch {
|
match ch {
|
||||||
' ' => return Some(Action::DoNothing),
|
' ' => return Some(Action::Attack(entity.direction)),
|
||||||
|
'z' => return Some(Action::DoNothing),
|
||||||
'w' => return Some(Action::Move(Direction::Up)),
|
'w' => return Some(Action::Move(Direction::Up)),
|
||||||
'a' => return Some(Action::Move(Direction::Left)),
|
'a' => return Some(Action::Move(Direction::Left)),
|
||||||
's' => return Some(Action::Move(Direction::Down)),
|
's' => return Some(Action::Move(Direction::Down)),
|
||||||
'd' => return Some(Action::Move(Direction::Right)),
|
'd' => return Some(Action::Move(Direction::Right)),
|
||||||
|
'q' => return None,
|
||||||
|
'?' => {
|
||||||
|
let _ = term.write_line("");
|
||||||
|
let _ = term.write_line("[wasd] => for movement");
|
||||||
|
let _ = term.write_line("[space] => for attacking the enemy in front");
|
||||||
|
let _ = term.write_line("[z] => for doing nothing");
|
||||||
|
let _ = term.write_line("[q] => for exit the game");
|
||||||
|
let _ = term.write("Press ANY button to continue...".as_bytes());
|
||||||
|
let _ = term.read_char();
|
||||||
|
let _ = term.clear_line();
|
||||||
|
let _ = term.clear_last_lines(4); // this number is from the previous message (4 total lines of help)
|
||||||
|
let _ = term.move_cursor_up(1);
|
||||||
|
let _ = term.move_cursor_right(prompt.len());
|
||||||
|
}
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user