赶知识网

微信小程序之大转盘

2019-03-11 / 1248次点击 Js/Css/jQuery
最近小程序的游戏挺火的,本节呢就用小程序做一个简单的大转盘
效果图














设计思路


大转盘转动,指针不动
要在小程序里面新建一个画布,并且铺满屏幕
画两个圆,一个绘制大转盘,一个绘制指针
获取用户点击的坐标,看是否点击到了指针
随机一个奖励,真正业务中应该是后端随机一个结果告诉前端
计算奖励的角度
旋转大转盘
计算角度减速大转盘
旋转完回调函数处理


完整代码
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);
};


pages/main/assets/wheel.png
















pages/main/assets/point.png


作者:IT实战联盟咖啡
链接:https://www.jianshu.com/p/63fa5944087f
来源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。

Top10

沪ICP备09053415号 © 赶知识网