Files
BA-VitePress-Pages/posts/studycase5.md
2025-12-02 18:28:53 +08:00

198 lines
6.5 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
title: studycase5
date: 2025-12-2 17:23:05
tags: [studycase, unity]
pinned: true
head:
- - meta
- name: description
content: vitepress-theme-bluearchive studycase5
- - meta
- name: keywords
content: vitepress theme bluearchive studycase5
---
# 虚拟摇杆
- [世界构筑的起始篇章-编辑器](#_1-世界构筑的起始篇章-编辑器)
- [光芒汇聚之所-章节目标](#_2-光芒汇聚之所-章节目标)
- [光流影卷-演示视频](#_3-光流影卷-演示视频)
- [初始祭坛-前置准备](#_4-初始祭坛-前置准备)
- [勇者行迹录-章节任务](#_5-勇者行迹录-章节任务)
- [异闻录-FAQ](#_6-异闻录-faq)
## 1.世界构筑的起始篇章-编辑器
- **Unity 2022.3.62f2**
- **Visual Studio 2022**
## 2.光芒汇聚之所-章节目标
- **使用Mirror实现简单联机**
- **打包exe**
## 3.光流影卷-演示视频
<video id="vdMain" controls muted poster="/video/studycase5/演示视频.png" playsinline>
<source id="vSource" src="/video/studycase5/演示视频.mp4" type="video/mp4" />
</video>
## 4.初始祭坛-前置准备
### 导入[资源](/resources/studycase5/case5.zip)(Mirror)
<img src="/image/studycase5/导入Mirror.png" data-fancybox="gallery"/>
<img src="/image/studycase5/导入Mirror步骤2.png" data-fancybox="gallery"/>
<img src="/image/studycase5/导入Mirror步骤3.png" data-fancybox="gallery"/>
## 5.勇者行迹录-章节任务
### 5.1 创建StudyCase5
- 复制场景改名为StudyCase5
- 删除道具Player移除ThirdCharacterController
### 5.2 了解 `Mirror`
- 打开示例Tanks场景
<img src="/image/studycase5/打开示例Tanks场景.png" data-fancybox="gallery"/>
- 为了查看联机效果,修改项目设置
<img src="/image/studycase5/Windows项目设置.png" data-fancybox="gallery"/>
- 把示例打包成exe
<img src="/image/studycase5/打包Windows.png" data-fancybox="gallery"/>
- 打开俩个exe一个选择host另一个选择client
<img src="/image/studycase5/打开host和client.png" data-fancybox="gallery"/>
- 体验联机效果
<img src="/image/studycase5/体验联机.png" data-fancybox="gallery"/>
### 5.2 使用 `Mirror`
- 首先将示例场景(MirrorTanks)中的网络控制器(NetworkManager)复制到我们的场景中(StudyCase5)
<img src="/image/studycase5/复制NetworkManager.png" data-fancybox="gallery"/>
- Player添加NetworkIdentity组件(联网对象需要这个组件)
<img src="/image/studycase5/Player添加NetworkIdentity组件.png" data-fancybox="gallery"/>
- 添加俩个NetworkTransform(Transform同步需要这个组件)
<img src="/image/studycase5/添加俩个NetworkTransform.png" data-fancybox="gallery"/>
- 设置NetworkTransform(Player和Model)
<img src="/image/studycase5/设置NetworkTransform.png" data-fancybox="gallery"/>
- Player添加NetworkAnimator组件并设置(动画状态同步需要这个组件)
<img src="/image/studycase5/Player添加NetworkAnimator组件并设置.png" data-fancybox="gallery"/>
- PlayerInputActions中创建Esc的监听事件
<img src="/image/studycase5/添加ESC.png" data-fancybox="gallery"/>
- 创建NetworkBehaviour命名为 `NetWorkPlayer`
<img src="/image/studycase5/创建NetworkBehaviour.png" data-fancybox="gallery"/>
- 编写脚本 `NetWorkPlayer`
```csharp
using UnityEngine;
using Mirror;
using UnityEngine.InputSystem;
using Cinemachine;
public class NetWorkPlayer : NetworkBehaviour
{
public CharacterController characterController;
public InputActionAsset inputAction;
public Animator animator;
public Transform forward;
public Transform model;
public CinemachineVirtualCamera vCam;
public CursorLockMode cursorLock;
public float moveSpeed = 5f;
public float jumpSpeed = 2f;
public float turnSpeed = 10f;
public float gravity = 10f;
Vector3 moveDir;
Vector2 moveInput;
public override void OnStartLocalPlayer()
{
Cursor.lockState = cursorLock;
vCam.Priority = 15;
inputAction.FindAction("Move").started += OnMove;
inputAction.FindAction("Move").performed += OnMove;
inputAction.FindAction("Move").canceled += OnMove;
inputAction.FindAction("Jump").performed += OnJump;
inputAction.FindAction("Esc").performed += OnEsc;
inputAction.Enable();
}
private void Update()
{
if (!isLocalPlayer) return;
moveDir = new Vector3(moveInput.x, moveDir.y, moveInput.y);
forward.eulerAngles = new Vector3(0, vCam.transform.eulerAngles.y, 0);
moveDir = forward.TransformDirection(moveDir);
if (moveInput != Vector2.zero)
{
animator.SetBool("Move", true);
Quaternion target = Quaternion.LookRotation(new Vector3(moveDir.x, 0, moveDir.z));
model.rotation = Quaternion.Slerp(model.rotation, target, turnSpeed * Time.deltaTime);
}
else animator.SetBool("Move", false);
if (!characterController.isGrounded)
moveDir.y -= gravity * Time.deltaTime;
characterController.Move(moveDir * moveSpeed * Time.deltaTime);
}
public void OnMove(InputAction.CallbackContext context)
{
if (!isLocalPlayer) return;
if (characterController.isGrounded)
moveInput = context.ReadValue<Vector2>();
else moveInput = Vector2.zero;
}
public void OnJump(InputAction.CallbackContext context)
{
if (!isLocalPlayer) return;
if (characterController.isGrounded)
{
moveDir.y = jumpSpeed;
}
}
public void OnEsc(InputAction.CallbackContext context)
{
if (!isLocalPlayer) return;
if(Cursor.lockState == CursorLockMode.Locked)
Cursor.lockState = CursorLockMode.None;
else
Cursor.lockState = CursorLockMode.Locked;
}
}
```
- Player挂载 `NetWorkPlayer` ,Player的设置
<img src="/image/studycase5/Player的设置.png" data-fancybox="gallery"/>
- 将Player保存为预制体(拖拽到文件夹中会自动保存为预制体)
<img src="/image/studycase5/保存玩家Prefab.png" data-fancybox="gallery"/>
- 删除场景中的Player后续由NetworkManager创建,创建俩个出生点,挂载 `NetworkStartPosition`
<img src="/image/studycase5/设置场景.png" data-fancybox="gallery"/>
- 将预制体Player拖拽到NetworkManager上的 `PlayerPrefab`
<img src="/image/studycase5/player替换tank.png" data-fancybox="gallery"/>
- 打包exe打开俩个体验联机
<img src="/image/studycase5/体验联机2.png" data-fancybox="gallery"/>
## 6.异闻录-FAQ