前言
最近小程序的游戏挺火的,本节呢就用小程序做一个简单的大转盘
效果图
设计思路
大转盘转动,指针不动
要在小程序里面新建一个画布,并且铺满屏幕
画两个圆,一个绘制大转盘,一个绘制指针
获取用户点击的坐标,看是否点击到了指针
随机一个奖励,真正业务中应该是后端随机一个结果告诉前端
计算奖励的角度
旋转大转盘
计算角度减速大转盘
旋转完回调函数处理
完整代码
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); };