//================================================================
//
// Copyright (C) 2017 Team Saluka
// All Rights Reserved
//
// Author:小妖精Balous
//
//================================================================

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

namespace Saruka
{
/// <summary>
/// 导航网格
/// </summary>
public class NavGrid : MonoBehaviour
{
/// <summary>
/// 景物层级,用来建立导航网格
/// </summary>
public LayerMask scapeMask;
/// <summary>
/// 导航网格大小
/// </summary>
public Vector2 navGridSize;
/// <summary>
/// 单个网格半径
/// </summary>
public float gridRadius;
/// <summary>
/// 单个网格直径
/// </summary>
float gridDiameter;
/// <summary>
/// 网格结点
/// </summary>
public NavNode[,] grids
{
private set;
get;
}
/// <summary>
/// X轴方向网格数量
/// </summary>
public int gridCountX
{
private set;
get;
}
/// <summary>
/// Y轴方向网格数量
/// </summary>
public int gridCountY
{
private set;
get;
}

/// <summary>
/// 创建导航网格
/// </summary>
void CreateNavGrid()
{
gridDiameter = gridRadius * 2;
gridCountX = Mathf.RoundToInt(navGridSize.x / gridDiameter);
gridCountY = Mathf.RoundToInt(navGridSize.y / gridDiameter);

grids = new NavNode[gridCountX, gridCountY];

//导航网格左下角,平面直角坐标系
Vector3 navGridBottomLeft = transform.position - Vector3.right * navGridSize.x / 2 - Vector3.up * navGridSize.y / 2;

//创建网格
for (int x = 0; x < gridCountX; x++)
for (int y = 0; y < gridCountY; y++)
{
//网格中心坐标
Vector3 gridCenter = navGridBottomLeft + Vector3.right * (x * gridDiameter + gridRadius) + Vector3.up * (y * gridDiameter + gridRadius);
bool isWalkable = !(Physics2D.CircleCast(new Vector2(gridCenter.x, gridCenter.y), gridRadius, Vector2.zero, 0.0f, scapeMask));
grids[x, y] = new NavNode(gridCenter, isWalkable, x, y);
}
}

/// <summary>
/// 获得世界坐标所在的结点
/// </summary>
/// <param name="worldPosition">世界坐标</param>
/// <returns>结点</returns>
public NavNode NavNodeFromWorldPosition(Vector3 worldPosition)
{
worldPosition -= transform.position;
float percentX = Mathf.Clamp01((worldPosition.x + navGridSize.x / 2) / navGridSize.x);
float percentY = Mathf.Clamp01((worldPosition.y + navGridSize.y / 2) / navGridSize.y);
int x = Mathf.RoundToInt((gridCountX - 1) * percentX);
int y = Mathf.RoundToInt((gridCountY - 1) * percentY);
return grids[x, y];
}

public List<NavNode> GetNeighborNodes(NavNode navNode)
{
List<NavNode> neighborNodes = new List<NavNode>();

for (int x = -1; x <= 1; x++)
{
for (int y = -1; y <= 1; y++)
{
if (x == 0 && y == 0) continue;

int checkX = navNode.gridX + x;
int checkY = navNode.gridY + y;
if (checkX >= 0 && checkX < gridCountX && checkY >= 0 && checkY < gridCountY) neighborNodes.Add(grids[checkX, checkY]);
}
}
return neighborNodes;
}

void OnDrawGizmos()
{
//导航网格边框
Gizmos.DrawWireCube(transform.position, new Vector3(navGridSize.x, navGridSize.y, 1));

if(grids != null)
{
foreach(NavNode node in grids)
{
Gizmos.color = (node.isWalkable) ? new Color(1, 1, 1, 0.4f) : new Color(1, 0, 0, 0.4f);
Gizmos.DrawCube(node.worldPosition, Vector3.one * (gridDiameter - 0.03f));
}
}
}

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

小妖精的完美游戏教室——人工智能,A*算法,导航网络篇的更多相关文章

  1. 小妖精的完美游戏教室——人工智能,A*算法,引言

    今天也要直播魔法,求科学的! 欢迎来到小妖精Balous的完美游戏教室! 经过前两周的学习,相信米娜桑已经对状态机有所了解了呢~虽然状态机能够实现几乎所有的人工智能,但是,在实践中,你们有没有发现,自 ...

  2. 小妖精的完美游戏教室——人工智能,A*算法,启发因子篇

    //================================================================//// Copyright (C) 2017 Team Saluk ...

  3. 小妖精的完美游戏教室——人工智能,A*算法,结点篇

    //================================================================//// Copyright (C) 2017 Team Saluk ...

  4. 小妖精的完美游戏教室——人工智能,A*算法,实现篇

    //================================================================//// Copyright (C) 2017 Team Saluk ...

  5. 小妖精的完美游戏教室——buff系统

    作者:小妖精Balous,未经作者允许,任何个人与单位不得将此源代码用于商业化项目 #region buff /// <summary> /// 是否魔法免疫,魔法免疫的生物不会受到除自己 ...

  6. 小妖精的完美游戏教室——东方PROJECT,同人,墙

    //================================================================//// Copyright (C) 东方同人社// All Rig ...

  7. 小妖精的完美游戏教室——东方PROJECT,同人,符卡系统

    //================================================================//// Copyright (C) 东方同人社// All Rig ...

  8. 小妖精的完美游戏教室——东方PROJECT,同人,th12灵梦A

    ╮(╯▽╰)╭没办法,小妖精Balous也很讨厌学院化的教育呀,一点意义都没有. 这次就上传东方地灵殿灵梦A逻辑部分的核心代码吧,估计连老师都看不懂.动画部分的代码就不放上来了. //======== ...

  9. 小妖精的完美游戏教室——东方PROJECT,同人,子机

    //================================================================//// Copyright (C)// All Rights Re ...

随机推荐

  1. springboot秒杀课程学习整理1-3

    1)实现手机验证码功能,用户注册功能,用户登入功能(这里讲开发流程,及本人遇到的问题,具体实现请看代码) 1.拦截请求,获取请求参数(这里的consumes是个常量,可以定义在baseControll ...

  2. 整数中x出现的次数

    求出1~13的整数中1出现的次数,并算出100~1300的整数中1出现的次数?为此他特别数了一下1~13中包含1的数字有1.10.11.12.13因此共出现6次,但是对于后面问题他就没辙了.ACMer ...

  3. python学习------面向对象进阶

    一 isinstance(obj,cls)和issubclass(sub,super) isinstance(obj,cls)检查是否obj是否是类 cls 的对象 class Foo(object) ...

  4. fastreport窗口重置(适用于属性、数据等窗口显示不出来)

    找到如下路径: C:/Users/账户名/AppData/Local/FastReport/FastReport.config 删除即可. 记得先退出使用FastReport的程序,再删除

  5. Spark在StandAlone模式下提交任务,spark.rpc.message.maxSize太小而出错

    1.错误信息org.apache.spark.SparkException: Job aborted due to stage failure:Serialized task 32:5 was 172 ...

  6. Sql Server 获取存储过程或函数创建语句

    通过该语句可以获取到sqlserver 所有的函数名或者存储过程名 SELECT name FROM sysobjects WHERE xtype='P'; 通过该语句可查询出函数或者存储过的的创建语 ...

  7. MyBatis-day2

    Properties 属性: 如果属性在不只一个地方进行了配置,那么 MyBatis 将按照下面的顺序来加载: 在 properties 元素体内指定的属性首先被读取. 然后根据 properties ...

  8. linux - man 提示:No entry for tty in section 4 of the manual

    在使用man手册时,出现空章节的情况: 如: 原因:在CentOS6.5安装时,采用了minimal方式安装,许多包都没有安装上,man手册的man-pages包也没有安装 解决方案:安装man-pa ...

  9. [硬件黑客]钉钉智能指纹考勤机M1硬件漏洞挖掘(不定期更新)

    mailto:wangkai0351@gmail.com 钉钉智能指纹考勤机M1s,支持指纹.WIFI.蓝牙.GPS四种考勤方式,并且可实时查看考勤数据,自动生成考勤报表,告别人工核算,数据云端存储不 ...

  10. json格式字符串用Uncaught SyntaxError: Unexpected token ' Uncaught SyntaxError: Unexpected number

    Unexpected number(index)的错误用的json字符串如 var jsonStr = "{1:'北京note备注信息',2:'上海note备注信息',3:'广东note备注 ...