//================================================================
//
// 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. CentOS 7安装部署ELK 6.2.4-SUCCESS

    一.ELK介绍 ELK是三款开源软件的缩写,即:ElasticSearch + Logstash + Kibana.这三个工具组合形成了一套实用.易用的监控架构,可抓取系统日志.apache日志.ng ...

  2. tensorflow (七) k-means

    tensorflow基础暂不介绍 Python 相关库的安装 在进入正式聚类实验之前,我们还需要配置计算及画图需要用到相关支持包. 安装 seaborn: pip install seaborn 安装 ...

  3. 通读SCRUM实战指南教材,提出5个问题。

    问题一:为什么要制定优先级的排定和调整? 创建一个排好优先级的项目组合并讲重点放在转移团队上,如果做得对,可以消除在项目数量超过团队能力 的情况下过于常见的多任务处理. 问题二:为什么我们要做文档? ...

  4. Forth 编译程序

    body, table{font-family: 微软雅黑; font-size: 13.5pt} table{border-collapse: collapse; border: solid gra ...

  5. lintcode 四道题

    我们考虑对每个字符进行两边扩展,寻找回文串,并记录长度.有两种情况,一种是bab,从a向两边扩展,一种abba,从bb中间向两边扩展. dp[i][j] 表示子串s[i-j]是否是回文 初始化:dp[ ...

  6. pandas groupby生成新的dataframe

    mark地址:https://blog.csdn.net/weixin_41784098/article/details/79486259

  7. UDP聊天工具的实现

    利用TIdUDPClient;   TIdUDPServer;  实现聊天,其实很不爽,没有解决中文乱码问题,以后补充吧!      代码如下: unit Unit1; interface uses ...

  8. C# 事件的使用方法

    事件 事件是C#中另一高级概念,使用方法和委托相关.奥运会参加百米的田径运动员听到枪声,比赛立即进行.其中枪声是事件,而运动员比赛就是这个事件发生后的动作.不参加该项比赛的人对枪声没有反应. 从程序员 ...

  9. 没有与这些操作数匹配的 "<<" 运算符 操作数类型为: std::ostream << std::string

    错误显示:没有与这些操作数匹配的 "<<" 运算符       操作数类型为:  std::ostream << std::string 错误改正:要在头文 ...

  10. CPU温度的实现

    CPU温度需要安装的模块:apt-get install lm-sensors   然后再安装:pip install sensors.py 代码如下: #coding=utf-8import sen ...