Unity simplemente realiza el juego del cubo de Rubik de tercer orden

Unity simplemente realiza el juego del cubo de Rubik de tercer orden

Dirección de la experiencia del cubo de Rubik.

Descarga gratuita de documentos de ingeniería.

Ideas de implementación

1. La rotación del cubo de Rubik

El cubo de Rubik de tercer orden consta de 26 cuadrados y 9 ejes de rotación. Cuando el eje de rotación gira, gira los bloques dentro de su rango de control.

¿Cómo impulsa el eje de rotación al bloque para que gire?

Configure los bloques dentro del rango de control del eje de rotación como subobjetos del eje de rotación, y cuando el eje de rotación gire, los subobjetos rotarán.

¿Cómo obtener los cuadrados dentro del rango de control del eje de rotación?

Aquí se usa un método API Collider.bounds.Intersects proporcionado por unity , ya sea que otro cuadro delimitador se superponga con el cuadro delimitador. Eso es agregar un Colisionador para cada bloque y eje de rotación, para juzgar si el bloque está dentro del rango de control del eje de rotación.

inserte la descripción de la imagen aquí

Agregar colisionador al bloque

inserte la descripción de la imagen aquí

Agregar colisionador al eje de rotación

2. Control del cubo de Rubik

Use el mouse para arrastrar el Cubo de Rubik para rotar como se muestra a continuación

Determinación del eje de rotación

ley definida

  1. La dirección de rotación de cada eje de rotación es fija;
  2. Cada bloque está controlado por tres ejes de rotación.
Determinación del eje de rotación

Use el mouse para hacer clic en los dos puntos del cubo de Rubik, es decir, el punto de clic del mouse y el punto de elevación del mouse, como base para el juicio. La normal de la superficie formada por los dos puntos y el punto central es la normal de rotación del eje de rotación.

Como se muestra en la figura, el punto A es el primer punto en el que se hizo clic, el punto B es el segundo punto en el que se hizo clic y el punto O es el origen.

La normal de la superficie compuesta por OAB es la normal de rotación del eje de rotación.

Determinación del sentido de giro

Multiplique en cruz OA como se muestra arriba ⃗ \vec{OA}O A × \veces× OB ⃗ \vec{OB}transmisión exterior Si la normal obtenida es positiva, girará hacia adelante, y si es negativa, girará hacia atrás.

   public void ToRotate(List<AxisControl> axisControls)
    {
        Vector3 vector =Vector3.Normalize( Vector3.Cross(FirstPoint - transform.position, SecondPoint - transform.position));//向量叉乘
        int length = axisControls.Count;
        for (int i = 0; i < length; i++)
        {
            if (axisControls[i].rotationFront.ToString() == ReturnRotate(vector))
            {
                axisControls[i].ToRotate(front);
                break;
            }
        }
    }
    int front = 1;
    string ReturnRotate( Vector3 vector)
    {

        float nx = Mathf.Abs(vector.x);
        float ny = Mathf.Abs(vector.y);
        float nz = Mathf.Abs(vector.z);

        if (nx> ny&& nx> nz)
        {
            vector.x = vector.x > 0 ? front = 1 : front = -1;
            return "X";
        }
        else if (ny > nx && ny > nz)
        {
            vector.y = vector.y > 0 ? front = 1 : front = -1;
            return "Y";
        }
      else  
        {
            vector.z = vector.z > 0 ? front = 1 : front = -1;
            return "Z";
        }
    }

código completo

El script de control del bloque (adjunto a cada bloque)

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;

public class CubeControl : MonoBehaviour
{
  public   List<AxisControl> AxisControls;
    private Collider _collider;

    public Collider Collider
    {
        get
        {
            if (_collider == null)
            {
                _collider = gameObject.GetComponent<Collider>();
            }
            return _collider;
        }
    }
    RubikManager rubikManager;

    public RubikManager RubikManager
    {
        get
        {
            if (rubikManager == null)
            {
                rubikManager = RubikManager.Instance;
            }
            return rubikManager;
        }
    }

  
    // Start is called before the first frame update
    void Start()
    {
        AddEventTrigger();
    }

    public void AddEventTrigger()
    {
        gameObject.AddComponent<EventTrigger>();
        addEventTrigger(transform, EventTriggerType.PointerUp, UpCude);
        addEventTrigger(transform, EventTriggerType.PointerDown, DownCude);
    }
    /// <summary>
    /// event事件绑定的方法
    /// </summary>
    /// <param name="insObject">事件物体</param>
    /// <param name="eventType">事件类型</param>
    /// <param name="myFunction">事件需要的回调方法</param>
    public void addEventTrigger(Transform insObject, EventTriggerType eventType, UnityEngine.Events.UnityAction<BaseEventData> myFunction)//泛型委托
    {
        EventTrigger trigger = insObject.GetComponent<EventTrigger>();
        EventTrigger.Entry entry = new EventTrigger.Entry();
        entry.eventID = eventType;
        entry.callback.AddListener(myFunction);
        trigger.triggers.Add(entry);
    }
   
    void DownCude(BaseEventData data)
    {
        if (Input.GetMouseButtonDown(0))
        {
            RubikManager.FirstPoint = RayPiont();
        }
    }
    Vector3 front = Vector3.zero;
    void UpCude(BaseEventData data)
    {
        if (!RubikManager.isOperation&& Input.GetMouseButtonUp(0))
        {
      
        Vector3 rayPiont = RayPiont();
        RubikManager.SecondPoint = rayPiont;
        List<AxisControl> axisControls = new List<AxisControl>();
        int length = AxisControls.Count;
         
                RubikManager.ToRotate(AxisControls);
                RubikManager.isOperation = true;
        }
    }

    Vector3 RayPiont()
    {
        Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
        RaycastHit raycastHit;
        if (Physics.Raycast(ray,out raycastHit))
        {
            return raycastHit.point;
        }
        else
        {
            return Vector3.zero;
        }
    }
    public void SetParent(Transform transformSelf)
    {
        transform.parent = transformSelf;
    }
}

El método de control del eje de rotación (ligado al eje de rotación)

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using FrameWorkSong;


public class AxisControl : MonoBehaviourSimplify
{
    public enum RotationFront
    {
        X, Y,Z
    }
    public List<CubeControl> Cubes;
    public RotationFront rotationFront;
     Collider _collider;
    RubikManager rubikManager;
    Vector3 vector = Vector3.zero;
    public RubikManager RubikManager
    {
        get
        {
            if (rubikManager==null)
            {
                rubikManager = RubikManager.Instance;
            }
            return rubikManager;
        }
    }

    public Collider Collider
    {
        get
        {
            if (_collider==null)
            {
                _collider = gameObject.GetComponent<Collider>();
            }
            return _collider;
        } }


    // Start is called before the first frame update
    void Start()
    {
        Delay(1, () => { FindSelfCube(); });
        vector = transform.eulerAngles;
    }

    public void FindSelfCube()
    {
        Cubes = new List<CubeControl>() ;
        List<CubeControl> allCubeControls = RubikManager.CubeControls;
        int length = allCubeControls.Count;
        for (int i = 0; i < length; i++)
        {
            if (Collider.bounds.Intersects(allCubeControls[i].Collider.bounds))//得到旋转轴控制范围内的方块
            {
                Cubes.Add(allCubeControls[i]);
                allCubeControls[i].AxisControls.Add(this);
            }
        }
    }

    public override void OnBeforeDestroy()
    {
        
    }
    public void ToRotate(int front)
    {
        int length = Cubes.Count;
        for (int i = 0; i < length; i++)
        {
            Cubes[i].SetParent(transform);
        }
       
        if (rotationFront== RotationFront.X)
        {
             vector += (front* new Vector3(90, 0, 0));
            if (vector.x>=360)
            {
                vector = Vector3.zero;
            }
         
           
        }
        if (rotationFront == RotationFront.Y)
        {
            vector += (front * new Vector3(0, 90, 0));
            if (vector.y>= 360)
            {
                vector = Vector3.zero;
            }

        }
        if (rotationFront == RotationFront.Z)
        {
            vector += (front * new Vector3(0, 0, 90));
            if (vector.z >= 360)
            {
                vector = Vector3.zero;
            }
        }
        DoRotate(transform, vector, 0.5f,()=> { RubikManager.Reset(); });
    }
}

Maestro del cubo de Rubik

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using FrameWorkSong;
using System;

public class RubikManager : Singleton<RubikManager>
{
    public List<AxisControl> AxisControls;
    public List<CubeControl> CubeControls;


    public Vector3 FirstPoint;
    public Vector3 SecondPoint;

    public override void OnBeforeDestroy() { }
    public bool isOperation = false;

    // Start is called before the first frame update
    void Start()
    {
        GameObject[] AllCubes = GameObject.FindGameObjectsWithTag("Cube");

        int cubeLength = AllCubes.Length;
        for (int i = 0; i < cubeLength; i++)
        {
            CubeControls.Add(AllCubes[i].GetComponent<CubeControl>());
        }

        GameObject[] AllAxis = GameObject.FindGameObjectsWithTag("Axis");
        int axisLength = AllAxis.Length;
        for (int j = 0; j < axisLength; j++)
        {
            AxisControls.Add(AllAxis[j].GetComponent<AxisControl>());
        }
    }
   public void ToRotate(List<AxisControl> axisControls)
    {
        Vector3 vector =Vector3.Normalize( Vector3.Cross(FirstPoint - transform.position, SecondPoint - transform.position));
        int length = axisControls.Count;
        for (int i = 0; i < length; i++)
        {
            if (axisControls[i].rotationFront.ToString() == ReturnRotate(vector))
            {
                axisControls[i].ToRotate(front);
                break;
            }
        }
    }
    int front = 1;
    string ReturnRotate( Vector3 vector)
    {

        float nx = Mathf.Abs(vector.x);
        float ny = Mathf.Abs(vector.y);
        float nz = Mathf.Abs(vector.z);

        if (nx> ny&& nx> nz)
        {
            vector.x = vector.x > 0 ? front = 1 : front = -1;
            return "X";
        }
        else if (ny > nx && ny > nz)
        {
            vector.y = vector.y > 0 ? front = 1 : front = -1;
            return "Y";
        }
      else  
        {
            vector.z = vector.z > 0 ? front = 1 : front = -1;
            return "Z";
        }
    }
    //重置
    public void Reset()
    {
        int Count = CubeControls.Count;
        for (int j = 0; j < Count; j++)
        {
            CubeControls[j].AxisControls.Clear();
        }
        int length = AxisControls.Count;
        for (int i = 0; i < length; i++)
        {
            AxisControls[i].FindSelfCube();
        }
        isOperation = false;
    }
}

único

using UnityEngine;
namespace FrameWorkSong
{

    public abstract class Singleton <T>: MonoBehaviourSimplify where T:Singleton<T>
    {
        protected static T mInstance=null;
        public static T Instance
        {
            get
            {
                if (mInstance == null)
                {
                    mInstance = FindObjectOfType<T>();
                    if (mInstance==null)
                    {
                        var instanceName = typeof(T).Name;
                        var instanceObj = GameObject.Find(instanceName);
                        if (!instanceObj)
                        {
                            instanceObj= new GameObject(instanceName);
                        }
                        mInstance = instanceObj.AddComponent<T>();
                        DontDestroyOnLoad(instanceObj);
                        Debug.LogFormat("创建新的{0}单例实体", instanceName);
                    }
                    else
                    {
                        Debug.LogFormat("已经有单例实体");
                    }
                }
                return mInstance;
            }
        }
        protected virtual void onDestroy()
        {
            mInstance = null;
        }
    }
}

Función de retardo

using System;
using System.Collections;
using UnityEngine;
namespace FrameWorkSong
{
    public partial class MonoBehaviourSimplify : MonoBehaviour
    {
        /// <summary>
        /// 清理缓存
        /// </summary>
        protected void ReleaseMemory()
        {
            Resources.UnloadUnusedAssets();
            GC.Collect();
        }
        protected string GetNowTime()
        {
            return DateTime.Now.ToString("yyyy-MM-dd hh:mm:ss");
        }
        /// <summary>
        /// 延时功能
        /// </summary>
        /// <param name="seconds">延迟时间</param>
        /// <param name="onFinished">调用方法</param>
        public void Delay(float seconds, Action onFinished)
        {
            StartCoroutine(DelayCoroutione(seconds, onFinished));
        }
        private IEnumerator DelayCoroutione(float seconds, Action onFinished)
        {
            yield return new WaitForSeconds(seconds);
            onFinished();
        }
    }
}

método de rotación

using System;
using System.Collections;
using UnityEngine;
namespace FrameWorkSong
{
    public partial class MonoBehaviourSimplify
    {
/// <summary>
        /// 旋转
        /// </summary>
        /// <param name="transformSelf"></param>
        /// <param name="target"></param>
        /// <param name="time"></param>
        /// <param name="id"></param>
        /// <param name="action"></param>
        public void DoRotate(Transform transformSelf, Quaternion target, float time, Action action = null, string id = null)
        {
            IEnumerator coroutine;
            coroutine = DoRotateIE(transformSelf, target, time, action);
            StartCoroutine(coroutine);
            if (id != null)
            {
                keyValueCoroutine.AddData(id, coroutine);
            }
        }
        public void DoRotate(Transform transformSelf, Vector3 target, float time, Action action = null, string id = null)
        {
            
            DoRotate(transformSelf, Quaternion.Euler(target), time, action, id);
        }
        IEnumerator DoRotateIE(Transform transformSelf, Quaternion targetQua, float time, Action action = null)
        {
            Quaternion formQua = transformSelf.rotation;
            float t = 0;
            while (t < 1)
            {
                t += Time.deltaTime / time;
                t = t > 1 ? 1 : t;
                transform.rotation = Quaternion.Lerp(formQua, targetQua, t);
                yield return null;
            }
            transform.rotation = targetQua;
            if (action != null)
            {
                action();
            }
        }
    }
}

Supongo que te gusta

Origin blog.csdn.net/dxs1990/article/details/128551273
Recomendado
Clasificación