网友真实露脸自拍10p,成人国产精品秘?久久久按摩,国产精品久久久久久无码不卡,成人免费区一区二区三区

小程序模板網(wǎng)

小程序canvas開發(fā)水果老虎機(jī)

發(fā)布時(shí)間:2020-05-22 09:56 所屬欄目:小程序開發(fā)教程

在這個(gè)超長假期中,無聊。。。,所以動(dòng)手做一個(gè)早就計(jì)劃要做的小玩意, 水果*** ,嗯,這是一個(gè)小程序而不是小游戲...

使用結(jié)構(gòu)還是canvas?

使用模板結(jié)構(gòu)(view)生成水果盤的好處一是用戶可自定義產(chǎn)出 n x n 的定制化***,二是容易通過算法樣式生成布局,三是通過 wx.selectQueryAll 的方法能夠很方便的抓到定位數(shù)據(jù)。但,問題是動(dòng)畫性能過于孱弱,如圖構(gòu)建一個(gè) 7x7 的水果盤,動(dòng)畫性能估計(jì)會慘不忍睹,而且純粹模板結(jié)構(gòu)無論使用 animation 動(dòng)畫方法還是 css 的keyframe的動(dòng)畫方法得到的動(dòng)畫效果都非常差(測試過的結(jié)論),還有是已知的動(dòng)畫方法可控性很差

使用canvas來生成水果盤好處是動(dòng)畫性能很好(canvas2d),但是定制性和擴(kuò)展性比較差

so綜上考慮,使用模板(view)布局,使用canvas來實(shí)現(xiàn)動(dòng)畫。既保證了組件的性能,同時(shí)定制型,擴(kuò)展性也很好

準(zhǔn)備計(jì)時(shí)器方法

動(dòng)畫的生成離不開計(jì)時(shí)器方法,settimeout/setinterval這兩兄弟真的不夠看啊,問題還多,做過web開發(fā)的一定都知道 window.requestAnimationFrame ,這貨在小程序的計(jì)時(shí)器方法中不存在,好在 canvas2d 中可以使用 Canvas.requestAnimationFrame(function callback) 方法來實(shí)現(xiàn)

準(zhǔn)備運(yùn)動(dòng)算法

在水果***中,激活狀態(tài)會沿著四方的水果盤做非線性運(yùn)動(dòng)(easeInOut比較好用),需要基礎(chǔ)的運(yùn)動(dòng)算法來計(jì)算實(shí)際的運(yùn)動(dòng)距離。在 animation 動(dòng)畫方法中,我們可以使用 ease-in/ease-out 等緩動(dòng)算法來實(shí)現(xiàn)動(dòng)畫效果,但在這里必須要借助 tween.js 中的緩動(dòng)算法來實(shí)現(xiàn)運(yùn)動(dòng)效果(因?yàn)樾枰刂七\(yùn)動(dòng)節(jié)點(diǎn))。

你會不會想到用css的keyframe動(dòng)畫來做這個(gè)運(yùn)動(dòng)效果,經(jīng)過我的測試,css的動(dòng)畫和animation的動(dòng)畫會在每一條邊上實(shí)現(xiàn)一次(ease)緩動(dòng)運(yùn)動(dòng)(很奇怪的效果

使用其中一個(gè),節(jié)省代碼量

/*
 * Tween.js
 * t: current time(當(dāng)前時(shí)間);
 * b: beginning value(初始值);
 * c: change in value(變化量);
 * d: duration(持續(xù)時(shí)間)。
 */
// Quart 四次方的緩動(dòng)
const easeInOutQuart = function (t, b, c, d) {
  if ((t /= d / 2) < 1) return c / 2 * t * t * t * t + b;
  return -c / 2 * ((t -= 2) * t * t * t - 2) + b;
}
復(fù)制代碼

tween算法是以時(shí)間為基準(zhǔn)(時(shí)間比率 = 距離比率)來計(jì)算單位時(shí)間的實(shí)際運(yùn)動(dòng)距離

布局

以上面的圖為例,我們需要做一個(gè) 7 x 7 的水果盤,實(shí)際有效的獎(jiǎng)品格子數(shù)為 7*4-4 共24個(gè)有效格子

有效格子算法

js

// 0-6 第一行所有格子全部有效  
// 21-27 最后一行所有格子全部有效  
// 中間部分 i%7===0 和 i%7 === (7-1) 有效
// 算法源碼有點(diǎn)無聊,依據(jù)上述思路,即可遍歷28個(gè)格子并標(biāo)識獎(jiǎng)品格子valide=true
// 可以擴(kuò)展想一想 6x6 5x5,思路是一樣的
復(fù)制代碼

wxml

<view class="fruits-container" >
    <view class="fruits-table" >
        <block wx:for="{{ary}}" wx:key="index" >
            <view wx:if="{{item.valide}}" class="valide">{{item.title}}</view>
            <view wx:else class="in-valide"></view>
        </block>
    </view>
    <canvas type="2d" .... />
</view>
復(fù)制代碼

樣式

只節(jié)選關(guān)鍵樣式,目的是讓canvas覆蓋在水果盤上,長寬一致

.fruits-container {
    position: relative;
    width: 400px;
    height: 400px;
    ...
}

.fruits-table {
    position: absolute;
    width: 100%;
    height: 100%;
    top: 0;
    left: 0;
    ...
}
復(fù)制代碼

抓取位置信息

canvas的繪制需要X軸, Y軸的精確信息,可以使用 wx.createSelectorQuery 方式抓取類名為‘valide’的 view (獎(jiǎng)品格子)的位置信息

let query = wx.createSelectorQuery().in(this)
query.selectAll(`.fruits-table .valide`).boundingClientRect(ret => {
    ....
    console.log(ret[0]) // top, left, right, bottom, width, height
    console.log(ret[1]) // top, left, right, bottom, width, height
    ...
    ...
    console.log(ret[23]) // top, left, right, bottom, width, height
})
復(fù)制代碼

得到每一個(gè)獎(jiǎng)品格子的位置信息后,就可以使用canvas的 fillRect 方法來繪制激活狀態(tài)了。

繪制一個(gè)激活狀態(tài)

let query = wx.createSelectorQuery().in(this)
query.selectAll(`.fruits-table .valide`).boundingClientRect(ret => {
    ....
    let {top, left, right, bottom, width, height} = ret[0]
    const canvasQuery = wx.createSelectorQuery()
    canvasQuery.select('#fruit-canvas')
    .fields({ node: true, size: true })
    .exec((res) => {
        const canvas = res[0].node
        const ctx = canvas.getContext('2d') 
        let x = top
        let y = left
        let dx = width
        let dy = height
        ctx.shadowOffsetX = 2
        ctx.shadowOffsetY = -2
        ctx.shadowColor = 'red'
        ctx.shadowBlur = 50
        ctx.lineWidth = 5
        ctx.strokeStyle = 'red'
        ctx.clearRect(0, 0, canvas.width, canvas.height)
        ctx.strokeRect(x, y, dx, dy)
    })
})
復(fù)制代碼

跑起來

已經(jīng)繪制了一個(gè)激活狀態(tài),接下來使它能夠簡單動(dòng)起來

// 抽象激活方法  
functon rect(point, canvas){
    let {x, y, dx, dy} = getPosition(point)
    ctx.shadowOffsetX = 2
    ctx.shadowOffsetY = -2
    ...
    ...
    ctx.clearRect(0, 0, canvas.width, canvas.height) // 擦除整個(gè)水果盤
    ctx.strokeRect(x, y, dx, dy) // 繪制激活區(qū)域
}

function run(){
    setTimeout(()=>{
        if (ret.length) {
            let point = ret.shift()
            rect(point, canvas)
            run()
        }
    }, 100)
}
復(fù)制代碼

執(zhí)行run方法后可以看到水果盤的激活狀態(tài)一步一步的往前走(100毫秒),拖拉機(jī)終于可以啟動(dòng)了

配上運(yùn)動(dòng)算法

經(jīng)過上面的試驗(yàn)我們終于可以看到基本的運(yùn)動(dòng)效果了,接下來配上運(yùn)動(dòng)算法和計(jì)時(shí)器方法

// Quart 四次方的緩動(dòng)
const easeInOutQuart = function (t, b, c, d) {
  if ((t /= d / 2) < 1) return c / 2 * t * t * t * t + b;
  return -c / 2 * ((t -= 2) * t * t * t - 2) + b;
}

let start = 0  // 開始時(shí)間
let begin = 0  // 開始獎(jiǎng)品位置
let end = 23  // 終點(diǎn)位置,這里跑一圈
let during = 5000 // 運(yùn)動(dòng)總時(shí)間

// 1000/60 ≈ 17,
// 17毫秒即表示屏幕60幀刷新率每秒 ≈ requestAnimationFrame計(jì)數(shù)頻率(一般情況)  
const steper = () => {
  // left為位移距離
  // ***的運(yùn)動(dòng)位移是節(jié)點(diǎn)位移,不是精確位移
  // 所以這里用parseInt處理,只取整數(shù)部分
  // 數(shù)據(jù)變化為 0,1,2,3,4,5...23
  // 間隔時(shí)間/距離由easeInOutQuart算法計(jì)算
  var left = easeInOutQuart(start, begin, end, during);
  let idx = parseInt(left)
  start = start + 17; 
  if (idx <= end) {
    let point = this.ret[idx] // 取節(jié)點(diǎn)位置信息
    this.rect(point) // 繪制
  }
  
  // 時(shí)間遞增
  if (start <= during) {
    this.ctx.requestAnimationFrame(steper); // 計(jì)時(shí)器
  } else {
    // 動(dòng)畫結(jié)束,這里可以插入回調(diào)...
    // callback()...
  }
};

steper(); // 啟動(dòng)
復(fù)制代碼

以上為我的小程序水果***的基本開發(fā)思路


易優(yōu)小程序(企業(yè)版)+靈活api+前后代碼開源 碼云倉庫:starfork
本文地址:http://www.xiuhaier.com/wxmini/doc/course/25254.html 復(fù)制鏈接 如需定制請聯(lián)系易優(yōu)客服咨詢:800182392 點(diǎn)擊咨詢
QQ在線咨詢
AI智能客服 ×