一 应用:关心与某逻辑Obj的距离(用于商人或者任务窗口/下拉菜单等,当距离超过一定距离后自动关闭)
二 实现
1 首先注册lua接口
INT CUIWindowItem::LUA_CareObject(LuaPlus::LuaState
*
pState)
{
LuaStack args(pState);
if ( ! (args[ 2 ].IsInteger()))
{
KLThrow( " LUA: CUIWindowItem::LUA_CareObject[2] Wrong Param1 " );
}
if ( ! (args[ 3 ].IsInteger()))
{
KLThrow( " LUA: CUIWindowItem::LUA_CareObject[3] Wrong Param1 " );
}
if ( ! (args[ 4 ].IsString()))
{
KLThrow( " LUA: CUIWindowItem::LUA_CareObject[4] Wrong Param1 " );
}
// Object的ID
INT nObjID = args[ 2 ].GetInteger();
// 是否关心
INT bCare = args[ 3 ].GetInteger() == 1 ;
// 谁在关心
std:: string str = args[ 4 ].GetString();
g_pObjectSystem -> CareObject(nObjID, bCare, str);
return 0 ;
}
{
LuaStack args(pState);
if ( ! (args[ 2 ].IsInteger()))
{
KLThrow( " LUA: CUIWindowItem::LUA_CareObject[2] Wrong Param1 " );
}
if ( ! (args[ 3 ].IsInteger()))
{
KLThrow( " LUA: CUIWindowItem::LUA_CareObject[3] Wrong Param1 " );
}
if ( ! (args[ 4 ].IsString()))
{
KLThrow( " LUA: CUIWindowItem::LUA_CareObject[4] Wrong Param1 " );
}
// Object的ID
INT nObjID = args[ 2 ].GetInteger();
// 是否关心
INT bCare = args[ 3 ].GetInteger() == 1 ;
// 谁在关心
std:: string str = args[ 4 ].GetString();
g_pObjectSystem -> CareObject(nObjID, bCare, str);
return 0 ;
}
2 保存到map里面
//
关心某物体的指定事件 id-物体ID, szSign:关心标志(谁关心) bCare-关心或者取消关心
// 修改说明:添加一个“是谁关心”的内容
VOID CObjectManager::CareObject(INT id, BOOL bCare, std:: string szSign)
{
// AxTrace(0,0,"C++ id =%d,bCare =%d,szSign =%s",id,(INT)bCare,szSign.c_str());
// 搜索物体
CObject * pObject = (CObject * )FindObject(id);
if ( ! pObject) return ;
// 是否已经加入
std::map < std:: string , OBJECT_BECARED > ::iterator it;
it = m_mapCaredObject.find(szSign);
// 在表中已经有
if (it != m_mapCaredObject.end()) // && !bCare)
{
if (bCare)
{
// 这个界面已经有关心的NPC,去关心新的 Npc 就可以了,
it -> second.id = id;
}
else
{
// 取消关心的操作
m_mapCaredObject.erase(it);
}
}
// 在表中没有
if (it == m_mapCaredObject.end() && bCare)
{
OBJECT_BECARED objNewCared;
objNewCared.id = id;
objNewCared.fLastDistance = KLU_GetDist(fVector2(GetMySelf() -> GetPosition().x, GetMySelf() -> GetPosition().z),
fVector2(pObject -> GetPosition().x, pObject -> GetPosition().z));
m_mapCaredObject.insert(std::make_pair(szSign, objNewCared));
}
}
// 修改说明:添加一个“是谁关心”的内容
VOID CObjectManager::CareObject(INT id, BOOL bCare, std:: string szSign)
{
// AxTrace(0,0,"C++ id =%d,bCare =%d,szSign =%s",id,(INT)bCare,szSign.c_str());
// 搜索物体
CObject * pObject = (CObject * )FindObject(id);
if ( ! pObject) return ;
// 是否已经加入
std::map < std:: string , OBJECT_BECARED > ::iterator it;
it = m_mapCaredObject.find(szSign);
// 在表中已经有
if (it != m_mapCaredObject.end()) // && !bCare)
{
if (bCare)
{
// 这个界面已经有关心的NPC,去关心新的 Npc 就可以了,
it -> second.id = id;
}
else
{
// 取消关心的操作
m_mapCaredObject.erase(it);
}
}
// 在表中没有
if (it == m_mapCaredObject.end() && bCare)
{
OBJECT_BECARED objNewCared;
objNewCared.id = id;
objNewCared.fLastDistance = KLU_GetDist(fVector2(GetMySelf() -> GetPosition().x, GetMySelf() -> GetPosition().z),
fVector2(pObject -> GetPosition().x, pObject -> GetPosition().z));
m_mapCaredObject.insert(std::make_pair(szSign, objNewCared));
}
}
3 Tick遍历
VOID CObjectManager::Tick(VOID)
{
// 检查是否有物体不再被关心
if (CGameProcedure::GetActiveProcedure() == CGameProcedure::s_pProcMain)
m_pLogicalObject -> Tick_CheckAlive();
// 执行逻辑函数
m_pLogicalObject -> Tick();
// 检查被UI关心的逻辑对象
std::map < std:: string , OBJECT_BECARED > ::iterator it;
for (it = m_mapCaredObject.begin(); it != m_mapCaredObject.end(); it ++ )
{
OBJECT_BECARED & obj = it -> second;
// 物体是否存在
CObject * pObject = (CObject * )FindObject(obj.id);
if ( ! pObject)
{
KLAssert( false && " Careobject error find! " );
continue ;
}
// 计算目前的距离
FLOAT fDistance = KLU_GetDist( fVector2(GetMySelf() -> GetPosition().x, GetMySelf() -> GetPosition().z),
fVector2(pObject -> GetPosition().x, pObject -> GetPosition().z));
float fStep = abs(fDistance - obj.fLastDistance);
if (fStep > 0.001 )
{
// 距离发生改变,产生事件
std::vector < STRING > vParam;
CHAR szTemp[MAX_PATH];
_snprintf(szTemp, MAX_PATH, " %d " , pObject -> GetID());
vParam.push_back(szTemp);
vParam.push_back( " distance " );
_snprintf(szTemp, MAX_PATH, " %.3f " , fDistance);
vParam.push_back(szTemp);
CEventSystem::GetMe() -> PushEvent(GE_OBJECT_CARED_EVENT, vParam);
}
obj.fLastDistance = fDistance;
}
// 加载队列工作
if (m_pLoadQueue)
{
m_pLoadQueue -> Tick();
}
// 删除队列
if (m_pDestoryQueue)
{
m_pDestoryQueue -> Tick();
}
}
{
// 检查是否有物体不再被关心
if (CGameProcedure::GetActiveProcedure() == CGameProcedure::s_pProcMain)
m_pLogicalObject -> Tick_CheckAlive();
// 执行逻辑函数
m_pLogicalObject -> Tick();
// 检查被UI关心的逻辑对象
std::map < std:: string , OBJECT_BECARED > ::iterator it;
for (it = m_mapCaredObject.begin(); it != m_mapCaredObject.end(); it ++ )
{
OBJECT_BECARED & obj = it -> second;
// 物体是否存在
CObject * pObject = (CObject * )FindObject(obj.id);
if ( ! pObject)
{
KLAssert( false && " Careobject error find! " );
continue ;
}
// 计算目前的距离
FLOAT fDistance = KLU_GetDist( fVector2(GetMySelf() -> GetPosition().x, GetMySelf() -> GetPosition().z),
fVector2(pObject -> GetPosition().x, pObject -> GetPosition().z));
float fStep = abs(fDistance - obj.fLastDistance);
if (fStep > 0.001 )
{
// 距离发生改变,产生事件
std::vector < STRING > vParam;
CHAR szTemp[MAX_PATH];
_snprintf(szTemp, MAX_PATH, " %d " , pObject -> GetID());
vParam.push_back(szTemp);
vParam.push_back( " distance " );
_snprintf(szTemp, MAX_PATH, " %.3f " , fDistance);
vParam.push_back(szTemp);
CEventSystem::GetMe() -> PushEvent(GE_OBJECT_CARED_EVENT, vParam);
}
obj.fLastDistance = fDistance;
}
// 加载队列工作
if (m_pLoadQueue)
{
m_pLoadQueue -> Tick();
}
// 删除队列
if (m_pDestoryQueue)
{
m_pDestoryQueue -> Tick();
}
}
4 事件触发通过event实现,具体以后再分析
5 lua响应,主要是关闭界面
elseif (
event
==
"
OBJECT_CARED_EVENT
"
) then
if (tonumber(arg0) ~= objCared) then
return ;
end
-- 如果和NPC的距离大于一定距离或者被删除,自动关闭
if ( arg1 == " distance " and tonumber(arg2) > MAX_OBJ_DISTANCE or arg1 == " destroy " ) then
-- if ( arg1 == " destroy " ) then
ContexMenu_HideAll();
this :Hide();
-- 取消关心
this :CareObject( objCared, 0 , " ContexMenu " );
end
elseif( event == " COLSE_SECOND_MENU " ) then
if ( this :IsVisible() )then
ContexMenu_HideAll();
this :Hide();
end
elseif( event == " PK_MODE_CHANGED " ) then
tempPKMode = Player:GetCurrentPKMode();
if tempPKMode ~= currentPKMode then
currentPKMode = tempPKMode;
PushDebugMessage(PKModeName[currentPKMode]);
end
elseif( event == " ALLOCATION_MODE_CHANGED " ) then
tempAcMode = tonumber(arg0);
if tempAcMode ~= currentAlloCationMode then
currentAlloCationMode = tempAcMode;
end
if (tonumber(arg0) ~= objCared) then
return ;
end
-- 如果和NPC的距离大于一定距离或者被删除,自动关闭
if ( arg1 == " distance " and tonumber(arg2) > MAX_OBJ_DISTANCE or arg1 == " destroy " ) then
-- if ( arg1 == " destroy " ) then
ContexMenu_HideAll();
this :Hide();
-- 取消关心
this :CareObject( objCared, 0 , " ContexMenu " );
end
elseif( event == " COLSE_SECOND_MENU " ) then
if ( this :IsVisible() )then
ContexMenu_HideAll();
this :Hide();
end
elseif( event == " PK_MODE_CHANGED " ) then
tempPKMode = Player:GetCurrentPKMode();
if tempPKMode ~= currentPKMode then
currentPKMode = tempPKMode;
PushDebugMessage(PKModeName[currentPKMode]);
end
elseif( event == " ALLOCATION_MODE_CHANGED " ) then
tempAcMode = tonumber(arg0);
if tempAcMode ~= currentAlloCationMode then
currentAlloCationMode = tempAcMode;
end
end