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

9.8 KiB
Raw Blame History

title, date, tags, pinned, head
title date tags pinned head
StudyCase3 2025-11-27 16:36:05
studycase
unity
true
meta
name content
description vitepress-theme-bluearchive StudyCase3
meta
name content
keywords vitepress theme bluearchive StudyCase3

物体拾取

1.世界构筑的起始篇章-编辑器

  • Unity 2022.3.62f2
  • Visual Studio 2022

2.光芒汇聚之所-章节目标

  • 射线检测拾取物体
  • 鼠标点击拾取物体

3.光流影卷-演示视频

4.初始祭坛-前置准备

导入资源(天空球,描边,道具模型)

5.勇者行迹录-章节任务

5.1 创建StudyCase3

  • 复制场景和脚本改名为StudyCase3
  • 修改控制器的命名空间

5.2 道具

  • 把导入的道具模型放到场景中
  • 新建道具层级
  • Assets\Scripts\StudyCase3下创建道具脚本Item.cs
using UnityEngine;

namespace StudyCase3
{
    public class Item : MonoBehaviour
    {
        Outline outline;
        bool pick;
        ThirdCharacterController player;
        private void Awake()
        {
            player = FindAnyObjectByType<ThirdCharacterController>();
            if (outline == null)
                outline = gameObject.AddComponent<Outline>();
            else
                outline = GetComponent<Outline>();
            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

5.3 Player脚本和设置

  • 修改Assets\Scripts\StudyCase3 下脚本 ThirdCharacterController.cs
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;
        [HideInInspector] public Transform itemRoot;
        Item selectItem;
        LineRenderer lineRenderer;
        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<Cinemachine.CinemachineVirtualCamera>();
            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.Enable();
            itemRoot = transform.Find("ItemRoot");
            if (lineRenderer == null)
            {
                lineRenderer = gameObject.AddComponent<LineRenderer>();
                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<Vector2>();
            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<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
    }
}
  • 玩家挂载脚本创建ItemRoot节点设置射线检测层级

6.异闻录-FAQ