用unity写一个2D类的拼图游戏

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

前几天接了一个拼图项目刚好现在写完了,拿出来分享,拼图不难,我也是看了一个官方案例写的,因为当我们写图片跟随鼠标的时候,鼠标已经有一个图片了,这个图片会遮挡射线,然后就无法判断当前拼图块在哪里,话不多说,上菜

1、新建总控脚本LevelManager

public enum State
{
        None,
        mousedown,
        mousemove,
        mouseup,
}
public PuzzleDivision PuzzleDivision;
public State state;
private void Awake()
{
        ins = this;
        Random.InitState((int)System.DateTime.Now.Ticks);
}
void Start()
{
        state = State.None;
}

2、新建PuzzleDivision脚本,用于初始化拼图块的克隆和选区

public class PuzzleDivision : MonoBehaviour
{
    public int size = 3;
    public List<Grid1> grids = new List<Grid1>();
    public Grid gridPrefab;
    public Grid1 gridPrefab1;
public void Init(Transform tra)
    {
        for (int i = 1; i <= size; i++)
            {
            for (int j = 1; j <= size; j++)
            {
                if ((i - 1) * size + j > grids.Count)
                {
                    Grid1 grids2 = Instantiate(gridPrefab1, gridLayoutGroup.transform);
                    grids2.transform.name = "Start" + i;
                    grids2.id = i;
                    grids2.size = size;
                    grids.Add(grids2);
                    Grid grid = Instantiate(gridPrefab, tra);
                    LevelManager.ins.grids.Add(grid);
                }
                else
                {
                    grids[i].gameObject.SetActive(true);
                    LevelManager.ins.grids[i].gameObject.SetActive(true);
                }
                grids[(i - 1) * size + j - 1].SetInf(this, size, new Vector2(i, j), Texture2D);
                LevelManager.ins.grids[(i - 1) * size + j - 1].SetInf(this, size, new Vector2(i, j), Texture2D);
            }
        }
        if (grids.Count > size * size)
        {
            for (int i = size * size; i < grids.Count; i++)
            {
                grids[i].gameObject.SetActive(false);
            }
        }
        for (int i = 0; i < grids.Count; i++)
        {
            grids[i].transform.GetComponent<RawImage>().color = new Color32(255, 255, 255, 27);
        }
        if (LevelManager.ins.grids.Count > size * size)
        {
            for (int i = size * size; i < LevelManager.ins.grids.Count; i++)
            {
                LevelManager.ins.grids[i].gameObject.SetActive(false);
            }
        }
}
}

分割图片只有RawImage才能使用,所以这里用的是RawImage,并且注意Grid1是上半部分的图

Grid是下半部分,也就是可以互动的图,如图

用unity写一个2D类的拼图游戏

下面是Grid的脚本:

using UnityEngine;
using UnityEngine.UI;
using DG.Tweening;
using UnityEngine.EventSystems;
using System;

public class Grid: MonoBehaviour, IBeginDragHandler, IDragHandler, IEndDragHandler
{
    Action Action;
    private PuzzleDivision game;
    private RawImage image;
    private Image bj;
    public Vector3 movepos;
    public float rotesize;
    public int id;
    public int size;
    public bool cheng = false;
    Vector3 pos;
    private void Awake()
    {
        Input.multiTouchEnabled = false;
        image = GetComponent<RawImage>();
        bj = GetComponent<Image>();
    }
    /// <summary>
    /// 设置当前Grid的信息
    /// </summary>
    /// <param name="size">n*n</param>
    /// <param name="id">Grid的ID</param>
    public void SetInf(PuzzleDivision game, int size, Vector2 id, Texture2D sp)
    {
        image.texture = sp;
        this.game = game;
        float width = 1f / size;

        gameObject.name = $"Grid_{id.x}_{id.y}";
        image.uvRect = new Rect(
            (id.x - 1) * width,
            (id.y - 1) * width,
            width,
            width
        );
        switch (size)
        {
            case 3:
                transform.GetComponent<RectTransform>().sizeDelta = new Vector2(394, 395);
                break;
            case 4:
                transform.GetComponent<RectTransform>().sizeDelta = new Vector2(298, 299);
                break;
            default:
                break;
        }
    }
    public void OnBeginDrag(PointerEventData eventData)//开始拖拽
    {
        LevelManager.ins.name = transform.name;
        transform.GetComponent<CanvasGroup>().blocksRaycasts = false;
        eventData.pointerDrag.GetComponent<RectTransform>().transform.DORotate(new Vector3(0,0,0),0.01f);
        LevelManager.ins.state = LevelManager.State.mousedown;
    }

    public void OnDrag(PointerEventData eventData)//拖拽中
    {
        //throw new System.NotImplementedException();
        transform.position = Input.mousePosition;
        eventData.pointerDrag.transform.GetComponent<RawImage>().transform.SetAsLastSibling();
        LevelManager.ins.state = LevelManager.State.mousemove;
    }

    public void OnEndDrag(PointerEventData eventData)//停止拖拽
    {
        //throw new System.NotImplementedException();
        transform.GetComponent<CanvasGroup>().blocksRaycasts = true;
        Debug.Log(eventData?.pointerDrag.name);//当前物体
        //Debug.Log(eventData.pointerEnter.name);//鼠标抬起后的物体

        if (eventData.pointerEnter!=null)
        {
            if (eventData.pointerEnter.name == eventData.pointerDrag.name)
            {
                switch (size)
                {
                    case 3:
                        eventData.pointerDrag.transform.GetComponent<RectTransform>().sizeDelta = new Vector2(394, 395);
                        AudioManager.ins.audios(3);
                        break;
                    case 4:
                        eventData.pointerDrag.transform.GetComponent<RectTransform>().sizeDelta = new Vector2(298, 299);
                        AudioManager.ins.audios(3);
                        break;
                    default:
                        break;
                }
               
                pos = eventData.pointerEnter.transform.position;
                if (Input.GetMouseButtonUp(0))
                {
                    eventData.pointerDrag.transform.position = eventData.pointerEnter.transform.position;
                    if (Vector3.Distance(pos, transform.position) <= 0.01)
                    {
                        cheng = true;
                        transform.GetComponent<Grid>().enabled = false;
                        Debug.LogError("当前手指数量:" + Input.touchCount);
                    }
                }
                if (Input.touchCount<=1&&Input.touchCount>0)
                {
                    eventData.pointerDrag.transform.position = eventData.pointerEnter.transform.position;
                    if (Vector3.Distance(pos, transform.position) <= 0.01)
                    {
                        cheng = true;
                        transform.GetComponent<Grid>().enabled = false;
                        Debug.LogError("当前手指数量:"+Input.touchCount);
                    }
                }
                LevelManager.ins.sum += 1;
                
            }
            else
            {
                eventData?.pointerDrag.GetComponent<RectTransform>().transform.DOLocalMove(movepos, 0.25f);
                eventData?.pointerDrag.GetComponent<RectTransform>().transform.DORotate(new Vector3(0, 0, rotesize), 0.1f);
            }
        }
        LevelManager.ins.state = LevelManager.State.mouseup;
    }
    private void Update()
    {
        if (Input.touchCount>0)
        {
            if (Input.GetTouch(0).phase == TouchPhase.Ended)
            {
                LevelManager.ins.state = LevelManager.State.mouseup;
            }
        }
        Action = LevelManager.ins.state switch
        {
            LevelManager.State.None => new Action(Nonetest),
            LevelManager.State.mousedown => new Action(mousedowntest),
            LevelManager.State.mousemove => new Action(mousemovetest),
            LevelManager.State.mouseup => new Action(mouseuptest),
            _ => throw new ArgumentOutOfRangeException(nameof(LevelManager.state))
        };
        Action.Invoke();
    }
    void mouseuptest()
    {
        Debug.Log("输出鼠标抬起回调");
        if (!cheng)
        {
            transform.DOLocalMove(movepos, 0.25f);
        }
        LevelManager.ins.state = LevelManager.State.None;
    }
}

 因为是webGL的项目,面对的bug解决方案也不同,代码可能有点乱,大家将就看看,webGL不支持禁用多点触控,所以在这里用了比较复杂的判定,不然直接一句话的事,而且策划说在松手状态下,拼图块要回到原位,并且要旋转到原来的位置,我当时听到这个真是mmp了(小声bb一句,狗策划)

Grid中size是设置拼图分割的块数,输入3,就分割成3*3的,输入4就是4*4,输入多少都可以,你输入一百也没事(其实我也不知道有没有事)

SetInf()是分割方

OnBeginDrag()是开始拖拽方法,到这步有聪明的小明就要问了,那我这个拼图块也要占用射线,我应该怎么判定拼图块是否到对应的位置了呢,问的好,用transform.GetComponent<CanvasGroup>().blocksRaycasts = false;

解决,这个是用于禁用当前的射线交互的,简单点说,射线可以直接穿过当前拼图块,这样就可以用来检测了,这个是官方的做法,我记得哪个插件里有示例,我也是根据那个示例来的,这个:

UI Samples

用unity写一个2D类的拼图游戏

OnDrag()是拖拽中的方法

OnEndDrag()是停止拖拽的方法

我们是拼图游戏,所有图块都是在松手后判定,所以写在OnEndDrag()中的东西会多一点,在OnEndDrag()中可以写你自己的判定逻辑,当然,也可以在其他方法里写这个就不多赘述,Update()中主要是判定屏幕中是否有手指,至于这个switch则是C#的新语法糖

注意!switch语法糖有时候在unity中可能会报错,因为mono对C#的支持不太好,还没更新到最新的语法糖

Action = LevelManager.ins.state switch
        {
            LevelManager.State.None => new Action(Nonetest),
            LevelManager.State.mousedown => new Action(mousedowntest),
            LevelManager.State.mousemove => new Action(mousemovetest),
            LevelManager.State.mouseup => new Action(mouseuptest),
            _ => throw new ArgumentOutOfRangeException(nameof(LevelManager.state))
        };

至于mouseuptest()则是松手后拼图块的归位

Grid1脚本如下:

using DG.Tweening;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;

public class Grid1 : MonoBehaviour, IDropHandler, IPointerEnterHandler, IPointerExitHandler
{
    private PuzzleDivision game;
    private RawImage image;
    [SerializeField] Image bj;
    public int id;
    public int size;
    Tween tween;
    private void Awake()
    {
        image = GetComponent<RawImage>();
    }
    /// <summary>
    /// 设置当前Grid1的信息
    /// </summary>
    /// <param name="size">n*n</param>
    /// <param name="id">Grid��ID</param>
    public void SetInf(PuzzleDivision game, int size, Vector2 id,Texture2D sp)
    {
        image.texture = sp;
        this.game = game;
        float width = 1f / size;

        gameObject.name = $"Grid_{id.x}_{id.y}";
        image.uvRect = new Rect(
            (id.x - 1) * width,
            (id.y - 1) * width,
            width,
            width
        );
        switch (size)
        {
            case 3:
                bj.transform.GetComponent<RectTransform>().sizeDelta = new Vector2(394 - 10, 395 - 10);
                break;
            case 4:
                bj.transform.GetComponent<RectTransform>().sizeDelta = new Vector2(298 - 10, 299 - 10);
                break;
            default:
                break;
        }
    }
    private void Update()
    {
        switch (LevelManager.ins.state)
        {
            case LevelManager.State.None:
                HIde();
                break;
            case LevelManager.State.mousedown:
                break;
            case LevelManager.State.mousemove:
                break;
            case LevelManager.State.mouseup:
                break;
            default:
                break;
        }
    }
    public void Show()
    {
        bj.DOFade(1, 0.01f);
        //bj.gameObject.SetActive(true);
        tween = bj.DOFade(0, 0.25f).SetLoops(-1, LoopType.Yoyo);
        AudioManager.ins.audios(2);
    }
    public void HIde()
    {
        tween.Kill();
        bj.DOFade(1, 0.01f);
    }
    public void OnDrop(PointerEventData eventData)//鼠标抬起
    {
        Debug.Log("鼠标抬起");
        HIde();
    }

    public void OnPointerEnter(PointerEventData eventData)//鼠标移入
    {
        Debug.Log("鼠标移入");
        if (LevelManager.ins.state == LevelManager.State.mousemove)
        {
            Show();
        }
    }

    public void OnPointerExit(PointerEventData eventData)//鼠标移出
    {
        //throw new System.NotImplementedException();

        if (LevelManager.ins.state == LevelManager.State.mousemove)
        {
            HIde();
        }
        Debug.Log("鼠标移出");
    }
}

Grid1就简单多了,Grid1主要用于上半部分的对比图展示,所以要判定鼠标是否移入、移出这种,这里就不做赘述,我们接着往下走

将Grid1和Grid做成预设,面板上是这样的:

用unity写一个2D类的拼图游戏

 用unity写一个2D类的拼图游戏

 用unity写一个2D类的拼图游戏

我这个套了个Image,是因为策划说要增加虚线,表示当前拖拽状态,我也是无语了

下面给你们看看示例 文章来源地址https://www.toymoban.com/news/detail-480501.html

到了这里,关于用unity写一个2D类的拼图游戏的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

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

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

相关文章

  • 【用unity实现100个游戏之15】开发一个类保卫萝卜的Unity2D塔防游戏5(附项目源码,完结)

    本期是本项目的最后一篇,主要内容是配置环境、生成不同敌人、结束重开。 我用的环境素材 https://assetstore.unity.com/packages/2d/environments/2d-sugar-world-asset-pack-urp-256585

    2024年02月05日
    浏览(53)
  • Java 获取日期前一年、月、日,指定日期的前几天,后几天

    LocalDate转化为指定格式的字符串 方法1 方法2

    2024年02月12日
    浏览(50)
  • Unity2d游戏项目--小狐狸

    (一) 在文件夹中找到back图片,并在检查器面板中将back图片的每单位像素数设置为16。 (文件所在地) (面板设置) (二) 将图片拖入到场景中 (一) 生成矩形的瓦片地图 (二) 打开平铺调色板 (三) 新建并命名为map,在原目录新建一个文件夹,用于存放你在这个瓦

    2024年02月03日
    浏览(35)
  • 【unity】制作一个角色的初始状态(左右跳二段跳)【2D横板动作游戏】

            hi~ 大家好!欢迎大家来到我的全新unity学习记录系列。现在我想在2d横板游戏中,实现一个角色的初始状态-闲置状态、移动状态、空中状态。并且是利用 状态机 进行实现的。         本系列是跟着视频教程走的,所写也是作者个人的学习记录笔记。如有错误请联系

    2024年02月04日
    浏览(46)
  • 【实现100个unity游戏之20】制作一个2d开放世界游戏,TileMap+柏林噪声生成随机地图(附源码)

    我的上一篇文章介绍了TileMap的使用,主要是为我这篇做一个铺垫,看过上一篇文章的人,应该已经很好的理解TileMap的使用了,这里我就不需要过多的解释一些繁琐而基础的知识了,省去很多时间。所有没看过上一篇文章的小伙伴我强烈建议先去看看:

    2024年01月20日
    浏览(49)
  • Unity小游戏——迷你拼图

    拼图演示 资源:  链接:https://pan.baidu.com/s/1BGeSmRCO_WZRUyl3MxefGw  提取码:0n4a 排列拼图碎片,拼出最后的图案。可以点住碎片的任意位置拖动;点击\\\"重来\\\"按钮,可以回到最初状态重新开始。 有很多电脑游戏的原型来自于现实世界中的玩具,拼图游戏就是其中的一个代表。 本

    2024年02月14日
    浏览(43)
  • 用JavaScript做一个拼图游戏

    喜欢的可以复制下面完整代码查看效果在自己本地查看效果 实现难度:不算大,毕竟是小游戏 开发工具: html,css,js,jquery 新增严谨模式判定(2023.06.04) 非严谨判定:数字按顺序排即可 例:1,2,3,【空卡槽】,4,5,6,7,8 严谨判定:数字按顺序排,且空卡槽必须在最

    2024年02月07日
    浏览(40)
  • 【经典游戏】坦克大战 Unity2D项目实战(保姆级教程)

    主要内容: 1.Unity3D引擎中的基础设置。 2.2D场景的搭建,预制体制作。 3.2D动画的制作。 4.图片图集的有关知识。 5.碰撞器,触发器,碰撞检测与触发检测。 6.2D游戏渲染的一些知识。 7.敌人AI的编写。 8.UGUI有关内容,场景切换等。 所需资源包链接:https://pan.baidu.com/s/199wuwM

    2024年02月06日
    浏览(61)
  • Unity 新建你的第一个游戏,以及如何按WASD控制角色运动 (Unity Demo2D)

    当你打开 Unity Hub,初始化一个 2D 项目,进入了 Unity 编辑器,你会发现在 左侧 : 一个叫 SampleScene (或者其他) 的场景 场景下有一个 Main Camera,主相机 这就是一个新建的 2D 项目自带的内容。 在 Main Camera 同级目录新建: 2D Object - Sprites - Capsule ,这里 Capsule 是精灵的种类,我们

    2024年02月02日
    浏览(45)
  • 前几天面了个30岁的测试员,年薪50w问题基本都能回答上,应该刷了不少八股文···

    互联网行业竞争是一年比一年严峻,作为测试工程师的我们唯有不停地学习,不断的提升自己才能保证自己的核心竞争力从而拿到更好的薪水,进入心仪的企业(阿里、字节、美团、腾讯等大厂.....) 所以,大家就迎来了一堆问题: 自己目前的能力能不能够支撑自己晋升?如

    2024年02月05日
    浏览(37)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包