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

296 lines
11 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: studycase4
date: 2025-11-30 12:40:05
tags: [studycase, unity]
pinned: true
head:
- - meta
- name: description
content: vitepress-theme-bluearchive studycase4
- - meta
- name: keywords
content: vitepress theme bluearchive studycase4
---
# 虚拟摇杆
- [世界构筑的起始篇章-编辑器](#_1-世界构筑的起始篇章-编辑器)
- [光芒汇聚之所-章节目标](#_2-光芒汇聚之所-章节目标)
- [光流影卷-演示视频](#_3-光流影卷-演示视频)
- [初始祭坛-前置准备](#_4-初始祭坛-前置准备)
- [勇者行迹录-章节任务](#_5-勇者行迹录-章节任务)
- [异闻录-FAQ](#_6-异闻录-faq)
## 1.世界构筑的起始篇章-编辑器
- **Unity 2022.3.62f2**
- **Visual Studio 2022**
## 2.光芒汇聚之所-章节目标
- **虚拟摇杆和按钮**
- **In game Debug**
- **打包APK**
## 3.光流影卷-演示视频
<video id="vdMain" controls muted poster="/video/studycase4/演示视频.png" playsinline>
<source id="vSource" src="/video/studycase4/演示视频.mp4" type="video/mp4" />
</video>
## 4.初始祭坛-前置准备
### 导入[资源](/resources/studycase4/case4.zip)(摇杆图标、Debug工具)
<img src="/image/studycase4/导入.png" data-fancybox="gallery"/>
### 导入InputSystem的OnScreen示例
<img src="/image/studycase4/onscreen.png" data-fancybox="gallery"/>
## 5.勇者行迹录-章节任务
### 5.1 创建StudyCase4
- 复制场景和脚本改名为studycase4
- 修改控制器和道具的命名空间
### 5.2 IngameDebugConsole
- 把IngameDebugConsole预制体拖入场景
<img src="/image/studycase4/debug.png" data-fancybox="gallery"/>
- 在Resources文件夹下创建材质LineShader选择Sprite-Unlit-Default
<img src="/image/studycase4/创建材质Line设置shader为Sprite-Unlit-Default.png" data-fancybox="gallery"/>
### 5.3 虚拟摇杆创建
- 全选mobile-controls-1下的Texture
<img src="/image/studycase4/全选mobile-controls-1下的Texture.png" data-fancybox="gallery"/>
- 切换到sprite(2d and ui)
<img src="/image/studycase4/切换到sprite.png" data-fancybox="gallery"/>
- 创建一个canvas再创建一个image命名为leftBgsprite使用joystick_circle_pad_a设置大小位置和锚点
<img src="/image/studycase4/创建leftBg.png" data-fancybox="gallery"/>
- 创建一个image命名为leftStick透明度0设置大小位置和锚点挂载On-Screen-Stick
<img src="/image/studycase4/创建leftStick.png" data-fancybox="gallery"/>
- 设置 `MovementRange` 为200设置 `ControlPath` 为LeftStick
<img src="/image/studycase4/设置leftStick.png" data-fancybox="gallery"/>
- 复制一个leftBg改名为rightBg设置大小位置和锚点
<img src="/image/studycase4/创建rightBg.png" data-fancybox="gallery"/>
- 复制一个leftStick改名为rightStick设置`ControlPath` 为RightStick
<img src="/image/studycase4/创建并设置rightStick.png" data-fancybox="gallery"/>
- 添加输入事件Move添加LeftStick创建Look添加Detla和RightStick
<img src="/image/studycase4/添加输入事件.gif" data-fancybox="gallery"/>
- 设置虚拟相机参数移动速度从300调到100限制角度0到70
<img src="/image/studycase4/设置虚拟相机参数.png" data-fancybox="gallery"/>
- 修改虚拟相机输入
<img src="/image/studycase4/配置虚拟相机输入.gif" data-fancybox="gallery"/>
### 5.4 Player脚本和设置
- 修改`Assets\Scripts\studycase4` 下脚本 `ThirdCharacterController.cs`
```csharp
using UnityEngine;
using UnityEngine.InputSystem;
using Cinemachine;
namespace StudyCase4
{
public enum PickMode
{
RayCast,
Mouse
}
public class ThirdCharacterController : MonoBehaviour
{
[Header("MoveSettings")]
CharacterController characterController;
InputActionAsset inputAction;
Animator animator;
Transform forward;
Transform model;
CinemachineVirtualCamera vCam;
public float moveSpeed = 5f;
public float jumpSpeed = 2f;
public float turnSpeed = 10f;
public float gravity = 10f;
Vector3 moveDir;
Vector2 moveInput;
[Header("PickSettings")]
public PickMode pickMode = PickMode.RayCast;
public CursorLockMode cursorLock;
public bool useDrawRay = true;
public float maxDistance = 5f;
public LayerMask layerMask;
public float itemsRotateSpeed = 120f;
public float minCameraDistance = 2f;
public float maxCameraDistance = 10f;
public float cameraZoomSpeed = 0.1f;
[HideInInspector] public Transform itemRoot;
Item selectItem;
LineRenderer lineRenderer;
CinemachineFramingTransposer framingTransposer;
private void Awake()
{
Cursor.lockState = cursorLock;
characterController = GetComponent<CharacterController>();
forward = transform.Find("Forward");
model = transform.Find("Model");
animator = model.GetComponentInChildren<Animator>();
vCam = transform.Find("Virtual Camera").GetComponent<CinemachineVirtualCamera>();
framingTransposer = vCam.GetCinemachineComponent<CinemachineFramingTransposer>();
inputAction = Resources.Load<InputActionAsset>("PlayerInputActions");
inputAction.FindAction("Move").started += OnMove;
inputAction.FindAction("Move").performed += OnMove;
inputAction.FindAction("Move").canceled += OnMove;
inputAction.FindAction("Jump").performed += OnJump;
inputAction.FindAction("Pick").performed += OnPickUp;
inputAction.FindAction("Zoom").started += OnZoom;
inputAction.FindAction("Zoom").performed += OnZoom;
inputAction.FindAction("Zoom").canceled += OnZoom;
inputAction.Enable();
itemRoot = transform.Find("ItemRoot");
if (lineRenderer == null)
{
lineRenderer = gameObject.AddComponent<LineRenderer>();
lineRenderer.material = Resources.Load<Material>("Line");
lineRenderer.useWorldSpace = true;
}
layerMask = LayerMask.GetMask("Item");
//开启多点触控
Input.multiTouchEnabled = true;
}
private void Update()
{
Move();
CheckRayHit();
ItemsRotate();
}
public void OnMove(InputAction.CallbackContext context)
{
if (characterController.isGrounded)
moveInput = context.ReadValue<Vector2>();
else moveInput = Vector2.zero;
}
public void OnJump(InputAction.CallbackContext context)
{
if (context.performed && characterController.isGrounded)
{
moveDir.y = jumpSpeed;
}
}
//增加控制相机距离的方法
public void OnZoom(InputAction.CallbackContext context)
{
float scrollValue = context.ReadValue<float>();
float newDistance = framingTransposer.m_CameraDistance + (scrollValue * cameraZoomSpeed * 0.01f);
framingTransposer.m_CameraDistance = Mathf.Clamp(newDistance, minCameraDistance, maxCameraDistance);
}
void Move()
{
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);
}
#region PickUp
public void OnPickUp(InputAction.CallbackContext context)
{
if (pickMode != PickMode.RayCast) return;
if (selectItem != null)
selectItem.PickUp(itemRoot);
selectItem = null;
}
void CheckRayHit()
{
lineRenderer.enabled = useDrawRay;
if (pickMode != PickMode.RayCast)
{
useDrawRay = false;
return;
}
Ray ray = new Ray(model.position, model.forward);
RaycastHit hit;
if (Physics.Raycast(ray, out hit, maxDistance, layerMask))
{
DrawRay(model.position, hit.point, new Color(0, 1, 1));
Item curItem = hit.transform.GetComponent<Item>();
if (curItem != null && curItem != selectItem)
{
if (selectItem != null)
selectItem.UnSelect();
selectItem = curItem;
selectItem.Select();
}
}
else
{
DrawRay(model.position, model.position+ model.forward* maxDistance, new Color(1, 1, 1));
if (selectItem != null)
selectItem.UnSelect();
selectItem = null;
}
}
void DrawRay(Vector3 startPos, Vector3 endPos, Color color)
{
lineRenderer.startColor = lineRenderer.endColor = color;
lineRenderer.startWidth = lineRenderer.endWidth = 0.1f;
lineRenderer.positionCount = 2;
lineRenderer.SetPosition(0, startPos);
lineRenderer.SetPosition(1, endPos);
lineRenderer.enabled = true;
}
void ItemsRotate()
{
itemRoot.Rotate(0,itemsRotateSpeed*Time.deltaTime, 0);
}
public void SetItems()
{
float radius = 1.5f;
float angleStep = 360 / itemRoot.childCount;
for (int i = 0; i < itemRoot.childCount; i++)
{
Transform item = itemRoot.GetChild(i);
float angle = angleStep * i;
Quaternion rot = Quaternion.Euler(0, angle, 0);
item.localPosition = rot * itemRoot.forward * radius;
item.localScale = Vector3.one * 0.1f;
}
}
#endregion
}
}
```
### 5.5打包并测试
- 玩家移除case3的脚本挂载case4脚本
- BuildSettings切换到Android平台
<img src="/image/studycase4/切换到Android平台.png" data-fancybox="gallery"/>
- 打包apk
<img src="/image/studycase4/打包apk.png" data-fancybox="gallery"/>
- 在手机上安装和运行
## 6.异闻录-FAQ