《Unity In Action》读书笔记

Unity学习(C#)——委托( delegate、Action、Func) 委托:指向一个方法,要定义方法的类型和返回值。 1.使用委托 using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace _703委托 { class Program { private delegate string GetString(); static void Main(string[] args) { 阅读详情

Unity最大的优点:可视化的工作流和跨平台的支持。Unity基于component的设计,使得一个component能被重复的使用。

Unity的缺点有:查找功能不够强大,有时候在项目中查找脚本比较麻烦;不支持链接到第三方库,要使用时必须手动拷贝到工程中来;prefab是Unity独有的重要功能,但是编辑prefab又不太方便。这些都希望在以后的版本中得到改进。

Unity开发的产品横跨三大平台(主机、PC、手机),比较著名的有:炉石传说、王者荣耀、神庙逃亡、捣蛋猪(愤怒的小鸟)、高尔夫俱乐部等。

Unity推荐的官方开发语言有C#和JavaScript,这里的JavaScript与标准版有所不同。

所有的Unity脚本都要继承MonoBehaviour,它提供了Start()和Update()方法以供重载。前者是在脚本关联的对象被激活时(也就是对象所在层级被加载时)调用。

构建一个FPS游戏场景需要:创建场景和人物,放置光源,将camera与人物绑定,处理移动脚本。

以大拇指为x轴,食指y轴,中指z轴,可将三维坐标系分为:左手系和右手系。Unity使用的是左手系,OpenGL用的是右手系。左手系和右手系区别在于:左手系的z轴由近及远,右手系的z轴由远及近。

Unity的对象层级结构是树状的,对象与对象之间呈父子关系。当没有合适的根对象时我们可以创建空的根对象。这里指的对象都是GameObject,它实际上是一系列component的容器,装载的component实际上决定了GameObject的作用。

Unity支持三种类型的光源:点光源(point)、聚光灯(spot)、平行光(directional)。分别类似于灯泡、手电筒、阳光。point和spot可以指定光照范围,它们比directional带来更多的内存消耗。离point越近照得越亮。

创建的Cube对象会自带如下基础component:Transform,Mesh Filter(几何形状),Box Collider(处理碰撞),Mesh Renderer(负责网格的渲染)。

Capsule默认自带capsule collider,这里移除并替换成character controller,为了更好地模拟人的动作。

CharacterController是Unity官方提供的模拟人动作的组件,特点是不受力的控制,只受碰撞影响。

将camera绑定在角色身上,设置位置为(0, 0.5, 0),让其跟着角色移动。

Rotate()方法默认使用本地坐标系,若需使用全局坐标系需额外注明:Rotate(0, speed, 0, Space.World)

下面是视角随鼠标旋转的代码:

// x轴上的变化对应的是y轴上的旋转
float rotationY = transform.localEulerAngles.y + Input.GetAxis("Mouse X") * sensitivityHor;
_rotationX -= Input.GetAxis("Mouse Y") * sensitivityVert;
// 对于x轴上的旋转,应控制范围
_rotationX = Mathf.Clamp(_rotationX, minimumVert, maximumVert);
// 将新的向量赋值给欧拉角
transform.localEulerAngles = new Vector3(_rotationX, rotationY, 0);

localRotation使用的是四元数,localEulerAngles使用的是欧拉角,两者可以互相转换。四元数的优点是:避免万向节锁,提供平滑插值,表达效率高。

Rigidbody中的freezeRotation属性可以禁用物理模拟引起的转动。

下面是位置随键盘输入移动的代码:

void Start() {
    // 要做碰撞必须使用CharacterController
    _charController = GetComponent<CharacterController>();
}
void Update() {
    float deltaX = Input.GetAxis("Horizontal") * speed;
    float deltaZ = Input.GetAxis("Vertical") * speed;
    Vector3 movement = new Vector3(deltaX, 0, deltaZ);
    // 斜线运动时不能超过最大速度
    movement = Vector3.ClampMagnitude(movement, speed);
    // 避免飞起来
    movement.y = gravity;
    // 考虑避免不同帧数的影响
    movement *= Time.deltaTime;
    // 从本地坐标系转成全局坐标系(若是用Translate()方法则是用本地坐标系,但是没有碰撞)
    movement = transform.TransformDirection(movement);
    _charController.Move(movement);
}

可以通过RequireComponent和AddComponentMenu声明来标注component依赖关系,使得component之间能够相互调用。

子弹的轨迹是由2D坐标屏幕的camera位置射向3D坐标世界的某个点(沿视椎体方向)。

Unity中的协程不是异步的,yield之后退出,下一帧再接着执行。执行时机是在update()和lateUpdate()之间。适合用于耗时操作:如等待几秒后销毁,文件加载好后处理。

发射子弹并击中目标的代码:

    void Start() {
        _camera = GetComponent<Camera>();
        // 鼠标锁定且隐藏,按ESC解除锁定
        Cursor.lockState = CursorLockMode.Locked;
        Cursor.visible = false;
    }
    // 在每一帧完成3D场景渲染后调用
    void OnGUI() {
        int size = 12;
        float posX = _camera.pixelWidth/2 - size/4;
        float posY = _camera.pixelHeight/2 - size/2;
        // 这里用基础GUI构造了一个TextLabel
        GUI.Label(new Rect(posX, posY, size, size), "*");
    }

    void Update() {
        if (Input.GetMouseButtonDown(0)) {
            // 从camera中心发出
            Vector3 point = new Vector3(_camera.pixelWidth/2, _camera.pixelHeight/2, 0);
            // 这个方法垂直屏幕发出射线
            Ray ray = _camera.ScreenPointToRay(point);
            RaycastHit hit;
            if (Physics.Raycast(ray, out hit)) {
                // 击中的对象
                GameObject hitObject = hit.transform.gameObject;
                ReactiveTarget target = hitObject.GetComponent<ReactiveTarget>();
                // 若找到相应脚本,则认为是敌人,否则是普通物体
                if (target != null) {
                    target.ReactToHit();
                } else {
                    StartCoroutine(SphereIndicator(hit.point));
                }
            }
        }
    }

    // 调用协程方法
    private IEnumerator SphereIndicator(Vector3 pos) {
        GameObject sphere = GameObject.CreatePrimitive(PrimitiveType.Sphere);
        sphere.transform.position = pos;
        // 暂停1秒再销毁(直接return, Unity会延迟1秒再执行下面的Destroy)
        yield return new WaitForSeconds(1);

        Destroy(sphere);
    }

tweens可以让敌人被击中后倾斜的动作更加顺滑。

敌人AI代码:

    void Start() {
        _alive = true;
    }

    void Update() {
        if (_alive) {
            // 1. 向前移动(rotate()和translate()都默认使用本地坐标系)
            transform.Translate(0, 0, speed * Time.deltaTime);

            Ray ray = new Ray(transform.position, transform.forward);
            RaycastHit hit;
            if (Physics.SphereCast(ray, 0.75f, out hit)) {
                GameObject hitObject = hit.transform.gameObject;
                // 2. 若发射线击中物体了
                if (hitObject.GetComponent<PlayerCharacter>()) {
                    // 若没有火球则产生火球
                    if (_fireball == null) {
                        _fireball = Instantiate(fireballPrefab) as GameObject;
                        _fireball.transform.position = transform.TransformPoint(Vector3.forward * 1.5f);
                        _fireball.transform.rotation = transform.rotation;
                    }
                }
                // 3. 若在一定范围内
                else if (hit.distance < obstacleRange) {
                    // 4. 则旋转随机角度
                    float angle = Random.Range(-110, 110);
                    transform.Rotate(0, angle, 0);
                }
            }
        }
    }

prefab是可被不同场景重复使用的GameObject,它可以看做是一种asset,在场景中需要使用时动态加载,这时产生的一个copy叫做instance。关键词:动态加载,重复使用。

敌人死亡后重生的做法是:创建一个空GameObject,下面挂载一个脚本SceneController,每帧判断下当前场景中是否有enemy prefab的instance,没有则创建。

火球运动的代码:

    void Update() {
        transform.Translate(0, 0, speed * Time.deltaTime);
    }

    // 碰撞时触发(需要设置rigidBody)
    void OnTriggerEnter(Collider other) {
        PlayerCharacter player = other.GetComponent<PlayerCharacter>();
        if (player != null) {
            // 执行扣血代码
            player.Hurt(damage);
        }
        Destroy(this.gameObject);
    }

敌人和玩家子弹的处理不一样,一个是用prefab,可以看到移动过程;另一个是raycast,瞬间击中。

art asset的类型分类:material, texture, model, animation, particle system。

Unity支持的2D图形文件类型:PNG,JPG,GIF,BMP,TGA,TIFF,PICT,PSD。其中PNG是无损压缩,JPG和GIF是有损压缩。Unity中推荐使用的格式是:PNG,TGA和PSD。

将texture应用到model的方法:可以直接拖拽到model上,这时material会自动生成;也可以先创建material,再将texture和material关联。

Unity支持的3D模型格式有:FBX,Collada,OBJ,3DS,DXF,Maya,3ds Max,Blender。推荐的是FBX和Collada,它们同时支持mesh和animation。

粒子系统用于表现大量物体的运动(如火焰、烟雾、水)。

sprite是直接在屏幕上显示的2D图片,而非贴在3D模型表面(texture)。拖入2D场景时自动设为sprite类型。

SendMessage()可以向指定对象通信,效率低于直接调用指定对象的方法,但是无需知道它的类型信息。

Application.LoadLevel()可以用来重新加载场景。

展示2D图形需要用orthographic(正交)摄像机。

对于pixel-perfect的图形,摄像机的大小应该是屏幕高度一半。

sprite若要支持点击,则需要在其上加2D collider。

UI text有多种创建方法,其中一种是通过创建3D text对象。

翻牌游戏相关代码片段:

初始化所有牌的代码:

        // place cards in a grid
        for (int i = 0; i < gridCols; i++) {
            for (int j = 0; j < gridRows; j++) {
                MemoryCard card;

                // use the original for the first grid space
                if (i == 0 && j == 0) {
                    card = originalCard;
                } else {
                    // Instantiate方法可以clone自定义类型的对象
                    card = Instantiate(originalCard) as MemoryCard;
                }

                // next card in the list for each grid space
                int index = j * gridCols + i;
                int id = numbers[index];
                card.SetCard(id, images[id]);

                float posX = (offsetX * i) + startPos.x;
                float posY = -(offsetY * j) + startPos.y;
                card.transform.position = new Vector3(posX, posY, startPos.z);
            }
        }

检查是否匹配的代码:

    private IEnumerator CheckMatch() {

        // increment score if the cards match
        if (_firstRevealed.id == _secondRevealed.id) {
            _score++;
            scoreLabel.text = "Score: " + _score;
        }

        // otherwise turn them back over after .5s pause
        else {
            yield return new WaitForSeconds(.5f);

            _firstRevealed.Unreveal();
            _secondRevealed.Unreveal();
        }

        _firstRevealed = null;
        _secondRevealed = null;
    }

GUI系统分为immediate mode和retained mode两种:前者每帧都会重绘(在OnGUI()方法中),使用简单但功能单一;后者是更新的方法,需要使用Canvas在场景中编辑,可支持更复杂的功能。

Canvas是Unity中用来绘制UI的特殊object。创建它时会自动加入EventSystem component。

UI的anchor可设置相对屏幕角的位置,这样屏幕缩放后相对位置也不会变。

sliced image:九宫格切片,切成九块,中间缩放,其余不变。这里的弹出窗口就是sliced image。

PlayerPrefs可以用来持久化存储应用的数据。

使用event来处理UI和场景之间的交互,好处是降低耦合性。如何使用event:1. 定义event;2.A模块广播event;3.B模块监听event并做处理。

阴影分为实时阴影和光照贴图。前者效果好,但消耗计算量大;后者是由烘焙出来的纹理贴图而成。一般来说,静态物体适合用光照贴图,动态物体(如人物)适合用实时阴影。

LateUpdate()调用时机是在所有对象的Update()调用完成之后。

在悬崖和边缘处用射线来处理地面探测,真实性更好。

animation由animation clip作为基本元素组成,animation controller是状态机,定义了各状态之间的转换条件。

TPS中camera绑定的代码:

    // Use this for initialization
    void Start() {
        _rotY = transform.eulerAngles.y;
        _offset = target.position - transform.position;
    }

    // Update is called once per frame
    // 用LateUpdate是因为要跟着人来走
    void LateUpdate() {
        // 无论是转视角还是水平移动,都需要绕着player旋转camera
        float horInput = Input.GetAxis("Horizontal");
        if (horInput != 0) {
            _rotY += horInput * rotSpeed;
        } else {
            _rotY += Input.GetAxis("Mouse X") * rotSpeed * 3;
        }

        Quaternion rotation = Quaternion.Euler(0, _rotY, 0);
        // 根据player的位置和旋转角度,来调整camera位置,并保持相对位置
        transform.position = target.position - (rotation * _offset);
        // camera转向player
        transform.LookAt(target);
    }

TPS中player绑定的代码:

    // Update is called once per frame
    void Update() {

        // start with zero and add movement components progressively
        Vector3 movement = Vector3.zero;

        // x z movement transformed relative to target
        float horInput = Input.GetAxis("Horizontal");
        float vertInput = Input.GetAxis("Vertical");
        if (horInput != 0 || vertInput != 0) {
            movement.x = horInput * moveSpeed;
            movement.z = vertInput * moveSpeed;
            movement = Vector3.ClampMagnitude(movement, moveSpeed);

            Quaternion tmp = target.rotation;
            target.eulerAngles = new Vector3(0, target.eulerAngles.y, 0);
            // 将基于camera的移动转成global的移动
            movement = target.TransformDirection(movement);
            target.rotation = tmp;

            // face movement direction
            //transform.rotation = Quaternion.LookRotation(movement);
            // 往移动方向转向
            Quaternion direction = Quaternion.LookRotation(movement);
            transform.rotation = Quaternion.Lerp(transform.rotation,
                                                 direction, rotSpeed * Time.deltaTime);
        }
        // 设置speed属性,触发进入动画的walk状态
        _animator.SetFloat("Speed", movement.sqrMagnitude);

        // raycast down to address steep slopes and dropoff edge
        bool hitGround = false;
        RaycastHit hit;
        // 利用射线更精确地做地面接触检测
        if (_vertSpeed < 0 && Physics.Raycast(transform.position, Vector3.down, out hit)) {
            float check = (_charController.height + _charController.radius) / 1.9f;
            hitGround = hit.distance <= check;  // to be sure check slightly beyond bottom of capsule
        }

        // y movement: possibly jump impulse up, always accel down
        // could _charController.isGrounded instead, but then cannot workaround dropoff edge
        // 若射线检测在地面
        if (hitGround) {
            if (Input.GetButtonDown("Jump")) {
                _vertSpeed = jumpSpeed;
            } else {
                _vertSpeed = minFall;
                // 落到地面后停止jump动作
                _animator.SetBool("Jumping", false);
            }
        } else {
            _vertSpeed += gravity * 5 * Time.deltaTime;
            if (_vertSpeed < terminalVelocity) {
                _vertSpeed = terminalVelocity;
            }
            // 实际没有碰撞
            if (_contact != null ) {    // not right at level start
                _animator.SetBool("Jumping", true);
            }

            // workaround for standing on dropoff edge
            // 实际在地面上(悬崖边)
            if (_charController.isGrounded) {
                if (Vector3.Dot(movement, _contact.normal) < 0) {
                    movement = _contact.normal * moveSpeed;
                } else {
                    movement += _contact.normal * moveSpeed;
                }
            }
        }
        movement.y = _vertSpeed;

        movement *= Time.deltaTime;
        _charController.Move(movement);
    }

    // store collision to use in Update
    void OnControllerColliderHit(ControllerColliderHit hit) {
        _contact = hit;
    }

trigger可以定义触发操作,它不是真实的物体,可以被穿透。

Awake()比Start()更早执行,它可以做一些初始化操作。

Resources.Load()可以从Resources目录加载一些assets。

人和场景中物体交互的一些代码:

Player上面绑定的代码:

    void Update() {
        // 若按下command键
        if (Input.GetButtonDown("Fire3")) {
            Collider[] hitColliders = Physics.OverlapSphere(transform.position, radius);
            foreach (Collider hitCollider in hitColliders) {
                Vector3 direction = hitCollider.transform.position - transform.position;
                if (Vector3.Dot(transform.forward, direction) > .5f) {
                    // 则向周围一定半径的物体发送Operate消息
                    hitCollider.SendMessage("Operate", SendMessageOptions.DontRequireReceiver);
                }
            }
        }
    }

门的trigger上绑定的代码:

    void OnTriggerEnter(Collider other) {
        if (requireKey && Managers.Inventory.equippedItem != "key") {
            return;
        }

        foreach (GameObject target in targets) {
            // 碰撞后,对门发送Activate消息
            target.SendMessage("Activate");
        }
    }

    void OnTriggerExit(Collider other) {
        foreach (GameObject target in targets) {
            target.SendMessage("Deactivate");
        }
    }

门上绑定的代码:

    // 无论是通过按键,还是碰撞,都可以实现门的开闭
    public void Operate() {
        if (_open) {
            Vector3 pos = transform.position - dPos;
            transform.position = pos;
        } else {
            Vector3 pos = transform.position + dPos;
            transform.position = pos;
        }
        _open = !_open;
    }

    public void Activate() {
        if (!_open) {
            Vector3 pos = transform.position + dPos;
            transform.position = pos;
            _open = true;
        }
    }
    public void Deactivate() {
        if (_open) {
            Vector3 pos = transform.position - dPos;
            transform.position = pos;
            _open = false;
        }
    }

场景中散落的道具上绑定的代码:

    void OnTriggerEnter(Collider other) {
        // 碰撞之后ui上增加,并将自己销毁
        Managers.Inventory.AddItem(itemName);
        Destroy(this.gameObject);
    }

UI相关的代码:

    // 实时绘制UI
    void OnGUI() {
        int posX = 10;
        int posY = 10;
        int width = 100;
        int height = 30;
        int buffer = 10;

        List<string> itemList = Managers.Inventory.GetItemList();
        if (itemList.Count == 0) {
            GUI.Box(new Rect(posX, posY, width, height), "No Items");
        }
        foreach (string item in itemList) {
            int count = Managers.Inventory.GetItemCount(item);
            Texture2D image = Resources.Load<Texture2D>("Icons/"+item);
            GUI.Box(new Rect(posX, posY, width, height), new GUIContent("(" + count + ")", image));
            posX += width+buffer;
        }

        string equipped = Managers.Inventory.equippedItem;
        if (equipped != null) {
            posX = Screen.width - (width+buffer);
            Texture2D image = Resources.Load("Icons/"+equipped) as Texture2D;
            GUI.Box(new Rect(posX, posY, width, height), new GUIContent("Equipped", image));
        }

        posX = 10;
        posY += height+buffer;

        foreach (string item in itemList) {
            // 创建button同时判断button是否被按下
            if (GUI.Button(new Rect(posX, posY, width, height), "Equip "+item)) {
                Managers.Inventory.EquipItem(item);
            }

            if (item == "health") {
                if (GUI.Button(new Rect(posX, posY + height+buffer, width, height), "Use Health")) {
                    Managers.Inventory.ConsumeItem("health");
                    Managers.Player.ChangeHealth(25);
                }
            }

            posX += width+buffer;
        }
    }

Trigger和Collider的区别:Collider是物理碰撞,isTrigger是Collider上的一个属性,勾选后只检测碰撞,但没有物理效果。

Action在Unity中的用途与用法(Unity3D) 在TimerCoroutine协程中,我们使用yield return new WaitForSeconds(interval)来等待一定的时间间隔后,再调用Action对象执行相应的操作。综上所述,Action在Unity中是一种常用的委托类型,用于处理游戏中的各种动作和事件。在这个示例中,我们在动画的第1秒添加了一个事件关键帧,并指定了事件处理方法为HandleAnimationEvent。其中的Action类是Unity中常用的一种委托类型,用于处理游戏中的各种动作和事件。希望以上内容对你有所帮助! 阅读详情

相关推荐

Unity in Action Multiplatform game development in C#(2nd) 无水印原版pdf

Unity in Action Multiplatform game development in C#(2nd) 英文无水印原版pdf 第2版 pdf所有页面使用FoxitReader、PDF-XChangeViewer、SumatraPDF和Firefox测试都可以打开 本资源转载自网络,如有侵权,请联系上传者或csdn删除查看此书详细信息请在美国亚马逊官网搜索此书

Unity in Action 第二版示例项目指南

Unity in Action 第二版示例项目指南 欢迎来到《Unity in Action》第二版的开源项目实战指导。本指南旨在帮助您快速了解并上手这个基于Unity引擎的示例项目集合。以下是对项目关键部分的详细介绍: 1. 项目目录结构及介绍 项目根目录下包含了该书中的所有示例项目的源代码。尽管具体的目录结构可能因版本更新而有所变化,典型的布局通常包括多个子目录,每个子目录对应书中的一个章节或...

gitblog_00619的博客 710

Unity in Action Multiplatform game development in C# with Unity 5.pdf

Unity in Action Multiplatform game development in C# with Unity 5 非扫描文字版 英文版

Unity in Action 第二版示例项目推荐

Unity in Action 第二版示例项目推荐 1. 项目基础介绍和主要编程语言 Unity in Action 第二版 是一个开源项目,包含了来自《Unity in Action》第二版书籍中的所有示例项目。该项目的主要目的是帮助开发者通过实际项目学习如何使用Unity引擎进行游戏开发。项目的主要编程语言是 C#,这是Unity开发中最常用的编程语言。 2. 项目的核心功能 该项目的核心功能...

gitblog_00216的博客 366

Unity in Action, 2nd Edition.pdf.zip

Unity in Action, Second Edition is a book about programming games in Unity. Think of it as an intro to Unity for experienced programmers. The goal of this book is straightfor- ward: to take people who have some programming experience but no experience with Unity and teach them how to develop a game using Unity. The best way of teaching development is through example projects, with students learning by doing, and that’s the approach this book takes. I’ll present topics as steps toward building sample games, and you’ll be encouraged to build these games in Unity while exploring the book. We’ll go through a selection of different projects every few chapters, rather than one monolithic project developed over the entire book. (Some- times other books take the “one monolithic project” approach, but that can make it hard to jump into the middle if the early chapters aren’t relevant to you.) This book will have more rigorous programming content than most Unity books (especially beginners’ books). Unity is often portrayed as a list of features with no pro- gramming required, which is a misleading view that won’t teach people what they need to know in order to produce commercial titles. If you don’t already know how to pro- gram a computer, I suggest going to a resource like Codecademy first (the computer programming lessons at Khan Academy work well, too) and then come back to this book after learning how to program. Don’t worry about the exact programming language; C# is used throughout this book, but skills from other languages will transfer quite well. Although the first part of the book will take its time introducing new concepts and will carefully and deliberately

Unity in Action, 2nd Edition--2018

Manning’s bestselling and highly recommended Unity book has been fully revised! Unity in Action, Second Editionteaches you to write and deploy games with the Unity game development platform. You’ll master the Unity toolset from the ground up, adding the skills you need to go from application coder to game developer.

Unity in Action 2nd Edition 项目教程

Unity in Action 2nd Edition 项目教程 1. 项目介绍 uia-2e 是 Unity in Action 2nd edition 的代码仓库,包含了书中所有项目的源代码。该项目旨在帮助开发者学习如何使用 Unity 引擎进行游戏开发。通过跟随书中的教程和示例代码,开发者可以逐步掌握 Unity 的核心概念和开发技巧。 2. 项目快速启动 2.1 克隆项目 首先,你需要克隆...

gitblog_00702的博客 1032

"Unity in Action" 是一本面向初学者的实用指南,专注于使用 Unity 进行多平台游戏开发 书中通过一系列逐步递

主要内容: 基础知识: 介绍 Unity 编辑器和基础操作。 讲解 C# 编程基础知识,适合初学者理解和上手。 游戏开发流程: 带领读者从零开始构建完整的游戏项目。 涵盖了游戏开发的各个阶段,包括设计、实现、测试和发布。 多平台支持: 讲解如何为不同平台(如 PC、移动设备和 Web)开发游戏。 介绍平台特定的优化技巧和注意事项。 项目实例: 通过多个实际项目,如 2D 横版游戏、3D 第一人称游戏等,帮助读者掌握不同类型游戏的开发技巧。 每个项目都详细分解成可操作的步骤,并配有示例代码和图示。 高级主题: 介绍了更高级的主题,如物理引擎、动画系统、UI 设计和音效集成。 讲解如何使用 Unity 的组件系统和脚本 API。 特点: 实用性强: 通过具体项目的实际操作,帮助读者将理论知识应用到实际开发中。 易于理解: 语言简明扼要,适合初学者快速上手,同时也包含了大量实用技巧和最佳实践。 全面覆盖: 涵盖了从基础到高级的各个方面,帮助读者全面掌握 Unity 开发技能。 适用对象: 初学者: 适合没有游戏开发经验的初学者,通过循序渐进的学习方式,逐步掌握 Unity 和

【Unity】Delegate, Event, UnityEvent, Action, UnityAction, Func 傻傻分不清

学习打开别人一个魔塔的项目,看到了满页的 `Action` 代码,而本人委托那一块自己写的时候压根不会用……遂学习相关知识。 **多数学习自知乎** **本文可能会有知识点错误,欢迎讨论。**

溢流眼泪的博客 1万+

基于ROS2的无人机野生动物巡查系统设计

自主巡检系统是嵌入式人工智能与机器人技术融合的关键应用方向,其核心在于多源感知融合、实时路径规划与端侧智能识别的协同实现。原理上依赖SLAM定位构建环境地图,结合栅格化建模与混合路径算法(如蚁群+BFS)达成全覆盖遍历;技术价值体现在资源受限平台下的确定性响应与时空对齐能力,支撑高鲁棒性野外作业。典型应用场景包括生态监测、禁飞区巡检及小尺度智能安防。本文围绕ROS2 Humble中间件架构、Livox激光雷达与MaixCAM视觉协同、YOLO11n INT8模型端侧部署等关键技术展开,突出嵌入式AI与实时控

weixin_30598047的博客 649

多边形裁剪算法

多边形裁剪算法 刚参加工作就跟多边形刚上了,对于多边形的裁剪做一些简单的总结。 多边形裁剪主要有四种算法 Greiner-Hormann裁剪算法 Sutherland-Hodgman算法 Vatti裁剪算法 Weiler-Atherton裁剪算法 作为一名想要成为优秀算法工程师的程序员,我们不能只会使用,而不知道其原理,倘若如此,我们无法做到应用于本身业务上的定制化的修改。 Greiner–H...

papalqi 6729

Unity in Action 2nd Edition 项目常见问题解决方案

Unity in Action 2nd Edition 项目常见问题解决方案 项目基础介绍 Unity in Action 2nd Edition 是一个开源项目,包含了来自《Unity in Action》第二版书籍中的所有示例项目。该项目旨在帮助开发者学习如何使用 Unity 引擎进行游戏开发。项目的主要编程语言是 C#,同时也包含了一些 ShaderLab、HTML、Objective-C+...

gitblog_00851的博客 374

Multisim14.3中FPGA接口电路设计:原理图项目应用

深入讲解在multisim14.3环境下构建FPGA接口电路的方法,结合原理图设计与项目实践,展现multisim14.3强大的电路仿真能力,提升数字系统开发效率。

weixin_42578963的博客 1157

unity UnityAction 和 C# action的区别

Unity中的UnityAction和Action有什么区别。首先,我需要回忆一下自己学过的Unity和C#知识。UnityAction应该是Unity引擎自己定义的一个委托类型,而Action是C#内置的泛型委托。对吧?首先,应该考虑它们的命名空间。UnityAction属于UnityEngine.Events命名空间,而Action是System下的。然后,它们的定义方式不同,UnityAction可能有不同版本,比如带不同数量参数的,而Action可以通过泛型来支持多个参数。

lcfengokok的博客 1083

Halcon一维测量实战:从measure_pos与measure_pairs的底层原理到精准应用

本文深入解析Halcon中measure_pos与measure_pairs算子的底层原理与精准应用,涵盖参数调优、测量矩形方向设置及典型工业场景实战。通过对比分析,揭示两者在一维测量中的核心差异与适用场景,提供从基础到高级的完整解决方案,助力工业视觉检测精度提升。

weixin_42525551的博客 424

E-Prime脑电实验打mark全攻略:从端口查询到串并口实战(附常见问题解决)

本文提供了E-Prime脑电实验打mark的完整实战指南,涵盖端口查询、并口与串口配置的核心步骤及常见问题解决。文章深入解析了mark原理,并详细介绍了通过E-Basic脚本和Serial设备对象发送信号的两种方法,帮助研究者实现E-Prime与脑电设备的高精度时间同步,确保实验数据可靠性。

4k5l6j7h8的博客 355

unity学习笔记-action的用法

unity学习笔记Action的用法使用方法12实际使用 Action的用法 今天和前端的同事学习了一个新的用法 这个用法解决了我之前一直困扰的问题 当然这个问题可以有别的方法解决,但是这个方法更适合编程的思维 实际的需求: 在协程里当协程完成了之后再进行后面的方法和函数 因为协程是异步的,不能像主程一样只有前面的方法执行完毕之后才能往下执行 但是在实际的使用过程中,我们避免不了的要用到协程去进行一些文件的读写,api的调用等功能 而协程会导致不同的线程之间数据的不同步 打个可能不是很恰当的例子 协程1访问

pure81的博客 5188

【学长笔记】点亮 STM32F411CEU6 板载 LED —— 入门级教程

本文提供了STM32F411CEU6开发板(Black Pill)点亮LED的完整教程。详细介绍了硬件信息(板载LED连接PC13,低电平有效)、CubeMX配置步骤(GPIO输出模式)、Keil5工程设置及完整代码实现(包含GPIO初始化和系统时钟配置)。教程还涵盖ST-Link下载器连接方法、程序下载步骤(需配合BOOT0按键操作)以及验证程序运行的方法。该教程特别适合STM32初学者,通过简单的LED闪烁示例快速入门STM32开发。

apple_53308981的博客 1323

C#的Delegate与Unity的Action、Func

Unity提供的Action和Func都是基于C#的委托Delegate加多一层封装,Action用于定义无返回值的委托,Func用于定义有返回值的委托。 使用 Delegate public delegate void Delegate(); Delegate myDelegate; myDelegate=myFun1(); myDelegate+=myFun2 Action Action action; action=myFun1(); action+=myFun2(); Func Func<

dddd 837

化工设计软件:AutoCAD Plant 3D二次开发_(1).AutoCADPlant3D概述

AutoCAD Plant 3D 是一款专为化工行业设计的三维工厂设计和建模软件。它基于AutoCAD平台,提供了强大的三维建模功能和专业的化工设计工具,帮助工程师和设计师在工厂设计过程中提高效率和准确性。AutoCAD Plant 3D不仅能够创建详细的三维模型,还可以进行管道设计、设备布置、支架设计等复杂任务。通过上述案例,我们可以看出 AutoCAD Plant 3D 在化工厂设计中的强大功能和优势。该软件不仅提供了丰富的建模工具和专业的设计功能,还支持二次开发,使用户能够根据具体需求进行定制化操作。

kkchenjj的博客 1103

AI大模型:(三)3.2 Spring AI实现Agent

SpringAI实现了流式对话功能,通过与Ollama模型集成完成前后端交互,当前版本存在thinking信息丢失问题。系统支持两种工具注册方式(方法注解和函数式),并内置时间工具类展示外部工具调用能力。记忆功能提供多种存储方案(内存、JDBC、NoSQL等),实现跨对话轮次的上下文保持。MCP协议集成方面,服务端实现计算和业务查询工具,客户端支持12306及自定义业务系统接入。完整演示了流式对话、工具调用与记忆功能的综合应用。该实践构建了具备复杂交互能力的AI系统,同时指出生产环境需关注的安全与优化问题。

haylee的专栏 1008

Unity XR Interaction Toolkit中Action与Device的差异探究

Unity XR交互的Action和Device两种类型的差异探究

m0_37965883的博客 1268

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

Unity使用Task后回调Action的问题

先看一段代码: private void Awake() { Debug.LogError("Awake"); TaskEvent(() => { Debug.LogError(gameObject.GetComponent<Transform>().forward); }); } private async void TaskEvent(Action callBa

越的专栏 1709

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

《Unity in Action》阅读笔记

用较短的时间读完。以一个完整的枪战游戏为例子,穿插讲解unity基本知识,适合入门,符合书名表达的理念:在实践中学。不过想要深入unity,还得靠多个项目实践和锻炼,急不来的,毕竟一门引擎的使用是偏向于实践性的技能。这本书只是提供一个入门的概要和框架,要深入还得需要补充更多图形学的知识,以及多加实践。 Chapter 1: Getting to know Unityunity优点:可视化的工作流:基

长三月的游戏开发 1303

SIMATIC S7-1200, S7-1500 PID 控制[手册]

SIMATIC S7-1200, S7-1500 PID 控制[手册]

Unity中使用Action进行简单的委托事件管理

Unity中使用Action进行简单的委托事件管理解决问题代码脚本挂载及运行效果 解决问题 可以用于Unity的事件处理,但是使用时要保证参数个数、类型、顺序必须完全⼀致。 代码 委托事件中心 _Delegation.cs using System; public class _Delegation { /// <summary> /// 一个参数 /// </summary> public static Action<string>

FutureDr的博客 7420
上一篇: 全球同服游戏服务端设计
下一篇: Recast源码解析(一):射线实现原理
长三月
博客等级 码龄9年 228粉丝 80原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值