1. 程式人生 > >遊戲中的常用演算法

遊戲中的常用演算法

<span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);">一,遞迴</span>
<span style="background-color: rgb(255, 255, 255); font-family: Arial, Helvetica, sans-serif; font-size: 12px;">一個簡單遞迴,計算階乘</span>

注:所有遞迴一定要有一個出口(一般的有1, 0  !  等等),否則會出錯

int fun(int n)
	{
		if (n==1||n==0)
		{
			return 1;
		}
		return n * fun(n - 1);
	
	}


二,A*自動尋路演算法

劣勢:有一定的侷限性,可能不會是最優路線

A*[1] (A-Star)演算法是一種靜態路網中求解最短路最有效的直接搜尋方法。 注意是最有效的直接搜尋演算法。之後湧現了很多預處理演算法(ALT,CH,HL等等),線上查詢效率是A*演算法的數千甚至上萬倍。 公式表示為: f(n)=g(n)+h(n), 其中 f(n) 是從初始點經由節點n到目標點的估價函式, g(n) 是在狀態空間中從初始節點到n節點的實際代價, h(n) 是從n到目標節點最佳路徑的估計代價。 保證找到最短路徑(最優解的)條件,關鍵在於估價函式f(n)的選取: 估價值h(n)<= n到目標
節點
的距離實際值,這種情況下,搜尋的點數多,搜尋範圍大,效率低。但能得到最優解。並且如果h(n)=d(n),即距離估計h(n)等於最短距離,那麼搜尋將嚴格沿著最短路徑進行, 此時的搜尋效率是最高的。 如果 估價值>實際值,搜尋的點數少,搜尋範圍小,效率高,但不能保證得到最優解。

先把一塊區域分成小網格

f  =g+h    尋路總消耗

g=從起點到當前位置(其中一個網格)的消耗

h=從當前點(其中一個網格)到終點的消耗

起點g=0;h計算用曼哈頓演算法起點的x,y和終點的x,y求差

open陣列 

找到當前點四周八個點( 全部存入open陣列 )中 f 值(可走斜線根號2 倍)最小的點 ,如果計算到某一步發現下一步不是最優解,可往回退到上級父集點(直線走或者斜線走)

open陣列中沒值時,不可再走


1,

2,

跳過幾步


最終:


close陣列 走過的點記錄到close中

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public enum GridType
{
	Normal,//正常
	Obstacle,//障礙物
	Start,//起點
	End//終點
}

//為了格子排序 需要繼承IComparable介面實現排序
public class MapGrid : IComparable//排序介面
{
	public int x;//記錄座標
	public int y;

	public int f;//總消耗
	public int g;//當前點到起點的消耗
	public int h;//當前點到終點的消耗


	public GridType type;//格子型別
	public MapGrid fatherNode;//父節點


	//排序
	public int CompareTo(object obj)	 //排序比較方法 ICloneable的方法
	{
		//升序排序
		MapGrid grid = (MapGrid)obj;
		if (this.f < grid.f)
		{
			return -1;					//升序
		}
		if (this.f > grid.f)
		{
			return 1;					//降序
		}
		return 0;
	}

}




public class AStar : MonoBehaviour
{
	//格子大小
	public int row = 5;
	public int col = 10;
	public int size = 70;				//格子大小

	public MapGrid[,] grids;			//格子陣列

	public ArrayList openList;			//開啟列表
	public ArrayList closeList;			//結束列表

	//開始,結束點位置
	private int xStart = 2;
	private int yStart = 1;

	private int xEnd = 2;
	private int yEnd = 5;
	private Stack<string> fatherNodeLocation;

	void Init()
	{
		grids = new MapGrid[row, col];	//初始化陣列
		for (int i = 0; i < row; i++)
		{
			for (int j = 0; j < col; j++)
			{
				grids[i, j] = new MapGrid();
				grids[i, j].x = i;
				grids[i, j].y = j;		//初始化格子,記錄格子座標
			}
		}
		grids[xStart, yStart].type = GridType.Start;
		grids[xStart, yStart].h = Manhattan(xStart, yStart);	//起點的 h 值

		grids[xEnd, yEnd].type = GridType.End;					//結束點
		fatherNodeLocation = new Stack<string>();

		//生成障礙物
		for (int i = 1; i <= 3; i++)
		{
			grids[i, 3].type = GridType.Obstacle;
		}

		openList = new ArrayList();
		openList.Add(grids[xStart, yStart]);
		closeList = new ArrayList();
	}

	int Manhattan(int x, int y)					//計算演算法中的 h
	{
		return (int)(Mathf.Abs(xEnd - x) + Mathf.Abs(yEnd - y)) * 10;
	}


	// Use this for initialization
	void Start()
	{
		Init();
	}

	void DrawGrid()
	{
		for (int i = 0; i < row; i++)
		{
			for (int j = 0; j < col; j++)
			{
				Color color = Color.yellow;
				if (grids[i, j].type == GridType.Start)
				{
					color = Color.green;
				}
				else if (grids[i, j].type == GridType.End)
				{
					color = Color.red;
				}
				else if (grids[i, j].type == GridType.Obstacle)	//障礙顏色
				{
					color = Color.blue;
				}
				else if (closeList.Contains(grids[i, j]))		//關閉列表顏色  如果當前點包含在closList裡
				{
					color = Color.yellow;
				}
				else { color = Color.gray; }

				GUI.backgroundColor = color;
				GUI.Button(new Rect(j * size, i * size, size, size), FGH(grids[i, j]));
			}
		}
	}

	//每個格子顯示的內容
	string FGH(MapGrid grid)
	{
		string str = "F" + grid.f + "\n";
		str += "G" + grid.g + "\n";
		str += "H" + grid.h + "\n";
		str += "(" + grid.x + "," + grid.y + ")";
		return str;
	}
	void OnGUI()
	{
		DrawGrid();
		for (int i = 0; i < openList.Count; i++)
		{
			//生成一個空行,存放開啟陣列
			GUI.Button(new Rect(i * size, (row + 1) * size, size, size), FGH((MapGrid)openList[i]));
		}
			//生成一個空行,存放關閉陣列
		for (int j = 0; j < closeList.Count; j++)
		{
			GUI.Button(new Rect(j * size, (row + 2) * size, size, size), FGH((MapGrid)closeList[j]));
		}

		if (GUI.Button(new Rect(col * size, size, size, size), "next"))
		{
			NextStep();//點選到下一步
		}
	}

	void NextStep()
	{
		if (openList.Count == 0)				//沒有可走的點
		{
			print("Over !");
			return;
		}
		MapGrid grid = (MapGrid)openList[0];	//取出openList陣列中的第一個點
		if (grid.type == GridType.End)			//找到終點
		{
			print("Find");
			FindFatherNode(grid);		//找節點//列印路線
			return;
		}

		for (int i = -1; i <= 1; i++)
		{
			for (int j = -1; j <= 1; j++)
			{
				if (!(i == 0 && j == 0))
				{
					int x = grid.x + i;
					int y = grid.y + j;
					//x,y不超過邊界,不是障礙物,不在closList裡面
					if (x >= 0 && x < row && y >= 0 && y < col && grids[x, y].type != GridType.Obstacle && !closeList.Contains(grids[x, y]))
					{


						//到起點的消耗
						int g = grid.g + (int)(Mathf.Sqrt((Mathf.Abs(i) + Mathf.Abs(j))) * 10);
						if (grids[x, y].g == 0 || grids[x, y].g > g)
						{
							grids[x, y].g = g;
							grids[x, y].fatherNode = grid;		//更新父節點
						}
						//到終點的消耗
						grids[x, y].h = Manhattan(x, y);		
						grids[x, y].f = grids[x, y].g + grids[x, y].h;
						if (!openList.Contains(grids[x,y]))
						{
							openList.Add(grids[x, y]);			//如果沒有則加入到openlist
						}
						openList.Sort();						//排序
					}
				}
			}
		}
		//新增到關閉陣列
		closeList.Add(grid);
		//從open陣列刪除
		openList.Remove(grid);
	}


	//回溯法 遞迴父節點
	void FindFatherNode(MapGrid grid)
	{
		if (grid.fatherNode != null)
		{
			//print(grid.fatherNode.x + "," + grid.fatherNode.y);
			string str = grid.fatherNode.x + "," + grid.fatherNode.y;
			fatherNodeLocation.Push(str);
			FindFatherNode(grid.fatherNode);
		}
		if (fatherNodeLocation.Count!=0)
		{
			print(fatherNodeLocation.Pop());
		}
	}

	
}

轉載請註明出處:http://blog.csdn.net/zhhf96