当前位置: 首页 > news >正文

php开发大型网站开发天津住房与城乡建设厅网站首页

php开发大型网站开发,天津住房与城乡建设厅网站首页,代理推广平台,标志设计ppt课件1、目标 实现NPC移动到目标点。 2、NPC在路径上移动架构图 流程拆解: 触发寻路请求:由AStartTest调用NPCPath.BuildPath,启动寻路流程调度管理模块:NPCPath进一步调用NPCManager.BuildPath,并把npcMovementStepStac…

1、目标

实现NPC移动到目标点。

2、NPC在路径上移动架构图

流程拆解:

  • 触发寻路请求:由AStartTest调用NPCPath.BuildPath,启动寻路流程
  • 调度管理模块:NPCPath进一步调用NPCManager.BuildPath,并把npcMovementStepStack(移动步骤的容器,后续存寻路结果)传递过去,让NPCManager接手统筹
  • 执行寻路算法:NPCManager调用AStar.BuildPath,带着npcMovementStepStack让A*算法工作,A*会计算出从起点到目标点的移动路径,把每一步的网格位置压入npcMovementStepStack
  • 更新路径数据 :寻路完成后,npcMovementStepStack带着计算好的路径,回传给NPC里的NPCPath,此时路径数据就位
  • 驱动NPC移动:NPCMovement里的Fixed Update被调用,从npcMovementStepStack里弹出下一步位置,驱动NPC移动到对应网格坐标,循环执行直到栈空

3、修改Enums.cs脚本

添加一个枚举类:

public enum Weather
{dry,raining,snowing,none,count
}

不同的天气会对应NPC不同的行为。

4、修改Settings.cs脚本 

5、修改TimeManager.cs脚本

添加函数:

public TimeSpan GetGameTime()
{TimeSpan gameTime = new TimeSpan(gameHour, gameMinute, gameSecond);return gameTime;
}

6、修改AStar.cs脚本

添加一行代码:

7、创建NPC.cs脚本

在Assets -> Scripts -> NPC目录下创建NPC.cs脚本

暂时是一个空类:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class NPC : MonoBehaviour
{}

然后把该组件加到NPC预制体上。

8、创建NPCManager.cs脚本

在Assets -> Scripts -> NPC目录下创建NPCManager.cs脚本

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;[RequireComponent(typeof(AStar))]
public class NPCManager : SingletonMonobehaviour<NPCManager>
{[HideInInspector]public NPC[] npcArray;private AStar aStar;protected override void Awake(){base.Awake();aStar = GetComponent<AStar>();// Get NPC gameobjects in scenenpcArray = FindObjectsOfType<NPC>();}private void OnEnable(){EventHandler.AfterSceneLoadEvent += AfterSceneLoad;}private void OnDisable(){EventHandler.AfterSceneLoadEvent -= AfterSceneLoad;}private void AfterSceneLoad(){SetNPCsActiveStatus();}private void SetNPCsActiveStatus(){foreach(NPC npc in npcArray){NPCMovement nPCMovement = npc.GetComponent<NPCMovement>();if(nPCMovement.npcCurrentScene.ToString() == SceneManager.GetActiveScene().name){nPCMovement.SetNPCActiveInScene();}else{nPCMovement.SetNPCInactiveInScene();}}}public bool BuildPath(SceneName sceneName, Vector2Int startGridPosition, Vector2Int endGridPosition, Stack<NPCMovementStep> npcMovementStepStack){if(aStar.BuildPath(sceneName, startGridPosition, endGridPosition, npcMovementStepStack)){return true;}else{return false;}}}

给NPCManager对象添加NPCManager组件。

9、创建NPCScheduleEvent.cs脚本

在Assets -> Scripts -> NPC目录下创建NPCScheduleEvent.cs脚本

该类会向NPC路径传递有关NPC必须做什么的信息。

这些NPC调度事件会由NPC调度程序创建。当某些事件发生时,其中一个NPC计划的事件会被创建指导NPC运动。

NPCScheduleEvent中的hour、minute是生效的事件。

priority:本来有几件事情时间一样,通过该字段区分它们的优先级。

using UnityEngine;[System.Serializable]
public class NPCScheduleEvent
{public int hour;public int minute;public int priority;public int day;public Weather weather;public Season season;public SceneName toSceneName;public GridCoordinate toGridCoordinate;public Direction npcFacingDirectionAtDestination = Direction.none;public AnimationClip animationAtDestination;public int Time{get{return (hour * 100) * minute;}}public NPCScheduleEvent(int hour, int minute, int priority, int day, Weather weather, Season season, SceneName toSceneName, GridCoordinate toGridCoordinate, AnimationClip animationAtDestination)       {this.hour = hour;this.minute = minute;this.priority = priority;this.day = day;this.weather = weather;this.season = season;this.toSceneName = toSceneName;this.toGridCoordinate = toGridCoordinate;this.animationAtDestination = animationAtDestination;}public NPCScheduleEvent(){}public override string ToString(){return $"Time: {Time}, Priority: {priority}, Day: {day} Weather: {weather}, Season: {season}";}
}

10、创建NPCPath.cs脚本

在Assets -> Scripts -> NPC目录下创建NPCPath.cs脚本。

建立一条路径,然后更新路径上每个点的时间。

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;[RequireComponent(typeof(NPCMovement))]
public class NPCPath : MonoBehaviour
{public Stack<NPCMovementStep> npcMovementStepStack;private NPCMovement npcMovement;private void Awake(){npcMovement = GetComponent<NPCMovement>();npcMovementStepStack = new Stack<NPCMovementStep>();}public void ClearPath(){npcMovementStepStack.Clear();}public void BuildPath(NPCScheduleEvent npcScheduleEvent){ClearPath();// If schedule event is for the same scene as the current NPC sceneif(npcScheduleEvent.toSceneName == npcMovement.npcCurrentScene){Vector2Int npcCurrentGridPosition = (Vector2Int)npcMovement.npcCurrentGridPosition;Vector2Int npcTargetGridPosition = (Vector2Int)npcScheduleEvent.toGridCoordinate;// Build path and add movement steps to movement step stackNPCManager.Instance.BuildPath(npcScheduleEvent.toSceneName, npcCurrentGridPosition, npcTargetGridPosition, npcMovementStepStack);// if stack count > 1, update times and then pop off 1st item which is the starting positionif(npcMovementStepStack.Count > 1){UpdateTimesOnPath();npcMovementStepStack.Pop(); // discard starting step// Set schedule event details in NPC movementnpcMovement.SetScheduleEventDetails(npcScheduleEvent);}}}/// <summary>/// Update the path movement steps with expected gametime/// </summary>public void UpdateTimesOnPath(){// Get current game timeTimeSpan currentGameTime = TimeManager.Instance.GetGameTime();NPCMovementStep previousNPCMovementStep = null;foreach(NPCMovementStep npcMovementStep in npcMovementStepStack){if(previousNPCMovementStep == null){previousNPCMovementStep = npcMovementStep;}npcMovementStep.hour = currentGameTime.Hours;npcMovementStep.minute = currentGameTime.Minutes;npcMovementStep.second = currentGameTime.Seconds;TimeSpan movementTimeStep;// if diagonalif(MovementIsDiagonal(npcMovementStep, previousNPCMovementStep)){movementTimeStep = new TimeSpan(0, 0, (int)(Settings.gridCellDiagonalSize / Settings.secondsPerGameSecond / npcMovement.npcNormalSpeed));}else{movementTimeStep = new TimeSpan(0, 0, (int)(Settings.gridCellSize / Settings.secondsPerGameSecond / npcMovement.npcNormalSpeed));}currentGameTime = currentGameTime.Add(movementTimeStep);previousNPCMovementStep = npcMovementStep;}}private bool MovementIsDiagonal(NPCMovementStep npcMovementStep, NPCMovementStep previoudNPCMovementStep){if((npcMovementStep.gridCoordinate.x != previoudNPCMovementStep.gridCoordinate.x)&& (npcMovementStep.gridCoordinate.y != previoudNPCMovementStep.gridCoordinate.y)){return true;}else{return false;}}}

11、创建NPCMovement.cs脚本

在Assets -> Scripts -> NPC目录下创建NPCMovement.cs脚本。

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;[RequireComponent(typeof(Rigidbody2D))]
[RequireComponent(typeof(Animator))]
[RequireComponent(typeof(NPCPath))]
[RequireComponent(typeof(SpriteRenderer))]
[RequireComponent(typeof(BoxCollider2D))]
public class NPCMovement : MonoBehaviour
{[HideInInspector] public SceneName npcCurrentScene;[HideInInspector] public SceneName npcTargetScene;[HideInInspector] public Vector3Int npcCurrentGridPosition;[HideInInspector] public Vector3Int npcTargetGridPosition;[HideInInspector] public Vector3 npcTargetWorldPosition;[HideInInspector] public Direction npcFacingDirectionAtDestination;private SceneName npcPreviousMovementStepScene;private Vector3Int npcNextGridPosition;private Vector3 npcNextWorldPosition;[Header("NPC Movement")]public float npcNormalSpeed = 2f;[SerializeField] private float npcMinSpeed = 1f;[SerializeField] private float npcMaxSpeed = 3f;private bool npcIsMoving = false;[HideInInspector] public AnimationClip npcTargetAniamtionClip; // 到达终点时的动画[Header("NPC Animation")][SerializeField] private AnimationClip blankAnimation = null;private Grid grid;private Rigidbody2D rigidbody2D;private BoxCollider2D boxCollider2D;private WaitForFixedUpdate waitForFixedUpdate;private Animator animator;private AnimatorOverrideController animatorOverrideController;private int lastMoveAnimationParameter;private NPCPath npcPath;private bool npcInitialised = false;private SpriteRenderer spriteRenderer;[HideInInspector] public bool npcActiveInScene = false;private bool sceneLoaded = false;private Coroutine moveToGridPositionRoutine;private void OnEnable(){EventHandler.AfterSceneLoadEvent += AfterSceneLoad;EventHandler.BeforeSceneUnloadEvent += BeforeSceneUnloaded; }private void OnDisable(){EventHandler.AfterSceneLoadEvent -= AfterSceneLoad;EventHandler.BeforeSceneUnloadEvent -= BeforeSceneUnloaded;}private void Awake(){rigidbody2D = GetComponent<Rigidbody2D>();boxCollider2D = GetComponent<BoxCollider2D>();animator = GetComponent<Animator>();npcPath = GetComponent<NPCPath>();spriteRenderer = GetComponent<SpriteRenderer>();animatorOverrideController = new AnimatorOverrideController(animator.runtimeAnimatorController);animator.runtimeAnimatorController = animatorOverrideController;// Initialise target world position, target grid postiion & target scene to currentnpcTargetScene = npcCurrentScene;npcTargetGridPosition = npcCurrentGridPosition;npcTargetWorldPosition = transform.position;}private void Start(){waitForFixedUpdate = new WaitForFixedUpdate();SetIdleAnimation();}private void SetIdleAnimation(){animator.SetBool(Settings.idleDown, true);}private void FixedUpdate(){if (sceneLoaded){if(npcIsMoving == false){// set npc current and next grid position - to take into account the npc might be animatingnpcCurrentGridPosition = GetGridPosition(transform.position);npcNextGridPosition = npcCurrentGridPosition;if(npcPath.npcMovementStepStack.Count > 0){NPCMovementStep npcMovementStep = npcPath.npcMovementStepStack.Peek();npcCurrentScene = npcMovementStep.sceneName;// If NPC is in current scene then set NPC to active to make visible, pop the movement step off the stack // and then call method to move NPCif(npcCurrentScene.ToString() == SceneManager.GetActiveScene().name){SetNPCActiveInScene();npcMovementStep = npcPath.npcMovementStepStack.Pop();npcNextGridPosition = (Vector3Int)npcMovementStep.gridCoordinate;TimeSpan npcMovementStepTime = new TimeSpan(npcMovementStep.hour, npcMovementStep.minute, npcMovementStep.second);MoveToGridPosition(npcNextGridPosition, npcMovementStepTime, TimeManager.Instance.GetGameTime());}}// else if no more NPC movement stepselse{ResetMoveAnimation();SetNPCFacingDirection();SetNPCEventAnimation();}}}}private void SetNPCEventAnimation(){if(npcTargetAniamtionClip != null){ResetIdleAnimation();animatorOverrideController[blankAnimation] = npcTargetAniamtionClip;animator.SetBool(Settings.eventAnimation, true);}else{animatorOverrideController[blankAnimation] = blankAnimation;animator.SetBool(Settings.eventAnimation, false);}}private void SetNPCFacingDirection(){ResetIdleAnimation();switch (npcFacingDirectionAtDestination){case Direction.up:animator.SetBool(Settings.idleUp, true);break;case Direction.down:animator.SetBool(Settings.idleDown, true);break;case Direction.left:animator.SetBool(Settings.idleLeft, true);break;case Direction.right:animator.SetBool(Settings.idleRight, true);break;case Direction.none:break;default:break;}}private void ResetMoveAnimation(){animator.SetBool(Settings.walkRight, false);animator.SetBool(Settings.walkLeft, false);animator.SetBool(Settings.walkUp, false);animator.SetBool(Settings.walkDown, false);}private void ResetIdleAnimation(){animator.SetBool(Settings.idleRight, false);animator.SetBool(Settings.idleLeft, false);animator.SetBool(Settings.idleUp, false);animator.SetBool(Settings.idleDown, false);}private void MoveToGridPosition(Vector3Int gridPosition, TimeSpan npcMovementStepTime, TimeSpan gameTime){moveToGridPositionRoutine = StartCoroutine(MoveToGridPositionRoutine(gridPosition, npcMovementStepTime, gameTime));}private IEnumerator MoveToGridPositionRoutine(Vector3Int gridPosition, TimeSpan npcMovementStepTime, TimeSpan gameTime){npcIsMoving = true;SetMoveAnimation(gridPosition);npcNextWorldPosition = GetWorldPosition(gridPosition);// If movement step time is in the future, otherwise skip and move NPC immediately to positionif(npcMovementStepTime > gameTime){// calculate time difference in secondsfloat timeToMove = (float)(npcMovementStepTime.TotalSeconds - gameTime.TotalSeconds);// Calculate speedfloat npcCalculatedSpeed = Vector3.Distance(transform.position, npcNextWorldPosition) / timeToMove / Settings.secondsPerGameSecond;// if speed is at least npc min speed and lesss npc max speed then process, otherwise skip and move NPC immediately to positionif(npcCalculatedSpeed >= npcMinSpeed && npcCalculatedSpeed <= npcMaxSpeed){while(Vector3.Distance(transform.position, npcNextWorldPosition) > Settings.pixelSize){Vector3 unitVector = Vector3.Normalize(npcNextWorldPosition - transform.position);Vector2 move = new Vector2(unitVector.x * npcCalculatedSpeed * Time.fixedDeltaTime, unitVector.y * npcCalculatedSpeed * Time.fixedDeltaTime);rigidbody2D.MovePosition(rigidbody2D.position + move);yield return waitForFixedUpdate;}}Debug.Log("here!");}rigidbody2D.position = npcNextWorldPosition;npcCurrentGridPosition = gridPosition;npcNextGridPosition = npcCurrentGridPosition;npcIsMoving = false;}private void SetMoveAnimation(Vector3Int gridPosition){// Reset idle animationResetIdleAnimation();// Reset move animationResetMoveAnimation();// get world positionVector3 toWorldPosition = GetWorldPosition(gridPosition);// get vectorVector3 directionVector = toWorldPosition - transform.position;if(Mathf.Abs(directionVector.x) >= Mathf.Abs(directionVector.y)){// Use left/right animationif(directionVector.x > 0){animator.SetBool(Settings.walkRight, true);}else{animator.SetBool(Settings.walkLeft, true);}}else{// Use up/down animationif(directionVector.y > 0){animator.SetBool(Settings.walkUp, true);}else{animator.SetBool(Settings.walkDown, true);}}}private Vector3Int GetGridPosition(Vector3 worldPosition){if(grid != null){return grid.WorldToCell(worldPosition);}else{return Vector3Int.zero;}}public void SetNPCActiveInScene(){spriteRenderer.enabled = true;boxCollider2D.enabled = true;npcActiveInScene = true;}private void AfterSceneLoad(){grid = GameObject.FindObjectOfType<Grid>();if (!npcInitialised){InitialisedNPC();npcInitialised = true;}sceneLoaded = true;}private void InitialisedNPC(){// Active in sceneif(npcCurrentScene.ToString() == SceneManager.GetActiveScene().name){SetNPCActiveInScene();}else{SetNPCInactiveInScene();}// Get NPC Current Grid PositionnpcCurrentGridPosition = GetGridPosition(transform.position);// Set next grid position and target grid position to current grid positionnpcNextGridPosition = npcCurrentGridPosition;npcTargetGridPosition = npcCurrentGridPosition;npcTargetWorldPosition = GetWorldPosition(npcTargetGridPosition);// Get NPC WorldPositionnpcNextWorldPosition = GetWorldPosition(npcCurrentGridPosition);}private void BeforeSceneUnloaded(){sceneLoaded = false;}public void SetScheduleEventDetails(NPCScheduleEvent npcScheduleEvent){npcTargetScene = npcScheduleEvent.toSceneName;npcTargetGridPosition = (Vector3Int)npcScheduleEvent.toGridCoordinate;npcTargetWorldPosition = GetWorldPosition(npcTargetGridPosition);npcFacingDirectionAtDestination = npcScheduleEvent.npcFacingDirectionAtDestination;npcTargetAniamtionClip = npcScheduleEvent.animationAtDestination;ClearNPCEventAnimation();}public void ClearNPCEventAnimation(){animatorOverrideController[blankAnimation] = blankAnimation;animator.SetBool(Settings.eventAnimation, false);// Clear any rotation on npctransform.rotation = Quaternion.identity;}public void SetNPCInactiveInScene(){spriteRenderer.enabled = false;boxCollider2D.enabled = false;npcActiveInScene = false;}/// <summary>/// returns the world position (centre of grid square) from gridPosition/// </summary>/// <param name="gridPosition"></param>/// <returns></returns>public Vector3 GetWorldPosition(Vector3Int gridPosition){Vector3 worldPosition = grid.CellToWorld(gridPosition);// Get centre of grid squarereturn new Vector3(worldPosition.x + Settings.gridCellSize / 2f, worldPosition.y + Settings.gridCellSize / 2f, worldPosition.z);}}

12、配置对象

(1)NPC_Butch配置组件

点击Assets -> Prefabs -> NPC,然后点击其下的NPC,添加NPC Movement组件,同时会自动添加NPCPath组件。配置其参数如下:

此时看NPC_Butch对象,也添加了NPCMovement和NPCPath组件。

(2)删除Grid对象

删除Hierarchy下的Grid对象。

(3)修改AStarTest.cs脚本

重写这块代码如下:

using UnityEngine;public class AStarTest : MonoBehaviour
{[SerializeField] private NPCPath npcPath = null;[SerializeField] private bool moveNPC = false;[SerializeField] private Vector2Int finishPosition;[SerializeField] private AnimationClip idleDownAnimationClip = null;[SerializeField] private AnimationClip eventAnimationClip = null;private NPCMovement npcMovement;private void Start(){npcMovement = npcPath.GetComponent<NPCMovement>();npcMovement.npcFacingDirectionAtDestination = Direction.down;npcMovement.npcTargetAniamtionClip = idleDownAnimationClip;}private void Update(){if (moveNPC){moveNPC = false;NPCScheduleEvent npcScheduleEvent = new NPCScheduleEvent(0, 0, 0, 0, Weather.none, Season.none, SceneName.Scene1_Farm, new GridCoordinate(finishPosition.x, finishPosition.y), eventAnimationClip);npcPath.BuildPath(npcScheduleEvent);}}
}

(4)配置NPCManager对象

13、VIP代码流程解读(走读代码先看这里)

  1. NPCScheduleEvent类定义了NPC要做的事项,大致上是在哪个场景下(场景信息)什么时间(时间信息)去哪里(位置信息)做什么事情(动画信息)。
  2. 在AStarTest中让npcPath.BuildPath处理NPCScheduleEvent中的路径信息。

     3. NPCPath主要是计算出路径(多个点)以及路径上每个点的时间,即什么时间需要到达点。路径是通过AStar算法计算出来的,该信息更新到npcMovementStepStack中。

计算时间的方式:获取当前的时间,然后每获取路径上一个点,该点的时间就往后延一点,这样就得到了路径上每个点需要到达的时间。该信息更新到npcMovementStep中。

     4. NPCMovement:通过协程的方式实现NPC的实际移动。在FixedUpdate中不断获取npcMovementStepStack的元素,对于每一个元素,如果当前时间超过了元素中的时间,则通过rigidbody2D.MovePosition逐步移动到元素中的位置。

14、运行游戏

(1)只行走

NPC当前位于(-6,0)

勾选Move NPC:

(2)行走完抽烟

因为录像的原因,导致Unity运行跳帧特别明显。

http://www.yayakq.cn/news/668757/

相关文章:

  • 网站策划书一般包括以下内容河北省招标投标公共服务平台
  • 哪些网站做的美剧广东建设职业注册中心网站
  • 国内网站做得好的公司上海工程相关的公司
  • dede笑话网站源码职业生涯规划大赛ppt
  • 网站网页制作模板修改wordpress插件怎么用
  • 网站设计规范西安比较厉害的软件公司
  • 英文 网站 字体云服务器租赁
  • 电子商务网站建设是学什么软件推广价格一般多少
  • 网站建设 类郑州厉害的seo优化顾问
  • 公司内部网站创建企业网站托管一年多少钱
  • 网站建设及维护保密协议金色世纪做网站的是哪个岗位
  • 网站怎么做超链接me域名网站
  • 梁山做网站宝安营销型网站制作
  • php5 mysql网站开发基础与应用大数据技术与应用
  • 网站子站怎么建设什么是二级域名网站
  • vi设计欣赏网站免费网站设计素材
  • 淄博便宜网站设wordpress 嵌入 php代码
  • 网站建设教程asp网站建设需要那种技术
  • 网站设计 psd软件开发流程流程图
  • 江西省飞宏建设工程有限公司 网站网页微信扫码登录
  • 网站优化步骤自考本科含金量高吗
  • 个人如何做网站建设信息港查询
  • 政务公开 加强门户网站建设旅游网站设计模板图片
  • 设计一个企业网站报价网站建设公司哪家强
  • 网站如何建设二级域名代理wordpress p=
  • 临沂做网站的公司有哪些红谷滩园林建设集团网站
  • 如何建做校园购物网站市场营销网站建设
  • vs2017 做网站微信公众号商城搭建
  • 为什么一个人做网站有难度长春网站建设案例
  • 网站建设技术方案模板海淀做网站设计的公司