如何在 Specs 系统中搜索另一个实体?

问题描述

我一直在跟随 Roguelike Tutorial 来玩 Rust,并开始扩展一些希望创建某种自然模拟。

在我的简单 POC 中,我试图让多个“生物”在地图上徘徊,寻找具有 ProvidesHealth 组件的实体(例如植物或灌木或被吃掉的东西)。

在 Roguelike 教程中,怪物可以随时轻松定位玩家,因为玩家作为资源在世界各地共享,但就我而言,我无法在我的规范中找出模拟这种行为的最佳方法系统。

生物实体有一个视域组件作为它们的视觉。我原本以为我可以遍历视域的 visible_tiles 并检查是否存在带有 ProvidesHealth 实体的​​实体,但我无法完成这项工作。

对此的任何想法将不胜感激!我不确定我的方法是否完全偏离,或者我遗漏了一些简单的东西。

谢谢!

// [dependencies]
// bracket-lib = { git = "https://github.com/thebracket/bracket-lib.git",rev = "927d229" }
// specs = "0.16.1"
// specs-derive = "0.4.1"

use bracket_lib::prelude::*;
use specs::prelude::*;
use specs_derive::*;
use std::{thread,time};

#[derive(Component)]
struct Position {
    x: i32,y: i32,}

#[derive(Component)]
struct Renderable {
    glyph: FontCharType,fg: RGB,bg: RGB,}

#[derive(Component)]
struct Creature {}

#[derive(Component)]
struct ProvidesHealth {
    pub hp_gain: i32
}

#[derive(Component)]
pub struct Viewshed {
    pub visible_tiles: Vec<Point>,pub range: i32,pub dirty: bool
}

struct State {
    ecs: World
}

impl State {
    fn run_systems(&mut self) {
        let mut vis = VisSystem {};
        vis.run_Now(&self.ecs);

        let mut ai = CreatureAI {};
        ai.run_Now(&self.ecs);

        self.ecs.maintain();
    }
}

impl GameState for State {
    fn tick(&mut self,ctx: &mut BTerm) {
        ctx.cls();

        self.run_systems();

        // map defined in separate file,but isn't really
        // important for this question
        // draw_map(&self.ecs,ctx);

        let positions = self.ecs.read_storage::<Position>();
        let renderables = self.ecs.read_storage::<Renderable>();

        for (pos,ren) in (&positions,&renderables).join() {
            ctx.set(pos.x,pos.y,ren.fg,ren.bg,ren.glyph);
        }

        let sleep = time::Duration::from_millis(200);
        thread::sleep(sleep);
    }
}

fn main() -> BError {
    let mut context = BTermBuilder::simple80x50()
        .build()?;

    let mut gs = State {
        ecs: World::new(),};

    gs.ecs.register::<Position>();
    gs.ecs.register::<Renderable>();
    gs.ecs.register::<Creature>();
    gs.ecs.register::<ProvidesHealth>();
    gs.ecs.register::<Viewshed>();

    // add one Creature
    gs.ecs
        .create_entity()
        .with(Position {x: 10,y: 20})
        .with(Renderable {
            glyph: to_cp437('@'),fg: RGB::named(WHITE),bg: RGB::named(BLACK)
        })
        .with(Creature {})
        .with(Viewshed { visible_tiles : Vec::new(),range: 6,dirty: true })
        .with(HealthStats { max_hp: 100,hp: 100 })
        .build();

    // add one "food" item
    gs.ecs
        .create_entity()
        .with(Position {x: 35,y: 35})
        .with(Renderable {
            glyph: to_cp437('*'),bg: RGB::named(BLACK),})
        .with(ProvidesHealth { hp_gain: 10 })
        .build();

    // map defined in separate file,but isn't really
    // important for this question
    let mut map = Map::new_map();
    gs.ecs.insert(map);

    main_loop(context,gs)
}

struct VisSystem {}
impl<'a> System<'a> for VisSystem {
    type SystemData = (
        WriteExpect<'a,Map>,Entities<'a>,WriteStorage<'a,Viewshed>,ReadStorage<'a,Position>,);

    fn run(&mut self,data: Self::SystemData) {
        let (map,entities,mut viewshed,pos) = data;

        for (_ent,viewshed,pos) in (&entities,&mut viewshed,&pos).join() {
            if viewshed.dirty {
                viewshed.visible_tiles = field_of_view(
                    Point::new(pos.x,pos.y),viewshed.range,&*map,)
            }
        }
    }
}

struct CreatureAI {}
impl<'a> System<'a> for CreatureAI {
    #[allow(clippy::type_complexity)]
    type SystemData = (
        // ...
    );

    fn run(&mut self,data: Self::SystemData) {
        // ... not sure what to do here\
        //
        // by doing a join on (viewshed,position),// i'd be able to iterate thru viewshed.visible_tiles,// but i can't figure out how I Could check if a given
        // entity located at the Point has the "ProvidesHealth"
        // component or not
    }
}

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)