☁️ UI 设计与开发经验 [Unity] 2023.2.8 版
2023-12-28
前言
自己是一名游戏开发进修中的学生,被朋友提醒,决定总结一下自己做游戏开发中的 UI 设计和开发经验,供自己快速回顾,也给在苦恼相同问题的伙伴一些参考。自己没有从业经验,本篇文章请当做无专业性的文章看待。如果有前辈能够给予指点,不甚感激。
〇、自己的 UI 设计流程
1. 在平面设计软件制作 UI 保真图
-
在这个阶段与伙伴敲定一个可用的版本 草图 成品 -
一些草图杂乱,很多部分都是在游戏中优化完成 草图 成品






2. 导出 UI 所需的图像素材
3. 在 Unity 中制作 UI
一、在 Unity 中制作 UI(UGUI)
Unity 中 GUI 对象管理
-
LevelUIManager (Canvas)
自定义 UI 组件 与 CustomEditor 与 预制体
编写自己的 UI 组件
我还没有做过兼容手柄的菜单,所以此处肯定是忽略了兼容手柄选择的情况。 对兼容手柄有需求的读者或许可以阅读 Selectable 类。
自定义 Inspector ( CustomEditor ) 方便地修改预制体参数
private MyUIComponent componetSelf;
private void OnEnable()
{
componetSelf = target as MyUIComponent;
}
public override void OnInspectorGUI()
{
base.OnInspectorGUI();
//objectSelf 指这个 editor 脚本所对应的组件(target)
//objectSelf.TextComponent 是一个例子,指这个预制体内被修改的组件,这里是文字
Undo.RecordObject(componetSelf.TextComponent, "descriptive name of this operation");
//这里执行需要做的操作,例如修改文字的内容和字号
componetSelf.TextComponent.text = EditorGUILayout.TextField("Name", componetSelf.TextComponent.text);
componetSelf.TextComponent.fontSize = EditorGUILayout.FloatField("Font Size", componetSelf.TextComponent.fontSize);
//标记文字组件被修改
EditorUtility.SetDirty(componetSelf.TextComponent);
PrefabUtility.RecordPrefabInstancePropertyModifications(componetSelf.TextComponent);
//标记场景中我们的物体被修改
EditorSceneManager.MarkSceneDirty(componetSelf.gameObject.scene);
}
资源文件管理
精灵图的注意事项
二、动效
1. DoTween:功能完整、使用方便
有些学习成本、管理复杂
2. 自己写个 Tweener:灵活可控,支持打断动画
数学基础是插值,推荐视频
[Serializable] // 使可以在 Inspector 编辑
public class SimpleTweener
{
[HideInInspector] public float time; // 动画的当前时间
public float duration; //动画的持续时长
public AnimationCurve curve; //动画曲线
private bool isActive; //是否正在进行
private bool isPositive; //是否进行正向计时
public float ProgressRate => time / duration; //动画播放的进度
public Action<float> doAnimation = (value) => { };
public void Update()
{
if (isActive)
{
time = isPositive ?
Mathf.Min(time + Time.deltaTime, duration) :
Mathf.Max(time - Time.deltaTime, 0);
if (time == 0 || time == duration) isActive = false;
float result = curve.Evaluate(ProgressRate); //对曲线进行采样
doAnimation.Invoke(result);
}
}
public void Start()
{
isActive = true;
isPositive = true;
}
public void Stop()
{
isActive = true;
isPositive = false;
}
}
public class AnimationTestBehaviour : MonoBehaviour, IPointerEnterHandler, IPointerExitHandler
{
public SimpleTweener tweener;
public Image image;
private void OnEnable()
{
tweener.doAnimation += DoTween;
}
private void OnDisable()
{
tweener.doAnimation -= DoTween;
}
private void Update()
{
tweener.Update();
}
void DoTween(float value)
{
Color color = image.color;
color.a = value;
image.color = color;
image.transform.localScale = (0.5f + value) * Vector3.one;
}
public void OnPointerEnter(PointerEventData eventData)
{
tweener.Start();
}
public void OnPointerExit(PointerEventData eventData)
{
tweener.Stop();
}
}


3. 无限趋近式:编写快捷、适应性高
动画形式单一、可控性差、无法达到目标值

float value = Mathf.Lerp(currentSize, targetSize, speed);
public void Update(){
float currentSize = transform.localScale.x;
currentSize = Mathf.Lerp(currentSize, targetSize, speed * (Time.deltaTime * 50f));
image.transform.localScale = currentSize * Vector3.one;
}

后记: