地图视野同步思路

本文介绍了一种基于AOI(Area of Interest)算法的场景管理实现方式,详细阐述了如何利用十字链表进行对象管理和更新,以及如何通过场景划分提高效率。文中还涉及了怪物刷新、角色进入和离开场景等具体实现细节。

普通的场景地图是二维的,一般思路都是aoi,大部分都是按照格子去划分。

aoi一般维护了3可见列表visiable_list, enter_list, levelist。每个实体都有visiable raidus[可见半径]。


也可以采用十字链表去做维护。


所谓的十字链表是x 方向 y方向的指针构成,性能极其高效。这个代码我准备贴上去,代码是借鉴一个博客http://www.codedump.info/?p=388写的,不过他代码写的很渣很多BUG,但是我复杂把代码贴上去,看一下就发现几个BUG,后来我同事移植到程序种,发现真心渣。



另外外面通用的做法是做一个二维数组,数组放之一个链表或者数组指针。这样的话每一次都要全局分配N*N格子指针数组。

维护的逻辑都查不多。寻找某个点是否有实体,(y-1)*ROW+LINE就可以算出来所在的位置。



 

#ifndef _SCENE_H
#define _SCENE_H


//#include    "sprite.h"

#include <ext/hash_map>
#include <map>
#include <list>
#include <set>
#include <vector>
using namespace std;

#include "object.h"
#include "npos.h"
#include "sceneconfig.h"
#include "skill/skillconfig.h"
#include "sgconf.h"

class PkObject;
#define DISTANCE 150
#include <set>

class Scene
{

public:
    Scene();
    ~Scene();
    void loop();
  
    // 业务逻辑需要的接口
 void notify_next_monster_fresh(uint32_t interval, uint32_t type); // 通知客户端下一次刷怪间隔
 void reset_noti_next_time() {this->alrdy_noti = 0;}  // 重置标志位
 void init_monster();   // 初始化怪物
 void refresh_monster();   // 新版刷怪
 void active_next_mp(uint32_t id); // 激活下一个刷怪点
 void produce_base(); // 生成基地
 int pkg_all_base_tower();
 Vector2 getFhd(int camp);

    void setSceneId( int id);
    int getSceneId();
 Object* getObjInScene(uint32_t id);
 void insertTargetObj(Object *obj, Object *iter,int release,Vector2 &pos, int r ,int camp, std::set<Object *> &targetList);
    void brocastMsg(int cmdid, int len);
    void onEnter(Object *role, bool isNotify);
 void onLeave(Object *role, bool sendToSelf);
    void brocastMsgExceptMe(Object *role, int cmdid, int len);
    void getTargetList(Object *object,const SkillConfig *base, Vector2 &pos, uint32_t camp, std::set<Object *> &targetList);
    void getNearObjList(Object *object, std::set<Object *> &targetList, float distance);
 void getAITargetList(PkObject *obj,int tarType ,Vector2 &pos, uint32_t r, std::set<PkObject *> &targetList);
 void getVisibleTargetList(Object *object, const SkillConfig *base, Vector2 &pos, uint32_t camp, std::set<Object *> &targetList);
    void sendMsgToView(Object *role, int cmdid, int len);
    void sendToViewAndCamp(Object *role, int cmdid, int len);
 void Add(Object* object);
    void Move(int id, int x, int y);
    void Leave(int id);
 void print_objs();
 uint32_t getPlayerCount();
 void set_wincamp(int camp) { this->wincamp = camp;}
 void set_start(bool is_start) { this->is_start = is_start;}
 uint32_t incr_gpmonster_cnt(uint32_t id);
 uint32_t decr_gpmonster_cnt(uint32_t id);
public:
    //aoi 逻辑整理
    uint32_t sceneid;    // 场景或者副本ID
 uint32_t guan;      // 关卡ID
 uint32_t chapter;    // 章节ID
 uint32_t create_time; // Scene的创建时间
    uint64_t cur_ms;   // 当前毫秒
 uint32_t cur_sec;  // 当前秒
 uint32_t npc_id;  // 用户创建Npc的自增npc_id
 int32_t last_sg_key; // 上一次刷怪使用的sg-key值
 int32_t last_tm_key; // 上一次刷怪使用的tm-key值
 uint32_t alrdy_noti; // 通知刷怪时间标志位
 uint32_t wincamp;  // 0:未分胜负,1:己方胜利,2:电脑胜利
 bool is_start;   // 是否开始场景loop中的动作:如刷怪等
 std::map<uint32_t, t_waveConf*> waveconf_map;  // 当前刷怪配置
 std::map<uint32_t, uint32_t> mon_interval_map;  // 刷怪间隔map
 std::map<uint32_t, uint32_t> gpmonster_cnt_map; // 聚集点存活怪物数量

    ObjMap  obj_map_;
 ObjMap  role_map_;
 ObjList obj_x_list_;
    ObjList obj_y_list_;

    ObjMap  move_map_;
    ObjMap  enter_map_;
    ObjMap  leave_map_;

    SceneConfig *pConfig;   
    int state;

//需要删除的尸体
 std::set<int> _del_npc;
private:
    void Update(Object *object);
    void GetRangeSet(Object *object, ObjMap *set);
    void UpdateObjectPosition(Object *object, int x, int y);   
};

 

#endif

 

 

 


#include "util/util.h"
#include "sceneconfig.h"
#include "global.h"
#include "proto/online_enum.h"
#include "npc.h"
#include "astar.h"
#include "sprite.h"
#include "Ctimer.h"
#include "scene.h"
#include "intersect.h"
#include "intersact2.h"
#include "pkobject.h"
#include "./model/mlogic.pb.h"

 

 


int debug_AOI = 0;

Scene::Scene()
{
 state = 0;
 pConfig = NULL;
 npc_id = 100000;
 last_sg_key = 0;
 last_tm_key = 0;
 alrdy_noti = 0;
 is_start = false;
 wincamp = 0;

 this->obj_map_.clear();
 this->obj_x_list_.clear();
 this->obj_y_list_.clear();
 this->enter_map_.clear();
 this->move_map_.clear();
 this->leave_map_.clear();
}


Scene::~Scene()
{
 DEBUG_LOG("DEL SCENE\t[%lu]",
  this->obj_map_.size());
 //删掉场景内存数据
 this->obj_x_list_.clear();
 this->obj_y_list_.clear();
 this->enter_map_.clear();
 this->move_map_.clear();
 this->leave_map_.clear();

 FOREACH(this->obj_map_, itr) {
  if (itr->second->type == Object_Player)
   continue;
  delete itr->second;
 }
 this->obj_map_.clear();
}

//场景帧循环
void Scene::loop()
{
 if(is_start) {
  uint64_t lcur_ms = getCurrentMsTime();
  this->cur_sec = lcur_ms / 1000;

  if (lcur_ms - this->cur_ms < 20)
   return;
  this->cur_ms = lcur_ms;

  //游戏回合结束
  //TODO 回合时间需要统一定义
  if(this->cur_sec - this->create_time >= 480) {
   DEBUG_LOG("times up[cur_sec:%d][create_time:%d]", this->cur_sec, this->create_time);
   this->set_wincamp(1);
   this->set_start(false);
   return;
  }
  //this->shuaguai();
  this->refresh_monster();
 
  FOREACH(_del_npc, iter){
   Leave(*iter);
   PkObject *obj = (PkObject *)getObjInScene(*iter);
   if(obj){
    delete obj;
   }
  }
  _del_npc.clear();
  //复活数组
  std::vector<uint32_t>  vect;
  FOREACH(this->obj_map_, iter) {  
   PkObject *pk= (PkObject*)iter->second;
   //判断类型是NPC 尸体存在的时间如果存在

   if(pk->get_type() == Object_NPC &&
      pk->getState() == SceneObject_Death &&
      this->cur_sec > pk->_del_body_time &&
      !pk->relive_time) {
     _del_npc.insert(pk->id);
   }
   bool brun = true;
   //删除实体 添加实体
   if(pk->get_type() == Object_Player && pk->getState() == SceneObject_Death){
    uint32_t current_time = cur_sec;
     if(current_time >= pk->relive_time) {
     vect.push_back(pk->id);
     brun = false;
     }
   }

   if(brun){
    pk->loop(lcur_ms);
   }
  }
  FOREACH(vect, iter2){
   PkObject *obj = (PkObject *)getObjInScene(*iter2);
   Leave(*iter2);
   obj->_pos = getFhd(0);
   Add(obj);
   obj->relive();
  }

 }


}

void Scene::notify_next_monster_fresh(uint32_t interval, uint32_t type)
{
 NextMonsterTimeNotify nextMonsterTimeNotify;
        nextMonsterTimeNotify.set_time(interval);
        nextMonsterTimeNotify.set_monstertype(type);
        int index = nextMonsterTimeNotify.ByteSize();
        nextMonsterTimeNotify.SerializeToArray(SEND_CLI_BUF, index);
        this->brocastMsg(noti_next_shuaguai_cmd, index);
}

void Scene::refresh_monster()
{
 //HDEBUG_LOG("htest sgd refresh_monster");

 uint32_t pass_time = this->cur_sec - this->create_time;
 FOREACH(this->waveconf_map, iter) {
  waveConf* pWaveConf = iter->second;
  std::map<uint32_t, uint32_t>::iterator iter_interval = this->mon_interval_map.find(pWaveConf->id);
  if(iter_interval == this->mon_interval_map.end()) {
   return;
  }

  uint32_t* interval = &iter_interval->second;
  if(pass_time < *interval) {
   return;
  }

  sgdConf* psgd = pConfig->get_sgdConf(pWaveConf->sgdid);
  if (!psgd) {
   ERROR_LOG("error sgd ID\t[g:%u c:%u %u]", this->guan, this->chapter, pWaveConf->sgdid);
   return;
  }
  // 获取野怪路径的配置
  ygpConf* pygp = pConfig->get_ygpConf(psgd->pathid);
  if (!pygp) {
   ERROR_LOG("error path ID\t[g:%u c:%u %u]", this->guan, this->chapter, psgd->pathid);
   return;
  }
  //FOREACH(pygp->ygp, itr) {
  //        HDEBUG_LOG("htest monster path:(%f,%f)", itr->x, itr->y);
  //}

  uint32_t monsterid = pWaveConf->mon_id;
  uint32_t monster_cnt = pWaveConf->mon_cnt;
  HDEBUG_LOG("htest sgd monster [monsterid:%u][monster_cnt:%u]", monsterid, monster_cnt);

  npc_base_t* pnb = get_npc_base(monsterid);
  if (pnb == NULL) {
   ERROR_LOG("err npcID\t[g:%u c:%u npcID:%u]", this->guan, this->chapter, monsterid);
   continue;
  }

  for(int i = 0; i < (int)monster_cnt; i++) {
   int offset = i  * 15;//随机一个偏移值
   int x = psgd->pos.x + offset;
   int y = psgd->pos.y + offset;
   if(this->pConfig->m_arr_bytes[y / GRID_SIZE][x / GRID_SIZE]) {
    x = psgd->pos.x;
    y = psgd->pos.y;
   }

   Npc* pn = new Npc(++this->npc_id, Object_NPC, (NpcType)pnb->npcType, psgd->camp, x, y, 0, 0, OFFENSE, pnb);
   HDEBUG_LOG("htest sgd ID\t[sgdid:%u pathid:%u][id:%u]", psgd->sgdid, psgd->pathid, pWaveConf->id);
   this->Add(pn);
   pn->startMove(pygp->ygp, e_march);
   //pn->adjustPath();
  }

  *interval += pWaveConf->interval;
  // 只广播下一波偷袭怪的时间
  HDEBUG_LOG("htest sgd next_monster_fresh[interval:%u][type:%u][sgdid:%u][id:%u][totaltime:%d][pasttime:%d]",
    pWaveConf->interval, psgd->type, pWaveConf->sgdid, pWaveConf->id, *interval, pass_time);
  if(psgd->type == 1) {
   this->notify_next_monster_fresh(pWaveConf->interval, psgd->type);
  }

 }
}

void Scene::active_next_mp(uint32_t id)
{
 std::map<uint32_t, t_waveConf*>::iterator iter = this->waveconf_map.find(id);
 if(iter != this->waveconf_map.end()) {
  this->waveconf_map.erase(iter);
 }
 
 if (!this->pConfig)
                return ;

        guanConf* psg = get_guanConf(this->guan, this->chapter);
        if (!psg || psg->sg_map.size() == 0) {
                return;
        }

 t_waveConf* pWaveConf = NULL;
        FOREACH(psg->sg_map, iter_sg) {
  if(id == iter_sg->second.pre_id) {
   HDEBUG_LOG("htest sgd active next mp[curid:%u][nextid:%u]", id, iter_sg->first);
   pWaveConf = &iter_sg->second;
   break;
  }
 }
 
 SgdDestroyNotify sgdDestroyNotify;
 sgdDestroyNotify.set_currentid(id);
 if(pWaveConf != NULL) {
  this->waveconf_map[pWaveConf->id] = pWaveConf;
  uint32_t pass_time = this->cur_sec - this->create_time;
         this->mon_interval_map[pWaveConf->id] = pWaveConf->starttime + pass_time;
  sgdDestroyNotify.set_nextid(pWaveConf->id);
 } else {
  sgdDestroyNotify.set_nextid(0);
 }

 int index = sgdDestroyNotify.ByteSize();
        sgdDestroyNotify.SerializeToArray(SEND_CLI_BUF, index);
        this->brocastMsg(noti_sgd_destroy_cmd, index);
 HDEBUG_LOG("sgdDestroyNotify");
}

void Scene::produce_base()
{
 if (!this->pConfig)
  return ;

 FOREACH(pConfig->m_jidi_map, it) {
  jidiConf* pj = &it->second;
  npc_base_t* pnb = get_npc_base(pj->deployid);
  if (pnb == NULL) {
   DEBUG_LOG("err BASE id\t[g:%u c:%u baseID:%u]", this->guan, this->chapter, pj->deployid);
   continue;
  }
  
  Npc* pn = new Npc(it->first, Object_NPC, (NpcType)pnb->npcType, pj->camp, pj->pos.x, pj->pos.y, pj->dir.x, pj->dir.y, OFFENSE, pnb );
  HDEBUG_LOG("htest base produce BASE TOWER INFO[id=%u npcID:%u subtype:%u x=%f, y=%f]",
                                pn->id, pn->npcID, pn->subtype, pn->_pos.x, pn->_pos.y);
  this->Add(pn);
 }

}

void Scene::init_monster()
{
 if (!this->pConfig) {
  HDEBUG_LOG("htest init_monster monster config is null");
                return ;
 }

 guanConf* psg = get_guanConf(this->guan, this->chapter);
        if (!psg || psg->sg_map.size() == 0) {
                HDEBUG_LOG("htest init_monster no monster config\t[g:%u c:%u]", this->guan, this->chapter);
                return;
        }

 this->waveconf_map.clear();

 SgdLocationNotify sgdLocationNotify;
 FOREACH(psg->sg_map, iter) {
  t_waveConf* pWaveConf = &iter->second;

  HDEBUG_LOG("htest init_monster id [id:%d] [preid:%d] ", pWaveConf->id, pWaveConf->pre_id);

  sgdConf* p_sgdConf = pConfig->get_sgdConf(pWaveConf->sgdid);
  if (!p_sgdConf) {
   ERROR_LOG("error sgd ID\t[g:%u c:%u sgdid%u]", this->guan, this->chapter, pWaveConf->sgdid);
   return;
  }

 
  // 加载当前刷怪配置
  if(pWaveConf->pre_id == 0) {
   this->waveconf_map[pWaveConf->id] = pWaveConf;
   this->mon_interval_map[pWaveConf->id] = pWaveConf->starttime;

   // 只广播下一波偷袭怪时间
   if(p_sgdConf->type == 1) {
    this->notify_next_monster_fresh(pWaveConf->starttime, p_sgdConf->type);
   }
  }

  // 获取聚集点的配置
  if(pWaveConf->gpid == 0) {
   continue;
  }

  if(pWaveConf->mon_cnt > 0) {
   SgdLocationNotify_Location* location = sgdLocationNotify.add_location();
   location->set_id(pWaveConf->id);
   location->set_x(p_sgdConf->pos.x);
   location->set_y(p_sgdConf->pos.y);
  }

  sgdConf* psgd = pConfig->get_sgdConf(pWaveConf->gpid);
                if (!psgd) {
   HDEBUG_LOG("htest init_monster error sgd ID\t[g:%u c:%u %u]", this->guan, this->chapter, pWaveConf->gpid);
                        ERROR_LOG("error sgd ID\t[g:%u c:%u %u]", this->guan, this->chapter, pWaveConf->gpid);
                        return;
                }

  FOREACH(pWaveConf->gpmon_map, iter_gpmon) {
   uint32_t monsterid = iter_gpmon->first;
   uint32_t monster_cnt = iter_gpmon->second;
                        npc_base_t* pnb = get_npc_base(monsterid);
                        if (pnb == NULL) {
    HDEBUG_LOG("htest init_monster err npcID\t[g:%u c:%u npcID:%u]", this->guan, this->chapter, monsterid);
                                ERROR_LOG("err npcID\t[g:%u c:%u npcID:%u]", this->guan, this->chapter, monsterid);
                                continue;
                        }
   for(uint32_t i = 0; i < monster_cnt; i++) {
    int offset = random() % 50;//随机一个偏移值
    Npc* pn = new Npc(++this->npc_id, Object_NPC, (NpcType)pnb->npcType, psgd->camp, psgd->pos.x + offset, psgd->pos.y + offset, 0, 0, DEFENCE, pnb);
    pn->startDefend();
    pn->gpid = pWaveConf->id;
    int count = this->incr_gpmonster_cnt(pWaveConf->id);
                         HDEBUG_LOG("htest init_monster sgd gp ID\t[sgdid:%u pathid:%u][monster_cnt:%d]", psgd->sgdid, psgd->pathid, count);
                         this->Add(pn);
   }
  }
  
 }

 int index = sgdLocationNotify.ByteSize();
 sgdLocationNotify.SerializeToArray(SEND_CLI_BUF, index);
 this->brocastMsg(noti_sgd_location_cmd, index);
 HDEBUG_LOG("sgdLocationNotify [index:%d]", index);
}

uint32_t Scene::incr_gpmonster_cnt(uint32_t id)
{
 std::map<uint32_t, uint32_t>::iterator iter = this->gpmonster_cnt_map.find(id);
 if(iter == this->gpmonster_cnt_map.end()) {
  this->gpmonster_cnt_map[id] = 1;
  return 1;
 }

 uint32_t* count = &iter->second;
 return ++(*count);
}

uint32_t Scene::decr_gpmonster_cnt(uint32_t id)
{
 std::map<uint32_t, uint32_t>::iterator iter = this->gpmonster_cnt_map.find(id);
        if(iter == this->gpmonster_cnt_map.end()) {
                return 0;
        }

        uint32_t* count = &iter->second;
        return --(*count);
}

void Scene::setSceneId(int id)
{
 this->sceneid = id;

}

int Scene::getSceneId()
{
 return this->sceneid;
}

Object* Scene::getObjInScene(uint32_t id)
{
 std::map<int, Object *>::iterator iter = this->obj_map_.find(id);
 if (iter != this->obj_map_.end()){
  return iter->second;
 }
 return  NULL;
}

//广播数据内存需要拷贝到公共缓存区里面
void Scene::brocastMsg(int cmdid, int len)
{
 /*
 FOREACH(this->obj_map_, iter) {
  PkObject *pkobj = (PkObject*)iter->second;
  if(pkobj->type == Object_Player)
  {
   Crole* pcr = reinterpret_cast<Crole*>(pkobj);
   if (!pcr->player_control()) continue;
   pkobj->send_msg_ex(cmdid, 0, len, false );
  }
 }
 */

 FOREACH(this->role_map_, iter) {
  Crole* pcr = reinterpret_cast<Crole*>(iter->second);
  if (!pcr->player_control()) continue;
  pcr->send_msg_ex(cmdid, 0, len, false );
 }
}


 
uint32_t Scene::getPlayerCount()
{
 uint32_t size = 0;
 FOREACH(this->obj_map_, iter) {
  PkObject *pkobj = (PkObject*)iter->second;
  if(pkobj->type == Object_Player)
  {
   size++;
  }
 }
 return size;
 
}

//广播消息给视野范围的玩家 包括自己
void Scene::sendMsgToView(Object *role, int cmdid, int len)
{
 PkObject *msgobj =  (PkObject *)role;
 FOREACH(msgobj->visible_map, iter) {
  PkObject *pkobj = iter->second;
  if(pkobj->type == Object_Player)
  {
   Crole* pcr = reinterpret_cast<Crole*>(pkobj);
   if (!pcr->player_control()) continue;
   pcr->send_msg_ex(cmdid, 0, len, false);
  }
 }

 if(msgobj->type == Object_Player) {
  Crole* pcr = reinterpret_cast<Crole*>(msgobj);
  if (!pcr->player_control()) return;
  pcr->send_msg_ex(cmdid, 0, len, false);
 }

}

 

void Scene::brocastMsgExceptMe(Object *role, int cmdid, int len)
{
 /*
 FOREACH(this->obj_map_, iter) {
  PkObject *pkobj = (PkObject*)iter->second;
  if(pkobj != role && pkobj->type == Object_Player)
  {
   Crole* pcr = reinterpret_cast<Crole*>(pkobj);
   if (!pcr->player_control()) continue;
   pkobj->send_msg_ex(cmdid, 0, len, false);
  }
 }
 */

 FOREACH(this->role_map_, iter) {
  Crole* pcr = reinterpret_cast<Crole*>(iter->second);
  if (role == pcr) continue;
  if (!pcr->player_control()) continue;
  pcr->send_msg_ex(cmdid, 0, len, false );
 }
}

void Scene::sendToViewAndCamp(Object* role, int cmdid, int len)
{
 PkObject *msgobj =  (PkObject *)role;
 FOREACH(msgobj->visible_map, iter) {
  PkObject *pkobj = iter->second;
  if(pkobj->type == Object_Player) {
   Crole* pcr = reinterpret_cast<Crole*>(pkobj);
   if (!pcr->player_control()) continue;
   pcr->send_msg_ex(cmdid, 0, len, false);
  }
 }
 if (msgobj->type != Object_Player) return;
 FOREACH(this->role_map_, iter) {
  Crole* pcr = reinterpret_cast<Crole*>(iter->second);
  if (pcr->camp != msgobj->camp) continue;
  if (!pcr->player_control()) continue;
  if (KEY_IN_MAP(msgobj->visible_map, pcr->id)) continue;
  pcr->send_msg_ex(cmdid, 0, len, false );
 }
}

/*
 该函数不能在中间return,必须执行到 最后的clear 处
*/
void Scene::Update(Object *object)
{
 static char self_info[102400] = {0};
 int  s_idx = sizeof(protocol_t);
 static char other_info[102400] = {0};
 int index = 0;

 PkObject* my_pk = reinterpret_cast<PkObject*>(object);
    // send ENTER msg
 if (!enter_map_.empty()) {
  if(debug_AOI) KDEBUG_LOG(object->id, "ENTER VIEW SIZE\[%lu]", enter_map_.size());
  // send others to me
  if (my_pk->type == Object_Player) {
   Crole* prole = reinterpret_cast<Crole*>(my_pk);
   if (prole->player_control()) {
    int num = 0;
    NpcEnterViewNotify npcEnterViewNotify;
    FOREACH(enter_map_, eitr) {
     PkObject* pp = reinterpret_cast<PkObject*>(eitr->second);
     if (pp->subtype != NpcType_Tower && pp->subtype != NpcType_Base) {
      num ++;
      //o_idx = pp->pkg_enter_map_info(other_info, o_idx);
      pp->pkg_enter_map_info(&npcEnterViewNotify);
     }
    }
    if (num) {
     index = npcEnterViewNotify.ByteSize();
     npcEnterViewNotify.SerializeToArray(&other_info[s_idx], index);
     prole->send_msg(other_info, noti_npc_enter_view_cmd, 0, index, false);
     if(debug_AOI) KDEBUG_LOG(prole->id, "SEND TO ME ENTER SIZE\[%u]", num);
    }
   }
  }
  // send me to others
  NpcEnterViewNotify npcEnterViewNotify2;
  my_pk->pkg_enter_map_info(&npcEnterViewNotify2);
  index = npcEnterViewNotify2.ByteSize();
  npcEnterViewNotify2.SerializeToArray(&self_info[s_idx], index);
  FOREACH(enter_map_, eiter) {
   PkObject* po = reinterpret_cast<PkObject*>(eiter->second);
   // ----
   my_pk->insert_to_visible_map(po);
   po->insert_to_visible_map(my_pk);
   // ----
   if(debug_AOI) KDEBUG_LOG(object->id, "VIEW OB\[%u x:%f y:%f]", eiter->first, po->_pos.x, po->_pos.y);
   if (po->type == Object_Player) {
    Crole* prole = reinterpret_cast<Crole*>(po);
    if (prole->player_control()) {
     prole->send_msg(self_info, noti_npc_enter_view_cmd, 0, index, false);
     if(debug_AOI) KDEBUG_LOG(prole->id, "OB ENTER VIEW\[%u]",object->id);
    }
   }
  }

 }
    ObjMap::iterator iter;
 // send MOVE msg
 if (this->cur_ms - my_pk->_last_sync_time > 300) {
  if (!move_map_.empty()) {
   NpcMoveNotify npcMoveNotify;
   my_pk->pkg_move_info(&npcMoveNotify);
   index = npcMoveNotify.ByteSize();
   npcMoveNotify.SerializeToArray(&self_info[s_idx], index);
  }
  for (iter = move_map_.begin(); iter != move_map_.end(); ++iter) {
   PkObject* po = reinterpret_cast<PkObject*>(iter->second);
   if (po->type == Object_Player) {
    Crole* prole = reinterpret_cast<Crole*>(po);
    if (prole->player_control()) {
     prole->send_msg(self_info, noti_npc_move_cmd, 0, index, false);
     if(debug_AOI) KDEBUG_LOG(prole->id, "OB MOVE VIEW\[%u]", object->id);
    }
   }
   // 受控状态下需要同步给客户端
   if (my_pk->type == Object_Player) {
    Crole* my_role = reinterpret_cast<Crole*>(my_pk);
    if (my_role->player_control() && my_role->move_mode != e_client) {
     my_role->send_msg(self_info, noti_npc_move_cmd, 0, index, false);
    }
   }
  }
  my_pk->_last_sync_time = this->cur_ms;
 }
    // send LEAVE msg
 if (!leave_map_.empty()) {
  // send me to others
  int num = 0;
  NpcLeaveViewNotify npcLeaveViewNotify;
  my_pk->pkg_leave_map_info(&npcLeaveViewNotify);
  index = npcLeaveViewNotify.ByteSize();
  npcLeaveViewNotify.SerializeToArray(&self_info[s_idx], index);
  FOREACH(leave_map_, liter) {
   PkObject* po = reinterpret_cast<PkObject*>(liter->second);
   //----
   my_pk->erase_from_visible_map(po);
   po->erase_from_visible_map(my_pk);
   //----
   if (po->type == Object_Player) {
    Crole* prole = reinterpret_cast<Crole*>(po);
    if (prole->player_control()) {
     prole->send_msg(self_info, noti_npc_leave_view_cmd, 0, index, false);
     if(debug_AOI) KDEBUG_LOG(prole->id, "OB LEAVE VIEW\[%u]", object->id);
    }
   }
  }
  // send others to me
  if (object->type == Object_Player) {
   Crole* prole = reinterpret_cast<Crole*>(object);
   if (prole->player_control()) {
    NpcLeaveViewNotify npcLeaveViewNotify1;
    FOREACH(leave_map_, litr) {
     PkObject* pp = reinterpret_cast<PkObject*>(litr->second);
     if (pp->subtype != NpcType_Tower && pp->subtype != NpcType_Base) {
      num ++;
      pp->pkg_leave_map_info(&npcLeaveViewNotify1);
     }
    }
    if (num) {
     int index = npcLeaveViewNotify1.ByteSize();
                   npcLeaveViewNotify1.SerializeToArray(&other_info[s_idx], index); 
     prole->send_msg(other_info, noti_npc_leave_view_cmd, 0, index, false);
     if(debug_AOI) KDEBUG_LOG(prole->id, "SEND TO ME LEAVE SIZE\[%u]", num);
    }
   }
  }

 }

    // clean the move, leave, enter set
    enter_map_.clear();
    move_map_.clear();
    leave_map_.clear();
}

void Scene::Add(Object* object)
{
 int distance = DISTANCE;
    if (obj_map_.find(object->id) != obj_map_.end()) {
  ERROR_LOG("Object already in scene\t[O:%u S:%u]", object->id, this->sceneid);
        return;
    }
    obj_map_[object->id] = object;
 if (object->type == Object_Player)
  role_map_[object->id] = object;

    object->setScene(this);

    ObjList::iterator iter, pos;
    bool flag;
    ObjMap x_set;
 if(debug_AOI) KDEBUG_LOG(object->id, "ADD OBJ\t[x:%f y:%f]", object->_pos.x, object->_pos.y);

    // iterator x-axis object list
    flag = false;
    for (iter = obj_x_list_.begin(); iter != obj_x_list_.end(); ++iter) {
  if(debug_AOI) KDEBUG_LOG(object->id, "Search X list\t[id:%u type:%u x:%f y:%f]",
   (*iter)->id, (*iter)->type, (*iter)->_pos.x, (*iter)->_pos.y);
        int diff = (*iter)->_pos.x - object->_pos.x;
        // into the x set
        if (abs(diff) <= distance) {
            x_set[(*iter)->id] = *iter;
   if(debug_AOI) KDEBUG_LOG(object->id, "ADD X\t[id:%u]", (*iter)->id);
        }
        if (!flag && diff > 0) {
            pos = iter;
            flag = true;
        }
        if (diff > distance) {
            break;
        }
    }
 
    if (flag) {
        obj_x_list_.insert(pos, object);
        object->x_pos = --pos;
    } else {
  /* modify by james
        obj_x_list_.push_front(object);
        object->x_pos = obj_x_list_.begin();
  */
        obj_x_list_.push_back(object);
        iter = obj_x_list_.end();
        object->x_pos = --iter;
    }

    // iterator y-axis object list
    flag = false;
    for (iter = obj_y_list_.begin(); iter != obj_y_list_.end(); ++iter) {
  if(debug_AOI) KDEBUG_LOG(object->id, "Search Y list\t[id:%u type:%u x:%f y:%f]",
   (*iter)->id, (*iter)->type, (*iter)->_pos.x, (*iter)->_pos.y);
        int diff = (*iter)->_pos.y - object->_pos.y;
        // into the enter set
        if (abs(diff) <= distance && x_set.find((*iter)->id) != x_set.end()) {
            enter_map_[(*iter)->id] = *iter;
   if(debug_AOI) KDEBUG_LOG(object->id, "ADD Y/E\t[id:%u]", (*iter)->id);
        }
        if (!flag && diff > 0) {
            pos = iter;
            flag = true;
        }
        if (diff > distance) {
            break;
        }
    }
    if (flag) {
        obj_y_list_.insert(pos, object);
        object->y_pos = --pos;
    } else {
  /* modify by james
        obj_y_list_.push_front(object);
        object->y_pos = obj_y_list_.begin();
  */
        obj_y_list_.push_back(object);
        iter = obj_y_list_.end();
        object->y_pos = --iter;
    }
 PkObject* pkobj = (PkObject*)object;
 pkobj->noti_self_enter_scene();
    Update(object);
}

void Scene::UpdateObjectPosition(Object *object, int x, int y) {
    int old_x = object->_pos.x;
    int old_y = object->_pos.y;
    object->_pos.x = x;
    object->_pos.y = y;

    ObjList::iterator iter, pos;

    // find the new x pos
    if (x > old_x) {
        if (object->x_pos != obj_x_list_.end()) {
            iter = object->x_pos;
            ++iter;
            obj_x_list_.erase(object->x_pos);
            while (iter != obj_x_list_.end()) {
                if (object->_pos.x - (*iter)->_pos.x < 0) {
                    pos = iter;
                    break;
                }
                ++iter;
            }
            if (iter != obj_x_list_.end()) {
                obj_x_list_.insert(pos, object);
    object->x_pos = --pos; // add by james
            } else {
                obj_x_list_.push_back(object);
    ObjList::iterator it = obj_x_list_.end(); // add by james
    object->x_pos = --it; // add by james
            }
        }
    } else if (x < old_x) {
        if (object->x_pos != obj_x_list_.begin()) {
            iter = object->x_pos;
            --iter;
            obj_x_list_.erase(object->x_pos);
   /* modidy by james
            while (iter != obj_x_list_.begin()) {
                if (object->_pos.x - (*iter)->_pos.x > 0) {
                    pos = ++iter;
                    break;
                }
                --iter;
            }
   */
   while (1) {
                if (object->_pos.x - (*iter)->_pos.x > 0) {
                    pos = ++iter;
                    break;
                }
    if (iter == obj_x_list_.begin()) {
     break;
    }
    --iter;
   }
            if (iter != obj_x_list_.begin()) {
                obj_x_list_.insert(pos, object);
    object->x_pos = --pos; // add by james
    //object->x_pos = obj_x_list_.insert(pos, object); // add by james
            } else {
                obj_x_list_.push_front(object);
    object->x_pos = obj_x_list_.begin(); // add by james
            }
        }
    }

    // find the new y pos
    if (y > old_y) {
        if (object->y_pos != obj_y_list_.end()) {
            iter = object->y_pos;
            ++iter;
            obj_y_list_.erase(object->y_pos);
            while (iter != obj_y_list_.end()) {
                if (object->_pos.y - (*iter)->_pos.y < 0) {
                    pos = iter;
                    break;
                }
                ++iter;
            }
            if (iter != obj_y_list_.end()) {
                obj_y_list_.insert(pos, object);
    object->y_pos = --pos; // add by james
            } else {
                obj_y_list_.push_back(object);
    ObjList::iterator it = obj_y_list_.end(); // add by james
    object->y_pos = --it; // add by james
            }
        }
    } else if (y < old_y) {
        if (object->y_pos != obj_y_list_.begin()) {
            iter = object->y_pos;
            --iter;
            obj_y_list_.erase(object->y_pos);
   /* modify by james
            while (iter != obj_y_list_.begin()) {
                if (object->_pos.y - (*iter)->_pos.y > 0) {
                    pos = ++iter;
                    break;
                }
                --iter;
            }
   */
   while (1) {
                if (object->_pos.y - (*iter)->_pos.y > 0) {
                    pos = ++iter;
                    break;
                }
    if (iter == obj_y_list_.begin()) {
     break;
    }
    --iter;
   }

            if (iter != obj_y_list_.begin()) {
                obj_y_list_.insert(pos, object);
    object->y_pos = --pos; // add by james
    //object->y_pos = obj_y_list_.insert(pos, object); // add by james
            } else {
                obj_y_list_.push_front(object);
    object->y_pos = obj_y_list_.begin(); // add by james
            }
        }
    }
}

void Scene::print_objs()
{
 FOREACH(obj_map_, itr) {
  Object* po = itr->second;
  if (debug_AOI) DEBUG_LOG("[id:%u x:%f y:%f]", po->id, po->_pos.x, po->_pos.y);
 }
}

void Scene::Move(int id, int x, int y)
{
 if (x <= 0 || y <= 0)
  KDEBUG_LOG(id, "ERRORPOS\t[(%d,%d)]", x, y);
    ObjMap::iterator obj_iter = obj_map_.find(id);
    if (obj_iter == obj_map_.end()) {
        return;
    }
    Object *object = obj_iter->second;

    ObjList::iterator list_iter;
    ObjMap old_set, new_set;
 old_set.clear();
 new_set.clear();

 //print_objs();
    // get the old set
    GetRangeSet(object, &old_set);
 if (debug_AOI) KDEBUG_LOG(id, "old set\t[%lu x:%f y:%f]", old_set.size(),
  object->_pos.x, object->_pos.y);

    // update object position
    UpdateObjectPosition(object, x, y);

 //print_objs();
    // get the new set
    GetRangeSet(object, &new_set);
 if (debug_AOI) KDEBUG_LOG(id, "new set\t[%lu x:%f y:%f]", new_set.size(),
  object->_pos.x, object->_pos.y);

    // move_set = old_set MIX new_set
    ObjMap::iterator iter;
    for (iter = old_set.begin(); iter != old_set.end(); ++iter) {
        if (new_set.find(iter->first) != new_set.end()) {
            move_map_[iter->first] = iter->second;
        }
    }

 if (debug_AOI) KDEBUG_LOG(id, "move set\t[%lu x:%f y:%f]", move_map_.size(),
  object->_pos.x, object->_pos.y);
    // leave_set = old_set SUB move_set
    for (iter = old_set.begin(); iter != old_set.end(); ++iter) {
        if (move_map_.find(iter->first) == move_map_.end()) {
            leave_map_[iter->first] = iter->second;
        }
    }

    // enter_set = new_set SUB move_set
    for (iter = new_set.begin(); iter != new_set.end(); ++iter) {
        if (move_map_.find(iter->first) == move_map_.end()) {
            enter_map_[iter->first] = iter->second;
        }
    }

    Update(object);
}

 


//插入目标对象
void Scene::insertTargetObj(Object *obj, Object *iter,int release, Vector2 &pos,int r,int camp,std::set<Object*> &targetList)
{
 if(obj != iter)
 {
  if(obj->type == Object_Player || obj->type == Object_NPC)
  {
   PkObject *pkobj = (PkObject *)(iter);
   if(camp)
   {
    if(pkobj->getCamp() == obj->getCamp() && pkobj->getState() == SceneObject_Normal)
    {
     if(release)
     {
   //   Vector2 tmpPos = pos - pkobj->_pos;
   //   float sqrtDist = r - tmpPos.sqrtMagnitude();
   //   if(sqrtDist > 0.0001)
   //   {
       targetList.insert(iter);
   //    KDEBUG_LOG(pkobj->id, "搜索到目标对象【%.2f,%.2f】", pkobj->_pos.x, pkobj->_pos.y);
   //   }
     }else
     {
      targetList.insert(iter);
     }
    }
   }else
   {
    if(pkobj->getCamp() != obj->getCamp() && pkobj->getState() == SceneObject_Normal)
    {
     if(release)
     {
   //   Vector2 tmpPos = pos - pkobj->_pos;
      //    float sqrtDist = r - tmpPos.sqrtMagnitude();
   //   if(sqrtDist > 0.0001)
   //   {
       targetList.insert(iter);
   //    KDEBUG_LOG(pkobj->id, "释放者[%.2f, %.2f] 坐标 [%.2f, %.2f]搜索到目标对象【%.2f,%.2f】",obj->_pos.x, obj->_pos.y,pos.x, pos.y , pkobj->_pos.x, pkobj->_pos.y);

   //   }
     }else
     {
      targetList.insert(iter);
     }
    }
   }

  }
 }

}

void Scene::getAITargetList(PkObject *obj,int tarType ,Vector2 &pos, uint32_t r, std::set<PkObject *> &targetList){
  PkObject *castobj = (PkObject *)obj;
 for(map<uint32_t, PkObject*>::iterator objIter = castobj->visible_map.begin(); objIter != castobj->visible_map.end(); objIter++){
  PkObject *tarObj = NULL;
  if(tarType){  
   tarObj = (PkObject *)(objIter->second);
   
   // 如果目标是敌方,不需要包括自己和友方
   if(0 == tarObj->camp || tarObj->getState() != SceneObject_Normal){
    continue;
   }
  }

  stCircleParam param;
  param.pCircle1Pos = pos;
  param.fCircle1Radius = r;
  param.fCircle2Radius = tarObj->getActorConfig()->modelRadius;
  param.pCircle2Pos = tarObj->_pos;
  bool ret = intersactCircle(&param);
  HDEBUG_LOG("htest near getAITargetList circle1[%.2f, %.2f, r=%d] circle2[%.2f, %.2f], [ret=%d]",
   param.pCircle1Pos.x, param.pCircle1Pos.y, r, param.pCircle2Pos.x, param.pCircle2Pos.y, ret);
  if(ret){
   targetList.insert(tarObj);
  }
 }

 DEBUG_LOG("getAITargetList size :=%ld",targetList.size());

}

void Scene::getVisibleTargetList(Object *object, const SkillConfig *base, Vector2 &pos, uint32_t camp, std::set<Object *> &targetList)
{
 Vector2 spos;
 ObjMap x_set;
 ObjList::iterator iter;
 if(camp){
  targetList.insert(object);
 }
 if(base->release){
  spos   = pos;
 }else{
  spos   = object->_pos;
 }
 
 PkObject *castobj = (PkObject *)object;
 for(map<uint32_t, PkObject*>::iterator objIter = castobj->visible_map.begin(); objIter != castobj->visible_map.end(); objIter++){
  PkObject *tarObj =  (PkObject *)(objIter->second);
  switch(base->range){
   case eSkillcircle:{
     stCircleParam param;
     param.pCircle1Pos = spos;
     param.fCircle1Radius = base->radius;
     param.fCircle2Radius = 0;
     param.pCircle2Pos = tarObj->_pos;
     bool ret = intersactCircle(&param);
     if(ret) {
      insertTargetObj(castobj, tarObj, base->release, spos, base->radius, camp, targetList);
     }
    }
    break;
   case eSkillSector:{
     stSectorParam param;
     param.pSectorPos  = spos ;
        param.fSectorRotation   = tarObj->direct;
     param.fSectorAngle      = base->angle;
     param.fSectorRadius     = base->radius;
     param.pCirclePos  = tarObj->_pos;
     param.fCircleRadius  = 0.0;
     bool bret = intersactArc(&param);
     if (bret) {
      insertTargetObj(castobj, tarObj, base->release, spos, base->radius, camp, targetList);
     }
    }
    break;
   case eSkillLine:{
    #if 0
     stRectParam param;
     param.pSectorPos = castobj->_pos;
     Vector2 rotation = castobj->_pos - tarObj->_pos;
     param.fSectorAngle = angleWithYaxis(rotation);
     param.fRectWidth  = base->height;
     param.fRectLength = base->width;
     param.pCirclePos  = tarObj->_pos;
     param.fCircleRadius = 0;
     bool ret = intersactRectangle(&param);
     if(ret) {
      insertTargetObj(castobj, tarObj, base->release, spos, base->radius, camp, targetList);
     }
    #endif
#if 0 
    struct stMidRectParam
     {
      double  fRectWidth;
      double  fRectLength;
      Vector2 pMidPos;        //中心点位置
       Vector2 pFacePos;       //面向
       Vector2 pCirclePos;     //判断目标点
       double fCircleRadius;
     };
#endif
     stMidRectParam param;
     param.fRectWidth  = base->width;
     param.fRectLength = base->length;
     param.pMidPos     = castobj->_pos;
     param.pFacePos    = castobj->direct;
     param.pCirclePos  = tarObj->_pos;
     param.fCircleRadius = 0;
     DEBUG_LOG("搜索矩形区域 %d %d Mid[%.2f,%.2f], Face[%.2f,%.2f], Circle[%.2f,%.2f]",base->width,\
            base->length,  \
           castobj->_pos.x, \
           castobj->_pos.y, \
           castobj->direct.x, \
           castobj->direct.y, \
           tarObj->_pos.x,  \
           tarObj->_pos.y);
     bool ret = intersactMidRectangle(&param);
     if(ret){
      insertTargetObj(castobj, tarObj, base->release, spos, base->radius, camp, targetList);
     }

    }
    break;
    case eRectangle:{
#if 0
     stRectParam param;
     param.pSectorPos = spos;
     param.fSectorAngle = angleWithYaxis(castobj->direct);
     param.fRectWidth  = base->width;
     param.fRectLength = base->height;
     param.pCirclePos  = tarObj->_pos;
     param.fCircleRadius = 0;
     bool ret = intersactRectangle(&param);
     if(ret){
      insertTargetObj(castobj, tarObj, base->release, spos, base->radius, camp, targetList);
     }
#endif
     if(fabs(castobj->_pos.x - tarObj->_pos.x) < base->length && fabs(castobj->_pos.y - tarObj->_pos.y) < base->width){
      insertTargetObj(castobj, tarObj, base->release, spos, base->radius, camp, targetList);
     }
    }
    break;
   default:
    {
    }
  }
 }


}


void Scene::getNearObjList(Object *object, std::set<Object *> &obj_list, float distance)
{
   ObjMap x_set;
    ObjList::iterator iter;
 Vector2 spos;
 // iterator x-axis object list, x轴是从小到大顺序排列的
    if (object->x_pos != obj_x_list_.end()) {
        iter = object->x_pos;
        while (1) {
            ++iter;
            if (iter == obj_x_list_.end()) break;
   if ((*iter)->_pos.x - object->_pos.x > distance) break;
   float sqrtDist = (object->_pos - (*iter)->_pos).sqrtMagnitude();
   if (sqrtDist < distance) obj_list.insert(*iter);
        }
    }

    if (object->x_pos != obj_x_list_.begin())
 {
        iter = object->x_pos;
        while (1)
  {
            --iter;     
   if (object->_pos.x - (*iter)->_pos.x > distance) break;
   float sqrtDist = (object->_pos - (*iter)->_pos).sqrtMagnitude();
   if (sqrtDist < distance) obj_list.insert(*iter);
            if (iter == obj_x_list_.begin())break;
        }
    }
}

void Scene::GetRangeSet(Object *object, ObjMap *set) {
    ObjMap x_set;
    ObjList::iterator iter;
    int distance = DISTANCE;

    // iterator x-axis object list
    if (object->x_pos != obj_x_list_.end()) {
        iter = object->x_pos;
        while (1) {
            ++iter;
            if (iter == obj_x_list_.end()) {
                break;
            }
   if (debug_AOI)
    KDEBUG_LOG(object->id, "next-x: id-%u x-%f y-%f", (*iter)->id, (*iter)->_pos.x, (*iter)->_pos.y);
            //if (object->_pos.x - (*iter)->_pos.x > distance) {
            if ((*iter)->_pos.x - object->_pos.x > distance) {
                break;
            }
            x_set[(*iter)->id] = *iter;
        }
    }
    if (object->x_pos != obj_x_list_.begin()) {
        iter = object->x_pos;
        while (1) {
            --iter;
   if (debug_AOI)
    KDEBUG_LOG(object->id, "pre-x: id-%u x-%f y-%f", (*iter)->id, (*iter)->_pos.x, (*iter)->_pos.y);
             //if ((*iter)->_pos.x - object->_pos.x > distance) {
            if (object->_pos.x - (*iter)->_pos.x > distance) {
                break;
            }
            x_set[(*iter)->id] = *iter;
            if (iter == obj_x_list_.begin()) {
                break;
            }
        }
    }

    // iterator y-axis object list
    if (object->y_pos != obj_y_list_.end()) {
        iter = object->y_pos;
        while (1) {
            ++iter;
            if (iter == obj_y_list_.end()) {
                break;
            }
   if (debug_AOI)
    KDEBUG_LOG(object->id, "next-y: id-%u x-%f y-%f",(*iter)->id, (*iter)->_pos.x, (*iter)->_pos.y);
            //if (object->_pos.y - (*iter)->_pos.y > distance) {
            if ((*iter)->_pos.y - object->_pos.y > distance) {
                break;
            }
            if (x_set.find((*iter)->id) != x_set.end()) {
                (*set)[(*iter)->id] = *iter;
            }
        }
    }
    if (object->y_pos != obj_y_list_.begin()) {
        iter = object->y_pos;
        while (1) {
            --iter;
   if (debug_AOI)
    KDEBUG_LOG(object->id, "pre-y: id-%u x-%f y-%f", (*iter)->id, (*iter)->_pos.x, (*iter)->_pos.y);
   // modify by james
            //if ((*iter)->_pos.y - object->_pos.y > distance) {
            if ( object->_pos.y - (*iter)->_pos.y > distance) {
                break;
            }
            if (x_set.find((*iter)->id) != x_set.end()) {
                (*set)[(*iter)->id] = *iter;
            }
            if (iter == obj_y_list_.begin()) {
                break;
            }
        }
    }
}

void Scene::Leave(int id) {
 ObjMap::iterator obj_iter = obj_map_.find(id);
 if (obj_iter == obj_map_.end()) {
  return;
 }

 Object *object = obj_iter->second;
 //obj_map_.erase(object->id);
 object->setScene(NULL);

 DEBUG_LOG("Scene::Leave[id=%d ]", id);

 // get the leave set
 GetRangeSet(object, &leave_map_);
 Update(object);

 obj_x_list_.erase(object->x_pos);
 obj_y_list_.erase(object->y_pos);
 obj_map_.erase(object->id);
 if (object->type == Object_Player)
  role_map_.erase(object->id);

}


int Scene::pkg_all_base_tower()
{
 
 AllBaseInfoNotify allBaseInfoNotify;
 FOREACH(this->obj_map_, iter) {
  Object *temp = iter->second;
  if(temp->type == Object_NPC
   && ( temp->subtype == NpcType_Shop
   || temp->subtype == NpcType_Base
   || temp->subtype == NpcType_Tower
   )) {
   Npc* pk = (Npc*)temp; 
   npc_base_t* pnb = dynamic_cast<npc_base_t*>(pk->getActorConfig());
   if (!pnb) continue;
   AllBaseInfoNotify_Building* building = allBaseInfoNotify.add_building();
   building->set_id(pk->id);
   building->set_type(pk->subtype);
   building->set_npcid(pk->npcID);
   building->set_camp(pk->camp);
   building->set_x(pk->_pos.x);
   building->set_y(pk->_pos.y);
   building->set_dirx(pk->direct.x);
                        building->set_diry(pk->direct.y);
   building->set_hp(pk->propAbility[ehp]);
   building->set_hpmax(pk->propAbility[emax_hp]);
   building->set_level(pnb->level);
   HDEBUG_LOG("htest base BASE TOWER INFO[id=%u npcID:%u subtype:%u x=%f, y=%f]",
    pk->id, pk->npcID, pk->subtype, pk->_pos.x, pk->_pos.y);
   DEBUG_LOG("BASE TOWER INFO[id=%u npcID:%u subtype:%u x=%f, y=%f]",
    pk->id, pk->npcID, pk->subtype, pk->_pos.x, pk->_pos.y);
  }
 }
 int i = allBaseInfoNotify.ByteSize();
 allBaseInfoNotify.SerializeToArray(SEND_CLI_BUF, i);
 return i;
}


Vector2 Scene::getFhd(int camp)
{
 Vector2 pos(0,0);
 FOREACH(pConfig->m_fhd_map, itr) {
  if (itr->second.camp == camp)
   return itr->second.pos;
 }
 return pos; 
}

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值