文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

C# AStar寻路算法怎么使用

2023-07-05 20:16

关注

这篇文章主要讲解了“C# AStar寻路算法怎么使用”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“C# AStar寻路算法怎么使用”吧!

概述

AStar算法是一种图形搜索算法,常用于寻路。他是以广度优先搜索为基础,集Dijkstra算法和最佳优先(best fit)于一身的一种算法。

示例1:4向

C# AStar寻路算法怎么使用

示例2:8向

C# AStar寻路算法怎么使用

思路

C# AStar寻路算法怎么使用

递归的通过估值函数找到最佳路径,估值函数与距离相关,也有可能与通过代价系数相关(例如平地系数为1,坡地系数为2),有三个参数:

过程大概:

C# AStar寻路算法怎么使用

代码示例

位置定义

public struct Vec2{    public int x;    public int y;    public Vec2(int x, int y)    {        this.x = x;        this.y = y;    }    public static Vec2 Zero    {        get        {            return new Vec2(0, 0);        }    }    public override bool Equals(object obj)    {        if (!(obj is Vec2))            return false;        var o = (Vec2)obj;        return x == o.x && y == o.y;    }    public override int GetHashCode()    {        return x.GetHashCode() + y.GetHashCode();    }    public static Vec2 operator +(Vec2 a, Vec2 b)    {        return new Vec2(a.x + b.x, a.y + b.y);    }    public static Vec2 operator *(Vec2 a, int n)    {        return new Vec2(a.x * n, a.y * n);    }    public static Vec2 operator *(int n, Vec2 a)    {        return new Vec2(a.x * n, a.y * n);    }    public static bool operator ==(Vec2 a, Vec2 b)    {        return a.x == b.x && a.y == b.y;    }    public static bool operator !=(Vec2 a, Vec2 b)    {        return !(a.x == b.x && a.y == b.y);    }}

方向定义

public enum EDir{    Up = 0,    Down = 1,    Left = 2,    Right = 3,    UpLeft = 4,    UpRight = 5,    DownLeft = 6,    DownRight = 7,}public abstract class CheckDirPol{    abstract public Dictionary<EDir, Vec2> GetDir();}public class CheckDir4Pol : CheckDirPol{    private Dictionary<EDir, Vec2> dirDict = new Dictionary<EDir, Vec2>    {        {EDir.Up, new Vec2(0, 1) },        {EDir.Down, new Vec2(0, -1) },        {EDir.Left, new Vec2(-1, 0) },        {EDir.Right, new Vec2(1, 0) },    };    override public Dictionary<EDir, Vec2> GetDir()    {        return dirDict;    }}public class CheckDir8Pol : CheckDirPol{    private Dictionary<EDir, Vec2> dirDict = new Dictionary<EDir, Vec2>    {        {EDir.Up, new Vec2(0, 1) },        {EDir.Down, new Vec2(0, -1) },        {EDir.Left, new Vec2(-1, 0) },        {EDir.Right, new Vec2(1, 0) },        {EDir.UpLeft, new Vec2(-1, 1) },        {EDir.UpRight, new Vec2(1, 1) },        {EDir.DownLeft, new Vec2(-1, -1) },        {EDir.DownRight, new Vec2(1, -1) },    };    override public Dictionary<EDir, Vec2> GetDir()    {        return dirDict;    }}

运用策略模式的技巧,以实现4向,8向搜索切换

估值函数

public abstract class EvaPol{abstract public float Calc(Vec2 a, Vec2 b);}public class MANEvaPol : EvaPol{    override public float Calc(Vec2 a, Vec2 b)    {        return Mathf.Abs(a.x - b.x) + Mathf.Abs(a.y - b.y);    }}

直接使用曼哈顿距离作为代价

节点定义

public class Node{    public int id;    public Vec2 pos;    public float g;    public float h;    public float f;    public Vec2 prePos;    public bool hasPrePos;    public Node(Vec2 pos)    {        this.pos = pos;    }    public void SetPrePos(Vec2 pos)    {        prePos = pos;        hasPrePos = true;    }}

算法上下文定义

Context context;EvaPol disPol;CheckDirPol checkDirPol;public struct Context{    public Vec2 end;    public Vec2 start;    public Node[,] nodes;    public List<Node> open;    public List<Node> close;    public int[,] map;    public List<Vec2> result;    public Vec2 size;}

寻路算法

初始化

public void Init(Vec2 start, Vec2 end, int[,] map){var x = map.GetLength(0);var y = map.GetLength(1);context = new Context(){start = start,end = end,open = new List<Node>(),close = new List<Node>(),map = map,result = new List<Vec2>(),size = new Vec2(x, y),};context.nodes = new Node[x, y];for (int i = 0; i < x; i++)for (int j = 0; j < x; j++)context.nodes[i, j] = new Node(new Vec2(i, j));disPol = new MANEvaPol();//checkDirPol = new CheckDir4Pol();checkDirPol = new CheckDir8Pol();}

获取路径

public List<Vec2> GetResult(){return context.result;}

寻路

寻路入口

public void FindPath(){var s = context.start;var sn = context.nodes[s.x, s.y];sn.g = 0;sn.h = disPol.Calc(s, context.end);sn.f = sn.g + sn.h;context.open.Add(sn);FindArrangement(sn);}

递归函数

void FindArrangement(Node node){context.close.Add(node);context.open.Remove(node);if (node.pos == context.end){SetResult(node);return;}CheckRound(node);if (context.open.Count == 0)return;Node next = context.open[0];for (int i = 1; i < context.open.Count; i++)if (context.open[i].f < next.f)next = context.open[i];FindArrangement(next);}

检查周围节点

void CheckRound(Node node){var dirDict = checkDirPol.GetDir();foreach (var pair in dirDict){var dir = node.pos + pair.Value;if (IsBlock(dir))continue;var dn = context.nodes[dir.x, dir.y];if (context.close.Contains(dn))continue;if (context.open.Contains(dn))TryOverridePath(node, dn);else{dn.g = disPol.Calc(dn.pos, context.start);dn.h = disPol.Calc(dn.pos, context.end);dn.f = dn.g + dn.h;dn.SetPrePos(node.pos);context.open.Add(dn);}}}// 若是从邻节点到该节点路径更优,则替换更新void TryOverridePath(Node a, Node b){var g = a.g + disPol.Calc(a.pos, b.pos);if (g < b.g){b.g = g;b.SetPrePos(a.pos);}}bool IsBlock(Vec2 pos){return !InMap(pos) || context.map[pos.x, pos.y] == 1;}bool InMap(Vec2 pos){var x = pos.x;var y = pos.y;var size = context.size;return x >= 0 && x < size.x && y >= 0 && y < size.y;}

生成路径

void SetResult(Node node){Queue<Node> q = new Queue<Node>();while(node.hasPrePos){q.Enqueue(node);node = context.nodes[node.prePos.x, node.prePos.y];}while(q.Count > 0){context.result.Add(q.Dequeue().pos);}}

完整代码

using System.Collections;using System.Collections.Generic;using UnityEngine;public struct Vec2{    public int x;    public int y;    public Vec2(int x, int y)    {        this.x = x;        this.y = y;    }    public static Vec2 Zero    {        get        {            return new Vec2(0, 0);        }    }    public override bool Equals(object obj)    {        if (!(obj is Vec2))            return false;        var o = (Vec2)obj;        return x == o.x && y == o.y;    }    public override int GetHashCode()    {        return x.GetHashCode() + y.GetHashCode();    }    public static Vec2 operator +(Vec2 a, Vec2 b)    {        return new Vec2(a.x + b.x, a.y + b.y);    }    public static Vec2 operator *(Vec2 a, int n)    {        return new Vec2(a.x * n, a.y * n);    }    public static Vec2 operator *(int n, Vec2 a)    {        return new Vec2(a.x * n, a.y * n);    }    public static bool operator ==(Vec2 a, Vec2 b)    {        return a.x == b.x && a.y == b.y;    }    public static bool operator !=(Vec2 a, Vec2 b)    {        return !(a.x == b.x && a.y == b.y);    }}public enum EDir{    Up = 0,    Down = 1,    Left = 2,    Right = 3,    UpLeft = 4,    UpRight = 5,    DownLeft = 6,    DownRight = 7,}public class AstarFindPath{    public class Node    {        public int id;        public Vec2 pos;        public float g;        public float h;        public float f;        public Vec2 prePos;        public bool hasPrePos;        public Node(Vec2 pos)        {            this.pos = pos;        }        public void SetPrePos(Vec2 pos)        {            prePos = pos;            hasPrePos = true;        }    }    public abstract class EvaPol    {        abstract public float Calc(Vec2 a, Vec2 b);    }    public class MANEvaPol : EvaPol    {        override public float Calc(Vec2 a, Vec2 b)        {            return Mathf.Abs(a.x - b.x) + Mathf.Abs(a.y - b.y);        }    }    public abstract class CheckDirPol    {        abstract public Dictionary<EDir, Vec2> GetDir();    }    public class CheckDir4Pol : CheckDirPol    {        private Dictionary<EDir, Vec2> dirDict = new Dictionary<EDir, Vec2>        {            {EDir.Up, new Vec2(0, 1) },            {EDir.Down, new Vec2(0, -1) },            {EDir.Left, new Vec2(-1, 0) },            {EDir.Right, new Vec2(1, 0) },        };        override public Dictionary<EDir, Vec2> GetDir()        {            return dirDict;        }    }    public class CheckDir8Pol : CheckDirPol    {        private Dictionary<EDir, Vec2> dirDict = new Dictionary<EDir, Vec2>        {            {EDir.Up, new Vec2(0, 1) },            {EDir.Down, new Vec2(0, -1) },            {EDir.Left, new Vec2(-1, 0) },            {EDir.Right, new Vec2(1, 0) },            {EDir.UpLeft, new Vec2(-1, 1) },            {EDir.UpRight, new Vec2(1, 1) },            {EDir.DownLeft, new Vec2(-1, -1) },            {EDir.DownRight, new Vec2(1, -1) },        };        override public Dictionary<EDir, Vec2> GetDir()        {            return dirDict;        }    }    public struct Context    {        public Vec2 end;        public Vec2 start;        public Node[,] nodes;        public List<Node> open;        public List<Node> close;        public int[,] map;        public List<Vec2> result;        public Vec2 size;    }    Context context;    EvaPol disPol;    CheckDirPol checkDirPol;    public void Init(Vec2 start, Vec2 end, int[,] map)    {        var x = map.GetLength(0);        var y = map.GetLength(1);        context = new Context()        {            start = start,            end = end,            open = new List<Node>(),            close = new List<Node>(),            map = map,            result = new List<Vec2>(),            size = new Vec2(x, y),        };                context.nodes = new Node[x, y];        for (int i = 0; i < x; i++)            for (int j = 0; j < x; j++)                context.nodes[i, j] = new Node(new Vec2(i, j));        disPol = new MANEvaPol();        //checkDirPol = new CheckDir4Pol();        checkDirPol = new CheckDir8Pol();    }    public void FindPath()    {        var s = context.start;        var sn = context.nodes[s.x, s.y];        sn.g = 0;        sn.h = disPol.Calc(s, context.end);        sn.f = sn.g + sn.h;        context.open.Add(sn);                FindArrangement(sn);    }    public List<Vec2> GetResult()    {        return context.result;    }    void FindArrangement(Node node)    {        context.close.Add(node);        context.open.Remove(node);        if (node.pos == context.end)        {            SetResult(node);            return;        }        CheckRound(node);        if (context.open.Count == 0)            return;        Node next = context.open[0];        for (int i = 1; i < context.open.Count; i++)            if (context.open[i].f < next.f)                next = context.open[i];                FindArrangement(next);    }    void SetResult(Node node)    {        Queue<Node> q = new Queue<Node>();        while(node.hasPrePos)        {            q.Enqueue(node);            node = context.nodes[node.prePos.x, node.prePos.y];        }        while(q.Count > 0)        {            context.result.Add(q.Dequeue().pos);        }    }    void CheckRound(Node node)    {        var dirDict = checkDirPol.GetDir();        foreach (var pair in dirDict)        {            var dir = node.pos + pair.Value;            if (IsBlock(dir))                continue;            var dn = context.nodes[dir.x, dir.y];            if (context.close.Contains(dn))                continue;            if (context.open.Contains(dn))                TryOverridePath(node, dn);            else            {                dn.g = disPol.Calc(dn.pos, context.start);                dn.h = disPol.Calc(dn.pos, context.end);                dn.f = dn.g + dn.h;                dn.SetPrePos(node.pos);                context.open.Add(dn);            }        }    }    void TryOverridePath(Node a, Node b)    {        var g = a.g + disPol.Calc(a.pos, b.pos);        if (g < b.g)        {            b.g = g;            b.SetPrePos(a.pos);        }    }    bool IsBlock(Vec2 pos)    {        return !InMap(pos) || context.map[pos.x, pos.y] == 1;    }    bool InMap(Vec2 pos)    {        var x = pos.x;        var y = pos.y;        var size = context.size;        return x >= 0 && x < size.x && y >= 0 && y < size.y;    }}

感谢各位的阅读,以上就是“C# AStar寻路算法怎么使用”的内容了,经过本文的学习后,相信大家对C# AStar寻路算法怎么使用这一问题有了更深刻的体会,具体使用情况还需要大家实践验证。这里是编程网,小编将为大家推送更多相关知识点的文章,欢迎关注!

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     807人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     351人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     314人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     433人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     221人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯