小程序实战-幸运大转盘

我是乔帮主 2018-01-03 17:28:35 ⋅ 713 阅读

前言

最近小程序的游戏挺火的,本节呢就用小程序做一个简单的大转盘

效果图

设计思路

  • 大转盘转动,指针不动

  • 要在小程序里面新建一个画布,并且铺满屏幕

  • 画两个圆,一个绘制大转盘,一个绘制指针

  • 获取用户点击的坐标,看是否点击到了指针

  • 随机一个奖励,真正业务中应该是后端随机一个结果告诉前端

  • 计算奖励的角度

  • 旋转大转盘

  • 计算角度减速大转盘

  • 旋转完回调函数处理


完整代码

pages/main/main.js


const utils = require('utils.js');const Animation = require('Animation.js');const Circle = require('Circle.js');
Page({  /**   * 页面的初始数据   */
  data: {    wheelImg: 'assets/wheel.png',    pointImg: 'assets/point.png',    touch: { x: 0, y: 0, isPressed: false }
  },  touchMove: function (event) {

  },  canvasTouchStart: function (event) {    var touch = event.changedTouches[0];
    touch.isPressed = true;    this.setData({      touch: touch
    })
  },  canvasTouchEnd: function (event) {    var touch = event.changedTouches[0];
    touch.isPressed = false;    this.setData({      touch: touch
    })
  },  /**   * 生命周期函数--监听页面加载   */
  onLoad: function (options) {    var that = this;    // 把设备的尺寸赋值给画布,以做到全屏效果
    wx.getSystemInfo({      success: function (res) {
        that.setData({          windowWidth: res.windowWidth,          windowHeight: res.windowHeight
        });
      },
    })
  },  /**   * 生命周期函数--监听页面初次渲染完成   */
  onReady: function () {    var that = this,
      fps = 100,
      slicePrizes = ["恭喜中了大奖", "50 积分", "500 积分", 
      "谢谢参与", "200 积分", "100 积分", "150 积分", "谢谢参与"],
      w = this.data.windowWidth,
      h = this.data.windowHeight,
      context = wx.createCanvasContext('canvas'),
      wheel = new Circle(w / 2, h / 2.5, 229),
      point = new Circle(w / 2, h / 2.5, 37.5),
      animation = new Animation(wheel)
      ;

    wheel.img = that.data.wheelImg;
    wheel.width = 458;
    wheel.height = 458;
    point.img = that.data.pointImg;
    point.width = 150;
    point.height = 150;    // 缩小比例
    wheel.scale(0.6, 0.6);
    point.scale(0.6, 0.6);    // 启用事件
    point.inputEvent = true;
    point.onInputDown = run;    // 更新动画
    var update = function () {      // 清空
      context.clearRect(0, 0, w, h);      // 画转盘
      wheel.draw(context);      // 画指针
      point.draw(context);      // 更新数据
      animation.update();      // 获取手指点击
      var touch = that.data.touch;      if (point.inputEvent && touch.isPressed && point.onInputDown) {        // 如果点击到了指针
        if (point.contains(touch)) {          // 调用点击回调方法
          point.onInputDown();
        }
      }      // 绘图
      context.draw();
    };

    setInterval(update, 1000 / fps, 1000 / fps);    // 开始转
    function run() {      // 避免重复调用
      if (animation.isRun) return;      // 随机一个奖品
      var prizeIndex = utils.getRandom(slicePrizes.length - 1);      var prize = slicePrizes[prizeIndex];      // 计算奖品角度
      var degrees = utils.getRandom(prizeIndex * 45 + 45, prizeIndex * 45);      // 当动画完成时
      animation.onComplete = function () {
        wx.showToast({          title: prize
        })

        setTimeout(function () {
          wx.hideToast()
        }, 1000)
      };

      animation.tween(5, degrees);
    }
  }
})


pages/main/Animation.js

/** * 动画 * @author qiao * @version 2017/12/30 */function Animation(circle) {  this.circle = circle;  // 角速度
  this.speed = 0;  // 最大速度
  this.maxSpeed = 10;  // 摩擦力
  this.friction = 0.98;  // 加速度
  this.acceleration = 0.1;  // 是否开始运行
  this.isRun = false;  // 圈数
  this.rounds = 0;  //角度
  this.degrees = 0;  // 当前角度
  this.angle = 0;  // 开始减速
  this.speedDown = false;  // 开始加速
  this.speedUp = true;  // 顺时针还是逆时针
  this.anticlockwise = false;  // 完成
  this.onComplete = null;
}

Animation.prototype.tween = function (rounds, degrees) {  this.circle.rotation = 0;  this.angle = 0;  this.speedDown = false;  this.speedUp = true;  this.rounds = rounds;  this.degrees = degrees;  this.isRun = true;  this.speed = 0;
};

Animation.prototype.update = function () {  if (this.isRun) {    // 是否要减速
    if (this.angle >= (this.rounds * 360 + this.degrees)) {      this.speedDown = true;      this.angle = 0;
    }    // 是否要停止加速
    if (this.speed >= this.maxSpeed) {      this.speedUp = false;
    }    // 转动角度
    this.angle += this.speed;    // 加速
    if (this.speedUp) {      this.speed += this.acceleration;
    }    // 减速
    if (this.speedDown) {      if (Math.abs(this.angle) >= 360) {        this.isRun = false;        this.speed = 0;        if (this.onComplete) this.onComplete();
      } else {        this.speed *= this.friction;
      }
    }    // 旋转方向
    if (this.anticlockwise) {      this.circle.rotation += (Math.PI / 180) * this.speed;
    } else {      this.circle.rotation -= (Math.PI / 180) * this.speed;
    }
  }
};module.exports = Animation;

pages/main/Circle.js

/** * 大转盘 * @author qiao * @version 2017/12/30 */function Circle(x, y, radius) {  this.x = x;  this.y = y;  this.width = 0;  this.height = 0;  this.radius = radius;  this.rotation = 0;  this.img = null;  this.scaleX = 1;  this.scaleY = 1;  this.inputEvent = false;  this.onInputDown = null;
}

Circle.prototype.draw = function (context) {  // 保存
  context.save();  // 移动到圆心
  context.translate(this.x, this.y);  // 旋转
  context.rotate(this.rotation);  // 缩放
  context.scale(this.scaleX, this.scaleY);  if (this.img) {    var imgX = -this.width / 2;    var imgY = -this.height / 2;
    context.drawImage(this.img, imgX, imgY);
  }  // 还原
  context.restore();
};

Circle.prototype.scale = function (x, y) {  this.scaleX = x;  this.scaleY = y;
};

Circle.prototype.contains = function (obj) {  return Circle.contains(this, obj.x, obj.y);
};

Circle.contains = function (a, x, y) {  //  Check if x/y are within the bounds first
  if (a.radius > 0 && x >= a.left && x <= a.right && y >= a.top && y <= a.bottom) {    var dx = (a.x - x) * (a.x - x);    var dy = (a.y - y) * (a.y - y);    return (dx + dy) <= (a.radius * a.radius);
  }  else {    return false;
  }
};Object.defineProperty(Circle.prototype, "left", {  get: function () {    return this.x - this.radius;
  },  set: function (value) {    if (value > this.x) {      this.radius = 0;
    }    else {      this.radius = this.x - value;
    }
  }
});Object.defineProperty(Circle.prototype, "right", {  get: function () {    return this.x + this.radius;
  },  set: function (value) {    if (value < this.x) {      this.radius = 0;
    }    else {      this.radius = value - this.x;
    }
  }
});Object.defineProperty(Circle.prototype, "top", {  get: function () {    return this.y - this.radius;
  },  set: function (value) {    if (value > this.y) {      this.radius = 0;
    }    else {      this.radius = this.y - value;
    }
  }
});Object.defineProperty(Circle.prototype, "bottom", {  get: function () {    return this.y + this.radius;
  },  set: function (value) {    if (value < this.y) {      this.radius = 0;
    }    else {      this.radius = value - this.y;
    }
  }
});module.exports = Circle;

pages/main/main.wxml

<canvas 
style='width: {{windowWidth}}px; height: {{windowHeight}}px' disable-scroll="true" bindtouchstart="canvasTouchStart" bindtouchmove="touchMove" bindtouchend="canvasTouchEnd" canvas-id="canvas"></canvas>

pages/main/main.wxss

page{  height: 100%;
}

pages/main/utils.js

var utils = {};

utils.getRandom = function (max, min) {
  min = arguments[1] || 0;  return Math.floor(Math.random() * (max - min + 1) + min);
};





全部评论: 0

    我有话说:

    微信程序营销之转盘(二)

    第一个版本的转盘都是用图片做的,奖品等信息都是不无法修改的,说白了就是没啥实际用途,作者我就直接用canvas撸了一个全手工绘制的转盘分享给大家

    微信程序电商实战-商品详情(上)

    先看一下今天要实现程序商品详情页吧!

    微信程序电商实战-购物车(上)

    好久没更新程序电商实战的文章了,是因为最近一直做整体架构调整,一些准备工作也是比较耗费时间的。在这几天将会有新版的 程序电商教程推出.......

    微信程序电商实战-首页(下)

    上一篇:微信程序电商实战-首页(上)好了,上一期我们把首页搜索、导航栏和广告轮播给做完了,那么接下来会继续

    微信程序电商实战-首页(上)

    上一篇:微信程序电商实战-入门篇 嗨,大家好!经过近两周的精心准备终于开始微信程序电商实战之路喽。那么最终会做成什么样呢?好了,不啰嗦了 我们先看首页长什么样吧!   首页效果图

    微信程序抖音实战-首页(下)

    抖音程序首页动态数据获取

    微信程序电商实战-入门篇

    程序开发工具有新版本更新啦!开发体验更好了,接下来一起为电商程序做一下准备前期准备工作~~

    微信程序抖音实战-首页(上)

    你也可以用微信程序编写一个抖音

    微信程序实现商品数量加减

    这是一个用微信程序原生代码实现的数量加减demo,主要是用于商品购物车或者商品详情修改数量使用

    微信程序 - iconfont 图标字体

    你还在使用图片作为程序的图标?猪告诉大家如何在程序上使用iconfont字体图标

    微信程序实战篇:程序之页面数据传递

    我们在写程序的时候经常会遇到子页面向主页面回传数据或者普通页面跳转到tabBar 页面携带数......

    微信程序实战篇:商品属性联动选择(案例)

    本期的微信程序实战篇来做一个电商网站经常用到的-商品属性联动选择的效果,素材参考了一点点

    微信程序微商城(一):https框架搭建并实现导航功能

    本文将带领大家搭建https的程序框架,并实现动态获取数据展示效果!

    微信程序实战篇:实现抖音评论效果

    我们在写程序的时候经常会遇到弹出层的效果而现有官网提供的跳转方法多数是不支持参数传递的。本文教大家做一个抖音评论效果的程序......

    微信程序抖音实战-视频弹幕

    如果你去抖音只是为了看视频就少了一乐趣,评论区才是最有趣的地方,边看视频边看评论的弹幕是不是更有意思

    微信程序实战篇:基于wxcharts.js绘制移动报表

    微信程序图表插件(wx-charts)是基于canvas绘制,体积巧,支持图表类型饼图、线图、柱状图 ......

    微信程序实战篇:如何解决https域名问题 ?

    开发自己的微信程序绕不开https问题,为了能在程序中调用我们自己的API服务请打开看一看吧!!!

    微信程序电商实战-商品列表流式布局

    今天给大家分享一下微信程序中商品列表的流式布局方式,根据文章内容操作就可以看到效果哦~~~

    微信程序电商实战-购物车(下)

    我们继续接着昨天的购物车写,主要把剩下的数量加减 template 模板、选中计算功能实现掉!