--- title: StudyCase3 date: 2025-11-26 21:33 tags: [studycase, unity] pinned: true head: - - meta - name: description content: vitepress-theme-bluearchive StudyCase3 - - meta - name: keywords content: vitepress theme bluearchive StudyCase3 --- # 物体拾取 - [世界构筑的起始篇章-编辑器](#_1-世界构筑的起始篇章-编辑器) - [光芒汇聚之所-章节目标](#_2-光芒汇聚之所-章节目标) - [光流影卷-演示视频](#_3-光流影卷-演示视频) - [初始祭坛-前置准备](#_4-初始祭坛-前置准备) - [勇者行迹录-章节任务](#_5-勇者行迹录-章节任务) - [异闻录-FAQ](#_6-异闻录-faq) ## 1.世界构筑的起始篇章-编辑器 - **Unity 2022.3.62f2**: - **Visual Studio 2022** ## 2.光芒汇聚之所-章节目标 - **射线检测拾取物体** - **鼠标点击拾取物体** ## 3.光流影卷-演示视频 ## 4.初始祭坛-前置准备 ### 导入[资源](/resources/studycase3/case3.unitypackage)(天空球,描边,道具模型) ## 5.勇者行迹录-章节任务 ### 创建StudyCase3 - 复制场景和脚本改名为StudyCase3 - 修改控制器的命名空间 ### 道具 - 把导入的道具模型放到场景中 - 新建道具层级 - 在`Assets\Scripts\StudyCase3`下创建道具脚本`Item.cs` ```csharp using UnityEngine; namespace StudyCase3 { public class Item : MonoBehaviour { Outline outline; bool pick; ThirdCharacterController player; private void Awake() { player = FindAnyObjectByType(); if (outline == null) outline = gameObject.AddComponent(); else outline = GetComponent(); outline.enabled = false; outline.OutlineMode = Outline.Mode.OutlineVisible; outline.OutlineColor = new Color(0, 1, 1); outline.OutlineWidth = 10f; gameObject.layer = LayerMask.NameToLayer("Item"); } public void Select() { if(!pick) outline.enabled = true; } public void UnSelect() { if (!pick) outline.enabled = false; } public void PickUp(Transform root) { if (pick) return; pick = true; transform.SetParent(root); outline.OutlineWidth = 2f; gameObject.layer = LayerMask.NameToLayer("Default"); player.SetItems(); } private void OnMouseEnter() { if (player.pickMode == PickMode.Mouse) Select(); } private void OnMouseExit() { if (player.pickMode == PickMode.Mouse) UnSelect(); } private void OnMouseDown() { if (player.pickMode == PickMode.Mouse) PickUp(player.itemRoot); } } } ``` - 道具挂载脚本 - 创建Pick输入事件,绑定按键F - 修改`Assets\Scripts\StudyCase3` 下脚本 `ThirdCharacterController.cs` ```csharp using UnityEngine; using UnityEngine.InputSystem; namespace StudyCase3 { public enum PickMode { RayCast, Mouse } public class ThirdCharacterController : MonoBehaviour { [Header("MoveSettings")] CharacterController characterController; InputActionAsset inputAction; Animator animator; Transform forward; Transform model; Cinemachine.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 Transform itemRoot; Item selectItem; LineRenderer lineRenderer; private void Awake() { Cursor.lockState = cursorLock; characterController = GetComponent(); forward = transform.Find("Forward"); model = transform.Find("Model"); animator = model.GetComponentInChildren(); vCam = transform.Find("Virtual Camera").GetComponent(); inputAction = Resources.Load("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.Enable(); itemRoot = transform.Find("ItemRoot"); if (lineRenderer == null) { lineRenderer = gameObject.AddComponent(); lineRenderer.material = new Material(Shader.Find("Universal Render Pipeline/2D/Sprite-Unlit-Default")); lineRenderer.useWorldSpace = true; } } private void Update() { Move(); CheckRayHit(); ItemsRotate(); } public void OnMove(InputAction.CallbackContext context) { if (characterController.isGrounded) moveInput = context.ReadValue(); else moveInput = Vector2.zero; } public void OnJump(InputAction.CallbackContext context) { if (context.performed && characterController.isGrounded) { moveDir.y = jumpSpeed; } } 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(); 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 } } ``` - 玩家挂载脚本,创建ItemRoot节点,设置射线检测层级 ## 6.异闻录-FAQ