IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 游戏开发 -> Unity数字孪生开发笔记——轿厢基本运动实现 -> 正文阅读

[游戏开发]Unity数字孪生开发笔记——轿厢基本运动实现

一、轿厢实例说明

  • 楼层信息获取----包括楼层名和在各楼层时轿厢的位置;
  • 轿厢上下移动----判断当前位置与目标点的距离,通过距离的正负来决定移动方向;
  • 对重移动----对重的移动取决于轿厢,同时与轿厢应保持速度相同和运动方向相反;
  • 开关层门与轿厢门----根据轿厢的状态以及轿厢当前位置判断是否停靠在某一层,播放动画;
  • 轿厢AI----根据情况自动调用以上各部分。

二、需求分析

1、轿厢移动

  • 定义列表变量----楼层信息
  • 轿厢运动状态判断及运行----上行、下行、停止

1>楼层信息

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

/// <summary>
/// 定义状态信息类,定义轿厢人员信息,
/// </summary>
public class StatusInfo : MonoBehaviour
{
    /// <summary>
    /// 当前电梯人数
    /// </summary>
    public int people = 2;

    /// <summary>
    /// 电梯可承载人数最大值
    /// </summary>
    public int maxPeople = 12;

    /// <summary>
    /// 当前正在走进或走出电梯的人数
    /// </summary>
    public int amountPeople = 2;

    /// <summary>
    /// 人员流动
    /// </summary>
    public bool MovePeople()
    {
        int currentPeople = people + amountPeople;
        //如果当前电梯没人或者没有人员流动
        if (people == 0 || currentPeople == people)
            return false;
        //如果电梯当前人数大于最大承载量
        else if (currentPeople > maxPeople)
            return false;
        else
            return true;
    }

}

2>轿厢运动

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

/// <summary>
/// 控制轿厢移动
/// </summary>
public class Move : MonoBehaviour
{
    public Transform[] points;
    public WayLine line;
    

    //当前路点索引
    private int currentPointIndex=0;

    public float MoveSpeed = 5;

    /// <summary>
    /// 定义轿厢运行状态
    /// </summary>
    public enum CarState
    {
        up,
        down,
        stop
    }
    public CarState carCurrentState = CarState.stop;

    /// <summary>
    /// 轿厢状态判断
    /// </summary>
    /// <param name="point">目标点坐标</param>
    public CarState CarStateJudge(Vector3 point)
    {
        if (this.transform.position.y < point.y && (decimal)Vector3.Distance(this.transform.position, point) > 0.05m)
            return carCurrentState = CarState.up;
        else if (this.transform.position.y > point.y && (decimal)Vector3.Distance(this.transform.position, point) > 0.05m)
            return carCurrentState = CarState.down;
        else
            return carCurrentState = CarState.stop;
    }

 

    /// <summary>
    /// 轿厢上行、下行、停止
    /// </summary>
    /// <param name="point">目标点</param>
    public void CarMovement()
    {
        try
        {
            //如果当前楼层的索引小于存储的楼层数
            if (currentPointIndex < points.Length)
            {
                CarStateJudge(points[currentPointIndex].position);
                switch (carCurrentState)
                {
                    case CarState.up:
                        this.transform.Translate(0, MoveSpeed * Time.deltaTime, 0);
                        break;
                    case CarState.down:
                        this.transform.Translate(0, -MoveSpeed * Time.deltaTime, 0);
                        break;
                    case CarState.stop:
                        this.transform.Translate(0, 0, 0);
                        break;
                }
            }            
        }
        catch { }
                  
    }

    /// <summary>
    /// 寻路,沿路线(Vector3[])移动
    /// </summary>
    /// <returns></returns>
    public bool Pathfinding()
    {
        //如果到达目标点(判断 当前位置 与 目标点间距 Vector3.Distance)
        //更新目标点(向下一个路点移动)
        if (points == null || currentPointIndex >= points.Length)
        {
            this.transform.Translate(0, 0, 0);
            return false;
        }
        else
        {
            //移动
            CarMovement();

            //如果到达目标点(当前位置 趋近于 目标点)
            if ((decimal)Vector3.Distance(this.transform.position, points[currentPointIndex].position) < 0.05m)
                currentPointIndex++;
            return true;//可以继续寻路
        }                
    }

}


2、对重移动

  • 对重移动与轿厢移动相反,同时要跟随轿厢移动
  • 欠缺:只能将轿厢的位置放在最高,对重的位置放在最低,后期可能会想着将这两个对象的位置时刻关联(估计有难度)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

/// <summary>
/// 对重移动
/// </summary>
public class CWMove : MonoBehaviour
{
    /// <summary>
    /// 根据轿厢状态判断对重运行状态
    /// </summary>
    /// <param name="car">轿厢</param>
    public void CwMoveByCar(bool IsRun,Move carmove)
    {
        //轿厢是否在移动
        if (IsRun == true)
        {
            //轿厢往上还是往下移动
            if (carmove.carCurrentState == Move.CarState.down)
            {
                this.transform.Translate(0,0, -carmove.MoveSpeed*3 * Time.deltaTime);
            }
            else if (carmove.carCurrentState == Move.CarState.up)
                this.transform.Translate(0, 0,carmove.MoveSpeed *3* Time.deltaTime);
        }
        else
            this.transform.Translate(0, 0, 0);
    }
}


3、开关门动画

1>挂载到物体上的动画类

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

/// <summary>
/// 开关门动画,定义需要播放的动画片段名称
/// </summary>
public class DoorAnimation : MonoBehaviour
{

    public string[] BuildingDoor; 

    /// <summary>
    /// 行为类
    /// </summary>
    public Animations action;
    private void Awake()
    {
        //查找后代中具有Animation组件的子物体(有则返回第一个,无返回null)
        action = new Animations(GetComponentInChildren<Animation>());
    }
}

2>普通C#动画类

  • 目前遇到问题----如何将同一个动画正播后停止在最后一帧,在过几秒钟后将该动画倒播回去
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

/// <summary>
/// 动画行为类,提供有关动画的行为
/// </summary>
public class Animations 
{
    //附加在敌人模型上的动画组件引用
    private Animation anim;

    /// <summary>
    /// 创建动画行为类
    /// </summary>
    /// <param name="anim">附加在敌人模型上的动画组件引用</param>
    public Animations(Animation anim)
    {
        this.anim = anim;
    }

    //播放动画
    public void Play(string animName)
    {
        //anim.CrossFade(animName);
        anim.Play(animName);
    }

    /// <summary>
    /// 判断指定动画是否正在播放
    /// </summary>
    /// <param name="animName">动画片段名称</param>
    /// <returns></returns>
    public bool IsPlaying(string animName)
    {
        return anim.IsPlaying(animName);
    }
}

4、轿厢AI

  • 定义电梯状态信息----运动、停止、待机、检修
  • 根据每个状态来定义各自实现的功能
  • 运行过程如果到达目标层----状态改为停止
  • 若不在规定的楼层停止----状态改为检修,在规定的楼层停止----播放开关门动画,没人后状态改为待机
  • 若在待机过程中,目标位置发生改变----运行状态改为运动
  • 欠缺:停止过程的动画只能播放一次(目前是倒播),DeBug过程他也能进去,但实际就是不管用,试了好几个函数都没用(气的暂停这步了)
  • 欠缺:检修状态的事件暂时没想到
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

/// <summary>
/// 轿厢AI
/// </summary>
[RequireComponent(typeof(DoorAnimation))]
[RequireComponent(typeof(StatusInfo))]


public class CarAI : MonoBehaviour
{
    //定义轿厢状态的枚举类型
    public enum State
    {
        Run,//运行
        Stop,//停止
        Check,//故障
        Rest//休息
    }

    private State currentState = State.Run;
    private DoorAnimation anim;
    private Move move;
    private CWMove cw;
    private FloorInfo floor;
    private StatusInfo stf;
    
    private void Start()
    {
        anim = GetComponent<DoorAnimation>();
        move = GetComponentInChildren<Move>();
        cw = GetComponentInChildren<CWMove>();
        floor = GetComponentInChildren<FloorInfo>();
        floor.AddFloor();
        stf = GetComponent<StatusInfo>();
    }

    private void Update()
    {
        //判断
        switch(currentState)
        {
            case State.Run:
                Run();
                break;
            case State.Stop:
                Stop();
                break;
            case State.Rest:
                Rest();
                break;
            case State.Check:
                Check();
                break;
        }
    }

    /// <summary>
    /// 判断在电梯停在哪层
    /// </summary>
    private void Stop()
    {
        //判断电梯是否停好了
        bool IsStopOk = false;

        int fl = 0;
        //运行停止
        //播放轿厢开门动画
        foreach (KeyValuePair<int,Vector3>kv in floor.Floor)
        {
            //判断当前位置与某一楼层的位置是否接近
            if((decimal)Vector3.Distance(move.transform.position, kv.Value) < 0.05m)
            {
                if (kv.Key == -1)
                {
                    anim.action.Play(anim.BuildingDoor[0]);
                }                    
                else
                {
                    anim.action.Play(anim.BuildingDoor[kv.Key]);//播放开门动画
                    fl = kv.Key;//拿到楼层信息
                }
                                    
                IsStopOk = true;//电梯停好了
                break;
            }
        }
        
        
        if(IsStopOk==true)
        {
            float i = 0;
            while (true)
            {   
                i += Time.deltaTime;
                //如果超过2秒没人,播放关门动画
                if (i >= 2 && stf.MovePeople() == false)
                {
                    anim.action.Close(anim.BuildingDoor[fl]);
                    currentState = State.Rest;
                    break;
                }
            }                      
        }
        else
        {
            currentState = State.Check;//将电梯标记为出故障
        }
    }

    private void Run()
    {
        //执行寻路(调用move中的寻路方法)
        move.Pathfinding();
        cw.CwMoveByCar(move.Pathfinding(), move);
        //如果寻路结束,修改状态为停止
        if (move.Pathfinding() == false) currentState = State.Stop;
    }


    private void Rest()
    {
        //Debug.Log("电梯处于待机状态");
        move.carCurrentState = Move.CarState.stop;
        move.CarMovement();
        if (move.CarStateJudge(move.points[0].position) != Move.CarState.stop)
            currentState = State.Run;

    }

    private void Check()
    {
        //Debug.Log("电梯故障,请及时处理");
    }
}


三、效果图

在这里插入图片描述

  • 整体缺陷:
    1、使用Translate进行移动,会存在到了指定楼层后一直上下抖动的情况,导致动画不播放(其实把判断的距离设大就行,但是看起来就不贴合实际了)
    2、同一个动画的正播和反播问题
    3、初步想法,后期有待完善
  游戏开发 最新文章
6、英飞凌-AURIX-TC3XX: PWM实验之使用 GT
泛型自动装箱
CubeMax添加Rtthread操作系统 组件STM32F10
python多线程编程:如何优雅地关闭线程
数据类型隐式转换导致的阻塞
WebAPi实现多文件上传,并附带参数
from origin ‘null‘ has been blocked by
UE4 蓝图调用C++函数(附带项目工程)
Unity学习笔记(一)结构体的简单理解与应用
【Memory As a Programming Concept in C a
上一篇文章      下一篇文章      查看所有文章
加:2021-12-13 13:11:29  更:2021-12-13 13:13:03 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/27 21:04:20-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码