Unity3D移动平台简单实现

在电子游戏中移动平台可谓是十分常见的,如平台从一处至另一处的来回移动,或当需要玩家触发机关时,平台浮动并按一定的路线移动至目标处。本文主要是在Unity3D引擎下使用少量脚本实现两点之间来回移动平台的最基本功能,是一种比较简单且好理解的移动平台解决方案。

涉及到的点如下:

  • 平台对象的实现
  • 平台移动路线的设定
  • 处于平台上游戏对象(如:玩家)的相对运动

创建平台控制对象

创建一个空对象,命名为PlatformObject,保证其transform.scale为默认值(1,1,1),为其添加Box Collider组件,Is Trigger设为True,添加一个脚本,命名为PlatformController.cs,需要提出的是,该对象不是平台的实体,而是主要用于控制平台实体的移动和实现相对运动。
PlatformObject

创建平台实体对象

使用方块构建平台的外形,在对象PlatformObject下新建一个cube子对象,命名为Platform,该子对象才是平台的实体,并适当的设置cube的transform.scale属性,调整方块的长宽高,并为其添加一个Box Collider组件,平台的其他属性可自行设置。
如下:
platfrom
层级关系
设置父对象的Box Collider的size与子对象的scale一致,保证父对象的碰撞范围与平台实体的大小一致。

实现平台控制

编辑PlatformController.cs脚本,以下代码主要实现:平台在两点之间来回移动并在到达两点时适当停留的功能,以及保证平台上的其他游戏对象相对于平台运动的功能。

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

/// <summary>
/// 来回移动平台的控制
/// </summary>
public class PlatformController : MonoBehaviour {

    [Tooltip("平台移动的结束位置")]
    public Vector3 stopPosiiton;
    [Tooltip("平台移动一次的时间")]
    public float moveTime = 1f;
    [Tooltip("平台到边界后的停留时间")]
    public float stayTime = 1f;

    private bool toStop = true;         // 是否朝结束位置移动
    private float speed;                // 移动的速度
    private Vector3 startPostion;       // 开始位置

    internal bool on = false;           // 平台移动开关,是否允许平台移动
    void Start() {
        startPostion = transform.position;
        speed = Vector3.Distance(transform.position, stopPosiiton) / moveTime;
    }
    void Update(){
        PlatformMoveOn(on);
    }

    /// <summary>
    /// 平台移动控制
    /// </summary>
    /// <param name="on">平台移动开关</param>
    void PlatformMoveOn(bool on){
        if(!on){return;}
        StartCoroutine(PlatformMove(stopPosiiton));
    }

    /// <summary>
    /// 具体平台移动控制
    /// </summary>
    /// <param name="stopPosiiton">停止位置</param>
    /// <returns></returns>
    IEnumerator PlatformMove( Vector3 stopPosiiton){
        Vector3 tempPosition = transform.position;
        if (toStop){
            tempPosition = Vector3.MoveTowards(tempPosition, stopPosiiton, speed*Time.deltaTime);
            transform.position = tempPosition;
            if (transform.position == stopPosiiton){
                yield return new WaitForSeconds(stayTime);
                toStop = false;
            }
        }
        else if (!toStop){
            tempPosition = Vector3.MoveTowards(tempPosition, startPostion, speed*Time.deltaTime);
            transform.position = tempPosition;
            if (transform.position == startPostion){
                yield return new WaitForSeconds(stayTime);
                toStop = true;
            }
        }
    }

    // 相对运动
    void OnTriggerEnter(Collider other){
        other.transform.SetParent(transform);
    }
    void OnTriggerExit(Collider other){
        other.transform.SetParent(null);
    }

    // 便于调试
    void OnDrawGizmosSelected() {
        Gizmos.color = Color.red;
        Gizmos.DrawWireCube(stopPosiiton, transform.GetChild(0).localScale);
    }
}

相对运动注意点

本解决方案通过将对象Platform即平台实体作为对象PlatformObject的子对象,并使用脚本控制PlatformObject对象来间接控制平台实体的移动,但是处于平台上的其他游戏对象相对于平台进行移动的功能与平台实体是无关的,可以理解为Platform对象是平台的外形,而平台的功能核心(移动、相对运动)是父对象PlatfomrObject。在以上脚本中有两个Trigger方法;

    void OnTriggerEnter(Collider other){
        other.transform.SetParent(transform);
    }
    void OnTriggerExit(Collider other){
        other.transform.SetParent(null);
    }

一个是当其他游戏对象进入对象PlatformObject的碰撞体时该对象则作为PlatformObject的子对象,当该对象脱离PlatformObject的碰撞体时则将其与PlatformObject的父子关系解除。即通过设定父子关系(SetParent())来实现平台上其他对象相对于平台进行相对运动。至此,平台移动的基本功能均已实现。
但是,需要注意的是,不能通过改变父对象的transform来改变平台的外形,且一定要保证父对象的scale为(1,1,1),为什么?因为,这是通过设定父子关系(SetParent())实现平台上其他对象相对于平台进行运动的关键,当父对象scale不是(1,1,1)时,其他对象进入平台碰撞时,其sacle会根据父对象的scale发生相应的变化,这就导致其他对象的变形。

方法参考:
Transform.SetParent
Transform.parent


题外话:实际上,在进行正式开发时,应该尽量保证对象的scale为(1,1,1),而对象外形的具体大小则应该在建模时就要考虑到,Unity3D官方文档也有提到这一点importance of scale & use the right size

猜你喜欢

转载自blog.csdn.net/Domain_Jacker/article/details/81087469