哪个网站可以学做包包,平面设计要什么学历,二手房网站平台怎么做,图片网站模版1、目标
实现NPC移动到目标点。
2、NPC在路径上移动架构图 流程拆解#xff1a;
触发寻路请求#xff1a;由AStartTest调用NPCPath.BuildPath#xff0c;启动寻路流程调度管理模块#xff1a;NPCPath进一步调用NPCManager.BuildPath#xff0c;并把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 : SingletonMonobehaviourNPCManager
{[HideInInspector]public NPC[] npcArray;private AStar aStar;protected override void Awake(){base.Awake();aStar GetComponentAStar();// Get NPC gameobjects in scenenpcArray FindObjectsOfTypeNPC();}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.GetComponentNPCMovement();if(nPCMovement.npcCurrentScene.ToString() SceneManager.GetActiveScene().name){nPCMovement.SetNPCActiveInScene();}else{nPCMovement.SetNPCInactiveInScene();}}}public bool BuildPath(SceneName sceneName, Vector2Int startGridPosition, Vector2Int endGridPosition, StackNPCMovementStep 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 StackNPCMovementStep npcMovementStepStack;private NPCMovement npcMovement;private void Awake(){npcMovement GetComponentNPCMovement();npcMovementStepStack new StackNPCMovementStep();}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/// /summarypublic 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 GetComponentRigidbody2D();boxCollider2D GetComponentBoxCollider2D();animator GetComponentAnimator();npcPath GetComponentNPCPath();spriteRenderer GetComponentSpriteRenderer();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.FindObjectOfTypeGrid();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 namegridPosition/param/// returns/returnspublic 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、配置对象
1NPC_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.GetComponentNPCMovement();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代码流程解读走读代码先看这里
NPCScheduleEvent类定义了NPC要做的事项大致上是在哪个场景下场景信息什么时间时间信息去哪里位置信息做什么事情动画信息。在AStarTest中让npcPath.BuildPath处理NPCScheduleEvent中的路径信息。 3. NPCPath主要是计算出路径多个点以及路径上每个点的时间即什么时间需要到达点。路径是通过AStar算法计算出来的该信息更新到npcMovementStepStack中。
计算时间的方式获取当前的时间然后每获取路径上一个点该点的时间就往后延一点这样就得到了路径上每个点需要到达的时间。该信息更新到npcMovementStep中。 4. NPCMovement通过协程的方式实现NPC的实际移动。在FixedUpdate中不断获取npcMovementStepStack的元素对于每一个元素如果当前时间超过了元素中的时间则通过rigidbody2D.MovePosition逐步移动到元素中的位置。 14、运行游戏
1只行走
NPC当前位于-60 勾选Move NPC 2行走完抽烟 因为录像的原因导致Unity运行跳帧特别明显。