Unity 实战项目 ☀️| 只用一个脚本做一个 刮刮乐 案例,一不小心刮出来一个女朋友!【学习娱乐一下】

  • 博客主页:https://blog.csdn.net/zhangay1998
  • 欢迎点赞 收藏 ⭐留言 如有错误敬请指正!
  • 本文由 呆呆敲代码的小Y 原创,首发于 CSDN
  • 未来很长,值得我们全力奔赴更美好的生活✨

        • 前言
    • 只用一个脚本做一个刮刮乐,一不小心刮出来一个女朋友!
        • ️‍第一步:打开Unity,新建一个项目
        • ️‍第二步:新建一个Image图片和RawImage图片
        • ️‍第三步:调整相机和画布的模式
        • ️‍第四步:写一个脚本,并挂载到Canvas上
        • ️‍最后一步:找两张图片放到场景中!
      • 效果展示
    • 总结
        • 往期优质文章分享

Unity 实战项目 ☀️| 只用一个脚本做一个 刮刮乐 案例,一不小心刮出来一个女朋友!【学习娱乐一下】_第1张图片


前言

  • 前几天CSDN一个大哥:孤寒者 使用HTML做了一个刮刮乐,大家都挺喜欢看的!

  • 我也感觉挺好玩的,那就寻思用 Unity 肯定也能做呀! Unity 是一个容易上手的游戏引擎

  • 做出来之后可以直接打包出来给别的 小哥哥小姐姐 直接在手机上玩都行!!

  • 那就来简单说一下怎样实现这样一个刮刮乐的小案例吧,只需要一个脚本 就能完成~

  • 本文章会从一个新手的角度完整的将全过程都会写出来!老手直接看脚本挂上即可!

  • 如果之前没接触过 Unity 也没关系,这正是你入坑的一个机会!Unity免费学习专栏 Unity基础知识学习


只用一个脚本做一个刮刮乐,一不小心刮出来一个女朋友!


️‍第一步:打开Unity,新建一个项目

既然我们是用 Unity 完成这个小项目,第一步就来新建一个项目!

如果你连 Unity 引擎是什么都不知道的话,那真的有点落伍啦~

这里推荐一个免费的 Unity 学习专栏,包括 怎样下载安装 Unity 和 配置基础环境 !

以最简单的一个视角了解 什么是Unity Unity最基础知识学习

打开UnityHub新建一个项目,改一下项目名称路径,然后点击创建
Unity 实战项目 ☀️| 只用一个脚本做一个 刮刮乐 案例,一不小心刮出来一个女朋友!【学习娱乐一下】_第2张图片

创建完之后,就会显示出一个默认的Unity空场景,可能窗口显示的位置不太一样,自己可以随意调整,这个都不重要~
Unity 实战项目 ☀️| 只用一个脚本做一个 刮刮乐 案例,一不小心刮出来一个女朋友!【学习娱乐一下】_第3张图片


️‍第二步:新建一个Image图片和RawImage图片

Hierarchy面板上右键创建一个Image和一个RawImage

如下图所示,只需要明白这两个Image组件都是用来显示图片的组件就OK啦~ 想学习更多可以去专栏学习哦!
Unity 实战项目 ☀️| 只用一个脚本做一个 刮刮乐 案例,一不小心刮出来一个女朋友!【学习娱乐一下】_第4张图片
然后将这两个Image调整成跟Canvas一个大小!

先点击Image,选中之后,将图片调整成Canvas一个大小,按照下图所示快捷操作即可

也可以手动的将Image图片调整成跟Canvas一个大小!
Unity 实战项目 ☀️| 只用一个脚本做一个 刮刮乐 案例,一不小心刮出来一个女朋友!【学习娱乐一下】_第5张图片
ImageRawImage都一样设置一下,然后场景中变成下面这样!
Unity 实战项目 ☀️| 只用一个脚本做一个 刮刮乐 案例,一不小心刮出来一个女朋友!【学习娱乐一下】_第6张图片


️‍第三步:调整相机和画布的模式

先选中相机Camera,将相机的投影模式改成 正交,就是改一下这个Projection设置,如下图所示!
Unity 实战项目 ☀️| 只用一个脚本做一个 刮刮乐 案例,一不小心刮出来一个女朋友!【学习娱乐一下】_第7张图片
然后再选中Canvas画布,改成画布的第二种模式,如下所示:
Unity 实战项目 ☀️| 只用一个脚本做一个 刮刮乐 案例,一不小心刮出来一个女朋友!【学习娱乐一下】_第8张图片
Canvas画布概念如下:
Unity 实战项目 ☀️| 只用一个脚本做一个 刮刮乐 案例,一不小心刮出来一个女朋友!【学习娱乐一下】_第9张图片
然后还没完,还要将Canvas画布缩放模式改为第二种

按照屏幕大小缩放,把分辨率调成1920*1080,然后把相机Main Camera挂载到这个Canvas上面!

如下所示
Unity 实战项目 ☀️| 只用一个脚本做一个 刮刮乐 案例,一不小心刮出来一个女朋友!【学习娱乐一下】_第10张图片
Unity 实战项目 ☀️| 只用一个脚本做一个 刮刮乐 案例,一不小心刮出来一个女朋友!【学习娱乐一下】_第11张图片


️‍第四步:写一个脚本,并挂载到Canvas上

上面的几步都是为了将图片显示的时候更加美观到位 ,这一步才是这个刮刮乐最关键的一步!

新建一个C#脚本,然后将以下代码复制到脚本中即可
Unity 实战项目 ☀️| 只用一个脚本做一个 刮刮乐 案例,一不小心刮出来一个女朋友!【学习娱乐一下】_第12张图片

直接上代码

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

public class Demo: MonoBehaviour, IPointerDownHandler, IDragHandler, IPointerUpHandler
{
     
    //是否擦除了
    public bool isStartEraser;
    //是否擦除结束了
    public bool isEndEraser;
    //开始事件
    public Action eraserStartEvent;
    //结束事件
    public Action eraserEndEvent;
    public RawImage uiTex;
    Texture2D tex;
    Texture2D MyTex;
    int mWidth;
    int mHeight;
    [Header("笔刷大小")]
    public int brushSize = 50;
    [Header("刮刮乐比例")]
    public int rate = 90;
    float maxColorA;
    float colorA;
    void Awake()
    {
     
        tex = (Texture2D)uiTex.mainTexture;
        MyTex = new Texture2D(tex.width, tex.height, TextureFormat.ARGB32, false);
        mWidth = MyTex.width;
        mHeight = MyTex.height;
        MyTex.SetPixels(tex.GetPixels());
        MyTex.Apply();
        uiTex.texture = MyTex;
        maxColorA = MyTex.GetPixels().Length;
        colorA = 0;
        isEndEraser = false;
        isStartEraser = false;
    }
    /// 
    /// 贝塞尔平滑
    /// 
    /// 起点
    /// 中点
    /// 终点
    /// 段数
    /// 
    public Vector2[] Beizier(Vector2 start, Vector2 mid, Vector2 end, int segments)
    {
     
        float d = 1f / segments;
        Vector2[] points = new Vector2[segments - 1];
        for (int i = 0; i < points.Length; i++)
        {
     
            float t = d * (i + 1);
            points[i] = (1 - t) * (1 - t) * mid + 2 * t * (1 - t) * start + t * t * end;
        }
        List<Vector2> rps = new List<Vector2>();
        rps.Add(mid);
        rps.AddRange(points);
        rps.Add(end);
        return rps.ToArray();
    }
    bool startDraw = false;
    bool twoPoints = false;
    Vector2 lastPos;//最后一个点
    Vector2 penultPos;//倒数第二个点
    float radius = 12f;
    float distance = 1f;
    #region 事件
    public void OnPointerDown(PointerEventData eventData)
    {
     
        if (isEndEraser) {
      return; }
        startDraw = true;
        penultPos = eventData.position;
        CheckPoint(penultPos);
    }

    public void OnDrag(PointerEventData eventData)
    {
     
        if (isEndEraser) {
      return; }
        if (twoPoints && Vector2.Distance(eventData.position, lastPos) > distance)//如果两次记录的鼠标坐标距离大于一定的距离,开始记录鼠标的点
        {
     
            Vector2 pos = eventData.position;
            float dis = Vector2.Distance(lastPos, pos);

            CheckPoint(eventData.position);
            int segments = (int)(dis / radius);//计算出平滑的段数                                              
            segments = segments < 1 ? 1 : segments;
            if (segments >= 10) {
      segments = 10; }
            Vector2[] points = Beizier(penultPos, lastPos, pos, segments);//进行贝塞尔平滑
            for (int i = 0; i < points.Length; i++)
            {
     
                CheckPoint(points[i]);
            }
            lastPos = pos;
            if (points.Length > 2)
                penultPos = points[points.Length - 2];
        }
        else
        {
     
            twoPoints = true;
            lastPos = eventData.position;
        }
    }

    public void OnPointerUp(PointerEventData eventData)
    {
     
        if (isEndEraser) {
      return; }
        //CheckPoint(eventData.position);
        startDraw = false;
        twoPoints = false;
    }


    #endregion
    void CheckPoint(Vector3 pScreenPos)
    {
     
        Vector3 worldPos = Camera.main.ScreenToWorldPoint(pScreenPos);
        Vector3 localPos = uiTex.gameObject.transform.InverseTransformPoint(worldPos);

        if (localPos.x > -mWidth / 2 && localPos.x < mWidth / 2 && localPos.y > -mHeight / 2 && localPos.y < mHeight / 2)
        {
     
            for (int i = (int)localPos.x - brushSize; i < (int)localPos.x + brushSize; i++)
            {
     
                for (int j = (int)localPos.y - brushSize; j < (int)localPos.y + brushSize; j++)
                {
     
                    if (Mathf.Pow(i - localPos.x, 2) + Mathf.Pow(j - localPos.y, 2) > Mathf.Pow(brushSize, 2))
                        continue;
                    if (i < 0) {
      if (i < -mWidth / 2) {
      continue; } }
                    if (i > 0) {
      if (i > mWidth / 2) {
      continue; } }
                    if (j < 0) {
      if (j < -mHeight / 2) {
      continue; } }
                    if (j > 0) {
      if (j > mHeight / 2) {
      continue; } }

                    Color col = MyTex.GetPixel(i + (int)mWidth / 2, j + (int)mHeight / 2);
                    if (col.a != 0f)
                    {
     
                        col.a = 0.0f;
                        colorA++;
                        MyTex.SetPixel(i + (int)mWidth / 2, j + (int)mHeight / 2, col);
                    }
                }
            }
            //开始刮的时候 去判断进度
            if (!isStartEraser)
            {
     
                isStartEraser = true;
                InvokeRepeating("getTransparentPercent", 0f, 0.2f);
                if (eraserStartEvent != null)
                    eraserStartEvent.Invoke();
            }
            MyTex.Apply();
        }
    }
    double fate;
    ///  
    /// 检测当前刮刮卡 进度
    /// 
    /// 
    public void getTransparentPercent()
    {
     
        if (isEndEraser) {
      return; }
        fate = colorA / maxColorA * 100;
        fate = (float)Math.Round(fate, 2);
         Debug.Log("当前百分比: " + fate);
        if (fate >= rate)
        {
     
            isEndEraser = true;
            CancelInvoke("getTransparentPercent");
            uiTex.gameObject.SetActive(false);
            //触发结束事件
            if (eraserEndEvent != null)
                eraserEndEvent.Invoke();
        }
    }
}

代码中有注释,新手的话直接挂上即可,不需要管什么代码释义,毕竟编程的真谛就是“CV大法”哈哈哈哈嗝~

代码中使用一个贝塞尔平滑的方法可以让待会刮刮乐的时候更平滑一些,不至于出现撕裂齿轮等等现象!

然后利用鼠标按下后的两个点的点击距离,计算出平滑的段数然后使用贝塞尔平滑进行刮刮乐效果~

最后再写一个方法,对完成刮刮乐的一个进度来进行判断,当超过一定比例后显示整张图片!

将脚本挂到Canvas画布上,然后将RawImage拖到这个脚本中,RawImage就是我们刮刮乐上面的那层图片

刮完之后显示的图片用Image,然后简单设置一下笔刷的大小可以控制刮的时候的大小,效果如下:
Unity 实战项目 ☀️| 只用一个脚本做一个 刮刮乐 案例,一不小心刮出来一个女朋友!【学习娱乐一下】_第13张图片
然后就是。。找两张惊艳的图片用来当做刮刮乐的上层和下层图片进行展示吧~


️‍最后一步:找两张图片放到场景中!

这一步说是最简单的一步,其实也挺难的!

难的地方是:要找怎样的图片才能吸引到CSDN看到这篇博客的各位精英呢!

我这里实在是没什么超级惊艳的美图来展示,那就随便选两张吧~

然后点击场景中的Image RawImage ,分别将图片挂载上去即可!

如下所示

Unity 实战项目 ☀️| 只用一个脚本做一个 刮刮乐 案例,一不小心刮出来一个女朋友!【学习娱乐一下】_第14张图片
Unity 实战项目 ☀️| 只用一个脚本做一个 刮刮乐 案例,一不小心刮出来一个女朋友!【学习娱乐一下】_第15张图片


效果展示

然后运行 Unity 进行刮刮乐就好了!千万不要刮上瘾了哦!

注意成年人防沉迷模式!


原图奉上

刮刮乐上层图片:
Unity 实战项目 ☀️| 只用一个脚本做一个 刮刮乐 案例,一不小心刮出来一个女朋友!【学习娱乐一下】_第16张图片
刮刮乐下层图片:


总结

  • 本文到此就结束啦, 主要写了一个刮刮乐的案例
  • 因为是从一个新手角度出发,所以每个步骤都多说了一点,方便使用和学习
  • 如果你对这个案例挺感兴趣或者对Unity挺感兴趣,可以三连一波关注我的博客
  • 后面还会分享更多的实用好玩的案例学习和小游戏学习哦!
  • 如果你都看到这里了,真的可以自己尝试一下做一些小游戏玩,上手挺简单的!
  • 非常适合大学生宿舍无聊的时候做小游戏哦~

往期优质文章分享

  • ❤️Unity零基础到入门 | 游戏引擎 Unity 从0到1的 系统学习 路线【全面总结-建议收藏】!
  • 花一天时间做一个高质量飞机大战游戏,过万字Unity完整教程!漂亮学妹看了直呼666!
  • 回忆童年和小伙伴一起玩过的经典游戏【炸弹人小游戏】制作过程+解析
  • 通宵一晚做出来的一款类似CS的第一人称射击游戏Demo!原来做游戏也不是很难
  • 爆肝整整一个周末写一款类似 皇室战争 的 即时战斗类 游戏Demo!两万多字游戏制作过程+解析!
  • 一款类似“恐龙快打”的 横版街机格斗游戏 该如何制作?| 一起来学习 顺便送源码【码文不易,建议收藏学习】
  • 【超实用技巧】| 提高写文的质量 和 速率必学技能: Typora 图床配置 详细说明

优质专栏分享
  • 如果感觉文章看完了不过瘾,可以来我的其他 专栏 看一下哦~
  • 比如以下几个专栏:Unity基础知识学习专栏Unity游戏制作专栏Unity实战类项目 算法学习专栏
  • 可以学习更多的关于Unity引擎的相关内容哦!直接点击下面颜色字体就可以跳转啦!
Unity基础知识学习专栏
⭐️ Unity游戏制作专栏 ⭐️
Unity实战类项目
小Y学算法

你可能感兴趣的:(⭐️Unity实战项目⭐️,c#,Unity,刮刮乐,小游戏)