返回

使用 Unity3D 创建一个幸运转盘

今天我们来做点和游戏无关的事情吧!博主最近情绪一直比较低落,因为在找工作的过程中遇到了些挫折。当一个人内心缺乏斗志的时候,通常会难以静下心来认真地做事情,所以这段时间博主并不打算再去为大家分享新的游戏案例,希望大家能够谅解啊。

好了,博主今天想和大家分享的是一个叫做幸运转盘的案例。我们知道平时在节假日商场为了促销商品,通常都会推出诸如转盘抽奖这样的游戏。在学了概率以后,虽然我们都知道中奖是一个小概率事件,可是人们对买彩票中奖这样的事情仍然乐此不疲。就像腾讯通过今年的春晚成功地为微信支付培养了大量忠实用户一样,虽然大家抢红包抢到的钱都不算多,可是大家都还是愿意去抢红包啊。为什么呢?呵呵,不就图一乐嘛。好了,那么下面我们一起乐一乐吧,因为激动人心的抽奖环节就要开始了!

首先我们来看看在 Unity3D 中如何实现转盘抽奖:

转盘游戏示意图
转盘游戏示意图

从这张图片我们可以看出,转盘抽奖有两部分组成:转盘是可以旋转的、转盘指针是固定不动的。那么,好了,抽奖无非就是让转盘转起来然后再停下来嘛,直接给出代码:

 1using UnityEngine;
 2using System.Collections;
 3
 4public class LuckyRoll : MonoBehaviour {
 5
 6    //幸运转盘
 7    private Transform mRoolPanel;
 8
 9    //初始旋转速度
10    private float mInitSpeed;
11    //速度变化值
12    private float mDelta=0.5f;
13
14    //转盘是否暂停
15    private bool isPause=true;
16
17    void Start () 
18    {
19        //获取转盘
20        mRoolPanel = this.transform.FindChild("Background");
21    }
22
23    //开始抽奖
24    public void OnClick()
25    {
26        if (isPause)
27        {
28            //随机生成一个初始速度
29            mInitSpeed=Random.Range(100,500);
30            //开始旋转
31            isPause = false;
32        }
33    }
34
35    void Update()
36    {
37        if(!isPause)
38        {
39
40            //转动转盘(-1为顺时针,1为逆时针)
41            mRoolPanel.Rotate(new Vector3(0,0,-1) * mInitSpeed * Time.deltaTime);
42            //让转动的速度缓缓降低
43            mInitSpeed -= mDelta;
44            //当转动的速度为0时转盘停止转动
45            if (mInitSpeed <= 0)
46            {
47                //转动停止
48                isPause = true;
49            }
50        }
51    }
52}

这里我们随机给出一个速度 mInitSpeed,然后让它按照 mDelta 的速率缓慢的减少,当 mInitSpeed 的数值为 0 时表示转盘停止转动。好了,我们来看看最后的效果:

转盘游戏演示
转盘游戏演示

从现在的效果来看,这个案例基本上成功了,所以以后如果碰到需要这种抽奖活动的场合,大家就可以跟美术协调好,快速地制作出这样一个幸运转盘来向身边的人们炫耀了。不过这个案例同样存在问题:

  • 基于随机数的转盘转动不受玩家控制,玩家无法参与到互动当中,可以考虑触摸操作,这样可以根据玩家的操作来模拟转动,提高游戏的真实性和可玩性。
  • 因为抽奖的结果是由美术设计在转盘上的,所以程序无法根据转盘停止后指针的位置直接判断出玩家抽奖的结果以及本次抽奖是否为有效的抽奖(指针恰好停留在两个扇形区域的分界线上)。
  • 因为这里转盘的旋转并没有严格地按照实际情况下转盘的受力情况来设计,因此可以说这个游戏中的概率分布可能不是均匀的,因此计算机里使用的随机数是伪随机数。

好了,暂时就发现这些问题,如果有朋友知道如何模拟触屏操作和阻尼运动,可以在这篇文章后面给我留言,今天的内容就是这样了,希望大家会喜欢!

2015 年 3 月 31 日更新

今天找到了关于转盘游戏概率设计的相关内容,所以经过整理后补充在这里:

首先,这种转盘游戏概率设计的前提是转盘固定不动,转盘指针绕中心位置旋转,与这篇文章中的恰好相反。如下图所示,在这个转盘游戏的设计中主要遵循基本的三角函数,这里以指针默认位置朝上来讲解该原理。如果指针的默认位置在其它位置上的,可以此类推。

转盘游戏示意图
转盘游戏示意图

x += xcosᶱ y += ycosᶱ

好了,现在我们就可以通过调整指针的角度来实现抽奖游戏了。比如我们将转盘平均分成 8 份,指针角度为 0 表示奖品 A,指针角度为 45 度表示奖品 B 等等,以此类推。这样的话,我们只要调整指针的角度就可以控制抽奖的结果。可是在实际生活中,指针不可能一次就指到对应的奖品上去,通常会在旋转若干圈后慢慢地停下来。因此我们可以使用下列公式:

指针角度 = 360 * 圈数 + (目标角度与初始角度的差值)

这里的圈数可以通过随机数来生成,这样可以让每次抽奖更加随机些,当然为了增加抽奖的真实感,我们可以采用这篇文章中提到的减速的方法来实现一个缓停的效果。那么问题来了,如果转盘上的奖项不是均匀分布的怎么呢?这种情况可以根据转盘上圆心角的大小为每一个奖项设定一个范围,然后在这个范围内随机生成一个角度来计算指针的角度,好了,下面给出代码实现:

 1using UnityEngine;
 2using System.Collections;
 3using System.Collections.Generic;
 4
 5public class LuckyRoll2 : MonoBehaviour {
 6
 7    //对奖项进行封装
 8    private class WrapItem
 9    {
10        public WrapItem(string name, float rank, float ang1, float ang2)
11        {
12            this.ItemName = name;
13            this.ItemRank = rank;
14            this.MinAngle = ang1;
15            this.MaxAngle  =ang2;
16        }
17
18        //奖项名称
19        public string ItemName { get; set; }
20        //奖项概率
21        public float ItemRank { get; set; }
22        //最大角度
23        public float MaxAngle { get; set; }
24        //最小角度
25        public float MinAngle { get; set; }
26    }
27
28    
29    //全部的奖项
30    private List<WrapItem> allItems;
31    void Start () 
32    {
33        //初始化奖品
34        allItems = new List<WrapItem>()
35        {
36           //圆心角为5°,概率为10%,以此类推
37            new WrapItem("奖品1", 10, 0, 30),
38            new WrapItem("奖品2", 15, 30, 90),
39            new WrapItem("奖品3", 20, 90, 165),
40            new WrapItem("奖品4", 25, 165, 255),
41            new WrapItem("奖品5", 30, 255, 360),
42        };
43
44        //模拟抽奖10次
45        for (int i = 0; i < 10; i++ )
46        {
47            Debug.Log(Roll());
48        }
49    }
50    
51    /// <summary>
52    /// 抽奖方法
53    /// </summary>
54    private string Roll()
55    {
56       //抽奖结果
57       string result = "";
58       //概率总精度为100
59       float totalRank = 100;
60       foreach(WrapItem item in allItems)
61       {
62          //产生一个0到100之间的随机数
63          float random  = Random.Range(0,totalRank);
64          //将该随机数和奖品的概率比较
65          if(random <= item.ItemRank)
66          {
67             //抽奖结果
68             result = item.ItemName;
69             //为转盘指针随机生成旋转角度
70             float angle = Random.Range(item.MinAngle, item.MaxAngle);
71             //旋转转盘指针,此处略
72             break;
73          }else
74          {
75             totalRank -= item.ItemRank;
76          }
77       }
78       return "抽奖结果为:" + result;
79    }
80}

好了,这里我们没有写转盘旋转的功能,这部分内容大家自己去实现好了,因为在 Unity3D 里面实现这样一个功能实在是太简单了。今天我们主要关注的内容是概率,所以我们重点对概率做了些研究,这里我们来讨论下算法中的概率计算问题,首先奖品 1、奖品 2、奖品 2、奖品 4、奖品 5 的概率分别为 10%、15%、20%、25%、30%,其概率之和为 100。因此

奖品 1:从 0~100 中随机抽取一个数,这个数值小于 10 的概率显然是 10%,这是第一轮数组遍历。

奖品 2:在第一轮数组遍历没有返回的情况下,进入第二轮遍历,此时从 0~90 中随机抽取一个数,其概率为:(1 - (10 / 100) * (15 / (100 - 10)) = 15%。同样的,抽到奖品 3 的概率为(1 - (25 / 100))*(20 / (100 - 25)) = 20%,以此类推。

好了,这部分内容终于补充到这篇文章里了,对于这个问题的研究基本上可以告一段落,不得不说概率对于游戏开发来说还是蛮重要的啊,有时间学习下数学吧,反正咱底子不弱啊,哈哈。

下面给出程序演示效果:

转盘游戏概率设计效果演示
转盘游戏概率设计效果演示

参考资料

大家快来玩转盘抽奖游戏(走在网页游戏开发的路上)(七) PHP + jQuery 实现转盘抽奖概率可任意调整

Built with Hugo
Theme Stack designed by Jimmy