轉眼間,已經實習了兩個月了,公司每個月都有個會員日的活動要做,這個月的任務是做一個扭蛋機抽獎的活動,數據什麼的都有接口,那麼前端剩下最大的任務就只剩下扭蛋機的動畫實現了。
背景原本興高采烈地從網路上找了一個扭蛋機動畫,但是發現它是直接用css動畫,把扭蛋們的動畫寫死了,這樣我不是很喜歡,於是還是選擇用canvas繪製扭蛋的隨機動畫。先寫了個簡單的扭蛋機Demo,效果預覽
開始佈局扭蛋機的佈局比較簡單,只要在基礎背景上加入一些元素就可以,最主要的是canvas標籤,其他都無所謂:
<div class=bg> <span id=message>點擊抽獎</span> <div class=lotterybg> <canvas id=myCanvas width=285px height=170px></canvas> <img src=img/lighting.png class =lighting/> </div></div><img src=img/start-btn.png id=start onclick=play()/><div class=award><span id=awardBall></span></div><img src=img/1.png id=ball1 class=imgSrc><img src= img/2.png id=ball2 class=imgSrc><img src=img/3.png id=ball3 class=imgSrc><img src=img/4.png id=ball4 class=imgSrc>
附上樣式表:
body {margin: 0;padding: 0;border: none;}.bg {background: url(../img/bg.png) top no-repeat;background-size: 100%;overflow: hidden;position: absolute ;width: 400px;height: 100%;margin-top: 0;margin-left: 50%;-webkit-transform: translate(-50%);-o-transform: translate(-50%);-ms-transform: translate(-50%);-o-transform: translate(-50%) ;transform: translate(-50%);}#message {position: absolute;text-align: center;height: 25px;font-size: 22px;margin-top: 110px;margin-left: 50%;-webkit-transform: translate(-50%);-moz-transform: translate(-50%);-ms-transform: translate(-50%);-o-transform: translate(-50%);transform: translate(-50%);}.lotterybg {background: url(../img/lotterybg.png) top no-repeat;background-size: 100%;overflow: visible;width: 80%;height: 100%; margin-top: 160px;margin-left: 50%;-webkit-transform: translate(-50%);-moz-transform: translate(-50%);-ms-transform: translate(-50%);-o-transform: translate(-50%);transform: translate(-50% );}#myCanvas {position: absolute;border: none;width: 285px;height: 170px;margin-top: 15px;margin-left: 50%;-webkit-transform: translate(-50%);-moz-transform: translate(-50%);-ms-transform: translate(-50%);-o-transform: translate(-50%);transform: translate(-50%);}.lighting {display: block;max-width: 99%;margin-top: 0;margin-left: 0;}#start {position: absolute;z-index: 3;width: 202px;margin-top: 413px;margin-left: 50%;-webkit-transform : translate(-50%);-moz-transform: translate(-50%);-ms-transform: translate(-50%);-o-transform: translate(-50%);transform: translate(-50%);}.imgSrc {display: none;position: absolute;}.award {position: absolute;border: none;width: 60px;height: 200px;top: 470px;margin-left: 50%;-webkit-transform: translate(-50%);-o-transform: translate(-50%);-ms-transform: translate(-50%);-o-transform: translate(-50%) ;transform: translate(-50%);}這樣子佈局就算完成了,接下來主要工作就在canvas繪製圖像上了。
扭蛋動畫先把各種變數定義好:
var canvas = document.getElementById('myCanvas');var ctx = canvas.getContext('2d');var ball1 = document.getElementById('ball1');//圖片物件var ball2 = document.getElementById('ball2' );//圖片物件var ball3 = document.getElementById('ball3');//圖片物件var ball4 = document.getElementById('ball4');//圖片物件var ballList = [ball1, ball2, ball3, ball4];//圖片物件陣列var ballNum = 4;//扭蛋機裡面的小球數var awardList = [];//扭蛋機中的小球集合var timer;//計時器var award = document.getElementById('awardBall');var message = document.getElementById('message');扭蛋對象扭蛋機裡面每個扭蛋都是對象,所以需要定義一個扭蛋對象:
function Ball(index, img) { this.r = 30;//小球半徑this.x = this.rand(canvas.width - this.r * 2);//小球初始橫坐標this.y = this .rand(canvas.height - this.r * 2);//小球初始縱座標this.color = index;//小球顏色,以下標表示this.img = img;//小球素材do { this.speedX = this.rand(20) - 10; } while (this.speedX < 5);//小球橫坐標改變速度do { this.speedY = this.rand( 20) - 10; } while (this.speedY < 5);//小球縱座標改變速度}傳入扭蛋對象的值index為小球的顏色,以數字1~4表示,img是圖片對象,用來繪製扭蛋。
扭蛋法在上一步已經為扭蛋添加了屬性,接下來就是給扭蛋添加方法:
Ball.prototype = { rand: function (num) {//隨機數return Math.random() * num; }, run: function () {//小球運動函數this.x += this.speedX; this. y += this.speedY; if (this.x > canvas.width - this.r * 2) {//小球碰到右邊界,橫座標速度變成負this.speedX = -this.speedX; } if (this.x < 0) {//小球碰到左邊界,橫座標速度變成正this.speedX = Math.abs(this.speedX); } if (this.y > canvas.height - this.r * 2) {//小球碰到下邊界,縱座標速度變成負this.speedY = -this.speedY; } if (this.y < 0) {//小球碰到上邊界,縱座標速度變成正this.speedY = Math.abs(this.speedY); } ctx.drawImage(this. img, this.x, this.y, 60, 60);//繪製小球}}主要是為扭蛋物件的原型添加上運動函數,運動函數的作用就是讓扭蛋根據其速度動起來,並且在接觸到邊界的時候反彈。
初始化接下來就是把扭蛋們放在扭蛋機裡面:
function init() {//初始化for (let i = 0; i < ballNum; i++) {//隨機產生各色小球let index = Math.floor(4 * Math.random()); awardList[i] = new Ball(index, ballList[index]);//新小球物件} window.clearInterval(timer);//清除計時器timer = setInterval(function () { ctx.clearRect(0, 0, canvas.width, canvas.height);//清空畫布for (let i = 0; i < awardList.length; i++) { awardList[i].run(); }//使小球運動}, 15);}這樣子扭蛋機裡面就已經有小球了。
開始扭蛋開始扭蛋主要經歷的過程就是點擊按鈕,扭蛋機扭蛋減少,獲得對應扭蛋,中獎顯示:
function play() { if (awardList.length === 0) {//獎金池中沒有小球alert('重新開始!'); init(); message.innerText = '點擊抽獎'; } else { window. clearInterval(timer);//清除計時器let r = awardList.pop();//將獎金池中的小球減少timer = setInterval(function () { ctx.clearRect(0, 0, canvas.width, canvas.height);//清空畫布for (let i = 0; i < awardList.length; i++) { awardList[i].run(); } //使小球運動}, 15); switch (r.color) {//小球掉落動畫case 0: award.setAttribute('class', 'dropBall1'); break; case 1: award.setAttribute('class', 'dropBall2'); break; case 2: award.setAttribute('class', 'dropBall3'); ; case 3: award.setAttribute( 'class', 'dropBall4'); break; } setTimeout(function () {//扭蛋成功提示award.setAttribute('class', ''); switch (r.color) { case 0: message.innerText = '紫色球!球! break; } }, 1100); }}在這裡扭蛋的掉落動畫使用css動畫的關鍵影格來完成:
.dropBall1 {content: ;position: absolute;left: 0;top: 0;width: 60px;height: 60px;display: block;background: url(../img/1.png) no-repeat;background-size : contain;animation: drop 1s ease-out forwards;-webkit-animation: drop 1s ease-out forwards;}.dropBall2 {content: ;position: absolute;left: 0;top: 0;width: 60px;height: 60px;display: block;background: url(../img/2.png) no -repeat;background-size: contain;animation: drop 1s ease-out forwards;-webkit-animation: drop 1s ease-out forwards;}.dropBall3 {content: ;position: absolute;left: 0;top: 0;width: 60px;height: 60px;display: block;background: url(.background: url(. ./img/3.png) no-repeat;background-size: contain;animation: drop 1s ease-out forwards;-webkit-animation: drop 1s ease-out forwards;}.dropBall4 {content: ;position: absolute;left: 0;top: 0;width: 60px;height: 60px;display: block;width: 60px;height: 60px;display: block;ground : url(../img/4.png) no-repeat;background-size: contain;animation: drop 1s ease-out forwards;-webkit-animation: drop 1s ease-out forwards;}@keyframes drop { 0% { transform: scale(0.7); } 50% { transform: scale(1); } 51% { transform: translateY(0px); } 100% { transform: translateY(100px); }}@-webkit-keyframes drop { 0% { -webkit-transform: scale(0.7); } 50% { -webkit-transform: scale(1); } 51% { -webkit-transform: translateY(0px); } 100% { -webkit-transform: translateY(100px); }}結束當然,需要最後加上init();來讓扭蛋機跑起來,到這裡,這個簡單的扭蛋機就算完成了,效果預覽
總結雖然這個Demo比較簡單,但還是有一些注意點和一些可優化的地方。
注意點
img對象
在html中的這些img標籤:
<img src=img/1.png id=ball1 class=imgSrc><img src=img/2.png id=ball2 class=imgSrc><img src=img/3.png id=ball3 class=imgSrc><img src=img/4.png id=ball4 class=imgSrc>
樣式也寫成display: none;,這樣寫是為了在js中取得img對象,當然也可以不在html中寫這些img標籤,直接在js檔案中寫:
var img = new Image(); img.src = 'img/1.png';
這樣子也可以得到img對象,也可以用來繪製扭蛋。
清除計時器程式碼中清除計時器都是在呼叫計時器之前,之所以這樣做的目的,是因為不清除計時器,計時器會一直計時,導致動畫越來越鬼畜。
畫布在canvas畫布上繪製可能會出現圖像不清晰、放大的情況,這種情況可以透過將canvas標籤的width和height屬性設定成和樣式的width和height屬性相同來解決。
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持VeVb武林網。