前言: cocosCreator实现两种效果转盘抽奖。
今天完成策划给的2个抽奖需求,我把核心逻辑提取出来并拓展了一个功能更丰富的效果,抛砖引玉分享出来。
远程Gitee: https://gitee.com/songhuiyuan/turntable-lottery—demo.git
一、转盘抽奖
A:使用cc.tween().to功能+缓动函数实现旋转。
优点:简单易懂,方便控制。
缺点:功能单一
B:使用适应对时间的插值计算 + cc.tween().by 。
奖励展示跟随指针选中效果
使用了es6写法,对于页游可能在部分浏览器上不支持(比如360的兼容模式),可改成es写法
二、轮询抽奖
同样使用了2中方式实现。
三、代码展示(展示转盘抽奖B方案)
节点树和脚本挂载
GameControl脚本
import GoLuckDraw from "./GoLuckDraw";
const { ccclass, property } = cc._decorator;
@ccclass
export default class GameControl extends cc.Component {
@property(cc.Node)
public RewardPre: cc.Node = null; //奖励预制节点
public AwardNode: cc.Node; //奖励父节
public Pointer: cc.Node; //指针
public LuckDraw: GoLuckDraw; //旋转组件
public rewardCount: number = 12; //奖品个数
public avgAngle: number = 360 / this.rewardCount; //平均角度
private angleStep = Math.PI * 2 / this.rewardCount; //平均弧度
private radius: number = 240; //半径
private curIndex: number = 0; //当前奖励下标
private tagetIndex: number = 0; //目标奖励下标
private reawadArr: Array<Number> = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ,10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33]; //奖品名称
onLoad() {
this.AwardNode = cc.find("ZhuanPanRoot/BackGround/AwardNode", this.node);
this.Pointer = cc.find("ZhuanPanRoot/BackGround/CentreNode/Pointer", this.node);
this.LuckDraw = cc.find("ZhuanPanRoot", this.node).getComponent(GoLuckDraw);
}
start() {
this._InitAwardPre();
}
private _InitAwardPre() {
for (let i = 0; i < this.rewardCount; i++) {
const angle = i * this.angleStep; // 计算当前点的角度
const x = this.radius * Math.cos(angle); // 使用余弦计算x偏移量
const y = this.radius * Math.sin(angle); // 使用正弦计算y偏移量
let rewardPre = cc.instantiate(this.RewardPre);
rewardPre.x = y, rewardPre.y = x;
rewardPre.parent = this.AwardNode;
rewardPre.active = true;
rewardPre.getChildByName('label').getComponent(cc.Label).string = i.toString();
}
}
//开始抽奖
private isTurnIng = false;
public BtnCallBack() {
if (this.isTurnIng) {
return;
}
this.isTurnIng = true;
let awardIndex = Math.floor(Math.random() * this.rewardCount);
this.tagetIndex = awardIndex;
console.log("========>>>>", awardIndex, this.reawadArr[awardIndex]);
this.LuckDraw.StartLuckDraw(this, this.curIndex, this.tagetIndex, 4, 4);
this.LuckDraw.CompleteCallBack = () => {
this.curIndex = this.tagetIndex;
this.isTurnIng = false;
}
}
// update (dt) {}
}
GoLuckDraw
import GameControl from "./GameControl";
const { ccclass, property } = cc._decorator;
@ccclass
export default class GoLuckDraw extends cc.Component {
public CompleteCallBack: () => void;
private EndDarwTick: number = 2; //最后一轮的秒数为2秒;
private CurIndex: number; //起始位置
private StopIndex: number; //停止位置
private Allticks: number; //总秒数
private MaxCount: number; //轮数
private MainThis: GameControl;
private ByAngle: number;
onLoad() {
}
/**
*
* @param curIndex 起始位置
* @param stopIndex 结束位置
* @param allticks 总时长
* @param maxCount 轮次
*/
public StartLuckDraw(gameControl: GameControl, curIndex: number, stopIndex: number, allticks: number, maxCount: number) {
this.MainThis = gameControl;
this.ByAngle = this.MainThis.avgAngle * -1;
this.CurIndex = curIndex;
this.StopIndex = stopIndex + this.MainThis.rewardCount;
this.Allticks = allticks > 3 ? allticks : 3;
this.MaxCount = maxCount;
this.LuckDrawRounds();
}
private async LuckDrawRounds() {
let time1 = 0, time2 = 0;
let sumCount = this.MaxCount * this.MainThis.rewardCount;
let avgTime = (this.Allticks - this.EndDarwTick) / sumCount; //平均时间
for (let i = this.CurIndex; i < sumCount; i++) {
time1 = cc.misc.lerp(0, avgTime * 2, (1 / sumCount) * (i + 1));
cc.tween(this.MainThis.Pointer).by(time1, { angle: this.ByAngle }).start();
this.SetAwardState(i);
await this.SleepTime(time1);
}
avgTime = this.EndDarwTick / this.StopIndex;
for (let i = 0; i < this.StopIndex; i++) {
time2 = cc.misc.lerp(time1, avgTime * 2, (1 / this.StopIndex) * (i + 1));
cc.tween(this.MainThis.Pointer).by(time2, { angle: this.ByAngle }).start();
this.SetAwardState(i);
await this.SleepTime(time2);
}
this.SetAwardState(this.StopIndex);
await this.SleepTime(1);
if (this.CompleteCallBack != null) {
this.CompleteCallBack();
}
}
private SleepTime(time: number): Promise<void> {
return new Promise((resolve, reject) => {
this.scheduleOnce(() => {
resolve();
}, time);
})
}
private SetAwardState(index: number) {
let _index = index % this.MainThis.rewardCount;
let label: cc.Node;
let lastIndex = _index - 1 < 0 ? this.MainThis.rewardCount - 1 : _index - 1;
label = this.MainThis.AwardNode.children[lastIndex]?.getChildByName("label");
if (label) {
label.color = cc.Color.WHITE;
}
label = this.MainThis.AwardNode.children[_index]?.getChildByName("label");
if (label) {
label.color = cc.Color.RED;
}
}
}