前言
最近小程序的游戏挺火的,本节呢就用小程序做一个简单的大转盘
效果图
设计思路
- 大转盘转动,指针不动
- 要在小程序里面新建一个画布,并且铺满屏幕
- 画两个圆,一个绘制大转盘,一个绘制指针
- 获取用户点击的坐标,看是否点击到了指针
- 随机一个奖励,真正业务中应该是后端随机一个结果告诉前端
- 计算奖励的角度
- 旋转大转盘
- 计算角度减速大转盘
- 旋转完回调函数处理
完整代码
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
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实战联盟是集产品、UI设计、前后端、架构、大数据和AI人工智能等为一体的实战交流服务平台!联盟嘉宾都为各互联网公司项目的核心成员,联盟主旨是“让实战更简单”,欢迎来撩~~~