//same as previous, but take into account movement cost of cells public static void FillPlayerBreath(ref BreathArea breath, ref List <ThingController> monstersList, bool cullByTrueDistance = false) { int maxDistance = breath.maxDistance; int arraySize = breath.size; Vec2I StartPoint = breath.position; breath.Invalidate(); monstersList.Clear(); if (GetHeat(StartPoint).x == -1) { return; } //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(StartPoint, 0)); openCheck[maxDistance, maxDistance] = true; breath.exist[maxDistance, maxDistance] = true; breath.steps[maxDistance, maxDistance] = 0; breath.distance[maxDistance, maxDistance] = 0; breath.direction[maxDistance, maxDistance] = 0; List <ThingController> monsters = new List <ThingController>(); int maxStepDistance = maxDistance * 10; while (openList.ItemCount > 0) { //get top of heap PathStep current = openList.RemoveFirst(); int ax = current.position.x - StartPoint.x + maxDistance; int ay = current.position.y - StartPoint.y + maxDistance; int currentDistance = breath.distance[ax, ay]; int currentSteps = breath.steps[ax, ay]; closedCheck[ax, ay] = true; TheGrid.GetNearbyMonsters(current.position, 0).Perform((n) => { monsters.Add(n.Data); }); if (cullByTrueDistance) { if (currentDistance >= maxStepDistance) { continue; } } Vector3 currentHeat = GetHeat(current.position); //no propagation through solids if (currentHeat.x >= 1f) { if (current.position != StartPoint) { continue; } } for (int i = 1; i < 9; i++) { Vec2I neighbor = current.position + Vec2I.directions[i]; //calculate array position int arrayX = neighbor.x - StartPoint.x + maxDistance; int arrayY = neighbor.y - StartPoint.y + maxDistance; //cull disallowed if (AxMath.RogueDistance(neighbor, StartPoint) > maxDistance) { continue; } if (openCheck[arrayX, arrayY]) { continue; } if (closedCheck[arrayX, arrayY]) { continue; } if (!CanPath(neighbor)) { continue; } if (HasLedge(current.position, neighbor, false)) { continue; } //calculate cost int travelCost = current.travelCost + GetTravelCost(neighbor); int heuristic = AxMath.WeightedDistance(neighbor, StartPoint); int fullCost = travelCost + heuristic; //reverse direction to point towards the source of breath int p = i + 4; if (p > 8) { p -= 8; } //check if we can update parent to better if (openCheck[arrayX, arrayY]) { if (openArray[arrayX, arrayY].travelCost > travelCost) { openArray[arrayX, arrayY].travelCost = travelCost; openArray[arrayX, arrayY].heuristic = heuristic; openArray[arrayX, arrayY].fullCost = fullCost; breath.direction[arrayX, arrayY] = p; breath.distance[arrayX, arrayY] = currentDistance + StepDistance(i); breath.steps[arrayX, arrayY] = currentSteps + 1; openList.UpdateItem(openArray[arrayX, arrayY]); continue; } else { continue; } } //priority sorted by heap PathStep step = new PathStep(neighbor, travelCost, heuristic); openList.Add(step); openArray[arrayX, arrayY] = step; openCheck[arrayX, arrayY] = true; breath.exist[arrayX, arrayY] = true; breath.direction[arrayX, arrayY] = p; breath.distance[arrayX, arrayY] = currentDistance + StepDistance(i); breath.steps[arrayX, arrayY] = currentSteps + 1; } } monstersList = monsters; }
//optimized A* pathfinding public static bool GetPath(Vec2I StartPoint, Vec2I EndPoint, int maxDistance, out Vec2I[] path) { if (StartPoint == EndPoint) { path = new Vec2I[1]; path[0] = EndPoint; return(true); } path = null; if (AxMath.RogueDistance(StartPoint, EndPoint) > maxDistance) { return(false); } if (GetHeat(StartPoint).x == -1) { return(false); } if (GetHeat(EndPoint).x == -1) { return(false); } //init arrays int arraySize = maxDistance * 2 + 1; bool[,] closedCheck = new bool[arraySize, arraySize]; bool[,] openCheck = new bool[arraySize, arraySize]; Vec2I[,] parents = 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(StartPoint, AxMath.WeightedDistance(StartPoint, EndPoint))); openCheck[maxDistance, maxDistance] = true; parents[maxDistance, maxDistance] = StartPoint; bool found = false; while (openList.ItemCount > 0) { //get top of heap PathStep current = openList.RemoveFirst(); closedCheck[current.position.x - StartPoint.x + maxDistance, current.position.y - StartPoint.y + maxDistance] = true; foreach (Vec2I neighbor in current.position.neighbors) { //calculate array position int arrayX = neighbor.x - StartPoint.x + maxDistance; int arrayY = neighbor.y - StartPoint.y + maxDistance; //cull disallowed if (AxMath.RogueDistance(neighbor, StartPoint) > maxDistance) { continue; } if (closedCheck[arrayX, arrayY]) { continue; } //found target if (neighbor == EndPoint) { parents[arrayX, arrayY] = current.position; found = true; goto finalize; } if (!CanPath(neighbor)) { continue; } //calculate cost int travelCost = current.travelCost + AxMath.WeightedDistance(current.position, neighbor); int heuristic = AxMath.WeightedDistance(neighbor, EndPoint); int fullCost = travelCost + heuristic; //check if we can update parent to better if (openCheck[arrayX, arrayY]) { if (openArray[arrayX, arrayY].travelCost > travelCost) { openArray[arrayX, arrayY].travelCost = travelCost; openArray[arrayX, arrayY].heuristic = heuristic; openArray[arrayX, arrayY].fullCost = fullCost; parents[arrayX, arrayY] = current.position; openList.UpdateItem(openArray[arrayX, arrayY]); continue; } else { continue; } } //priority sorted by heap PathStep step = new PathStep(neighbor, travelCost, heuristic); openList.Add(step); openCheck[arrayX, arrayY] = true; openArray[arrayX, arrayY] = step; parents[arrayX, arrayY] = current.position; } } finalize: if (found) { SingleLinkedList <Vec2I> list = new SingleLinkedList <Vec2I>(); Vec2I current = EndPoint; while (current != StartPoint) { list.InsertFront(current); current = parents[current.x - StartPoint.x + maxDistance, current.y - StartPoint.y + maxDistance]; } //list.InsertFront(current); //adds the starting point to the path path = list.ToArray(); return(true); } return(false); }
public override void Tick() { if (!alert) { if (decisionTime > 0f) { decisionTime -= Time.deltaTime; return; } decisionTime = Random.Range(.4f, .6f); int distance = AxMath.WeightedDistance(owner.cell, GameManager.Instance.Player[0].cell); if (distance > SeeDistance) { return; } if (Random.value <= NearSoundChanceSleeping) { if (mc.NearSounds.Length > 0) { if (!mc.audioSource.isPlaying) { mc.audioSource.clip = mc.NearSounds[Random.Range(0, mc.NearSounds.Length)]; mc.audioSource.Play(); } } } if (SeePlayerRay()) { alert = true; decisionTime = 0f; } if (!alert) { return; } } if (painFrame) { mc.moveVector = Vector3.zero; painFrame = false; attackTime = 0f; decisionTime = 0f; return; } if (attackTime > 0f) { attackTime -= Time.deltaTime; Vector3 aimAt = (GameManager.Instance.Player[0].transform.position - mc.transform.position).normalized; //mc.transform.rotation = Quaternion.LookRotation(Vector3.Lerp(mc.transform.forward, new Vector3(aimAt.x, 0, aimAt.z), Time.deltaTime * mc.turnSpeed), Vector3.up); //instantenous rotation towards target mc.transform.rotation = Quaternion.LookRotation(new Vector3(aimAt.x, 0, aimAt.z), Vector3.up); if (attackTime < AttackHappenTime && !attacked) { attacked = true; if (mc.AttackSounds.Length > 0) { GameManager.Create3DSound(mc.transform.position, mc.AttackSounds[Random.Range(0, mc.AttackSounds.Length)], 10f); } PlayerThing player = GameManager.Instance.Player[0]; if (player != null) { //swap layers for a while to avoid hitting self int originalLayer = owner.gameObject.layer; owner.gameObject.layer = 9; for (int i = 0; i < shotCount; i++) { Vector3 eyePos = owner.transform.position + Vector3.up * EyeHeight; Vector3 toPlayer = ((player.transform.position + Random.onUnitSphere * player.RayCastSphereRadius) - eyePos).normalized; toPlayer += Random.insideUnitSphere * attackSpread; toPlayer.Normalize(); Ray ray = new Ray(eyePos, toPlayer); /*GameObject visualLine = new GameObject(); * LineRenderer lr = visualLine.AddComponent<LineRenderer>(); * lr.positionCount = 2; * lr.SetPosition(0, ray.origin); * lr.SetPosition(1, ray.origin + ray.direction * 200); * lr.widthMultiplier = .02f; * visualLine.AddComponent<DestroyAfterTime>();*/ RaycastHit hit; if (Physics.Raycast(ray, out hit, 200, ~((1 << 9) | (1 << 14)), QueryTriggerInteraction.Ignore)) { Damageable target = hit.collider.gameObject.GetComponent <Damageable>(); if (target != null) { target.Damage(Random.Range(DamageMin, DamageMax + 1), DamageType.Generic, owner.gameObject); if (target.Bleed) { GameObject blood = GameObject.Instantiate(GameManager.Instance.BloodDrop); blood.transform.position = hit.point - ray.direction * .2f; } else { GameObject puff = GameObject.Instantiate(GameManager.Instance.BulletPuff); puff.transform.position = hit.point - ray.direction * .2f; } } else { GameObject puff = GameObject.Instantiate(GameManager.Instance.BulletPuff); puff.transform.position = hit.point - ray.direction * .2f; } } } owner.gameObject.layer = originalLayer; } } return; } if (wantDirection != Vector3.zero) { mc.transform.rotation = Quaternion.LookRotation(Vector3.Lerp(mc.transform.forward, wantDirection, Time.deltaTime * mc.turnSpeed), Vector3.up); } if (decisionTime > 0f) { decisionTime -= Time.deltaTime; return; } if (Random.value <= PokeChance) { Ray ray = new Ray(owner.transform.position + Vector3.up, owner.transform.forward); RaycastHit hit; if (Physics.Raycast(ray, out hit, 2, ~((1 << 9) | (1 << 11)), QueryTriggerInteraction.Ignore)) { Pokeable lc = hit.collider.gameObject.GetComponent <Pokeable>(); if (lc != null) { if (lc.AllowMonsters()) { lc.Poke(owner.gameObject); } } } } if (Random.value <= NearSoundChanceAwake) { if (mc.NearSounds.Length > 0) { if (!mc.audioSource.isPlaying) { mc.audioSource.clip = mc.NearSounds[Random.Range(0, mc.NearSounds.Length)]; mc.audioSource.Play(); } } } decisionTime = Random.Range(.4f, .6f); wantDirection = Vector3.zero; bool aggro = false; if (Random.value < AggroChance) { Ray toPlayer; if (SeePlayerRay(out toPlayer)) { wantDirection = new Vector3(toPlayer.direction.x, 0, toPlayer.direction.z); wantMove = false; aggro = true; attacked = false; attackTime = 1f; decisionTime = 0f; mc.InitAttackAnimation(); } } if (!aggro) { float moveRoll = Random.value; if (moveRoll < randomMoveChance) { MoveToRandomNearbyCell(); } else if (moveRoll < closestMoveChance) { if (!MoveToRandomClosestBreath()) { MoveToRandomNearbyCell(); } } else { if (!MoveTowardsBreath()) { if (!MoveToRandomClosestBreath()) { MoveToRandomNearbyCell(); } } } } if (Random.value < IdleChance) { wantMove = false; } if (wantMove) { mc.moveVector.x = 1; } else { mc.moveVector.x = 0; } }
public override void Tick() { if (!alert) { if (decisionTime > 0f) { decisionTime -= Time.deltaTime; return; } decisionTime = Random.Range(.4f, .6f); int distance = AxMath.WeightedDistance(owner.cell, GameManager.Instance.Player[0].cell); if (distance > SeeDistance) { return; } if (Random.value <= NearSoundChanceSleeping) { if (mc.NearSounds.Length > 0) { if (!mc.audioSource.isPlaying) { mc.audioSource.clip = mc.NearSounds[Random.Range(0, mc.NearSounds.Length)]; mc.audioSource.Play(); } } } if (SeePlayerRay()) { alert = true; decisionTime = 0f; } if (!alert) { return; } } if (painFrame) { mc.moveVector = Vector3.zero; painFrame = false; attackTime = 0f; decisionTime = 0f; return; } if (attackTime > 0f) { attackTime -= Time.deltaTime; Vector3 aimAt = (GameManager.Instance.Player[0].transform.position - mc.transform.position).normalized; //mc.transform.rotation = Quaternion.LookRotation(Vector3.Lerp(mc.transform.forward, new Vector3(aimAt.x, 0, aimAt.z), Time.deltaTime * mc.turnSpeed), Vector3.up); //instantenous rotation towards target mc.transform.rotation = Quaternion.LookRotation(new Vector3(aimAt.x, 0, aimAt.z), Vector3.up); if (attackTime < AttackHappenTime && !attacked) { attacked = true; float distance = (owner.transform.position + Vector3.up * AttackHeight - GameManager.Instance.Player[0].transform.position).magnitude; if (distance < meleeAttackRange) { if (CanMeleeRay(distance)) { if (mc.AttackSounds.Length > 0) { GameManager.Create3DSound(mc.transform.position, mc.AttackSounds[1], 5f); } Damageable d = GameManager.Instance.Player[0].GetComponent <Damageable>(); if (d != null) { d.Damage(Random.Range(MeleeDamageMin, MeleeDamageMax + 1), DamageType.Generic, owner.gameObject); } } } else { if (mc.AttackSounds.Length > 0) { GameManager.Create3DSound(mc.transform.position, mc.AttackSounds[0], 5f); } if (mc.AttackProjectile != null) { FireballProjectile fireball = GameObject.Instantiate(mc.AttackProjectile).GetComponent <FireballProjectile>(); if (fireball != null) { fireball.transform.position = owner.transform.position + Vector3.up * AttackHeight; fireball.owner = owner.gameObject; fireball.transform.LookAt(GameManager.Instance.Player[0].transform.position + Random.insideUnitSphere * AttackSpread + Vector3.up * TargetHeightAimFix); fireball.transform.SetParent(GameManager.Instance.TemporaryObjectsHolder); } } } } return; } if (wantDirection != Vector3.zero) { mc.transform.rotation = Quaternion.LookRotation(Vector3.Lerp(mc.transform.forward, wantDirection, Time.deltaTime * mc.turnSpeed), Vector3.up); } if (decisionTime > 0f) { decisionTime -= Time.deltaTime; return; } if (Random.value <= PokeChance) { Ray ray = new Ray(owner.transform.position + Vector3.up, owner.transform.forward); RaycastHit hit; if (Physics.Raycast(ray, out hit, 2, ~((1 << 9) | (1 << 11)), QueryTriggerInteraction.Ignore)) { Pokeable lc = hit.collider.gameObject.GetComponent <Pokeable>(); if (lc != null) { if (lc.AllowMonsters()) { lc.Poke(owner.gameObject); } } } } if (Random.value <= NearSoundChanceAwake) { if (mc.NearSounds.Length > 0) { if (!mc.audioSource.isPlaying) { mc.audioSource.clip = mc.NearSounds[Random.Range(0, mc.NearSounds.Length)]; mc.audioSource.Play(); } } } decisionTime = Random.Range(.4f, .6f); wantDirection = Vector3.zero; bool aggro = false; { float distance = (owner.transform.position + Vector3.up * AttackHeight - GameManager.Instance.Player[0].transform.position).magnitude; if (distance < meleeAttackRange) { wantMove = false; aggro = true; attacked = false; attackTime = .7f; decisionTime = 0f; mc.InitAttackAnimation(); mc.frametime = .2f; } else if (Random.value < AggroChance) { Ray toPlayer; if (SeePlayerRay(out toPlayer)) { wantDirection = new Vector3(toPlayer.direction.x, 0, toPlayer.direction.z); wantMove = false; aggro = true; attacked = false; attackTime = 1f; decisionTime = 0f; mc.InitAttackAnimation(); } } } if (!aggro) { float moveRoll = Random.value; if (moveRoll < randomMoveChance) { MoveToRandomNearbyCell(); } else if (moveRoll < closestMoveChance) { if (!MoveToRandomClosestBreath()) { MoveToRandomNearbyCell(); } } else { if (!MoveTowardsBreath()) { if (!MoveToRandomClosestBreath()) { MoveToRandomNearbyCell(); } } } } if (Random.value < IdleChance) { wantMove = false; } if (wantMove) { mc.moveVector.x = 1; } else { mc.moveVector.x = 0; } }
public override void Tick() { if (!alert) { if (decisionTime > 0f) { decisionTime -= Time.deltaTime; return; } decisionTime = Random.Range(.4f, .6f); int distance = AxMath.WeightedDistance(owner.cell, GameManager.Instance.Player[0].cell); if (distance > SeeDistance) { return; } if (Random.value <= NearSoundChanceSleeping) { if (mc.NearSounds.Length > 0) { if (!mc.audioSource.isPlaying) { mc.audioSource.clip = mc.NearSounds[Random.Range(0, mc.NearSounds.Length)]; mc.audioSource.Play(); } } } if (SeePlayerRay()) { alert = true; decisionTime = 0f; } if (!alert) { return; } } if (painFrame) { mc.moveVector = Vector3.zero; painFrame = false; attackTime = 0f; decisionTime = 0f; return; } if (attackTime > 0f) { attackTime -= Time.deltaTime; Vector3 aimAt = (GameManager.Instance.Player[0].transform.position - mc.transform.position).normalized; //mc.transform.rotation = Quaternion.LookRotation(Vector3.Lerp(mc.transform.forward, new Vector3(aimAt.x, 0, aimAt.z), Time.deltaTime * mc.turnSpeed), Vector3.up); //instantenous rotation towards target mc.transform.rotation = Quaternion.LookRotation(new Vector3(aimAt.x, 0, aimAt.z), Vector3.up); if (attackTime < AttackHappenTime && !attacked) { attacked = true; float distance = (owner.transform.position + Vector3.up * AttackHeight - GameManager.Instance.Player[0].transform.position).magnitude; if (distance < meleeAttackRange) { if (CanMeleeRay(distance)) { if (mc.AttackSounds.Length > 0) { GameManager.Create3DSound(mc.transform.position, mc.AttackSounds[0], 5f); } Damageable d = GameManager.Instance.Player[0].GetComponent <Damageable>(); if (d != null) { d.Damage(Random.Range(MeleeDamageMin, MeleeDamageMax + 1), DamageType.Generic, owner.gameObject); } } } } return; } if (wantDirection != Vector3.zero) { mc.transform.rotation = Quaternion.LookRotation(Vector3.Lerp(mc.transform.forward, wantDirection, Time.deltaTime * mc.turnSpeed), Vector3.up); } if (decisionTime > 0f) { decisionTime -= Time.deltaTime; return; } if (Random.value <= NearSoundChanceAwake) { if (mc.NearSounds.Length > 0) { if (!mc.audioSource.isPlaying) { mc.audioSource.clip = mc.NearSounds[Random.Range(0, mc.NearSounds.Length)]; mc.audioSource.Play(); } } } decisionTime = Random.Range(.2f, .3f); wantDirection = Vector3.zero; bool aggro = false; { float distance = (owner.transform.position + Vector3.up * AttackHeight - GameManager.Instance.Player[0].transform.position).magnitude; if (distance < meleeAttackRange) { wantMove = false; aggro = true; attacked = false; attackTime = .7f; decisionTime = 0f; mc.InitAttackAnimation(); mc.frametime = .2f; } } if (!aggro) { if (!MoveToRandomClosestBreath()) { if (!MoveTowardsBreath()) { MoveToRandomNearbyCell(); } } } if (Random.value < IdleChance) { wantMove = false; } if (wantMove) { mc.moveVector.x = 1; } else { mc.moveVector.x = 0; } }
public override void Tick() { if (!alert) { if (decisionTime > 0f) { decisionTime -= Time.deltaTime; return; } decisionTime = .5f; int distance = AxMath.WeightedDistance(owner.cell, GameManager.Instance.Player[0].cell); if (distance > 400) { return; } Vector3 eyePos = owner.transform.position + Vector3.up * 1.55f; Vector3 toPlayer = ((GameManager.Instance.Player[0].transform.position + Random.onUnitSphere * .5f) - eyePos).normalized; if (Vector3.Dot(owner.transform.forward, toPlayer) < -.15f) { return; } Ray ray = new Ray(eyePos, toPlayer); RaycastHit hit; if (Physics.Raycast(ray, out hit, 400, ~((1 << 9) | (1 << 11) | (1 << 14)), QueryTriggerInteraction.Ignore)) { if (hit.collider.GetComponent <PlayerThing>() != null) { alert = true; } } if (!alert) { return; } } /*float mag = (lastpos - owner.transform.position).magnitude; * if (mag > 0.001f && mag < .02f) * Debug.Log("hug"); * lastpos = owner.transform.position;*/ if (painFrame) { mc.moveVector = Vector3.zero; painFrame = false; return; } if (wantDirection != Vector3.zero) { mc.transform.rotation = Quaternion.LookRotation(Vector3.Lerp(mc.transform.forward, wantDirection, Time.deltaTime * mc.turnSpeed), Vector3.up); mc.moveVector = mc.transform.forward; } if (decisionTime > 0f) { decisionTime -= Time.deltaTime; return; } decisionTime = Random.Range(.6f, 2f); wantDirection = Vector3.zero; if (!MoveToRandomClosestBreath()) { if (!MoveTowardsBreath()) { MoveToRandomNearbyCell(); } } }