使用unity在Android环境开发记录(第三部分)

1.创建新项目,导入资源

 在unity商店导入素材

导入 Input System和Device Simulator Devices包,并进行配置。

Device Simulator Devices包,UI适配神器 移动设备模拟器

Input System配置

Device Simulator Devices配置

2.修改主相机的参数

3.在场景中新建空物体Player,将位置Reset,在Player上添加组件Rigidbody。

将飞机模型预制体放到Player下方

4.在Player上新建脚本PlayerMovement,控制飞机的移动

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

// 玩家移动脚本,用于控制玩家角色的移动
public class PlayerMovement : MonoBehaviour
{
    // 力的大小,用于计算每帧要施加给刚体的力
    [SerializeField] private float forceMagnitude = 10f;
    // 最大力限制,用于限制刚体速度的最大值
    [SerializeField] private float maxVelocity = 5f;
    [SerializeField] private float rotationSpeed = 5f;
    // 移动方向,存储玩家每帧想要移动的方向
    private Vector3 movementDirection;
    // 刚体组件,用于控制玩家的物理行为
    private Rigidbody rb;
    // 主相机,用于将屏幕坐标转换为世界坐标
    private Camera mainCamera;

    // 初始化方法,用于缓存刚体和主相机的引用
    void Start()
    {
        rb = GetComponent<Rigidbody>();
        mainCamera = Camera.main;
    }

    // 更新方法,用于处理玩家的输入和移动方向的计算
    void Update()
    {
        // 处理玩家的输入
        ProcessInput();
        // 限制玩家在屏幕内
        KeepPlayerOnScreen();
        // 旋转对象以面对刚体的运动方向
        RotateToFaceVelocity();
    }

    // 固定更新方法,用于应用力和限制速度
    void FixedUpdate()
    {
        // 如果移动方向为零向量,则不执行任何操作
        if (movementDirection == Vector3.zero) { return; }

        // 根据移动方向和力的大小施加力给刚体
        rb.AddForce(movementDirection * forceMagnitude * Time.deltaTime, ForceMode.Force);
        // 限制刚体速度的最大值
        rb.velocity = Vector3.ClampMagnitude(rb.velocity, maxVelocity);
    }

    private void ProcessInput()
    {
        // 检查是否有触摸按下
        if (Touchscreen.current.primaryTouch.press.isPressed)
        {
            // 获取触摸位置并转换为世界坐标
            Vector2 mousePosition = Touchscreen.current.primaryTouch.position.ReadValue();
            Vector3 worldPosition = mainCamera.ScreenToWorldPoint(mousePosition);

            // 计算玩家位置与触摸位置的方向
            movementDirection = transform.position - worldPosition;
            // 忽略Z轴,仅在XOY平面上移动
            movementDirection.z = 0;
            // 归一化方向向量
            movementDirection.Normalize();
        }
        else
        {
            // 如果没有触摸按下,重置移动方向为零向量
            movementDirection = Vector3.zero;
        }
    }

    private void KeepPlayerOnScreen()
    {
        // 获取玩家当前位置
        Vector3 playerPosition = transform.position;
        // 获取玩家的视图空间位置
        Vector3 viewportPosition = mainCamera.WorldToViewportPoint(transform.position);

        // 检查玩家是否在屏幕外
        if (viewportPosition.x < 0)
        {
            // 如果在屏幕外,将玩家移动到屏幕内
            playerPosition.x = -playerPosition.x - 0.1f;
        }
        else if (viewportPosition.x > 1)
        {
            // 如果在屏幕外,将玩家移动到屏幕内
            playerPosition.x = -playerPosition.x + 0.1f;
        }
        if (viewportPosition.y < 0)
        {
            // 如果在屏幕外,将玩家移动到屏幕内
            playerPosition.y = -playerPosition.y - 0.1f;
        }
        else if (viewportPosition.y > 1)
        {
            // 如果在屏幕外,将玩家移动到屏幕内
            playerPosition.y = -playerPosition.y + 0.1f;
        }
        // 更新玩家的位置
        transform.position = playerPosition;
    }

    /// <summary>
    /// 使对象旋转以面对刚体的运动方向。
    /// </summary>
    private void RotateToFaceVelocity()
    {
        // 如果刚体的运动速度为零,则不执行旋转操作。
        if (rb.velocity == Vector3.zero) { return; }

        // 计算目标旋转,使对象面对刚体的运动方向。
        Quaternion targetRotation = Quaternion.LookRotation(rb.velocity, Vector3.back);

        // 通过插值平滑地将当前旋转过渡到目标旋转。
        transform.rotation = Quaternion.Lerp(transform.rotation, targetRotation, Time.deltaTime * rotationSpeed);
    }
}

5.将行星放入场景,飞机碰到行星后消失

将行星模型放入场景,并做成预制体,挂载脚本Asteroid

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

public class Asteroid : MonoBehaviour
{
    private void OnTriggerEnter(Collider other)
    {
        PlayerHealth playerHealth = other.GetComponent<PlayerHealth>();

        if (playerHealth == null) { return; }

        playerHealth.Crash();
    }
}

给Player物体挂载脚本PlayerHealth

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

public class PlayerHealth : MonoBehaviour
{
    public void Crash()
    {
        gameObject.SetActive(false);
    }
}

6.添加星空背景特效,在Hierarchy面板右键,选择Effrcts-Particle System

7.行星的实例化与移动

创建一个空物体AsteroidSpawner,在上面挂载一个脚本AsteroidSpawner

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

public class AsteroidSpawner : MonoBehaviour
{
    /// 要生成的小行星预制体数组。
    [SerializeField] private GameObject[] asteroidPrefabs;
    /// 每次生成小行星之间的间隔时间(秒)。
    [SerializeField] private float secondsBetweenAsteroids;

    /// 小行星生成时的速度范围。
    [SerializeField] private Vector2 forceRange;

    /// 主摄像机引用。
    private Camera mainCamera;
    /// 计时器,用于控制生成小行星的时间间隔。
    private float timer;

    /// <summary>
    /// 设置主摄像机引用。
    /// </summary>
    void Start()
    {
        mainCamera = Camera.main;
    }

    /// <summary>
    /// 用于检查是否需要生成新的小行星。
    /// </summary>
    void Update()
    {
        timer -= Time.deltaTime;
        if (timer <= 0)
        {
            SpawnAsteroid();

            timer += secondsBetweenAsteroids;
        }
    }

    /// <summary>
    /// 生成小行星的方法。
    /// </summary>
    private void SpawnAsteroid()
    {
        // 随机选择一个边作为生成点
        int side = Random.Range(0, 4);

        Vector2 spawnPoint = Vector2.zero;
        Vector2 direction = Vector2.zero;

        // 根据选择的边设置生成点和方向
        switch (side)
        {
            case 0:
                spawnPoint.x = 0;
                spawnPoint.y = Random.value;
                direction = new Vector2(1f, Random.Range(-1f, 1f));
                break;
            case 1:
                spawnPoint.x = 1;
                spawnPoint.y = Random.value;
                direction = new Vector2(-1f, Random.Range(-1f, 1f));
                break;
            case 2:
                spawnPoint.x = Random.value;
                spawnPoint.y = 1;
                direction = new Vector2(Random.Range(-1f, 1f), -1);
                break;
            case 3:
                spawnPoint.x = Random.value;
                spawnPoint.y = 0;
                direction = new Vector2(Random.Range(-1f, 1f), 1);
                break;
        }

        // 将生成点从视口坐标转换为世界坐标
        Vector3 worldSpawnPoint = mainCamera.ViewportToWorldPoint(spawnPoint);

        // 设置生成点的 Z 坐标为 0
        worldSpawnPoint.z = 0;

        // 随机选择一个小行星预制体
        GameObject asteroidPrefab = asteroidPrefabs[Random.Range(0, asteroidPrefabs.Length)];

        // 实例化小行星
        GameObject asteroidInstance = Instantiate(asteroidPrefab, worldSpawnPoint, Quaternion.Euler(0, 0, Random.Range(0, 360f)));

        // 获取小行星的刚体组件并设置其速度
        Rigidbody rb = asteroidInstance.GetComponent<Rigidbody>();
        
        rb.velocity = direction.normalized * Random.Range(forceRange.x, forceRange.y);
    }
}

修改行星预制体上脚本Asteroid

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

public class Asteroid : MonoBehaviour
{
    /// <summary>
    /// 当触发器被激活时调用此方法,检查碰撞对象是否为玩家,并对玩家造成撞击效果。
    /// </summary>
    /// <param name="other">与之发生碰撞的碰撞器。</param>
    private void OnTriggerEnter(Collider other)
    {
        // 尝试获取碰撞对象的玩家健康组件
        PlayerHealth playerHealth = other.GetComponent<PlayerHealth>();

        // 如果碰撞对象不是玩家,则忽略
        if (playerHealth == null) { return; }

        // 对玩家造成撞击效果
        playerHealth.Crash();
    }

    /// <summary>
    /// 当对象变得不可见时调用此方法,销毁当前游戏对象。
    /// </summary>
    private void OnBecameInvisible()
    {
        // 销毁当前游戏对象
        Destroy(gameObject);
    }
}

将场景中行星删除。