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 static void CreateMeshes() { Transform holder = new GameObject("MapMeshes").transform; holder.transform.SetParent(GameManager.Instance.transform); //walls { int index = 0; foreach (Linedef l in MapLoader.linedefs) { //if (l.lineType > 0 || l.lineTag > 0) //Debug.Log("Line " + index + " type: " + l.lineType + " tag: " + l.lineTag); //add linedef to the fast lookup cache AxMath.CartesianLineF(l.start.Position, l.end.Position).Perform((n) => { int gridX = n.Data.x - TheGrid.origoX; int gridY = n.Data.y - TheGrid.origoY; TheGrid.linedefs[gridX, gridY].Add(l); TheGrid.existenceBox.data[gridX, gridY] = true; }); if (l.Back != null) { //top part (front) if (l.Front.Sector.ceilingHeight > l.Back.Sector.ceilingHeight) { l.TopFrontObject = CreateLineQuad ( l.Front, l.Back.Sector.ceilingHeight, l.Front.Sector.ceilingHeight + (l.Back.Sector.ceilingHeight - l.Back.Sector.minimumCeilingHeight), l.Front.tHigh, l.Front.offsetX, (l.flags & (1 << 3)) != 0 ? l.Front.offsetY : -l.Front.offsetY, (l.flags & (1 << 3)) != 0 ? 0 : 1, false, l.Front.Sector.brightness, true, "Wall_" + index + "_top_front", holder ); } //lowering ceiling (front) else if (l.Front.Sector.ceilingHeight > l.Back.Sector.minimumCeilingHeight) { l.TopFrontObject = CreateLineQuad ( l.Front, l.Back.Sector.ceilingHeight, l.Front.Sector.ceilingHeight + (l.Back.Sector.ceilingHeight - l.Back.Sector.minimumCeilingHeight), l.Front.tHigh, l.Front.offsetX, (l.flags & (1 << 3)) != 0 ? l.Front.offsetY : -l.Front.offsetY, (l.flags & (1 << 3)) != 0 ? 0 : 1, false, l.Front.Sector.brightness, true, "Wall_" + index + "_top_front", holder ); } //top part (back) if (l.Front.Sector.ceilingHeight < l.Back.Sector.ceilingHeight) { l.TopBackObject = CreateLineQuad ( l.Back, l.Front.Sector.ceilingHeight, l.Back.Sector.ceilingHeight, l.Back.tHigh, l.Back.offsetX, (l.flags & (1 << 3)) != 0 ? l.Back.offsetY : l.Back.offsetY, (l.flags & (1 << 3)) != 0 ? 0 : 1, true, l.Back.Sector.brightness, true, "Wall_" + index + "_top_back", holder ); } //bottom part (front) if (l.Front.Sector.minimumFloorHeight < l.Back.Sector.floorHeight) { l.BotFrontObject = CreateLineQuad ( l.Front, l.Front.Sector.minimumFloorHeight, l.Back.Sector.floorHeight, l.Front.tLow, l.Front.offsetX, l.Front.offsetY, ((l.flags & (1 << 4)) != 0) ? 2 : 0, false, l.Front.Sector.brightness, true, "Wall_" + index + "_bot_front", holder ); } //rising floor (front) else if (l.Front.Sector.maximumFloorHeight > l.Back.Sector.floorHeight && l.Front.Sector.maximumFloorHeight > l.Front.Sector.floorHeight) { l.BotFrontObject = CreateLineQuad ( l.Front, l.Front.Sector.floorHeight - (l.Front.Sector.maximumFloorHeight - l.Back.Sector.floorHeight), l.Front.Sector.floorHeight, l.Front.tLow, l.Front.offsetX, l.Front.offsetY, ((l.flags & (1 << 4)) != 0) ? 2 : 0, false, l.Front.Sector.brightness, true, "Wall_" + index + "_bot_front", holder ); } //bottom part (back) if (l.Front.Sector.floorHeight > l.Back.Sector.minimumFloorHeight) { l.BotBackObject = CreateLineQuad ( l.Back, l.Back.Sector.minimumFloorHeight, l.Front.Sector.floorHeight, l.Back.tLow, l.Back.offsetX, l.Front.offsetY, ((l.flags & (1 << 4)) != 0) ? 2 : 0, true, l.Back.Sector.brightness, true, "Wall_" + index + "_bot_back", holder ); } //rising floor (back) else if (l.Back.Sector.maximumFloorHeight > l.Front.Sector.floorHeight && l.Back.Sector.maximumFloorHeight > l.Back.Sector.floorHeight) { l.BotBackObject = CreateLineQuad ( l.Front, l.Back.Sector.floorHeight - (l.Back.Sector.maximumFloorHeight - l.Front.Sector.floorHeight), l.Back.Sector.floorHeight, l.Front.tLow, l.Front.offsetX, l.Front.offsetY, ((l.flags & (1 << 4)) != 0) ? 2 : 0, false, l.Front.Sector.brightness, true, "Wall_" + index + "_bot_front", holder ); } //middle (front) if (l.Front.tMid != "-") { l.MidFrontObject = CreateLineQuad ( l.Front, Mathf.Max(l.Front.Sector.floorHeight, l.Back.Sector.floorHeight), Mathf.Min(l.Front.Sector.ceilingHeight, l.Back.Sector.ceilingHeight), l.Front.tMid, l.Front.offsetX, l.Front.offsetY, ((l.flags & (1 << 4)) != 0) ? 1 : 0, false, l.Front.Sector.brightness, false, "Wall_" + index + "_mid_front", holder ); } //middle (back) if (l.Back.tMid != "-") { l.MidBackObject = CreateLineQuad ( l.Back, Mathf.Max(l.Front.Sector.floorHeight, l.Back.Sector.floorHeight), Mathf.Min(l.Front.Sector.ceilingHeight, l.Back.Sector.ceilingHeight), l.Back.tMid, l.Back.offsetX, l.Back.offsetY, ((l.flags & (1 << 4)) != 0) ? 1 : 0, true, l.Back.Sector.brightness, false, "Wall_" + index + "_mid_back", holder ); } if ((l.flags & (1 << 0)) != 0) { CreateInvisibleBlocker ( l, Mathf.Max(l.Front.Sector.floorHeight, l.Back.Sector.floorHeight), Mathf.Min(l.Front.Sector.ceilingHeight, l.Back.Sector.ceilingHeight), "Wall_" + index + "_blocker", holder ); } } else //solid wall { l.MidFrontObject = CreateLineQuad ( l.Front, l.Front.Sector.minimumFloorHeight, l.Front.Sector.maximumCeilingHeight, l.Front.tMid, l.Front.offsetX, l.Front.offsetY, ((l.flags & (1 << 4)) != 0) ? 1 : 0, false, l.Front.Sector.brightness, true, "Wall_" + index, holder ); } index++; } } //sectors { Triangulator triangulator = new Triangulator(); int index = 0; foreach (Sector s in MapLoader.sectors) { //if (s.specialType > 0 || s.tag > 0) //Debug.Log("Sector " + index + " type: " + s.specialType + " tag: " + s.tag); triangulator.Triangulate(s); if (Triangulator.vertices.Count == 0) { Debug.Log("Triangulation failed for sector " + index); } //floor { GameObject sectorObject = new GameObject("Sector_" + index + "_floor"); s.floorObject = sectorObject.AddComponent <SectorController>(); sectorObject.transform.SetParent(holder); MeshRenderer mr = sectorObject.AddComponent <MeshRenderer>(); MeshFilter meshFilter = sectorObject.AddComponent <MeshFilter>(); Mesh mesh = new Mesh(); meshFilter.mesh = mesh; if (!MaterialManager.Instance.OverridesFlat(s.floorTexture, sectorObject, mr)) { mr.material = MaterialManager.Instance.defaultMaterial; } if (mr.material.mainTexture == null) { MaterialPropertyBlock materialProperties = new MaterialPropertyBlock(); materialProperties.SetTexture("_MainTex", TextureLoader.Instance.GetFlatTexture(s.floorTexture)); mr.SetPropertyBlock(materialProperties); } mesh.name = "Sector_" + index + "_floor_mesh"; int vc = Triangulator.vertices.Count; Vector3[] vertices = new Vector3[vc]; Vector3[] normals = new Vector3[vc]; Vector2[] uvs = new Vector2[vc]; Color[] colors = new Color[vc]; int[] indices = new int[vc]; int v = 0; int i = 0; int g = 0; Triangle t = null; BooleanBox[] bboxes = new BooleanBox[Triangulator.vertices.Count / 3]; foreach (Vector2 p in Triangulator.vertices) { vertices[v] = new Vector3(p.x, s.floorHeight, p.y); indices[v] = v; normals[v] = Vector3.up; uvs[v] = new Vector2(p.x / MapLoader.flatUVdividor, 1 - (p.y / MapLoader.flatUVdividor)); colors[v] = Color.white * s.brightness; v++; //add the triangle to the fast lookup cache if (i == 0) { t = new Triangle(); } t.vertices[i] = p; i++; if (i == 3) { i = 0; t.sector = s; s.triangles.Add(t); BooleanBox bbox = t.SelectBox; if (bbox != null) { for (int y = 0; y < bbox.size.y; y++) { for (int x = 0; x < bbox.size.x; x++) { if (bbox.data[x, y]) { int gridX = bbox.origo.x - TheGrid.origoX + x; int gridY = bbox.origo.y - TheGrid.origoY + y; TheGrid.triangles[gridX, gridY].Add(t); TheGrid.existenceBox.data[gridX, gridY] = true; } } } } bboxes[g++] = bbox; } } //combine all triangles and add the sector to the fast lookup cache BooleanBox sectorBox = BooleanBox.Combine(bboxes); for (int y = 0; y < sectorBox.size.y; y++) { for (int x = 0; x < sectorBox.size.x; x++) { if (sectorBox.data[x, y]) { int gridX = sectorBox.origo.x - TheGrid.origoX + x; int gridY = sectorBox.origo.y - TheGrid.origoY + y; TheGrid.sectors[gridX, gridY].Add(s); TheGrid.existenceBox.data[gridX, gridY] = true; } } } mesh.vertices = vertices; mesh.triangles = indices; mesh.normals = normals; mesh.uv = uvs; mesh.colors = colors; mesh.RecalculateBounds(); MeshCollider mc = sectorObject.AddComponent <MeshCollider>(); mc.sharedMesh = mesh; } //ceiling Triangulator.vertices.Reverse(); { GameObject sectorObject = new GameObject("Sector_" + index + "_ceiling"); s.ceilingObject = sectorObject; sectorObject.transform.SetParent(holder); MeshRenderer mr = sectorObject.AddComponent <MeshRenderer>(); MeshFilter meshFilter = sectorObject.AddComponent <MeshFilter>(); Mesh mesh = new Mesh(); meshFilter.mesh = mesh; mesh.name = "Sector_" + index + "_ceiling_mesh"; if (!MaterialManager.Instance.OverridesFlat(s.ceilingTexture, sectorObject, mr)) { mr.material = MaterialManager.Instance.defaultMaterial; } if (mr.material.mainTexture == null) { MaterialPropertyBlock materialProperties = new MaterialPropertyBlock(); materialProperties.SetTexture("_MainTex", TextureLoader.Instance.GetFlatTexture(s.ceilingTexture)); mr.SetPropertyBlock(materialProperties); } int vc = Triangulator.vertices.Count; Vector3[] vertices = new Vector3[vc]; Vector3[] normals = new Vector3[vc]; Vector2[] uvs = new Vector2[vc]; Color[] colors = new Color[vc]; int[] indices = new int[vc]; int v = 0; foreach (Vector2 p in Triangulator.vertices) { vertices[v] = new Vector3(p.x, s.ceilingHeight, p.y); indices[v] = v; normals[v] = -Vector3.up; uvs[v] = new Vector2(p.x / MapLoader.flatUVdividor, 1 - (p.y / MapLoader.flatUVdividor)); colors[v] = Color.white * s.brightness; v++; } mesh.vertices = vertices; mesh.triangles = indices; mesh.normals = normals; mesh.uv = uvs; mesh.colors = colors; mesh.RecalculateBounds(); MeshCollider mc = sectorObject.AddComponent <MeshCollider>(); mc.sharedMesh = mesh; } s.floorObject.sector = s; s.floorObject.Init(); index++; } } }
void Update() { if (GameManager.Paused) { return; } if (dynamic) { ApplySimpleGravity(); } if (dead) { frametime += Time.deltaTime; if (frametime > .15f) { frametime = 0f; frameindex++; if (frameindex == 2) { Collider[] hits = Physics.OverlapSphere(transform.position, explosionRadius, ~(1 << 9), QueryTriggerInteraction.Ignore); foreach (Collider hit in hits) { Damageable d = hit.GetComponent <Damageable>(); if (d != null) { float distance = (hit.transform.position - transform.position).magnitude; d.Damage(AxMath.Lerp(blastDamage, 1, distance / explosionRadius), DamageType.Explosion, gameObject); d.Impulse((hit.transform.position - transform.position).normalized, Mathf.Lerp(pushForce, 100, distance / explosionRadius)); } } } if (frameindex >= ExplodeTextures.Length) { Destroy(gameObject); for (int y = -1; y <= 1; y++) { for (int x = -1; x <= 1; x++) { AI.CalculateHeat(cell.x + x, cell.y + y); } } if (GameManager.Instance.Player[0].playerBreath.GetBreath(cell) != null) { GameManager.Instance.Player[0].RecastBreath(); } return; } SetSprite(ExplodeTextures[frameindex]); } return; } frametime += Time.deltaTime; if (frametime > .25f) { frametime = 0; frameindex++; if (frameindex >= IdleTextures.Length) { frameindex = 0; } SetSprite(IdleTextures[frameindex]); } }
public Quaternion TowardsPosition(Vector3 position) { Vector2 dif = (position - transform.position); return(Quaternion.Euler(0, 0, AxMath.SafeAtan2(dif.y, dif.x) * Mathf.Rad2Deg)); }
public bool ContainsPoint(float x, float y) { return(AxMath.PointInTriangle(new Vector2(x, y), vertices[0], vertices[1], vertices[2])); }
public float GetAreaSigned() { return(AxMath.TriangleAreaSigned(vertices[0], vertices[1], vertices[2])); }
public static void NaturalizePath(ref Vec2I[] path, int maxSteps) { if (path.Length < 3) { return; } if (maxSteps < 2) { return; } SingleLinkedList <Vec2I> naturalized = new SingleLinkedList <Vec2I>(); naturalized.InsertBack(path[0]); int s = 0; int e = 2; Vec2I[] lastLine = new Vec2I[0]; while (e < path.Length) { int steps = 0; again: Vec2I[] line = AxMath.CartesianLine(path[s], path[e]); for (int i = 0; i < line.Length; i++) { HeatmapNode n = Heatmap.GetNode(line[i]); if (n == null) { goto failed; } if (!n.WideOpen) { goto failed; } } if (steps <= maxSteps) { if (e == path.Length - 1) { naturalized.InsertBack(path[e]); path = naturalized.ToArray(); return; } lastLine = line; steps++; e++; goto again; } failed: if (e > s + 2) { naturalized.InsertBack(lastLine[lastLine.Length - 1]); s = e; e = s + 2; continue; } naturalized.InsertBack(path[++s]); e = s + 2; } while (s < path.Length) { naturalized.InsertBack(path[s++]); } path = naturalized.ToArray(); }
public bool ContainsPoint(Vector2 point) { return(AxMath.PointInTriangle(point, vertices[0], vertices[1], vertices[2])); }
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(); } } }
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); 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; } }
/// <summary> /// Tries to make pathfinding more natural like, instead of hugging walls the object tries to move toward corners and doors. /// </summary> public static void NaturalizePath(ref Vec2I[] path, int maxSteps) { if (path.Length < 3) { return; } if (maxSteps < 2) { return; } SingleLinkedList <Vec2I> naturalized = new SingleLinkedList <Vec2I>(); int s = 0; int e = 2; Vec2I[] lastLine = new Vec2I[0]; while (e < path.Length) { int steps = 0; again: Vec2I[] line = AxMath.RogueLine(path[s], path[e]).ToArray(); for (int i = 0; i < line.Length; i++) { if (!CanPath(line[i])) { goto failed; } } if (e < path.Length - 1 && steps <= maxSteps) { lastLine = line; steps++; e++; goto again; } failed: if (e > s + 2) { for (int i = 0; i < lastLine.Length; i++) { naturalized.InsertBack(lastLine[i]); } s = e; e = s + 2; continue; } naturalized.InsertBack(path[s]); s++; e = s + 2; } while (s < path.Length) { naturalized.InsertBack(path[s++]); } path = naturalized.ToArray(); }
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; }
public static void FillBreath(ref BreathArea breath, ref List <ThingController> monstersList, bool cullByTrueDistance = false) { int maxDistance = breath.maxDistance; int arraySize = breath.size; Vec2I StartPoint = breath.position; breath.Invalidate(); if (GetHeat(StartPoint).x == -1) { return; } //init arrays bool[,] closedCheck = new bool[arraySize, arraySize]; bool[,] openCheck = new bool[arraySize, arraySize]; //set start point SingleLinkedList <Vec2I> openList = new SingleLinkedList <Vec2I>(); openList.InsertFront(StartPoint); 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>(); SingleLinkedList <int> randomNeighbors = new SingleLinkedList <int>(); int maxStepDistance = maxDistance * 10; while (openList.Count > 0) { //get top of heap Vec2I current = openList.RemoveHead(); int ax = current.x - StartPoint.x + maxDistance; int ay = current.y - StartPoint.y + maxDistance; int currentDistance = breath.distance[ax, ay]; int currentSteps = breath.steps[ax, ay]; closedCheck[ax, ay] = true; TheGrid.GetNearbyMonsters(current, 0).Perform((n) => { monsters.Add(n.Data); }); if (cullByTrueDistance) { if (currentDistance >= maxStepDistance) { continue; } } Vector3 currentHeat = GetHeat(current); //no propagation through solids if (currentHeat.x >= 1f) { if (current != StartPoint) { continue; } } //don't hassle, shuffle for (int i = 1; i < 9; i++) { if (Random.value > .5f) { randomNeighbors.InsertFront(i); } else { randomNeighbors.InsertBack(i); } } while (randomNeighbors.Count > 0) { int i = randomNeighbors.RemoveHead(); Vec2I neighbor = current + 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; } openList.InsertBack(neighbor); openCheck[arrayX, arrayY] = true; //reverse direction to point towards the source of breath int p = i + 4; if (p > 8) { p -= 8; } 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; }
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 UpdateFrame() { var keyboardState = WindowContext.Current.Window.KeyboardState; if (keyboardState.IsKeyDown(Key.R)) { Reset(); } if (StartMovement) { var speed = Speed; if (keyboardState[Key.ControlLeft]) { speed = speed * 0.1f; } var delta = (float)Application.Current.UpdateCounter.Elapsed.TotalMilliseconds / 1000.0f; var movement = direction * speed * delta; var updatedPosition = gfx.RelativeTranslation + new Vector3(movement.X, movement.Y, 0); var collision = false; var ballRadius = gfx.RelativeScale.X / 2; if (updatedPosition.X + ballRadius > WorldSize.X / 2 || updatedPosition.X - ballRadius < -WorldSize.X / 2) { Reset(); return; } if (updatedPosition.Y + ballRadius > WorldSize.Y / 2 || updatedPosition.Y - ballRadius < -WorldSize.Y / 2) { direction.Y = -direction.Y; collision = true; } bool firstPlayCollision = FirstPlayer.CollidesWithBall(updatedPosition.Xy, ballRadius); bool secondPlayerCollision = SecondPlayer.CollidesWithBall(updatedPosition.Xy, ballRadius); if (firstPlayCollision || secondPlayerCollision) { if ((firstPlayCollision && direction.X < 0) || (secondPlayerCollision && direction.X > 0)) { var player = firstPlayCollision ? FirstPlayer : SecondPlayer; direction.X = -direction.X; collision = true; var normalizedBounds = player.Bounds; normalizedBounds.Center = Vector2.Zero; var translatedDiff = player.Bounds.Center.Y; var translatedBallPos = gfx.RelativeTranslation.Y - translatedDiff; var scaledPaddleCollisionPos = translatedBallPos / player.Bounds.HalfSize.Y; // 0..1 scaledPaddleCollisionPos *= 0.5f; var posY = AxMath.SinNorm(scaledPaddleCollisionPos / 4f); var posX = AxMath.CosNorm(scaledPaddleCollisionPos / 4f); var pos = new Vector2(posX, posY).Normalized(); var newDirX = AxMath.SetSign(pos.X, direction.X); //var newDirY = AxMath.SetSign(pos.Y, direction.Y); direction = new Vector2(newDirX, pos.Y); } } if (collision) { AudioManager.Default.PlayAsync("Audio/collision.rack.json"); } else { gfx.RelativeTranslation = updatedPosition; } } }