unity引擎基础学习 各种控件,对象实战 动画和画面的添加 基础架构

游戏引擎

Unity c#

Unreal Engine cpp

Cocos Creator js

入口点

在Unity中,程序的入口点是一个名为void Main()的静态方法,它位于一个名为Program的类中。这个类和方法是由Unity自动生成的,你不需要手动创建或修改它们。

在Unity项目中,程序的入口点由Unity引擎负责管理。当你运行游戏或应用程序时,Unity会自动创建一个GameManager的游戏对象,并将其附加到一个tag为MainCamera的摄像机上。然后,Unity会在GameManager上调用Awake()Start()Update()等方法,这些方法是你编写的脚本中的入口点。

因此,你可以将你的逻辑代码写在这些方法中,以便在游戏开始时执行初始化操作,并在游戏运行时更新游戏状态。你也可以创建自己的脚本,并将其附加到游戏对象上,以便在特定事件发生时调用相应的方法。

总结起来,Unity的程序入口点是由Unity引擎管理的,你可以通过编写脚本的Awake()Start()Update()等方法来定义你的逻辑代码的入口点。

地图绘制

整体架构

首先地图大小调小点

地图高度整体拔高,为了后面能绘制低谷

图形显示

图形以三角形网格形式存储,三角形越少,性能越高

图形的渲染需要网格模型(mesh)+材质(material)

标签

可通过修改tag和icon进行区分不同的物体

不同图层可通过相机拍摄过滤掉

预设体和变体

预设体相当于类,变体相当于类的继承

绘制好后拖到assetsf中就会生成后.prefab预设体文件

预设体的实例独有的组件会有+标志,可通过覆盖到预制件中,即修改双向可同步

将修改后的实例拖到assets时选择变体,跟父类相同的组件会同步变化

灯光

type : directional是无穷远的光,跟角度有关,跟位置无关

area仅烘焙,先将flags设为contribute UI,然后window->rendering->light

mode: realtime baked 阴影的实时计算和提前计算,性能消耗差距

shadow type: 光线的阴影很消耗性能,软阴影消耗最大光周围一圈

图层,接受光照的图层

摄像机

投影摄像机,正常视角,常用于3D

正交摄像机(orthographic),三视图,常用于2D

清除标志,在scene中不显示,在摄像机中添加skybox组件,会显示到Game框中,清除标记仅深度会将不同相机叠加

多相机深度越高越优先显示

范围控制 : 视野(filed of view)和近远面(clipping plane)

viewport rect控制相机显示在game框的范围,用0-1之间的数表示

给相机添加target texture(空的,用于存储)会将拍摄内存存储在纹理之中,而不会渲染到game之中了,这个纹理可以拖到游戏内使用

选中摄像机 ctrl+shift+F将game与scene视图同步,就不需要手调了

射线检测

利用射线碰撞来获得坐标,进行移动,而不是直接使用鼠标位置,避免悬空移动

void Update()
{
    if(Input.GetMouseButtonDown(0))
    {
        Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
        RaycastHit hit;//利用碰撞组件检测射线和平面碰撞
        bool res = Physics.Raycast(ray, out hit);//out表示接受返回值
        if(res)
        {
            transform.position = hit.point;
        }
        //多检测,检测到碰撞后不停止,一直贯穿,直到没有碰撞
        RaycastHit[] hits = Physics.RaycastAll(ray,100,1<<10);//碰撞距离,碰撞图层10
    }
}

脚本

生命周期

初始化

  1. Awake():

    • 当组件被创建并附加到游戏对象上时,Awake 方法会被调用。
    • 在这里,你可以进行初始化操作,但不能保证其他组件都已经被初始化。
  2. OnEnable():

    • 当组件被激活时,即使在 Start 方法之前,OnEnable 方法也会被调用。
    • 通常用于订阅事件或启用资源
  3. Start():

    • 在 Awake 方法之后,第一次 Update 方法之前调用。
    • 通常用于初始化,但确保其他组件都已经被创建和初始化。

    执行

  4. Update():

    • 每一帧中都会被调用,通常用于处理游戏逻辑的更新。
  5. FixedUpdate():

    • 固定时间间隔(默认0.02s)内被调用,适合处理物理相关的计算和更新。
  6. LateUpdate():

    • 在 Update 方法之后调用,通常用于在所有对象更新后执行一些操作,如摄像机跟随。

    销毁

  7. OnDisable():

    • 当组件被禁用时(通过SetActive(false)或者在Inspector中禁用),OnDisable 方法会被调用。
    • 可用于取消订阅事件或释放资源
  8. OnDestroy():

    • 当组件被销毁时,OnDestroy 方法会被调用。
    • 在这里进行资源清理和释放。

实例化

public class App : MonoBehaviour
{
    public UIManager ui;//拖拽绑定
    void Start()
    {
        ui = GetComponent<UIManager>();//如果已经挂载了该脚本组件
        ui =new UIManager();
    }
}

多脚本

执行顺序

任选一个脚本打开excution order进行编排,更方便管理

通过awake与start优先级区分

C#

Vector3

用于空间变换,可实现坐标,旋转,缩放

基本方法

Vector3 v1 = Vector3.forward;
Vector3 v2 = Vector3.up;
Vector3.Angle(v1, v2);
Vector3.Distance(v1, v2);
Vector3.Dot(v1, v2);//点乘
Vector3.Cross(v1, v2);//叉乘
Vector3.Lerp(v1, v2, 0.5f);//线性插值,Linear Interpolation,用于平滑过度,返回中间向量 = v1+(v2-v1)*0.5f
Debug.Log(v1.magnitude);//模长
Debug.Log(v1.normalized);//模长

四元数

  1. 欧拉角(0-360°)

  2. 四元数

满足以下定义,高维虚数

避免万向锁,即线性代数旋转乘法后秩降低的不可逆

几何意义,ijk构成三维空间,实数轴为第四维垂直于这个三维空间
q = a + b i + c j + d k i 2 = j 2 = k 2 = i j k = − 1 将其用欧拉公式表示 , q = ∣ q ∣ ∗ ( c o s ( θ ) + u ∗ s i n ( θ ) ) q = a+bi+cj+dk\\ i^2=j^2=k^2=ijk=-1\\ 将其用欧拉公式表示,\\ q = |q| * (cos(θ) + u * sin(θ)) q=a+bi+cj+dki2=j2=k2=ijk=1将其用欧拉公式表示,q=q(cos(θ)+usin(θ))
其中u表示旋转角度的单位向量,类似于复数中的i

四元数计算旋转 P为被旋转的点的四元数形式,Q为旋转的单位四元数

P ′ = Q ∗ P ∗ Q − 1 P' = Q * P * Q^-1 P=QPQ1

Debug

private void Awake()
{
    Debug.Log("debug");
    Debug.LogWarning("warning");
    Debug.LogError("error");
}
void Update()
{
    Debug.DrawLine(Vector3.zero, Vector3.one, Color.red);
    Debug.DrawRay(Vector3.zero, Vector3.up, Color.blue);
}

gameObject

所有物体都有一个自己的类进行管理

public GameObject Prefab;//放在全局,可通过在unity中拖动网格赋值,用于创建新网格

// Start is called before the first frame update
void Start()
{

    //访问属性
    Debug.Log(gameObject.name);
    Debug.Log(gameObject.tag);
    Debug.Log(gameObject.activeInHierarchy);//继承后的激活状态
    Debug.Log(transform.position);
    //获取组件
    BoxCollider collider = GetComponent();
    GetComponentInChildren(collider);
    GetComponentInParent(collider);
    //获取网格
    GameObject test = GameObject.Find("sphere");
    test = GameObject.FindWithTag("Player");
    //修改属性
    test.SetActive(false);
    //创建组件
    gameObject.AddComponent();
    Instantiate(Prefab);
    Instantiate(Prefab,Vector3.zero,Quaternion.identity);//生成实例于原点不旋转
    //销毁
    Destroy(test);
}

Time

Debug.Log(Time.time);//游戏开始到现在的时间
Debug.Log(Time.timeScale);//游戏速度
Debug.Log(Time.fixedDeltaTime);//固定间隔时间,默认0.02s 
Debug.Log(Time.deltaTime);//每帧的时间间隔

Application

//只读,后面的文件会加密
Debug.Log(Application.dataPath + "/userdata.dat");
//系统的数据路径
Debug.Log(Application.persistentDataPath);
//只读,但不会加密
Debug.Log(Application.streamingAssetsPath);
//临时文件夹
Debug.Log(Application.temporaryCachePath);
//控制是否在后台运行
Debug.Log(Application.runInBackground);//失去交点后是否继续运行
//打开URL
Application.OpenURL("https://space.bilibili.com/696782160/favlist?fid=1763669060&ftype=create");
//退出游戏
Application.Quit();

Transform

维持网格父子级关系,实现位置和缩放

void Start()
{
    //获取位置(全局,相对)
    Debug.Log(transform.position);
    Debug.Log(transform.localPosition);
    //获取旋转(四元数,欧拉角)
    Debug.Log(transform.rotation);
    Debug.Log(transform.localRotation);
    Debug.Log(transform.eulerAngles);
    Debug.Log(transform.localEulerAngles);
    //获取缩放
    Debug.Log(transform.localScale);
    //方向向量,z代表前,y代表上,x代表右
    Debug.Log(transform.forward);
    Debug.Log(transform.up);
    Debug.Log(transform.right);
    //父子关系
    Debug.Log(transform.parent.gameObject);
    Debug.Log(transform.childCount);
    //查找子物体(名称,下标)
    Transform trans = transform.Find("Child");
    trans = transform.GetChild(0);
    //解绑和捆绑
    transform.DetachChildren();
    trans.SetParent(transform);
    Debug.Log(trans.IsChildOf(transform));
}
void Update()
{
    //转向和旋转
    transform.LookAt(Vector3.zero);
    transform.Rotate(Vector3.up, 1);//自转,绕自转轴
    transform.RotateAround(Vector3.zero, Vector3.up, 1);//公转,点向式确定转轴
    transform.Translate(Vector3.forward * 0.1f);//以每帧0.1的速度向前走,闪现就是不按帧调用
}

SceneManager

游戏->场景->物体->组件

先file->building setting将场景添加到scene in build

加载

using UnityEngine.SceneManagement;


//SceneManager.LoadScene(1);//build setting里的序号
SceneManager.LoadScene("MyScene");
SceneManager.LoadScene("scene", LoadSceneMode.Additive);
//获取当前场景信息
Scene scene = SceneManager.GetActiveScene();
Debug.Log(scene.isLoaded);
Debug.Log(scene.path);
Debug.Log(scene.buildIndex);
Debug.Log(scene.name);
GameObject[] sc = scene.GetRootGameObjects();
Debug.Log(sc.Length);
//场景管理
Scene newScene = SceneManager.CreateScene("newScene");
Debug.Log(SceneManager.sceneCount);
SceneManager.UnloadSceneAsync(newScene);//卸载场景

异步加载

分工合作,将耗时代码让其他执行(多线程,协程)

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

public class test : MonoBehaviour
{
    AsyncOperation operation;
    void Start()
    {
        StartCoroutine(LoadScene());
    }
    //协程异步加载场景
    IEnumerator LoadScene() {
        operation = SceneManager.LoadSceneAsync(1);
        operation.allowSceneActivation = false;//加载完后不自动跳转
        yield return operation;//yield创建迭代器,将加载结果一段段的返回,实现异步加载
    }
    float timer = 0;
    void Update()
    {
        Debug.Log(operation.progress);//进度条0-0.9
        timer+= Time.deltaTime; 
        if(timer > 5)
        {
            operation.allowSceneActivation = true;  
        }
    }
}

Input

键鼠

void Update()
{
    //鼠标点击 0左键 1右键 2滚轮
    if(Input.GetMouseButtonDown(0))
    {
        Debug.Log("按下了鼠标左键");
    }
    //鼠标长按
    if(Input.GetMouseButton(0))
    {
        Debug.Log("长按鼠标左键");
    }
    if(Input.GetKeyDown(KeyCode.A))
    {
        Debug.Log("按下了A");
    }
    if (Input.GetKey(KeyCode.A))
    {
        Debug.Log("长按A");
    }
}

虚拟轴

用于模拟输入,用于表示一个连续的数值,在-1~1之间,实现PC,掌机等不同平台兼容

在Project Setting->input manager进行管理

只有horizontal和Vertical是轴(wasd控制方向),其他基本都是模拟按键,入fire

void Update()
{
    float horizontal = Input.GetAxis("Horizontal");
    float vertical = Input.GetAxis("Vertical");
    Vector3 dir = new Vector3(horizontal, 0, vertical);
    Debug.Log(horizontal + "   " + vertical);
    if (Input.GetButtonDown("Jump"))
    {
        Debug.Log("按下了跳跃");
    }
}

触摸

void Start()
{
    //开启多点触摸
    Input.multiTouchEnabled = true;

}
void Update()
{
    //单点触摸
    if(Input.touchCount == 1)
    {
        Touch touch = Input.touches[0];
        Debug.Log(touch.position);
        switch (touch.phase)
        {
            case TouchPhase.Began:
                break;
            case TouchPhase.Moved:
                break;
            case TouchPhase.Stationary:
                break;
            case TouchPhase.Ended:
                break;
            case TouchPhase.Canceled:
                break;
        }
        //多点触摸
        if(Input.touchCount==2)
        {
            Touch touch1 = Input.touches[0];
            Touch touch2 = Input.touches[1];
        }
    }

music

音乐和音效

如何播放 1.摄像机的audio listener,只需要一个摄像机有该组件就行

​ 2.网格的audio sourse组件

//依旧是拖动绑定资源
public AudioClip music;
public AudioClip soundEffect;
private AudioSource player;

void Start()
{
    player = GetComponent<AudioSource>();
    player.clip = music;
    player.loop = false;
    player.volume = 1.0f;
    player.Play();
}
void Update()
{
    //音乐循环播放的暂停与继续
    if(Input.GetKeyDown(KeyCode.Space))
    {
        if(player.isPlaying) player.Pause();
        else player.UnPause();
        //player.Play();
        //player.Stop();用这两个控制会重新播放
    }
    //音效播放
    if(Input.GetMouseButtonDown(0))
    {
        player.PlayOneShot(soundEffect);
    }

}

对于重复性声音,比如脚步,枪声,需要考虑重叠

//脚步
if((horizontal != 0 || vertical != 0)&&isGround ==true)
    if(audio.isPlaying == false)
        audio.Play(); 
else    audio.Stop();

video

先创建一个长方形网格,添加vidio player组件,并添加一个新纹理,在组件中绑定网格和纹理,视频会播放到纹理然后再通过纹理绑定网格,进行显示,也可以将纹理绑定到UI->raw image中播放

using UnityEngine.Video;//视频需要使用
//其他就跟音频一样了
private VideoPlayer player;
void Start()
{
    player = GetComponent<VideoPlayer>();
}
void Update()
{

}

CharacterController

private CharacterController player;
void Start()
{
    player = GetComponent<CharacterController>();
}
void Update()
{
    float horizontal = Input.GetAxis("Horizontal");
    float vertical = Input.GetAxis("Vertical");
    Vector3 dir = new Vector3(horizontal, 0, vertical);
    player.SimpleMove(dir*2);//自动以秒为单位,translate以帧为单位
    //transform.Translate(dir * 2 * Time.deltaTime);也可乘上每帧时间,变成秒为单位移动,但Move不能进行物理交互
}

物理

rigidbody

刚体,如果取消该组件就可以实现穿墙?

碰撞的对象是组件mesh collider,刚体实现碰撞

is Kinematic 勾上后就不会移动,或者在constraints三个维全部冻结(人物把旋转冻结,npc把行走冻结)

collision detection选用离散的(discrete)会导致高速物体穿墙,但节省性能

碰撞

产生条件,两物体都有collider组件,其中一个有rigidbody组件

对于飞弹击中后的爆炸效果,在效果后的销毁应该在各自独立的网格里

飞弹

public GameObject Explosion;    
private void OnCollisionEnter(Collision collision)//Stay,Exit;碰撞后停留,碰撞结束
{
    Instantiate(Explosion,transform.position,Quaternion.identity);
    Destroy(gameObject);
     Debug.Log(collision.gameObject.name);//被撞者的信息
}

爆炸

void Update()
{
    timer += Time.deltaTime;
    if(timer > 1) { Destroy(gameObject); }
}

触发

跟碰撞差不多,把其中一个的collider勾选istrigger(就不会产生碰撞了),所以一般选用无网格的当触发器

通过机关开门

private void OnTriggerEnter(Collider other)
{
    GameObject door = GameObject.Find("door");
    if(door != null)
    {
        door.SetActive(false);
    }
}

物理关节

铰链

Hinge Joint铰链关节,即将刚体的一条边固定,可实现门绕轴开关,宝箱打开

轴的位置,中心为0,长宽是按比例计算,控制anchor和axis,即点向式

入anchor (-0.5,0,0) axis(0,1,0)绕着左边垂线为轴

use motor实现自动旋转

弹簧

Spring Joint弹簧,添加connected body

Fixed Joint,固定连接,可设置最大断开链接的力

物理材质

create physic material

可设置摩擦系数,弹力,以及多材质组合时的计算方法(平均,最小,最大)

粒子系统

effect->particle system

prewarm 提前加载到稳定状态,不会重头开始

simulation space 已生成的粒子 local整体移动,world,不跟随移动

emissions 调节发射数量,发射方使(突发,渐变)

动画

旧版

利用animation组件,先添加组件,然后到window->animation->animation 创建动画,因为动画是属性的改变,所以之后需要添加属性

然后对关键帧进行属性数值修改

或者录制关键帧,将动画添加到animations中,可通过代码控制播放什么动画

void Update()
{
    if(Input.GetMouseButtonDown(0))
    {
        GetComponent<Animation>().Play("right move");
    }
}

新版

利用animator控制器组件,更方便管理,将动画状态进行导图可视化

添加组建后,创建animator controler,然后绑定物体后再跟旧版一样创建动画,一定要先绑定

然后双击animator controler

通过脚本控制

private Animator animator;
void Start()
{
    animator = GetComponent<Animator>();
}
void Update()
{
    if(Input.GetMouseButtonDown(0))
    {
        animator.Play("right");
    }
}

角色运动

通过控制器控制,添加过渡动画

添加动画触发条件 : 动作切换时使用

  1. parameter -> trigger 跳跃等用trigger,走,跑等用bool

  2. 过渡线->condition

去掉过渡线的有退出时间,以便于按键后立刻执行其他动作,去掉过渡时间使动作更跟手,加上使动作更自然,不那么生硬

运动脚本

public class test : MonoBehaviour
{
    private Animator animator;
    void Start()
    {
        animator = GetComponent<Animator>();
    }
    void Update()
    {
        float horizontal = Input.GetAxis("Horizontal");
        float vertical = Input.GetAxis("Vertical");
        Vector3 dir = new Vector3(horizontal, 0, vertical);


        if (Input.GetKeyDown(KeyCode.F)) {
            animator.SetTrigger("wave");
        }
        if (Input.GetKeyDown(KeyCode.Space)){
            animator.SetTrigger("jump");
        }

        if(dir!=Vector3.zero) {
            transform.rotation = Quaternion.LookRotation(dir);
            animator.SetBool("IsWalk", true);
            transform.Translate(Vector3.forward*2*Time.deltaTime);
        }else{
            animator.SetBool("IsWalk", false);
        }
    }
}

animation

动作一般在fbx(filebox)文件中,我们常用其中的animation属性页,

  • 任何修改之后要滑到最底部,点击应用
  • 可设置不同clip
  • 单击底部可弹出预览动作页
  • 可将部分动作进行烘焙,从而只显示动作,不改变数据,如跑步时y轴变化,
  • curve可以随着运动进度返回不同值,用于其他的技能跟随运动变化,如出拳蓄力,添加float参数,名称应该跟曲线名称一样,然后
Debug.Log(animator.GetFloat("Test"));
  • event,根据动画执行到某帧时会调用的函数,如脚落地时添加时间,产生脚印特效,脚步声,子弹射击弹弹壳
void leftfoot()
{
    Debug.Log("左脚");
}
void rightfoot()
{
    Debug.Log("右脚");
}

混合树

形成过渡动作

blend tree,创建后会默认使用参数列表中的第一个float参数,范围0-1

将不同动作混合在一起,如将走跟跑混合,做成起跑动作

图层

将不同动作组合,多动作通过权重直接相加,通过骨骼遮罩(avatar mask)(绿色代表该层控制的骨骼部分)(avatar 阿凡达 化身)

能够将身体的不同部分分别播放动画,如举着枪行走,拿着刀行走

反向动力学

先勾选图层的IK(Inverse Kinematics)

身体控制本来应该是从中间到四周,在需要锁定一个点(如头朝向某个点)时,应该是先转头,然后再计算其他身体部位的位置

可用于npc面对玩家时改变朝向

public Transform target;//绑定目标
private void OnAnimatorIK(int layerIndex)
{
    animator.SetLookAtWeight(1);//头部IK
    animator.SetLookAtPosition(target.position);
    //身体其他部分IK
    animator.SetIKPositionWeight(AvatarIKGoal.RightHand, 1);
    animator.SetIKRotationWeight(AvatarIKGoal.RightHand, 1);
    animator.SetIKPosition(AvatarIKGoal.RightHand, target.position);
    animator.SetIKRotation(AvatarIKGoal.RightHand, target.rotation);
}

画面

UI

登录界面,开始菜单,角色信息,背包,商城…

UI->canvas

render mode : overlay在最上层,打开背包 world 实现3d UI

UI Scale Mode : 设成scale with screem size,用以固定分辨率,如1920*1080

Rect transform

为了适配不同分辨率,能够自动调节,于是出现了锚点和轴心点,例如控制一个image的坐标

锚点是一个x形准星,可拉开成矩形,其为长宽为一个0-1的范围,即锚点咱canvas的比例

image坐标是相对于锚点(anchor)四条边的坐标,从而在屏幕不同时,图片也进行拉伸,维持到四条边的位置,

人物头像之类,将所有锚点拉到左上角

轴心点,image中间的小圆圈,将坐标轴设为轴心可拉动轴心,用于代表图片进行各种计算,其他部分进行跟随,如修改轴心点后,绕某点旋转

预设中黄点代表锚点,蓝点代表轴心点

图片添加mask组件,会让子图片只显示在父图范围内的部分

text

旧版

rich text Text Text 利用标签进行格式

勾选best fit进行自适应调整大小

新版

依赖于text mesh pro框架(TMP),创建后根据提示导入框架

设置自动字号,类似于best fit

控件content size filter,进行垂直适应,选择合适大小,会自动将文本显示完

文本控件

按钮,输入框,选项和下拉框,新旧版唯一不同就是基于的文本版本的不同

可设置是否可交互(在触发事件后解锁)

按钮

  • 设置文本和图像
  • 设置过渡颜色或spirit(图片)
  • navigation 键盘或手柄选择不同选项,explicit可进行手动控制上下级

图片有不同类型,图片不可用可能是类型错误

  • 添加事件响应,将脚本挂在到canvas后,在button->onclick中添加就行

写一个public函数,用于添加响应

public void ButtonClick()
{
    Debug.Log("click");
}

输入框

占位文本 text

content type 设为password后会用*遮盖密码,设置光标

添加事件与上面相同,获取文本内容通过下面代码

public TMP_InputField inputField;
public void Inputting()
{
    Debug.Log(inputField.text);
}

下拉列表

dropdown,进行选择,分辨率,语言选择,利用脚本添加新选项

    void Start()
    {
        Dropdown dropdown = GetComponent<Dropdown>();
        List<Dropdown.OptionData>options = dropdown.options;
        options.Add(new Dropdown.OptionData("俄罗斯"));
        dropdown.options = options;
    }

选择框

toggle,控制多个toggle只能且必须选择一个,如性别选择

在第一个toggle中添加逐渐toggle group,并将其拖到toggle组件的group里

然后将第一个toggle拖到后续控件的toggle组件的group里,后续更多一样,实现多选一

滑动条

将Handle Slide Area(活动条当前进度的圆点指示)删掉就可以做血条了

滚动条

scroll view 用于显示服务器列表,传送点,世界地图

面板

将多个控件进行分类,如人物状态由多个控件显示,在改变时更方便和清晰

打包

如何打包

File->BuildSetting

将需要运行的场景Scene拖拽到ScenesInBuild列表里

点击PlayerSettings,打开PlayerSettings配置CompanyName和ProductName

返回BuildSettings窗口,点击Build,选择路径创建文件夹,开始打包.exe文件及其他dll和资源文件。

打包完毕后可以看到.exe程序及其他dll文件和文件夹,.exe文件必须在此目录里执行,不可以随意更改位置,可以将整个文件夹进行转移。

打包结构

Managed目录:存放unity引擎、第三方和游戏逻辑托管dll 如:Assembly-CSharp.dll、Assembly-CSharp-firstpass.dll

Mono目录:Mono虚拟机相关的文件

Plugins目录:第三方Native dll库

Resources目录 :资源文件

unity default resources:unity引擎自带缺省资源

unity_builtin_extra:内置shader(如:Standard.shader)、缺省material等 里面99%是shader文件

StreamingAssets\Windows目录:项目工程中的StreamingAssets文件夹的内容不会压缩原封不动的拷贝到该目录下

globalgamemanagers:所有gameobject、shader、monobehaviour脚本、mesh、material、transform、audio,texture、spirite等的总览以及setting信息

globalgamemanagers.assets:playersetting中用到的资源

resources.assets:项目工程中的Resources文件夹的内容会打包到该文件中,但如果有资源被某场景使用,该资源则会存储于该场景对应的sharedassets<0~n>.assets中

level0、level1、level2、level44、level165:地图关卡文件,有几张地图就对应几个level文件

sharedassets0.assets、sharedassets1.assets、sharedassets2.assets、sharedassets44.assets、sharedassets165.assets:各关卡引用的texture,material,shader,material,animator,monobehaviour脚本等外部资源

架构

ESC

ECS,即 Entity-Component-System(实体-组件-系统) 的缩写,其模式遵循组合优于继承原则,游戏内的每一个基本单元都是一个实体,每个实体又由一个或多个组件构成,每个组件仅仅包含代表其特性的数据(即在组件中没有任何方法),例如:移动相关的组件MoveComponent包含速度、位置、朝向等属性,一旦一个实体拥有了MoveComponent组件便可以认为它拥有了移动的能力,系统便是来处理拥有一个或多个相同组件实体集合的工具,其只拥有行为(即在系统中没有任何数据),在这个例子中,处理移动的系统仅仅关心拥有移动能力的实体,它会遍历所有拥有MoveComponent组件实体,并根据相关的数据(速度、位置、朝向等),更新实体的位置。

实体组件是一个一对多的关系,实体拥有怎样的能力,完全是取决于其拥有哪些组件,通过动态添加或删除组件,可以在(游戏)运行时改变实体的行为。

单入口

程序流很清晰,所有操作都在代码上进行,不需要过多关注于unity细节上,静态可读性好

UI只做获取输入输出的作用,不处理逻辑

分层 app>facades>manager>models

一般不采用拖拽绑定,在共享工程时容易出错,通过代码绑定,使用AA包进行绑定

AA包,即插件Addressables,需要先安装

添加后不能使用可以用assembly definition,将引用的那个dll(unity.Addressables),包含到我们的代码assembly-Csharp.dll

window->asset management->addressables->groups,然后用组来统一管理资源

资源

-Unity(游戏开发引擎)
-Visual Studio(编程)
-Git(源代码管理)
-Trello(项目管理)
-Aseprite(像素动画制作)
-Pinterest(游戏素材参考)
-XMind(思维导图)
-Todoist(代办事项管理)
-Evernote(知识管理)
-Twitter(游戏开发社交)
-Discord(游戏开发交流) -blender开源的建模免费软件,十分方便迅速
-mixmo免费的动画库,虽然动画不多,u3d的动画库,虚幻还要骨骼重定向

你可能感兴趣的:(unity,学习,游戏引擎)