unity 简单实现三阶魔方游戏

这篇具有很好参考价值的文章主要介绍了unity 简单实现三阶魔方游戏。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

unity 简单实现三阶魔方游戏

魔方体验地址

工程文件免费下载

实现思路

一、魔方的旋转

三阶魔方由26个方块与 9个旋转轴组成。旋转轴旋转时带动在其控制范围的方块旋转。

旋转轴如何带动方块旋转?

把旋转轴控制范围内的方块设置成旋转轴的子物体,旋转轴旋转时便会带动子物体旋转。

如何得到旋转轴控制范围内的方块?

这里运用的unity提供的一个API方法Collider.bounds.Intersects,另一个包围盒是否与该包围盒交叠。即为每一个方块和旋转轴添加Collider,从而判断方块是否为旋转轴控制范围内的方块。

unity 魔方,Unity,unity,游戏,游戏引擎

方块添加Collider

unity 魔方,Unity,unity,游戏,游戏引擎

旋转轴添加Collider
二、魔方的控制

使用鼠标拖拽魔方旋转如下图

unity 魔方,Unity,unity,游戏,游戏引擎

旋转轴的确定

确定的规律

  1. 每一个旋转轴的旋转方向是固定的;
  2. 每一个方块都有三个旋转轴控制。
旋转轴的确定

用鼠标点击魔方的两个点,即鼠标点击点和鼠标抬起点,来做判断依据。两点与中心点组成的面的法线即是旋转轴的旋转法线。

unity 魔方,Unity,unity,游戏,游戏引擎

如图,A点是点击的第一个点,B点是点击的第二个点,O点是原点。

OAB组成的面就是的法线就是 旋转轴的旋转法线。

旋转方向的确定

如上图叉乘 O A ⃗ \vec{OA} OA × \times × O B ⃗ \vec{OB} OB 得到法线如果是正值正向旋转,为负值逆向旋转。

   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";
        }
    }

完整代码

方块的控制脚本(绑到每个方块上)

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;
    }
}

旋转轴的控制方法(绑在旋转轴上)

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(); });
    }
}

魔方的总控

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;
    }
}

单例

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;
        }
    }
}

延时功能

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();
        }
    }
}

旋转方法文章来源地址https://www.toymoban.com/news/detail-663482.html

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();
            }
        }
    }
}

到了这里,关于unity 简单实现三阶魔方游戏的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Unity 游戏开发、01 基础知识大全、简单功能脚本实现

    Unity默认窗口布局 Hierarchy 层级窗口 Scene 场景窗口,3D视图窗口 Game 游戏播放窗口 Inspector 检查器窗口,属性窗口 Project 项目窗口 Console 控制台窗口 恢复默认布局 Window | Layouts | Default 调大页面字体 Preference | UI Scaling 新项目默认创建了 SampleScene 场景 {摄像机,平行光} SampleScen

    2024年02月09日
    浏览(52)
  • Unity 游戏开发、01 基础篇 | 知识大全、简单功能脚本实现

    Unity默认窗口布局 Hierarchy 层级窗口 Scene 场景窗口,3D视图窗口 Game 游戏播放窗口 Inspector 检查器窗口,属性窗口 Project 项目窗口 Console 控制台窗口 恢复默认布局 Window | Layouts | Default 调大页面字体 Preference | UI Scaling 新项目默认创建了 SampleScene 场景 {摄像机,平行光} SampleScen

    2024年02月09日
    浏览(45)
  • 【制作100个unity实战之2】实现一款简单的FPS游戏

    实现一款FPS游戏需要以下步骤: 1.创建场景:在Unity中创建3D场景,设定地形、灯光、天气等环境,新增角色、武器等道具。 2.角色控制:创建角色,并添加Unity内置的角色控制器或自定义控制器脚本,处理角色的移动、射击、跳跃、动作等。 3.武器系统:创建武器模型,添加

    2024年02月04日
    浏览(46)
  • 十八、Unity游戏引擎入门

    1、下载     首先需要下载Unity Hub,下载网址:https://unity.com/cn。     然后在其中下载Unity编辑器并安装,可选择最新版本。     接着需要选择适合的开发环境,例如Android Studio或Xcode,以便进行手机游戏开发。在安装完Unity后,需要根据项目需求下载对应的模块和插件,例

    2024年02月16日
    浏览(51)
  • 使用团结引擎开发Unity 3D射击游戏

           本案例是初级案例,意在引导想使用unity的初级开发者能较快的入门,体验unity开发的方便性和简易性能。       本次我们将使用团结引擎进行开发,帮助想体验团结引擎的入门开发者进行较快的环境熟悉。      本游戏是一个俯视角度的射击游戏。主角始终位于屏幕

    2024年01月19日
    浏览(52)
  • Unity、UE、Cocos游戏开发引擎的区别

    Unity、Unreal Engine(UE)和Cocos引擎是三个常用的游戏开发引擎,它们在功能和特性上有一些区别。以下是它们之间的主要区别: 编程语言:Unity使用C#作为主要的编程语言,开发者可以使用C#脚本进行游戏逻辑编写。Unreal Engine主要使用C++作为编程语言,但也支持蓝图系统,允许

    2024年02月22日
    浏览(47)
  • Unity vs Godot :哪个游戏引擎更适合你?

    游戏引擎的选择对开发过程和最终产品质量有着重大影响。近年来,Godot和Unity这两款引擎受到广泛关注。本文将从多个维度对两者进行比较,以期为开发者提供正确的选择建议。 Godot和Unity都有各自的优势,没有绝对的好坏之分。Godot开源免费,上手简单,更适合2D和小型游戏

    2024年01月23日
    浏览(74)
  • 30分钟了解所有引擎组件,132个Unity 游戏引擎组件速通!【收藏 == 学会】

    🎬 博客主页:https://xiaoy.blog.csdn.net 🎥 本文由 呆呆敲代码的小Y 原创,首发于 CSDN 🙉 🎄 学习专栏推荐:Unity系统学习专栏 🌲 游戏制作专栏推荐:游戏制作 🌲Unity实战100例专栏推荐:Unity 实战100例 教程 🏅 欢迎点赞 👍 收藏 ⭐留言 📝 如有错误敬请指正! 📆 未来很长

    2024年02月11日
    浏览(52)
  • Unity Physics2D 2d物理引擎游戏 笔记

    2d 材质 里面可以设置 摩擦力 和 弹力 Simulated:是否在当前的物理环境中模拟,取消勾选该框类似于Disable Rigidbody,但使用这个参数更加高效,因为Disable会销毁内部产生的GameObject,而取消勾选Simulated只是禁用。 Kinematic 动力学刚体 动力学刚体不受重力和力的影响,而受用户的

    2023年04月24日
    浏览(102)
  • Unity和UE4两大游戏引擎,你该如何选择?

    目录 游戏引擎 2 —— 难易区别 编程语言 3 —— 游戏产品 UE4制作的游戏产品  Unity制作的游戏产品  产品类型 5 —— 资源商店 6 —— 人才需求 平均薪资 总结      Unity和UE4都是游戏引擎,所谓游戏引擎就是集成了复杂功能的游戏开发软件,他们帮我们实现了复杂的底层逻

    2023年04月08日
    浏览(53)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包