하아찡
[C++] 몬스터 움직임 - 2 본문
언리얼 버전 5.5.3
서버언어 C++로 구성했습니다.
실행화면
문제점.
도착좌표를 저장하고 몬스터 그리드에 넣다보닌깐 클라이언트 상에서는 몬스터가 해당 좌표에없지만 서버에는 해당 좌표에 있다고 처리돼서 몬스터가 맞는 처리가 됨.
해결 : 서버에서 움직임 처리를 해줌. 0.1초마다 몬스터 위치를 갱신해줌.
몬스터 객체에다가 도착지 위치를 따로 저장시켜 위치값을 계속 갱신시킴.
SendBufferRef Monster::ServerMove(MonsterRef monster, float deltaTime)
{
uint64 spawnerID = monster->SpawnerID;
Vector3 NowPos(monster->objectInfo->posinfo().x(), monster->objectInfo->posinfo().y(), monster->objectInfo->posinfo().z());
Vector3 DestPos(monster->movePosInfo->x(), monster->movePosInfo->y(), monster->movePosInfo->z());
Vector3 Direction = (DestPos - NowPos).GetSafeNormal();
Vector3 NewPosition = NowPos + (Direction * monster->objectInfo->speed() * deltaTime);
Protocol::S_MOVE pkt;
Protocol::PosInfo* pos = pkt.mutable_posinfo();
pos->CopyFrom(monster->objectInfo->posinfo());
pos->set_x(NewPosition.X);
pos->set_y(NewPosition.Y);
pos->set_movestate(Protocol::MOVE_STATE_RUN);
//서버도 똑같이 이동된 좌표값을 가지게함.
monster->posInfo->set_x(NewPosition.X);
monster->posInfo->set_y(NewPosition.Y);
monster->posInfo->set_movestate(Protocol::MOVE_STATE_RUN);
// 해당위치 도착
float Dist = monster->Distance2D(DestPos.X, DestPos.Y);
if (Dist <= 30.0f)
{
pos->set_x(DestPos.X);
pos->set_y(DestPos.Y);
monster->posInfo->set_x(NewPosition.X);
monster->posInfo->set_y(NewPosition.Y);
if (monster->GetState() == MonsterState::MOVE) {
monster->posInfo->set_movestate(Protocol::MOVE_STATE_IDLE);
pos->set_movestate(Protocol::MOVE_STATE_IDLE);
monster->SetState(MonsterState::IDLE);
monster->bmovePos = false;; // 이동 중지
}
}
SendBufferRef sendBuffer = ClientPacketHandler::MakeSendBuffer(pkt);
return sendBuffer;
}
Room.cpp
void Room::ProcessMonster()
{
for (auto item : _monsters) {
if(item.second == nullptr) continue;
MonsterRef monster = item.second;
MonsterState monsterState = monster->GetState();
if (monsterState == MonsterState::IDLE || monsterState == MonsterState::MOVE) {
// TODO 대기상태이거나 움직이는중일때만 몬스터 어그로 가능
float x = _levelMonsterSpawnLocation[monster->SpawnerID].x;
float y = _levelMonsterSpawnLocation[monster->SpawnerID].x;
float AggroRange = monster->GetAggroRange();
int searchRange = std::ceil(AggroRange / GRID_SIZE); // 서치범위
for (auto playerid : GetNearbyPlayers(x, y, searchRange))
{
ObjectRef player = _objects[playerid];
if(!player) continue;
if (monster->Distance2D(player->posInfo->x(), player->posInfo->y()) > AggroRange)
continue;
// TODO 해당 몬스터 근처에 사람검색 일단은 바로 잡힌사람으로 어그로
monster->SetTarget(playerid);
break; // 지금은 처음잡은사람 바로 나감
}
}
else if(monsterState == MonsterState::AGGRO || monsterState == MonsterState::ATTACK)
{
// TODO 어그로 상태이거나 공격상태일때만 확인 스폰위치에서 타겟이 거리를 벗어나면 어그로 잃음
uint64 spawnerID = monster->SpawnerID;
float x = _levelMonsterSpawnLocation[spawnerID].x;
float y = _levelMonsterSpawnLocation[spawnerID].y;
//Vector3 SpawnerVector(x, y, 0);
float AggroRange = monster->GetAggroRange();
uint64 TargetID = monster->GetTarget();
if (TargetID == 0) {
// TODO 타겟아이디값이없는데 상태값이 이상함으로 상태값을 돌려줌
monster->LostTarget();
}
}
if (monsterState != MonsterState::ATTACK)
{
// 일단 움직여
SendMonsterMove(monster);
}
}
}
void Room::SendMonsterMove(MonsterRef monster)
{
if (monster == nullptr) return;
uint64 objectid = monster->objectInfo->object_id();
// 움직이기전 그리드 데이터를 삭제
RemoveMonsterToGrid(objectid, monster->posInfo->x(), monster->posInfo->y());
if (monster->GetState() == MonsterState::AGGRO)
{
ObjectRef object = _objects[monster->GetTarget()];
if (object != nullptr) {
// 몬스터 어글자 위치 설정
monster->SetDestPos(monster, _objects[monster->GetTarget()]);
if (object->Distance2D(_levelMonsterSpawnLocation[monster->SpawnerID].x, _levelMonsterSpawnLocation[monster->SpawnerID].y) >= monster->GetAggroRange()) {
// 어그로 범위를 벗어남
monster->LostTarget();
}
else {
// 어그로 범위 안에있을경우 움직임
Broadcast(monster->ServerMove(monster, (updateTick / (float)1000)), NotObjectID);
}
}
else {
monster->LostTarget();
}
}
else
{
if (monster->bmovePos)
{
// 몬스터 움직임 예상
Broadcast(monster->ServerMove(monster, (updateTick / (float)1000)), NotObjectID);
}
else {
// 몬스어 어슬렁어슬렁 위치 설정
monster->SetDestPos(monster, _levelMonsterSpawnLocation);
}
}
//움직인 후 위치 값을 그리드 데이터에 추가
AddMonsterToGrid(objectid, monster->posInfo->x(), monster->posInfo->y());
}
이것저것 생각해보고 해보고 했는데 제가 생각하기에 최선의 방법이라고 생각해서 작성해봤습니다...
더 좋은 방법이있다면, 가르침을 주신다면 감사하겠습니다...(너무 많은일이 있었어요...)
반응형
'C++ > 이것저것서버테스트' 카테고리의 다른 글
[C++] 몬스터 정보, 아이템 정보 XML에서 불러오기 (0) | 2025.03.22 |
---|---|
[C++] 서버 DB업로드 (1) | 2025.03.20 |
[언리얼5] 마지막 종료지점 저장 (0) | 2025.03.12 |
[언리얼5, C++] 몬스터 어그로 (0) | 2025.03.12 |
[언리얼5, C++] 몬스터 움직임 (0) | 2025.03.06 |