发布于2026-07-01 阅读(0)
扫一扫,手机访问
说到数组和列表,很多Unity初学者都会问:这玩意儿到底有什么用?我直接声明几个变量不行吗?
先不急着回答,我们看一个实际场景:假设你要管理游戏中的敌人,敌人数量可能是10个,也可能是100个。如果每个敌人都用一个单独的变量来存储,代码会变成什么样?总不能在项目里写100个变量声明吧。显然,这需要一个更聪明的办法——数据容器。而数组和列表,就是两组最基础、最常用的数据容器。

上一章我们聊完了循环语句(for/while)的实战应用,这一章自然要接上数据容器的部分。毕竟,循环处理的往往是大量数据,而没有容器,数据从哪儿来呢?
简单来说,数组和列表是用于存储同一类型多个数据的“盒子”。数组大小固定,一旦声明就改不了;列表则灵活得多,可以随时增删元素。这是Unity C#开发中最基础、最频繁使用的知识点,没有之一。
// Unity C# 示例代码
using UnityEngine;
public class ExampleScript : MonoBeha viour
{
// Start is called before the first frame update
void Start()
{
Debug.Log("Hello, Unity!");
}
// Update is called once per frame
void Update()
{
// 每帧执行的逻辑
}
}
在实际开发中,这项技能的分量体现在几个关键层面:
数组和列表在Unity中几乎无处不在——从角色控制、UI交互到物理模拟、资源管理,每个环节都离不开它们。
| 场景类型 | 具体应用 | 技术要点 |
|---|---|---|
| 游戏开发 | 角色控制、游戏逻辑 | 组件设计、脚本编写 |
| UI系统 | 界面交互、数据展示 | Canvas布局、事件系统 |
| 物理模拟 | 碰撞检测、刚体运动 | 物理组件、射线检测 |
| 资源管理 | 资源加载、内存优化 | AssetBundle、对象池 |
Unity的整体架构可以理解为几个关键模块的协作:
┌─────────────────────────────────────────────────────────┐
│ Unity核心架构 │
├─────────────────────────────────────────────────────────┤
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ 游戏对象 │ │ 组件系统 │ │ 场景管理 │ │
│ │ (GameObject)│ │ (Component) │ │ (Scene) │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
│ ↑ ↓ │
│ ┌─────────────────────────────────────────────────┐ │
│ │ 脚本系统 (MonoBeha viour) │ │
│ └─────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────┘
无论你处理的是数组还是列表,底层都离不开MonoBeha viour脚本系统。数据在哪个生命周期方法中被初始化、如何被访问和修改,这些细节直接影响游戏运行时的表现。
using UnityEngine; ////// Unity组件示例类 /// public class UnityDemo : MonoBeha viour { [Header("基本设置")] [SerializeField] private string objectName = "Unity对象"; [SerializeField] private float moveSpeed = 5f; private Transform cachedTransform; ////// 初始化方法 /// private void Awake() { cachedTransform = transform; Debug.Log($"{objectName} 已初始化"); } ////// 开始方法 /// private void Start() { // 初始化逻辑 } ////// 更新方法 /// private void Update() { // 移动逻辑 float horizontal = Input.GetAxis("Horizontal"); float vertical = Input.GetAxis("Vertical"); Vector3 movement = new Vector3(horizontal, 0, vertical); cachedTransform.Translate(movement * moveSpeed * Time.deltaTime); } }
| 技术点 | 说明 | 重要性 |
|---|---|---|
| 组件化设计 | 一切皆组件,灵活组合 | ⭐⭐⭐⭐⭐ |
| 生命周期函数 | Awake/Start/Update等 | ⭐⭐⭐⭐⭐ |
| 序列化字段 | Inspector面板显示 | ⭐⭐⭐⭐ |
| 预制体Prefab | 资源复用与实例化 | ⭐⭐⭐⭐⭐ |
① 安装Unity Hub
步骤1: 访问Unity官网下载Unity Hub
步骤2: 安装Unity Hub并登录账号
步骤3: 在Unity Hub中安装Unity编辑器
步骤4: 创建新项目或打开现有项目
② 创建第一个脚本
// 右键 Assets 文件夹
// Create -> C# Script
// 命名为 MyFirstScript
using UnityEngine;
public class MyFirstScript : MonoBeha viour
{
// 在Inspector面板中显示的变量
public int health = 100;
public float speed = 5.0f;
public string playerName = "Player1";
void Start()
{
Debug.Log($"玩家 {playerName} 已创建,生命值: {health}");
}
void Update()
{
if (Input.GetKeyDown(KeyCode.Space))
{
Debug.Log("空格键被按下");
}
}
}
示例一:游戏对象控制
using UnityEngine;
public class PlayerController : MonoBeha viour
{
[Header("移动设置")]
public float moveSpeed = 5f;
public float rotateSpeed = 100f;
private Rigidbody rb;
private void Awake()
{
rb = GetComponent();
}
private void Update()
{
// 获取输入
float horizontal = Input.GetAxis("Horizontal");
float vertical = Input.GetAxis("Vertical");
// 移动
Vector3 movement = new Vector3(horizontal, 0, vertical);
transform.Translate(movement * moveSpeed * Time.deltaTime);
// 旋转
if (Input.GetKey(KeyCode.Q))
{
transform.Rotate(0, -rotateSpeed * Time.deltaTime, 0);
}
if (Input.GetKey(KeyCode.E))
{
transform.Rotate(0, rotateSpeed * Time.deltaTime, 0);
}
}
}
示例二:UI交互
using UnityEngine;
using UnityEngine.UI;
public class UIManager : MonoBeha viour
{
[Header("UI组件")]
public Text scoreText;
public Button startButton;
public Slider healthSlider;
private int score = 0;
private void Start()
{
// 绑定按钮事件
startButton.onClick.AddListener(OnStartButtonClicked);
// 初始化UI
UpdateScoreDisplay();
healthSlider.value = 100;
}
public void AddScore(int points)
{
score += points;
UpdateScoreDisplay();
}
private void UpdateScoreDisplay()
{
scoreText.text = $"分数: {score}";
}
private void OnStartButtonClicked()
{
Debug.Log("游戏开始!");
// 开始游戏逻辑
}
}
using UnityEngine; using System; ////// 单例模式管理器示例 /// public class GameManager : MonoBeha viour { // 单例实例 public static GameManager Instance { get; private set; } [Header("游戏设置")] [SerializeField] private int maxLives = 3; [SerializeField] private float gameTime = 0f; // 事件 public event ActionOnLivesChanged; public event Action OnTimeChanged; private int currentLives; private bool isGameRunning; private void Awake() { // 单例初始化 if (Instance != null && Instance != this) { Destroy(gameObject); return; } Instance = this; DontDestroyOnLoad(gameObject); // 初始化游戏状态 currentLives = maxLives; } private void Update() { if (isGameRunning) { gameTime += Time.deltaTime; OnTimeChanged?.Invoke(gameTime); } } public void StartGame() { isGameRunning = true; gameTime = 0f; currentLives = maxLives; OnLivesChanged?.Invoke(currentLives); } public void LoseLife() { currentLives--; OnLivesChanged?.Invoke(currentLives); if (currentLives <= 0) { GameOver(); } } private void GameOver() { isGameRunning = false; Debug.Log("游戏结束!"); } }
问题一:脚本无法挂载到游戏对象
现象:
Can't add script component 'ExampleScript' because the script class cannot be found.
解决方案:
1. 确保脚本类名与文件名完全一致
2. 确保脚本继承自MonoBeha viour
3. 检查脚本是否有编译错误
4. 尝试在Unity中右键 -> Reimport All
问题二:Inspector面板变量不显示
现象:public变量在Inspector中看不到
解决方案:
// 方案1: 使用public(不推荐)
public int value;
// 方案2: 使用SerializeField(推荐)
[SerializeField] private int value;
// 方案3: 添加Header属性
[Header("设置")]
[SerializeField] private int value;
// 方案4: 添加Range属性
[Range(0, 100)]
[SerializeField] private int value;
问题三:空引用异常
现象:
NullReferenceException: Object reference not set to an instance of an object
解决方案:
// 错误写法
private void Start()
{
rb.AddForce(Vector3.up); // rb可能为null
}
// 正确写法
private Rigidbody rb;
private void Awake()
{
rb = GetComponent();
}
private void Start()
{
if (rb != null)
{
rb.AddForce(Vector3.up);
}
else
{
Debug.LogError("Rigidbody组件未找到!");
}
}
问题四:性能问题
现象:游戏运行卡顿
解决方案:
// 优化1: 缓存组件引用
private Transform cachedTransform;
private void Awake()
{
cachedTransform = transform; // 缓存Transform
}
// 优化2: 避免在Update中使用Find
private GameObject target;
private void Start()
{
target = GameObject.Find("Target"); // 只在Start中查找一次
}
// 优化3: 使用对象池
private List objectPool = new List();
public GameObject GetObject()
{
foreach (var obj in objectPool)
{
if (!obj.activeInHierarchy)
{
obj.SetActive(true);
return obj;
}
}
// 创建新对象...
return null;
}
// 1. 使用有意义的变量名 public float playerMoveSpeed = 5f; // ✅ 好 public float s = 5f; // ❌ 不好 // 2. 添加注释和文档 ////// 玩家控制器,处理玩家输入和移动 /// public class PlayerController : MonoBeha viour { ////// 玩家移动速度 /// [Tooltip("玩家移动速度,单位:米/秒")] [SerializeField] private float moveSpeed = 5f; } // 3. 使用SerializeField而非public [SerializeField] private int health; // ✅ 推荐 public int health; // ❌ 不推荐 // 4. 使用事件解耦 public event Action OnPlayerDeath; private void Die() { OnPlayerDeath?.Invoke(); }
| 技巧 | 说明 | 效果 |
|---|---|---|
| 缓存组件引用 | 避免重复GetComponent | 提升10倍速度 |
| 对象池 | 复用游戏对象 | 减少GC压力 |
| 批量处理 | 合并相同操作 | 减少Draw Call |
| LOD系统 | 根据距离降低细节 | 提升渲染效率 |
安全检查清单:
要点一:理解数组与列表List的创建与使用的核心概念和原理
要点二:掌握基本的实现方法和代码示例
要点三:了解常见问题及解决方案
要点四:学会最佳实践和性能优化技巧
| 学习阶段 | 建议内容 | 时间安排 |
|---|---|---|
| 入门 | 完成所有基础示例 | 1-2周 |
| 进阶 | 独立完成一个小游戏 | 2-4周 |
| 高级 | 优化性能,处理复杂场景 | 1-2月 |
说到底,数组和列表的熟练运用是Unity开发绕不开的基本功。不要觉得基础就不重视,实际项目中大量的问题都出在最基础的数据管理上。把这一章的内容动手敲一遍,最好结合自己的小项目试一试,效果要比单纯看代码好得多。
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
正版软件
正版软件
正版软件
正版软件
正版软件
1
2
3
7
8