private void Awake() { Messaging.Player.Position.AddListener((v) => { Vec2I g = TheGrid.GridPosition(v); if (lastPlayerGridPosition == g) { return; } lastPlayerGridPosition = g; int gridDistance = Vec2I.Max(g, TheGrid.GridPosition(transform.position)); if (gridDistance <= ShowTextDistance) { if (floatingText == null) { floatingText = Messaging.GUI.FloatingText(transform.position + Offset, ShowText, TextColorFar); } floatingText.color = gridDistance <= UseDistance ? TextColorClose : TextColorFar; } else if (floatingText != null && gridDistance > ShowTextDistance) { Destroy(floatingText.gameObject); floatingText = null; } }); }
private void OnInputRequest(ref MonsterCharacter.InputFrame frame) { if (target == null) return; if (dualSwingTimer > 0f) dualSwingTimer -= Time.deltaTime; frame.LocalTransform = true; int steps = Vec2I.Max(thing.gridPos, target.thingController.gridPos); if (steps <= MaxAttackConsiderationStepCount) { frame.WantDirection = TowardsTarget; if (character.CurrentWeapon.IsReady && character.CurrentOffhand.IsReady) { if (Random.value > .5f) frame.PrimaryAttackContinuous = true; else frame.SecondaryAttackContinuous = true; dualSwingTimer = DualSwingDelay; } else if (dualSwingTimer <= 0f) { frame.PrimaryAttackContinuous = true; frame.SecondaryAttackContinuous = true; } frame.up = 1f; return; } if (CanSeeTargetGrid) { frame.WantDirection = TowardsTarget; if (steps > StopMovingStepCount) frame.up = 1f; return; } Vec2I smart = SmartMove; if (SmartMove != Vec2I.zero) { frame.WantDirection = Quaternion.Euler(0, 0, AxMath.SafeAtan2(smart.y, smart.x) * Mathf.Rad2Deg); if (steps > StopMovingStepCount) frame.up = 1; } }
//returns best step direction towards target public static int RogueDirection(Vec2I origo, Vec2I target) { if (origo.x == target.x && origo.y == target.y) { return(0); } Vec2I d = target - origo; int dx = Mathf.Abs(d.x); int dy = Mathf.Abs(d.y); return(Vec2I.Max(origo, target) / 2 >= Mathf.Abs(dx - dy) ? (d.x > 0 ? (d.y > 0 ? 6 : 4) : (d.y > 0 ? 8 : 2)) : (dx > dy ? (d.x > 0 ? 5 : 1) : (d.y > 0 ? 7 : 3))); }
public void Use(MonsterCharacter caller) { if (AllowOnlyPlayer) { if (caller.GetComponent <PlayerControls>() == null) { return; } } if (Vec2I.Max(TheGrid.GridPosition(caller.transform.position), TheGrid.GridPosition(transform.position)) > UseDistance) { return; } OnUse.Invoke(caller); AfterUse.Invoke(); }
private void FillInputFrame(ref MonsterCharacter.InputFrame frame) { frame.up = dir.y; frame.right = dir.x; frame.WantDirection = Quaternion.Euler(0, 0, AxMath.SafeAtan2(dir.y, dir.x) * Mathf.Rad2Deg); if (timer > 0f) { return; } timer = DecisionTime; dir = Vector2.zero; Mouse.UpdateWorldPosition(); if (Mouse.InWorld) { if (Mouse.GridPosition != lastMouseGrid) { Vec2I a = thing.gridPos; Vec2I b = Mouse.GridPosition; if (AI.GetPath(a, b, Vec2I.Max(a, b), out Vec2I[] path))
private void MoveOut(ref MonsterCharacter.InputFrame frame) { if (target != null) { character.OnInputRequest = Hesitate; return; } if (PlayerTooFar) { character.OnInputRequest = StandAround; } if (moveTarget != Vec2I.illegalMin) { Vector2 dif = TheGrid.WorldPosition(moveTarget) - (Vector2)transform.position; if (dif != Vector2.zero) { dir = dif.normalized; } frame.up = dir.y; frame.right = dir.x; if (LookAtMoveDir) { lookDir = dir; } frame.WantDirection = Quaternion.Euler(0, 0, AxMath.SafeAtan2(lookDir.y, lookDir.x) * Mathf.Rad2Deg); } if (decisionTimer > 0f) { decisionTimer -= Time.deltaTime; return; } decisionTimer = Random.Range(DecisionInterval.x, DecisionInterval.y); LookAtMoveDir = Random.value < LookAtMoveDirChance; if (targetRoom < 0 || targetRoom >= Room.Rooms.Length) { return; } Room room = Room.Rooms[targetRoom]; if (Vec2I.Max(room.gridPos, thing.gridPos) < 3) { if (MissionObjective == 0) { Messaging.GUI.CommsMessage.Invoke(0, OnExitMessagePortrait, OnExitMessage); MissionObjective++; Messaging.Mission.MissionStatus.Invoke(true); } Instantiate(TeleportEffect, transform.position, Quaternion.identity, LevelLoader.TemporaryObjects); Destroy(gameObject); } if (!AI.RoomPath(thing.gridPos, room, MaxSteps, out Vec2I[] path))
private void OnInputRequest(ref MonsterCharacter.InputFrame frame) { if (target == null) { return; } frame.WantDirection = TowardsTarget; if (character.ChargePoints >= MinChargePointsForSkill) { if (character.Skills.Length > 0) { if (character.Skills[0] != null) { if (character.SkillCooldowns[0] <= 0f) { if (CanSeeTargetGrid) { character.Skills[0].Activate(character, 0); } } } } } if (dualSwingTimer > 0f) { dualSwingTimer -= Time.deltaTime; } int steps = Vec2I.Max(thing.gridPos, target.thingController.gridPos); if (steps <= MaxAttackConsiderationStepCount) { if (character.CurrentWeapon.IsReady && character.CurrentOffhand.IsReady) { if (Random.value > .5f) { frame.PrimaryAttackContinuous = true; } else { frame.SecondaryAttackContinuous = true; } dualSwingTimer = DualSwingDelay; } else if (dualSwingTimer <= 0f) { frame.PrimaryAttackContinuous = true; frame.SecondaryAttackContinuous = true; } } frame.LocalTransform = false; if (chargeTimer > 0f) { if (AngleToTarget(target.transform.position) > MaxChargeAngle) { chargeTimer = 0f; } frame.LocalTransform = true; chargeTimer -= Time.deltaTime; frame.up = 1f; character.walkSpeed = RunSpeed; character.TurnSpeed = RunTurnSpeed; return; } if (chargeCooldownTimer > 0f) { chargeCooldownTimer -= Time.deltaTime; } character.walkSpeed = walkSpeed; character.TurnSpeed = walkTurnSpeed; float distanceSqr = (target.transform.position - transform.position).sqrMagnitude; if (steps > StopMovingStepCount) { if (chargeCooldownTimer <= 0f) { if (distanceSqr >= StopRange * StopRange && distanceSqr <= RunRange * RunRange) { if (AngleToTarget(target.transform.position) <= MaxChargeAngle) { if (CanSeeTargetGrid) { chargeTimer = ChargeTime; chargeCooldownTimer = ChargeCooldown; return; } } } } } if (hesitateTimer > 0f) { hesitateTimer -= Time.deltaTime; return; } if (Random.value < IdleChance) { frame.up = 0; frame.right = 0; hesitateTimer = Random.Range(IdleTime.x, IdleTime.y); return; } if (Random.value < RandomMoveChance) { float a = Random.value * Mathf.PI * 2f; frame.right = Mathf.Cos(a); frame.up = Mathf.Sin(a); return; } //path find to target { Vec2I smart = SmartMove; frame.up = smart.y; frame.right = smart.x; } }
public static bool GetPath(Vec2I StartPos, Vec2I EndPos, int maxDistance, out Vec2I[] path) { if (StartPos == EndPos) { path = new Vec2I[1]; path[0] = EndPos; return(true); } path = null; if (Vec2I.Max(StartPos, EndPos) > maxDistance) { return(false); } if (Heatmap.GetNode(EndPos) == null) { return(false); } HeatmapNode startNode = Heatmap.GetNode(StartPos); if (startNode == null) { return(false); } //init arrays int arraySize = maxDistance * 2 + 1; bool[,] closedCheck = new bool[arraySize, arraySize]; bool[,] openCheck = new bool[arraySize, arraySize]; Vec2I[,] parent = new Vec2I[arraySize, arraySize]; PathStep[,] openArray = new PathStep[arraySize, arraySize]; //set start point BinaryHeap <PathStep> openList = new BinaryHeap <PathStep>(arraySize * arraySize); openList.Add(new PathStep(startNode, Heuristic(StartPos, EndPos))); openCheck[maxDistance, maxDistance] = true; parent[maxDistance, maxDistance] = StartPos; bool found = false; while (openList.ItemCount > 0) { //get top of heap PathStep current = openList.RemoveFirst(); int cx = current.node.gridPos.x - StartPos.x + maxDistance; int cy = current.node.gridPos.y - StartPos.y + maxDistance; closedCheck[cx, cy] = true; foreach (HeatmapNode neighbor in current.node.neighbors) { //calculate array position int nx = neighbor.gridPos.x - StartPos.x + maxDistance; int ny = neighbor.gridPos.y - StartPos.y + maxDistance; //cull disallowed if (Vec2I.Max(neighbor.gridPos, StartPos) > maxDistance) { continue; } if (closedCheck[nx, ny]) { continue; } if (!CanTravel(current.node, neighbor)) { continue; } //found target if (neighbor.gridPos == EndPos) { parent[nx, ny] = current.node.gridPos; found = true; goto finalize; } //calculate cost int travelCost = current.travelCost + TravelCostAstar(current.node, neighbor); int heuristic = Heuristic(neighbor.gridPos, EndPos); int fullCost = travelCost + heuristic; //check if we can update parent to better if (openCheck[nx, ny]) { if (openArray[nx, ny].fullCost > fullCost) { openArray[nx, ny].travelCost = travelCost; openArray[nx, ny].heuristic = heuristic; openArray[nx, ny].fullCost = fullCost; parent[nx, ny] = current.node.gridPos; openList.UpdateItem(openArray[nx, ny]); continue; } else { continue; } } //priority sorted by heap PathStep step = new PathStep(neighbor, travelCost, heuristic); openList.Add(step); openArray[nx, ny] = step; openCheck[nx, ny] = true; parent[nx, ny] = current.node.gridPos; } } finalize: if (found) { SingleLinkedList <Vec2I> list = new SingleLinkedList <Vec2I>(); Vec2I current = EndPos; while (current != StartPos) { list.InsertFront(current); current = parent[current.x - StartPos.x + maxDistance, current.y - StartPos.y + maxDistance]; } list.InsertFront(current); //adds the starting point to the path path = list.ToArray(); return(true); } return(false); }
public static void FillBreath(HeatmapNode startNode, ref BreathArea breath) { int maxDistance = breath.maxDistance; int arraySize = breath.size; //start sanity check if (startNode == null) { return; } if (startNode.neighbors.Count == 0) { return; } breath.startPos = startNode.gridPos; breath.Invalidate(); //init arrays bool[,] closedCheck = new bool[arraySize, arraySize]; bool[,] openCheck = new bool[arraySize, arraySize]; PathStep[,] openArray = new PathStep[arraySize, arraySize]; //set start point BinaryHeap <PathStep> openList = new BinaryHeap <PathStep>(arraySize * arraySize); openList.Add(new PathStep(startNode, 0)); openCheck[maxDistance, maxDistance] = true; //add start breath to area breath.exist[maxDistance, maxDistance] = true; breath.steps[maxDistance, maxDistance] = 0; breath.travelCost[maxDistance, maxDistance] = 0; breath.parent[maxDistance, maxDistance] = breath.startPos; while (openList.ItemCount > 0) { //get top of heap PathStep current = openList.RemoveFirst(); int cx = current.node.gridPos.x - breath.startPos.x + maxDistance; int cy = current.node.gridPos.y - breath.startPos.y + maxDistance; int currentCost = breath.travelCost[cx, cy]; int currentSteps = breath.steps[cx, cy]; closedCheck[cx, cy] = true; if (currentSteps >= maxDistance) { continue; } //shuffle the neighbor nodes to give some noise List <HeatmapNode> shuffled = new List <HeatmapNode>(); foreach (HeatmapNode neighbor in current.node.neighbors) { shuffled.Insert(Random.Range(0, shuffled.Count), neighbor); } foreach (HeatmapNode neighbor in shuffled) { //calculate array position int nx = neighbor.gridPos.x - breath.startPos.x + maxDistance; int ny = neighbor.gridPos.y - breath.startPos.y + maxDistance; //cull disallowed if (Vec2I.Max(neighbor.gridPos, breath.startPos) > maxDistance) { continue; } if (closedCheck[nx, ny]) { continue; } if (openCheck[nx, ny]) { continue; } if (!CanTravel(current.node, neighbor)) { continue; } //calculate cost int travelCost = current.travelCost + TravelCostBreath(current.node, neighbor); //priority sorted by heap PathStep step = new PathStep(neighbor, travelCost, 0); openList.Add(step); openArray[nx, ny] = step; openCheck[nx, ny] = true; //add breath to area breath.exist[nx, ny] = true; breath.parent[nx, ny] = current.node.gridPos; breath.travelCost[nx, ny] = travelCost; breath.steps[nx, ny] = currentSteps + 1; } } }