public Vector2int GetFrontCellPos(MoveDir dir) { Vector2int cellPos = CellPos; switch (dir) { case MoveDir.Up: cellPos += Vector2int.up; break; case MoveDir.Down: cellPos += Vector2int.down; break; case MoveDir.Left: cellPos += Vector2int.left; break; case MoveDir.Right: cellPos += Vector2int.right; break; } return(cellPos); }
public bool ApplyMove(GameObject gameObject, Vector2int dest) { ApplyLeave(gameObject); if (gameObject.Room == null) { return(false); } if (gameObject.Room._Map != this) { return(false); } PositionInfo posinfo = gameObject.PosInfo; if (CanGo(dest, true) == false) { return(false); } { int x = dest.x - MinX; int y = MaxY - dest.y; _objects[y, x] = gameObject; } // 실제 좌표 이동 posinfo.PosX = dest.x; posinfo.PosY = dest.y; return(true); }
protected virtual void UpdateSkill() { if (_coolTick == 0) { // 유효한 타겟 if (_target == null || _target.Room != Room || _target.HP <= 0) { _target = null; State = CreatureState.Moving; BroadCastMove(); return; } // 스킬이 아직 사용 가능한지 Vector2int dir = (_target.CellPos - CellPos); int dist = dir.cellDistFromZero; bool canUseSkill = (dist <= _skillRange && (dir.x == 0 || dir.y == 0)); if (canUseSkill == false) { State = CreatureState.Moving; BroadCastMove(); return; } // 타게팅 방향 주시 MoveDir lookDir = GetDirFromVec(dir); if (Dir != lookDir) { Dir = lookDir; BroadCastMove(); } SKill skilldata = null; DataManager.SkillDict.TryGetValue(1, out skilldata); // 데미지 판정 _target.OnDamaged(this, skilldata.damage + Stat.Attack); // 스킬 사용 BroadCast S_Skill skillPacket = new S_Skill() { Info = new SKillInfo() }; skillPacket.ObjectId = Id; skillPacket.Info.Skillid = skilldata.id; Room.BroadCast(skillPacket); // 스킬 쿨타임 적용 int coolTick = (int)(1000 * skilldata.cooldown); _coolTick = Environment.TickCount64 + coolTick; } if (_coolTick > Environment.TickCount64) { return; } _coolTick = 0; }
protected virtual void UpdateMoving() { if (_nextMoveTick > Environment.TickCount64) { return; } int moveTick = (int)(1000 / Speed); _nextMoveTick = Environment.TickCount64 + moveTick; if (_target == null || _target.Room != Room) { _target = null; State = CreatureState.Idle; BroadCastMove(); return; } Vector2int dir = _target.CellPos - CellPos; int dist = dir.cellDistFromZero; if (dist == 0 || dist > _chaseCellDist) { _target = null; State = CreatureState.Idle; BroadCastMove(); return; } List <Vector2int> path = Room._Map.FindPath(CellPos, _target.CellPos, checkObjects: false); if (path.Count < 2 || path.Count > _chaseCellDist) { _target = null; State = CreatureState.Idle; BroadCastMove(); return; } // 스킬로 넘어갈지 체크 if (dist <= _skillRange && (dir.x == 0 || dir.y == 0)) { _coolTick = 0; State = CreatureState.Skill; return; } // 이동 Dir = GetDirFromVec(path[1] - CellPos); Room._Map.ApplyMove(this, path[1]); BroadCastMove(); }
public override void Update() { if (Data == null || Owner == null || Room == null) { return; } if (Data.projectile == null) { return; } if (_nextMoveTick >= Environment.TickCount64) { return; } long tick = (long)(1000 / Data.projectile.speed); _nextMoveTick = Environment.TickCount64 + tick; Vector2int destPos = GetFrontCellPos(); if (Room._Map.CanGo(destPos)) { CellPos = destPos; S_Move movePacket = new S_Move(); movePacket.ObjectId = Id; movePacket.PosInfo = PosInfo; Room.BroadCast(movePacket); Console.WriteLine("Move Arrow"); } else { GameObject target = Room._Map.Find(destPos); if (target != null) { // 피격 판정 target.OnDamaged(this, Data.damage + Owner.Stat.Attack); //Console.WriteLine($"damage : {Data.damage}"); } // 소멸 Room.Push(Room.LeaveGame, Id); } }
public GameObject Find(Vector2int cellPos) { if (cellPos.x < MinX || cellPos.x > MaxX) { return(null); } if (cellPos.y < MinY || cellPos.y > MaxY) { return(null); } int x = cellPos.x - MinX; int y = MaxY - cellPos.y; return(_objects[y, x]); }
public bool CanGo(Vector2int cellPos, bool bCheckObjects = true) { if (cellPos.x < MinX || cellPos.x > MaxX) { return(false); } if (cellPos.y < MinY || cellPos.y > MaxY) { return(false); } int x = cellPos.x - MinX; int y = MaxY - cellPos.y; return(!_collision[y, x] && (!bCheckObjects || _objects[y, x] == null)); }
public static MoveDir GetDirFromVec(Vector2int dir) { if (dir.x > 0) { return(MoveDir.Right); } else if (dir.x < 0) { return(MoveDir.Left); } else if (dir.y > 0) { return(MoveDir.Up); } else { return(MoveDir.Down); } }
protected virtual void UpdateIdle() { if (_nextSearchTick > Environment.TickCount64) { return; } _nextSearchTick = Environment.TickCount64 + 1000; Player target = Room.FindPlayer(p => { Vector2int dir = p.CellPos - CellPos; return(dir.cellDistFromZero <= _searchCellDist); }); if (target == null) { return; } _target = target; State = CreatureState.Moving; }
public void HandleSkill(Player player, C_Skill skillPacket) { if (player == null) { return; } // 일단 서버에서 좌표 이동 ObjectInfo info = player.Info; if (info.PosInfo.State != CreatureState.Idle) { return; } // 스킬 사용 가능 여부 체크 info.PosInfo.State = CreatureState.Skill; S_Skill skill = new S_Skill() { Info = new SKillInfo() }; skill.ObjectId = info.ObjectId; skill.Info.Skillid = skillPacket.Info.Skillid; BroadCast(skill); Data.SKill SkillData = null; if (DataManager.SkillDict.TryGetValue(skillPacket.Info.Skillid, out SkillData) == false) { return; } switch (SkillData.skillType) { case SkillType.SkillAuto: { // 데미지 판정 Vector2int skillPos = player.GetFrontCellPos(info.PosInfo.Movedir); GameObject target = _Map.Find(skillPos); if (target != null) { Console.WriteLine("Hit GameObject!"); } } break; case SkillType.SkillProjectile: { // 화살 스킬 Arrow arrow = ObjectManager.Instance.Add <Arrow>(); if (arrow == null) { return; } arrow.Owner = player; arrow.Data = SkillData; arrow.PosInfo.State = CreatureState.Moving; arrow.PosInfo.Movedir = player.PosInfo.Movedir; arrow.PosInfo.PosX = player.PosInfo.PosX; arrow.PosInfo.PosY = player.PosInfo.PosY; arrow.Speed = SkillData.projectile.speed; Push(EnterGame, arrow); } break; } }
Pos Cell2Pos(Vector2int cell) { // CellPos -> ArrayPos return(new Pos(MaxY - cell.y, cell.x - MinX)); }
public List <Vector2int> FindPath(Vector2int startCellPos, Vector2int destCellPos, bool checkObjects = true) { List <Pos> path = new List <Pos>(); // 점수 매기기 // F = G + H // F = 최종 점수 (작을 수록 좋음, 경로에 따라 달라짐) // G = 시작점에서 해당 좌표까지 이동하는데 드는 비용 (작을 수록 좋음, 경로에 따라 달라짐) // H = 목적지에서 얼마나 가까운지 (작을 수록 좋음, 고정) // (y, x) 이미 방문했는지 여부 (방문 = closed 상태) bool[,] closed = new bool[SizeY, SizeX]; // CloseList // (y, x) 가는 길을 한 번이라도 발견했는지 // 발견X => MaxValue // 발견O => F = G + H int[,] open = new int[SizeY, SizeX]; // OpenList for (int y = 0; y < SizeY; y++) { for (int x = 0; x < SizeX; x++) { open[y, x] = Int32.MaxValue; } } Pos[,] parent = new Pos[SizeY, SizeX]; // 오픈리스트에 있는 정보들 중에서, 가장 좋은 후보를 빠르게 뽑아오기 위한 도구 PriorityQueue <PQNode> pq = new PriorityQueue <PQNode>(); // CellPos -> ArrayPos Pos pos = Cell2Pos(startCellPos); Pos dest = Cell2Pos(destCellPos); // 시작점 발견 (예약 진행) open[pos.Y, pos.X] = 10 * (Math.Abs(dest.Y - pos.Y) + Math.Abs(dest.X - pos.X)); pq.Push(new PQNode() { F = 10 * (Math.Abs(dest.Y - pos.Y) + Math.Abs(dest.X - pos.X)), G = 0, Y = pos.Y, X = pos.X }); parent[pos.Y, pos.X] = new Pos(pos.Y, pos.X); while (pq.Count > 0) { // 제일 좋은 후보를 찾는다 PQNode node = pq.Pop(); // 동일한 좌표를 여러 경로로 찾아서, 더 빠른 경로로 인해서 이미 방문(closed)된 경우 스킵 if (closed[node.Y, node.X]) { continue; } // 방문한다 closed[node.Y, node.X] = true; // 목적지 도착했으면 바로 종료 if (node.Y == dest.Y && node.X == dest.X) { break; } // 상하좌우 등 이동할 수 있는 좌표인지 확인해서 예약(open)한다 for (int i = 0; i < _deltaY.Length; i++) { Pos next = new Pos(node.Y + _deltaY[i], node.X + _deltaX[i]); // 유효 범위를 벗어났으면 스킵 // 벽으로 막혀서 갈 수 없으면 스킵 if (next.Y != dest.Y || next.X != dest.X) { if (CanGo(Pos2Cell(next), checkObjects) == false) // CellPos { continue; } } // 이미 방문한 곳이면 스킵 if (closed[next.Y, next.X]) { continue; } // 비용 계산 int g = 0; // node.G + _cost[i]; int h = 10 * ((dest.Y - next.Y) * (dest.Y - next.Y) + (dest.X - next.X) * (dest.X - next.X)); // 다른 경로에서 더 빠른 길 이미 찾았으면 스킵 if (open[next.Y, next.X] < g + h) { continue; } // 예약 진행 open[dest.Y, dest.X] = g + h; pq.Push(new PQNode() { F = g + h, G = g, Y = next.Y, X = next.X }); parent[next.Y, next.X] = new Pos(node.Y, node.X); } } return(CalcCellPathFromParent(parent, dest)); }