zoukankan      html  css  js  c++  java
  • Unity3D 2D游戏中寻径算法的一些解决思路

    需求

    unity3d的3d开发环境中,原生自带了Navigation的组件,可以很便捷快速的实现寻路功能。但是在原生的2d中并没有相同的功能。

    现在国内很多手机游戏都有自动寻路的功能,或者游戏中存在一些例如机器人、npc等,都需要自动寻路的功能。

    我需要实现的功能类似于当年FC游戏中淘金者的运动方式。游戏中有淘金者、敌人,可移动,不可移动区域,只能沿着直线的向前向后或者向上向下。

    思路

    unity3d中也有一些2d寻路的插件。例如A Pathfinding Project Pro和NavMesh 2D。

    两个插件都是收费插件,可以满足不同需求,但是我用过之后发现并不是我想要的效果,而且修改别人的代码的还是挺难受的。所以决定自己写一遍A*算法。

    A*算法已经有很多大牛的博客中,都有非常不错的介绍。我看的是这篇,给大家推荐下:传送

    这篇文章的代码在于拐点的处理上是有一定问题的,我在下面的代码中有进行修改。

    解决方案

     先上结果,实现后的路径是这样的。请忽略那只乱入恐龙,他其实只是来打酱油的~~

    核心代码如下:

     1 public Point FindPath (Point start, Point end, bool IsIgnoreCorner)
     2     {
     3         OpenList.Add (start);
     4         while (OpenList.Count != 0) {
     5             //找出F值最小的点
     6             var tempStart = OpenList.MinPoint ();
     7             OpenList.RemoveAt (0);
     8             CloseList.Add (tempStart);
     9             //找出它相邻的点
    10             var surroundPoints = SurrroundPoints (tempStart, IsIgnoreCorner);
    11             foreach (Point point in surroundPoints) {
    12                 if (OpenList.Exists (point))
    13                         //计算G值, 如果比原来的大, 就什么都不做, 否则设置它的父节点为当前点,并更新G和F
    14                     FoundPoint (tempStart, point);
    15                 else
    16                         //如果它们不在开始列表里, 就加入, 并设置父节点,并计算GHF
    17                     NotFoundPoint (tempStart, end, point);
    18             }
    19             if (OpenList.Get (end) != null)
    20                 return OpenList.Get (end);
    21         }
    22         return OpenList.Get (end);
    23     }

    原文中有些小问题的CanReach方向,我修改的如下:

     1 public bool CanReach (Point start, int x, int y, bool IsIgnoreCorner)
     2     {
     3         if (!CanReach (x, y) || CloseList.Exists (x, y))
     4             return false;
     5         else {
     6             if (Math.Abs (x - start.X) + Math.Abs (y - start.Y) == 1)
     7                 return true;
     8                 //如果是斜方向移动, 判断是否 "拌脚"
     9                 else {
    10                 if (IsIgnoreCorner) {
    11                     if (CanReach (Math.Abs (x - 1), y) && CanReach (x, Math.Abs (y - 1)))
    12                         return true;
    13                     else
    14                         return false;
    15                 } else
    16                     return false;
    17             }
    18         }
    19     }

    总结

     算法还是要多自己写一些,总是拿来主义不利于自己的成长,在大学里学过了,基本都还给老师了,项目里的东西,要用也要明明白白的用,防止为以后的开发留下隐患,到时候从头再找就需要话费给多的时间了。

    项目源代码中包含了spine的例子,所以有点大,有兴趣的朋友可以下载去玩一玩。

    点击下载源代码

  • 相关阅读:
    Java实现 LeetCode 697 数组的度(类似于数组的map)
    Java实现 LeetCode 697 数组的度(类似于数组的map)
    Java实现 LeetCode 697 数组的度(类似于数组的map)
    Java实现 LeetCode 696 计数二进制子串(暴力)
    Java实现 LeetCode 696 计数二进制子串(暴力)
    Java实现 LeetCode 696 计数二进制子串(暴力)
    Java实现 LeetCode 695 岛屿的最大面积(DFS)
    Java实现 LeetCode 695 岛屿的最大面积(DFS)
    PHP serialize() 函数
    PHP print_r() 函数
  • 原文地址:https://www.cnblogs.com/nightcat/p/unity3d_005.html
Copyright © 2011-2022 走看看