Commit 2ff4cf21 authored by Luke A Smith's avatar Luke A Smith

Merge branch 'EnemyPathing' into 'master'

Enemy pathing



See merge request !11
parents 24b12369 87ab6458
using UnityEngine;
using System;
using System.Collections;
using System.Collections.Generic;
public class Heap {
Tile[] heapTiles;
int itemCount;
//replace openList with Heap
//add heapIndex, compareTo to tile class
//compare fCost of node then hCost
//item.compareTo(item2) should return pos if item is less than item2, neg if item is greater than item2
//create heap
public Heap(int maxSize)
{
heapTiles = new Tile[maxSize];
}
//add item into heap and sort it into position
public void Add(Tile item)
{
item.heapIndex = itemCount;
heapTiles[itemCount] = item;
SortUp(item);
itemCount++;
}
//remove first tile and resort heap
public Tile RemoveFirst()
{
Tile first = heapTiles[0];
itemCount--;
heapTiles[0] = heapTiles[itemCount];
heapTiles[0].heapIndex = 0;
SortDown(heapTiles[0]);
return first;
}
//resort item position
public void UpdateItem(Tile item)
{
SortUp(item);
}
public int Count
{
get
{
return itemCount;
}
}
//does heap contain item
public bool Contains(Tile item)
{
return Equals(heapTiles[item.heapIndex], item);
}
//sort tile lower into heap
void SortDown(Tile item)
{
while (true)
{
int leftChildIndex = item.heapIndex * 2 + 1;
int rightChildIndex = (item.heapIndex * 2) + 2;
int swapIndex = 0;
if (leftChildIndex < itemCount)
{
swapIndex = leftChildIndex;
if (rightChildIndex < itemCount)
{
if (heapTiles[leftChildIndex].CompareTo(heapTiles[rightChildIndex]) < 0)
{
swapIndex = rightChildIndex;
}
}
if (item.CompareTo(heapTiles[swapIndex]) < 0)
{
Swap(item, heapTiles[swapIndex]);
}
else
{
return;
}
}
else
{
return;
}
}
}
//sort item higher into heap
void SortUp(Tile item)
{
int indexOfParent = (item.heapIndex - 1) / 2;
while (true)
{
Tile parent = heapTiles[indexOfParent];
if (item.CompareTo(parent) > 0)
{
Swap(item, parent);
}
else
{
break;
}
indexOfParent = (item.heapIndex - 1) / 2;
}
}
//swap tiles
void Swap(Tile item1, Tile item2)
{
heapTiles[item1.heapIndex] = item2;
heapTiles[item2.heapIndex] = item1;
int tempIndex = item1.heapIndex;
item1.heapIndex = item2.heapIndex;
item2.heapIndex = tempIndex;
}
}
public interface HeapItem<Tile> : IComparable<Tile>
{
int heapIndex
{
get;
set;
}
}
\ No newline at end of file
fileFormatVersion: 2
guid: 243bb794b9f808b409bcd50557270e5b
timeCreated: 1477007304
licenseType: Free
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
public class MapGen : MonoBehaviour {
public int rows = 6;
public int cols = 6;
public GameObject tile;
public GameObject enemy;
public static Tile[,] map;
public Tile startPos;
public Tile endPos;
public Heap open;
void Start () {
map = new Tile[rows, cols];
float startx = -(float)rows / 2f * tile.transform.lossyScale.x;
float starty = (float)cols / 2f * tile.transform.lossyScale.y;
for (int y = 0; y < cols; y++) {
for (int x = 0; x < rows; x++) {
map[x, y] = ((GameObject) Instantiate (tile, new Vector2(startx + x * tile.GetComponent<BoxCollider2D>().size.x,
starty - y * tile.GetComponent<BoxCollider2D>().size.x), Quaternion.identity)).GetComponent<Tile> ();
map [x, y].x = x;
map [x, y].y = y;
}
}
open = new Heap (rows * cols);
enemy = (GameObject)(Instantiate (enemy, map[0, 0].transform.position, Quaternion.identity));
}
void FixedUpdate () {
if (map[rows - 1, cols - 1].prev != null) {
Tile current = map [rows - 1, cols - 1];
while (current.prev != null) {
Debug.DrawLine (current.transform.position, current.prev.transform.position, Color.red);
current = current.prev;
}
}
}
public void BeginPath () {
Path (map[0, 0], map[rows - 1, cols - 1]);
}
void Path (Tile start, Tile finish) {
if (start == finish) {
return;
}
open.Add (start);
start.goal = 0;
start.fitness = EstimateHeuristic (start, finish);
while (open.Count != 0) {
Tile current = open.RemoveFirst ();
current.closed = true;
List<Tile> neighbors = current.GetNeighbors();
for (int i = 0; i < neighbors.Count; i++) {
if (neighbors[i].closed) {
continue;
}
float tempGoal = current.goal + DistBetween(current, neighbors[i]) + 1 / neighbors[i].speedPercent;
if (!open.Contains (neighbors[i])) {
neighbors [i].prev = current;
neighbors [i].goal = tempGoal;
neighbors [i].fitness = neighbors[i].goal + EstimateHeuristic(neighbors[i], finish);
open.Add (neighbors [i]);
}else if (tempGoal >= neighbors[i].goal) {
continue;
}
}
}
// PrintPathRetrace (finish);
enemy.GetComponent<TraversePath> ().BeginTraversingPath (CreatePath (finish));
}
float EstimateHeuristic (Tile current, Tile finish) {
return Mathf.Abs (current.x - finish.x) + Mathf.Abs (current.y - finish.y);
}
float DistBetween (Tile current, Tile neighbor) {
return Mathf.Pow(current.x - neighbor.x, 2) + Mathf.Pow(current.y - neighbor.y, 2);
}
void PrintPathRetrace (Tile end) {
while (end != null) {
Debug.Log (end.x + ", " + end.y);
end = end.prev;
}
}
Path CreatePath (Tile finish) {
Path path = new Path ();
while (finish != null) {
path.Push (finish);
finish = finish.prev;
}
return path;
}
}
fileFormatVersion: 2
guid: 70e6a95fe794ae440b970c4d8b7de014
timeCreated: 1476404541
licenseType: Free
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
using UnityEngine;
using System.Collections;
public class MapMaker : MonoBehaviour {
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update () {
}
}
fileFormatVersion: 2
guid: b20dbd9f19ada364ca36dceb48c769a1
timeCreated: 1477071770
licenseType: Free
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
public class Path {
public Tile start;
public Tile finish;
private Stack<Tile> path;
public Path () : this(0) { }
public Path (int count) {
path = new Stack<Tile> (count);
}
public void Push (Tile t) {
path.Push (t);
}
public Tile Pop () {
return path.Pop ();
}
public Tile Peek () {
return path.Peek ();
}
public bool IsEmpty () {
return path.Count == 0;
}
}
fileFormatVersion: 2
guid: 08de29a6326faae40a823cdef658790f
timeCreated: 1476750832
licenseType: Free
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
using UnityEngine;
using System;
using System.Collections;
using System.Collections.Generic;
public class Tile : MonoBehaviour, IComparable {
public bool passable = true;
public Color canPas = new Color (255f, 255f, 255f);
public Color cantPas = new Color (0f, 0f, 0f);
private SpriteRenderer sprite;
public int x;
public int y;
public Tile prev;
public float goal = float.MaxValue;
public float fitness = float.MaxValue;
public float speedPercent = 1f;
public int heapIndex;
public bool closed;
void Start () {
sprite = GetComponent<SpriteRenderer> ();
}
void OnMouseDown () {
passable = !passable;
if (passable) {
sprite.color = canPas;
} else {
sprite.color = cantPas;
}
}
public int CompareTo (object obj) {
if (!(obj is Tile)) {
return -1;
}
return fitness - ((Tile) obj).fitness < 0 ? 1 : -1;
}
public List<Tile> GetNeighbors () {
List<Tile> neighbors = new List<Tile> ();
if (x < MapGen.map.GetLength(0) - 1 && MapGen.map[x + 1, y].passable) {
neighbors.Add (MapGen.map[x + 1, y]);
}
if (x < MapGen.map.GetLength(0) - 1 && y < MapGen.map.GetLength(1) - 1 && MapGen.map[x + 1, y + 1].passable
&& MapGen.map[x, y + 1].passable && MapGen.map[x + 1, y].passable) {
neighbors.Add (MapGen.map[x + 1, y + 1]);
}
if (y < MapGen.map.GetLength (1) - 1 && MapGen.map [x, y + 1].passable) {
neighbors.Add (MapGen.map[x, y + 1]);
}
if (x > 0 && y < MapGen.map.GetLength(1) - 1 && MapGen.map[x - 1, y + 1].passable
&& MapGen.map[x, y + 1].passable && MapGen.map[x - 1, y].passable) {
neighbors.Add (MapGen.map[x - 1, y + 1]);
}
if (x > 0 && MapGen.map[x - 1, y].passable) {
neighbors.Add (MapGen.map[x - 1, y]);
}
if (x > 0 && y > 0 && MapGen.map[x - 1, y - 1].passable
&& MapGen.map[x, y - 1].passable && MapGen.map[x - 1, y].passable) {
neighbors.Add (MapGen.map[x - 1, y - 1]);
}
if (y > 0 && MapGen.map[x, y - 1].passable) {
neighbors.Add (MapGen.map[x, y - 1]);
}
if (x < MapGen.map.GetLength(0) - 1 && y > 0 && MapGen.map[x + 1, y - 1].passable
&& MapGen.map[x, y - 1].passable && MapGen.map[x + 1, y].passable) {
neighbors.Add (MapGen.map[x + 1, y - 1]);
}
return neighbors;
}
}
fileFormatVersion: 2
guid: 73c2a34237ac9dc4e98a964e7145a761
timeCreated: 1476403999
licenseType: Free
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
using UnityEngine;
using System.Collections;
public class TraversePath : MonoBehaviour {
public float speed;
public float pathErrorRange;
private float speedLerpDistance;
private Path path;
void Start () {
speedLerpDistance = speed * Time.fixedDeltaTime;
}
void FixedUpdate () {
if (path != null && !path.IsEmpty ()) {
Vector3 tilePos = path.Peek ().transform.position;
float distance = Vector3.Distance (transform.position, tilePos);
transform.position = Vector3.Lerp (transform.position, tilePos, 1 / distance * speedLerpDistance);
if (distance <= pathErrorRange) {
path.Pop ();
}
}
}
//path must begin on current tile
public void BeginTraversingPath (Path path) {
this.path = path;
}
}
fileFormatVersion: 2
guid: 4fe7713de92267947aa9b6222287ca84
timeCreated: 1476751357
licenseType: Free
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
public class MapGen : MonoBehaviour {
public int rows = 6;
public int cols = 6;
public GameObject tile;
public GameObject enemy;
public static Tile[,] map;
public Tile startPos;
public Tile endPos;
public List<Tile> open;
public List<Tile> closed;
void Start () {
map = new Tile[rows, cols];
float startx = -(float)rows / 2f * tile.transform.lossyScale.x;
float starty = (float)cols / 2f * tile.transform.lossyScale.y;
for (int y = 0; y < cols; y++) {
for (int x = 0; x < rows; x++) {
map[x, y] = ((GameObject) Instantiate (tile, new Vector2(startx + x * tile.GetComponent<BoxCollider2D>().size.x,
starty - y * tile.GetComponent<BoxCollider2D>().size.x), Quaternion.identity)).GetComponent<Tile> ();
map [x, y].x = x;
map [x, y].y = y;
}
}
open = new List<Tile> ();
closed = new List<Tile> ();
enemy = (GameObject)(Instantiate (enemy, map[0, 0].transform.position, Quaternion.identity));
}
void FixedUpdate () {
if (map[rows - 1, cols - 1].prev != null) {
Tile current = map [rows - 1, cols - 1];
while (current.prev != null) {
Debug.DrawLine (current.transform.position, current.prev.transform.position, Color.red);
current = current.prev;
}
}
}
public void BeginPath () {
Path (map[0, 0], map[rows - 1, cols - 1]);
}
void Path (Tile start, Tile finish) {
if (start == finish) {
return;
}
open.Add (start);
start.goal = 0;
start.fitness = EstimateHeuristic (start, finish);
while (open.Count != 0) {
Tile current = null;
int index = 0;
float lowestFitness = open[0].fitness;
for (int i = 0; i < open.Count; i++) {
if (open[i].fitness < lowestFitness) {
lowestFitness = open [i].fitness;
index = i;
}
}
current = open[index];
open.RemoveAt (index);
closed.Add (current);
List<Tile> neighbors = current.GetNeighbors();
for (int i = 0; i < neighbors.Count; i++) {
if (closed.Contains (neighbors[i])) {
continue;
}
float tempGoal = current.goal + DistBetween(current, neighbors[i]);
if (!open.Contains (neighbors[i])) {
open.Add (neighbors [i]);
}else if (tempGoal >= neighbors[i].goal) {
continue;
}
neighbors [i].prev = current;
neighbors [i].goal = tempGoal;
neighbors [i].fitness = neighbors[i].goal + EstimateHeuristic(neighbors[i], finish);
}
}
// PrintPathRetrace (finish);
enemy.GetComponent<TraversePath> ().BeginTraversingPath (CreatePath (finish));
}
float EstimateHeuristic (Tile current, Tile finish) {
return Mathf.Abs (current.x - finish.x) + Mathf.Abs (current.y - finish.y);
}
float DistBetween (Tile current, Tile neighbor) {
return Mathf.Pow(current.x - neighbor.x, 2) + Mathf.Pow(current.y - neighbor.y, 2);
}
void PrintPathRetrace (Tile end) {
while (end != null) {
Debug.Log (end.x + ", " + end.y);
end = end.prev;
}
}
Path CreatePath (Tile finish) {
Path path = new Path ();
while (finish != null) {
path.Push (finish);
finish = finish.prev;
}
return path;
}
}
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
public class Path {
public Tile start;
public Tile finish;
private Stack<Tile> path;
public Path () : this(0) { }
public Path (int count) {
path = new Stack<Tile> (count);
}
public void Push (Tile t) {
path.Push (t);
}
public Tile Pop () {
return path.Pop ();
}
public Tile Peek () {
return path.Peek ();
}
public bool IsEmpty () {
return path.Count == 0;
}
}
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
public class Tile : MonoBehaviour {
public bool passable = true;
public Color canPas = new Color (255f, 255f, 255f);
public Color cantPas = new Color (0f, 0f, 0f);
private SpriteRenderer sprite;
public int x;
public int y;
public Tile prev;
public float goal = float.MaxValue;
public float fitness = float.MaxValue;
<