冰川网络

ref,out的区别以及各自的应用场景?

ref 关键字

  • 传递前必须初始化:调用方法前,实参必须被赋值(初始化),否则编译报错。
  • 作用:既可以将外部变量的值传入方法,也允许方法修改该变量的值并反馈给调用者。
  • 本质:”双向传递”—— 输入 + 输出。

out 关键字

  • 传递前可以不初始化:调用方法前,实参可以未赋值,方法内部必须为其赋值(否则编译报错)。
  • 作用:主要用于让方法返回多个值(除了方法的返回值外,通过 out 参数输出额外结果)。
  • 本质:”单向输出”—— 仅输出(方法必须给 out 参数赋值)。

一款游戏再游玩的过程中内存消耗大,帧率低,定位原因以及怎么解决(C#,xlua的游戏)?

问题定位方法

  1. 内存消耗大
    • 用 Unity Profiler 区分托管内存(C# 对象)和非托管内存(资源),关注 GC 分配和内存泄漏(如场景切换后内存未下降)。
    • xLua 侧检查闭包、全局变量泄漏,用 xLua Profiler 分析 table 创建释放情况。
  2. 帧率低
    • 用 Unity Profiler 定位 CPU/GPU 瓶颈(如 Main Thread 耗时、Gfx.WaitForPresent)。
    • xLua 侧通过 luaProfiler 统计高频函数耗时,检查跨语言调用频率(如每帧多次交互)。

二、内存优化方案

  1. C# 层面
    • 减少 GC:避免高频函数创建临时对象,用对象池复用实例,StringBuilder 替代字符串拼接。
    • 资源管理:压缩纹理、场景切换时卸载无用资源,避免单例滥用导致内存常驻。
  2. xLua 层面
    • 减少泄漏:用 local 变量替代全局变量,及时释放 Lua 与 C# 引用(如 Dispose 无用对象)。
    • 优化交互:减少跨语言调用次数,避免 Lua 存储大量 C# 对象引用。

三、帧率优化方案

  1. C# 逻辑
    • 降低计算量:非关键逻辑分帧处理,用空间分区算法优化碰撞检测,避免高频函数复杂计算。
    • 渲染优化:合并静态 Mesh 减少 Draw Call,关闭不可见物体渲染,降低粒子数量。
  2. xLua 逻辑
    • 减少耗时:高频逻辑迁移到 C#,优化 Lua 循环,启用 xLua 性能模式。
    • 跨语言优化:用 C# 数组传递大量数据,批量处理交互以减少调用损耗。
  3. GPU 优化
    • 降低纹理分辨率、模型面数,减少透明材质使用。

Awake,Enable,Start的区别以及调用时机?

  1. Awake(唤醒)
    • 调用时机:游戏对象被实例化时立即调用(在场景加载或实例化对象时)
    • 特点:
      • 无论脚本是否启用(enabled),只要对象被创建就会调用
      • 同一帧中,所有对象的 Awake 会在任何对象的 Start 和 OnEnable 之前执行
      • 常用于初始化基础数据、获取组件引用(如GetComponent)等基础设置
  2. OnEnable(启用)
    • 调用时机:当脚本被启用时调用(包括对象首次激活时)
    • 特点:
      • 每次脚本从禁用(disabled)状态切换到启用(enabled)状态时都会调用
      • 在 Awake 之后,Start 之前首次调用;后续启用时在 Update 之前调用
      • 适合重置状态、注册事件监听等需要在脚本可用时执行的操作
  3. Start(开始)
    • 调用时机:脚本启用后,第一次进入 Update 之前调用
    • 特点:
      • 仅在脚本启用状态下调用,且整个生命周期中只调用一次
      • 执行顺序晚于 Awake 和首次 OnEnable
      • 适合处理需要依赖其他对象已经初始化完成的设置

调用顺序总结

  • 对象首次创建并启用时:Awake → OnEnable → Start
  • 之后每帧更新:Update(如果启用)
  • 当脚本被禁用后再次启用时:OnEnable(此时不会再调用 Awake 和 Start)

实现一个简易的对象池框架

实现常规的人物移动

方法 核心原理 适用场景 关键特点
Transform直接操作 直接修改游戏对象的Position或使用Translate方法。 简单的原型验证、2D游戏、无需物理交互的场景。 实现简单,但容易穿模,缺乏真实的物理反馈。
Rigidbody物理组件 通过力(AddForce)、速度(velocity)或插值移动(MovePosition)驱动,受物理引擎管理。 需要真实物理效果的游戏,如滚球、赛车、受力影响的物体。 🌍物理效果真实,有碰撞反馈。操作需在FixedUpdate中进行。
CharacterController组件 专为角色移动设计的组件,提供MoveSimpleMove方法。 第一人称/第三人称角色扮演游戏(RPG)、平台跳跃游戏。 🧍 优秀的碰撞处理(如爬坡、走楼梯),但不参与复杂的物理模拟
导航网格(NavMesh) 为游戏场景生成可行走区域,角色可自动寻路到指定点。 AI控制的角色移动,如NPC、敌人自动寻路。

CharacterController实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
using UnityEngine;

class PlayerController{
//基础属性
public float moveSpeed;
public float jumpForce;
public float gravity = 20f;

private Vector3 moveDirection;
private CharacterController controller;
private float verticalVelocity; // 用于处理跳跃和下落的Y轴速度

public void Start(){
controller = GetComponent<CharacterController>();
}
public void update(){
// 获取输入
float horizontalInput = Input.GetAxis("Horizontal");
float verticalInput = Input.GetAxis("Vertical");

ControlMove();

}
public void ControlMove(){
bool isGrounded = controller.isGrounded;
// 处理地面上的移动
Vector3 move = transform.right * horizontalInput + transform.forward * verticalInput;
controller.Move(move * moveSpeed * Time.deltaTime);
// 处理跳跃
if (isGrounded)
{
// 着地时重置Y轴速度,提供一个小的向下的力使其紧贴地面
verticalVelocity = -0.5f;

if (Input.GetButtonDown("Jump"))
{
verticalVelocity = jumpForce;
}
}
else
{
// 空中时受重力影响
verticalVelocity -= gravity * Time.deltaTime;
}

// 应用Y轴移动(跳跃/重力)
moveDirection.y = verticalVelocity;
controller.Move(moveDirection * Time.deltaTime);
}
}

直接操作Transform

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
using UnityEngine;

public class PlayerMovement_Transform : MonoBehaviour
{
public float moveSpeed = 5f;

void Update()
{
// 获取输入(使用GetAxisRaw实现即时起停)
float moveX = Input.GetAxisRaw("Horizontal");
float moveY = Input.GetAxisRaw("Vertical");

// 计算移动方向并归一化,防止斜向移动更快
Vector3 movement = new Vector3(moveX, moveY, 0).normalized;

// 应用移动
transform.position += movement * moveSpeed * Time.deltaTime;
}
}