摘要:最近工作中重構了抽獎轉盤,給大家提供一個開發(fā)轉盤抽獎的思路需求轉盤根據獎品數(shù)量不同而有變化目錄結構由于業(yè)務需要所以開發(fā)了兩個版本抽獎,和,不過部分只能替換圖片,沒有功能邏輯。
最近工作中重構了抽獎轉盤,給大家提供一個開發(fā)轉盤抽獎的思路
需求1、轉盤根據獎品數(shù)量不同而有變化 2、canvas目錄結構
由于業(yè)務需要所以開發(fā)了兩個版本抽獎,dom和canvas,不過editor.js部分只能替換圖片,沒有功能邏輯。
需要注意的是此目錄隱藏了一個動態(tài)數(shù)據類(dataStore),因為集成在項目里了,所以沒有體現(xiàn)。
Spirts精靈類生成實例,會包括基礎屬性:width、height、x、y和方法:setOpacity、drawCircular、setRotate、draw
下面是幾個重要的精靈構造器:背景、轉盤背景和每一個獎品
/* * 精靈核心 基類 * */ class Spirt { constructor({}) {} // 精靈透明度調節(jié) setOpacity(opy, callback) {} // 畫圓形圖片 drawCircular(fn) {} // 精靈旋轉調節(jié) setRotate() {} // 畫精靈 draw() {} } // 背景 class Bg extends Spirt { constructor({ ...args }) { super({ ...args }); if (args.height == "100%") { this.height = this.canvas.height; } } } // 轉盤背景 class Turn extends Spirt { constructor({ ...args }) { super({ ...args }); } draw() { this.drawCircular(() => { super.draw(); }); } } // 每一個獎品 class Item extends Spirt { constructor({ ...args }, rid) { super({ ...args }); this.rid = rid; } draw(angle, x, y) { this.setRotate(angle, () => super.draw(), x, y); } }Config
基礎數(shù)據類,包括基礎數(shù)據:轉盤分塊、角度、半徑、每一塊對應獎品、旋轉總時長、旋轉速度等
主要說一下轉盤分塊:如果符合規(guī)律,就用函數(shù)代替,如果不符合規(guī)律就用映射
let layout = { 1: [1, 10, 1, 10, 1, 10], 2: [1, 2, 10, 1, 2, 10], 3: [1, 10, 2, 10, 3, 10], 4: [2, 10, 3, 10, 4, 10, 1, 10], 5: [2, 3, 4, 10, 5, 10, 1, 10], 6: [2, 3, 4, 10, 5, 6, 1, 10], 7: [3, 4, 10, 5, 6, 7, 10, 1, 2, 10], 8: [3, 4, 10, 5, 6, 7, 8, 10, 1, 2] };
下面為部分代碼
class Config { constructor(prize = new Array(3), resImg) { this.awards_len = prize.length >= 7 ? 10 : prize.length >= 4 ? 8 : 6; this.awards_angle = 360 / this.awards_len; this.awards_r = 320; this.awards_cir = 2 * Math.PI * this.awards_r; let nums = { 6: 2.5, 8: 2, 10: 2 }; this.awards_item_margin = 40; this.award_item_size = this.awards_cir / this.awards_len / nums[this.awards_len]; this.duration = 2000; // 獎品詳情 this.awards = getAwards(resImg, prize.length); } } /** * 獲取獎品列表 * @param {*} num */ function getAwards(resImg, num) { let arr = layout[num]; return arr.map(rid => { let res = resImg[mapAwards[rid]]; return { rid, res, className: mapAwards[rid] }; }); }Res
資源類主要做一些圖片初始化的操作
// 獲取游戲資源 class Res extends Resource { constructor(dataStore) { super({ dataStore }); let { gameJson } = dataStore; this.res = { ...gameJson.staticSpirts.BG }; this.dataStore = dataStore; } // 編輯頁面改變頁面圖片能力。 setImg(data) { this.res[data.num].imgUrl = data.imgUrl; if (["BG", "TITLE", "TURNTABLE_BG", "PLAYBTN"].includes(data.num)) { $(`.turnTableNew_${data.num}`).css( "background-image", `url("${HOST.FILE + data.imgUrl}")` ); } else { $(`.turnTableNew_${data.num}`).attr( "src", `${HOST.FILE + data.imgUrl}` ); } return { staticSpirts: this.res }; } }Director
導演類,主要操作的是轉盤動畫的邏輯
主要邏輯是:
1、addCLick: canvas添加點擊事件
2、drawStatic:畫靜態(tài)元素
3、drawZhuanPan:這個為多帶帶canvas,group內部包括畫轉盤,獎品
4、drawPlayBtn: 畫按鈕
5、當點擊抽獎按鈕執(zhí)行updatedRotate函數(shù)讓多帶帶轉盤canvas旋轉即可
6、當旋轉角度和獲取獎品角度一致時停止
class turnTable extends Director { constructor(dataStore) { let { gameManager } = dataStore; super(gameManager); // 從倉庫中獲取基礎數(shù)據,canvas和config總配置 this.dataStore = dataStore; this.canvas = dataStore.canvas; this.config = dataStore.$gameConfig; // 當前抽獎的一些基礎數(shù)據 this.angle = 0; this.isAnimate = true; this.lastTime = 0; this.num = 0; this.addCLick(); } // 抽獎結束,需要初始化抽獎 initGame() { this.state = this.START; this.angle = 0; this.num = 0; this.prizeId = null; this.isAnimate = true; this.turnAudio.pause(); this.drawAllElements(this.res, this.set); } /** * 畫所有元素 * @param {*} store * @param {*} res */ drawAllElements(res, set) { this.res = res; this.set = set; this.drawStatic(res); this.drawZhuanPan(this.angle); this.drawPlayBtn(this.canvas, res); } /** * 畫靜態(tài)元素 */ drawStatic(res) { ["BG", "TITLE"].forEach(item => { let str = item.toLowerCase(); str = str.replace(str[0], str[0].toUpperCase()); let ele = new Spirts[str]({ canvas: this.canvas, ...res[item] }); ele.draw(); }); } // 畫轉盤 drawZhuanPan(angle) { this.group = new Spirts["Group"]({ canvas: this.canvas, ...this.res["TURNTABLE_BG"] }); this.items = this.drawDynamic(this.group.group_canvas, this.res); this.group.draw( angle, +this.res["TURNTABLE_BG"].x + +this.res["TURNTABLE_BG"].width / 2, +this.res["TURNTABLE_BG"].y + +this.res["TURNTABLE_BG"].height / 2 ); } // 畫動態(tài)元素 drawDynamic(canvas, res) { let set = this.set; let items = []; // 轉盤背景1,裝飾物 let turnBg = new Spirts["Turn"]({ canvas, img: res["TURNTABLE_BG"].img, width: res["TURNTABLE_BG"].width, height: res["TURNTABLE_BG"].height, x: 0, y: 0 }); turnBg.draw(); // 轉盤背景2,盤面 let turnPan = new Spirts["Turn"]({ canvas, img: res["TURNTABLE_PAN"].img, width: res["TURNTABLE_PAN"].width, height: res["TURNTABLE_PAN"].height, x: (res["TURNTABLE_BG"].width - res["TURNTABLE_PAN"].width) / 2, y: (res["TURNTABLE_BG"].height - res["TURNTABLE_PAN"].height) / 2 }); turnPan.draw(); for (let i = 0; i < set.awards_len; i++) { // 每一個獎品 let item = new Spirts["Item"]( { canvas, img: set.awards[i].res.img, width: set.award_item_size, height: set.award_item_size, x: turnBg.width / 2 - set.award_item_size / 2, y: (turnBg.height - turnPan.height) / 2 + set.awards_item_margin }, set.awards[i].rid ); item.draw( set.awards_angle / 2 + set.awards_angle * i, turnBg.width / 2, turnBg.height / 2 ); // 畫線 let line = new Spirts["Item"]({ canvas, img: res["LINE"].img, width: res["LINE"].width, height: res["LINE"].height, x: turnBg.width / 2 - res["LINE"].width / 2, y: (turnBg.height - turnPan.height) / 2 }); line.draw( set.awards_angle * i, turnBg.width / 2, turnBg.height / 2 ); // 放到items數(shù)組內,后期轉盤停止校驗用 items.push(item); } return items; } // 畫按鈕 drawPlayBtn(canvas, res) { let playBtn = new Spirts["PlayBtn"]({ canvas, ...res["PLAYBTN"] }); playBtn.draw(); this.playBtn = playBtn; } // 點擊事件 addCLick() { let initX, isClickState, cScale = this.config["cScale"] || 1; this.canvas.addEventListener(tapstart, event => { initX = event.targetTouches ? event.targetTouches[0].clientX : event.offsetX / cScale; let y = event.targetTouches ? event.targetTouches[0].clientY : event.offsetY / cScale; isClickState = isCheck.call(this.playBtn, initX, y); // 點擊回調 if (isClickState && this.isAnimate) { /** * 按鈕不可點擊 * 初始化總時長 * 初始化速度 * 初始化當前時間 */ this.isAnimate = false; this.set.is_animate = true; this.set.jumping_total_time = Math.random() * 1000 + this.set.duration; this.set.speed = (this.set.jumping_total_time / 2000) * 10; this.lastTime = new Date().getTime(); this.run(); this.getPrize() .then(res => { if (!res) { this.prizeId = 10; return; } this.prizeId = +res.prizeLevel + 1; }) .catch(_ => { this.prizeId = 10; this.initGame(); this.state = this.END; }); } }); } updatedRotate() { let curTime = new Date().getTime(), set = this.set, speed = 1; /** * 轉盤停止,需要滿足一下條件 * 1.大于總時間 * 2.有獎品id * 3.速度降為1 * 4.轉盤角度對應獎品id位置 * 角度做了容錯處理,當前角度范圍中心位置,偏移量為5 * 公式:通過旋轉角度計算當前獎品index * 通過items獎品列表計算當前獎品rid * rid和prizeId對比,如果結束抽獎 */ if ( curTime - this.lastTime >= set.jumping_total_time && this.prizeId && speed == 1 ) { let resultAngle = 360 - (this.angle % 360); let index = (resultAngle / set.awards_angle) >> 0; let centerAngle = set.awards_angle * (index + 0.5); if ( this.items[index].rid == this.prizeId && (resultAngle > centerAngle - 5) & (resultAngle < centerAngle + 5) ) { this.comAudio.play(); this.state = this.PAUSE; } } this.num++; speed = Math.max( set.speed - (18 * this.num * (set.speed - 1)) / set.jumping_total_time, 1 ); this.angle += speed; this.drawAllElements(this.res, this.set); } // 渲染畫布 render() { switch (this.state) { case this.START: this.updatedRotate(); break; case this.ERROR: break; case this.PAUSE: this.state = this.END; setTimeout(() => { this.showResult(); this.initGame(); }, 1000); break; case this.END: // 打開指定頁面 break; } } }
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/106906.html
摘要:圓盤抽獎應用頁面圓盤抽獎應用演示抱歉瀏覽器不支持。 HTML5 Canvas圓盤抽獎應用DEMO html頁面 HTML5 Canvas圓盤抽獎應用DEMO演示 抱歉!瀏覽器不支持。 抱歉!瀏覽器不支持。 抱歉!瀏覽器...
摘要:圓盤抽獎應用頁面圓盤抽獎應用演示抱歉瀏覽器不支持。 HTML5 Canvas圓盤抽獎應用DEMO html頁面 HTML5 Canvas圓盤抽獎應用DEMO演示 抱歉!瀏覽器不支持。 抱歉!瀏覽器不支持。 抱歉!瀏覽器...
摘要:圓盤抽獎應用頁面圓盤抽獎應用演示抱歉瀏覽器不支持。 HTML5 Canvas圓盤抽獎應用DEMO html頁面 HTML5 Canvas圓盤抽獎應用DEMO演示 抱歉!瀏覽器不支持。 抱歉!瀏覽器不支持。 抱歉!瀏覽器...
閱讀 1598·2021-11-04 16:11
閱讀 3309·2021-09-09 11:33
閱讀 1558·2019-08-30 15:54
閱讀 619·2019-08-30 15:44
閱讀 3173·2019-08-30 15:43
閱讀 2553·2019-08-30 13:06
閱讀 1697·2019-08-29 17:00
閱讀 894·2019-08-29 15:33