void World::updateNaviMap(bool full_recompute) { FWK_PROFILE("updateNaviMap"); //TODO: what about static entities that are added during the game? if(full_recompute) { vector<IBox> bboxes, blockers; bboxes.reserve(m_tile_map.size() + m_entity_map.size()); for(int n = 0; n < m_tile_map.size(); n++) { const Tile *tile = m_tile_map[n].ptr; if(!tile || !Flags::test(tile->flags(), Flags::all | Flags::colliding)) continue; bool is_walkable = Flags::test(tile->flags(), Flags::walkable_tile | Flags::wall_tile); (is_walkable? bboxes : blockers).push_back((IBox)m_tile_map[n].bbox); } for(int n = 0; n < m_entity_map.size(); n++) if(m_entity_map[n].ptr && Flags::test(m_entity_map[n].flags, Flags::static_entity | Flags::colliding)) blockers.push_back(enclosingIBox(m_entity_map[n].ptr->boundingBox())); NaviHeightmap heightmap(m_tile_map.dimensions()); heightmap.update(bboxes, blockers); //heightmap.saveLevels(); //heightmap.printInfo(); for(int m = 0; m < (int)m_navi_maps.size(); m++) { m_navi_maps[m].update(heightmap); //m_navi_maps[m].printInfo(); } } for(int m = 0; m < (int)m_navi_maps.size(); m++) { NaviMap &navi_map = m_navi_maps[m]; navi_map.removeColliders(); for(int n = 0; n < m_entity_map.size(); n++) { auto &object = m_entity_map[n]; if(!object.ptr) continue; if(Flags::test(object.flags, Flags::dynamic_entity | Flags::colliding)) { const IBox &box = enclosingIBox(object.ptr->boundingBox()); navi_map.addCollider(box, n); } } navi_map.updateReachability(); } }
bool Actor::handleOrder(TrackOrder &order, EntityEvent event, const EntityEventParams ¶ms) { if(event == EntityEvent::init_order || event == EntityEvent::think) { order.m_time_for_update -= timeDelta(); const Entity *target = refEntity(order.m_target); if(!target) return false; if(order.m_time_for_update < 0.0f) { fixPosition(); int3 cur_pos = (int3)pos(); int3 target_pos; FBox target_box = target->boundingBox(); if(!world()->findClosestPos(target_pos, cur_pos, enclosingIBox(target_box), ref())) return failOrder(); order.m_path_pos = PathPos(); if(!world()->findPath(order.m_path, cur_pos, target_pos, ref())) return failOrder(); order.m_time_for_update = 0.25f; } if(distance(boundingBox(), target->boundingBox()) <= order.m_min_distance) return false; if(event == EntityEvent::init_order) { if(order.m_please_run && m_proto.simpleAnimId(Action::run, m_stance) == -1) order.m_please_run = 0; if(!animate(order.m_please_run? Action::run : Action::walk)) return failOrder(); } FollowPathResult result = order.needCancel()? FollowPathResult::finished : followPath(order.m_path, order.m_path_pos, order.m_please_run); if(result != FollowPathResult::moved) return false; } if(order.m_path.length(order.m_path_pos) > 1.0f) { if(event == EntityEvent::anim_finished && m_stance == Stance::crouch) { animate(m_action); } if(event == EntityEvent::step) { SurfaceId standing_surface = surfaceUnder(); playSound(m_proto.step_sounds[m_stance][standing_surface], pos()); } } return true; }