Make Things Move -- Javascript html5版(二)實現最基本的Sprite類和stage管理對象

  如今這幾篇寫的都是比較基礎的東西,有過相應開發經驗的朋友可直接忽略啦。html

  計算機模擬的動畫都是由不少靜態的一連串影像(sprite)在必定幀率(fps)內逐幀播放出來的。前端

  對於js來講,咱們能夠用提供的定時器(setInterval或setTimeout,二者其實均可以),製造一個逐幀播放的舞臺現場(stage),每一幀清空畫布後再把全部的精靈全畫上去,下一幀再清再畫,只要改變精靈的相應屬性就能產生動畫的效果。因此咱們對於精靈(Sprite)類來講,要提供一個畫(draw)的方法,一個進入每一幀時(onenter)要執行的方法;對於舞臺(stage)對象,就提供往舞臺添加和刪除精靈(addChild/removeChild)的方法,定時器的相關操做方法(start,stop,step)。再來看,其實Sprite也是能夠添加精靈達到同樣的層次關係的,因此也依然能夠提供addChild,removeChild的方法,因此咱們能夠把Sprite作爲基類,stage對象繼承了Sprite的方法後可根據須要重寫和添加本身的方法html5

  Sprite類android

  根據實際須要實現了其餘一些方法。在js/lib/目錄下新建一個Sprite.js文件(不瞭解文件目錄結構請查看上一篇介紹文章,若是是讀者本身規劃的文件結構那仍是按本身的方法來放吧):ios

  

this.Sprite = __class__({

    x: 0,         // 精靈的中心點在stage上的x座標
    y: 0,         // 精靈的中心點在stage上的y座標
    width: 0,     // 寬
    height: 0,    // 高
alpha: 1, // 透明度 0 ~ 1 scaleX:
1, // X軸上的縮放比 scaleY: 1, // Y軸上的縮放比 rotation: 0, // 旋轉角度 visible: true, // 可見否 DEG_TO_RAD: Math.PI / 180, // 一角度多少弧度,常量 __init__: function () { this._object = [] // 存放精靈 },
// 把精靈畫到畫布前的修正,如把x,y修正爲sprite的中心點座標,畫的時候不會以左上角爲錨點 __beforedraw__:
function (ctx) { ctx.translate(-this.width/2, -this.height/2) if (this.scaleX !== 1 || this.scaleY !== 1) ctx.scale(this.scaleX, this.scaleY) if (this.rotation % 360 !== 0) ctx.rotate(this.DEG_TO_RAD * this.rotation) if (this.alpha !== 1) ctx.globalAlpha = this.alpha this.draw(ctx) // 真正調用畫的方法 this._drawall(ctx) // 把全部的子精靈都 畫出來 }, draw: function (ctx) { // 現階段版本要本身實現畫的方法 // implement your own draw method }, _drawall: function (ctx) { if (this.size() > 0) for (var i = 0, obj; obj = this._object[i]; i++) { this.onenter() if (obj.visible) { // 精靈可見才畫,不可見它與它的子精靈都不會畫到stage上 ctx.save() obj.__beforedraw__(ctx) ctx.restore() } } },
// 進入每幀時調用,若是有作逐幀動畫的需求能夠實現(就是重寫)該方法 onenter:
function () { // implement your own onenter method }, addChild: function (obj) { return this.addChildAt(this.size(), obj) }, removeChild: function (obj) { this.removeChildAt(this.indexOf(obj)) return this },
// 獲取指定索引的子精靈 child:
function (index) { return this._object[index] },
// 添加精靈到指定位置 addChildAt:
function (index, obj) { if (this._object.indexOf(obj) === -1) this._object.splice(index, 0, obj) return this },
// 刪除指定位置的精靈,若是存在 removeChildAt:
function (index) { if (this.child(index) !== void 0) this._object.splice(index, 1) return this },
// 獲取指定精靈的索引 indexOf:
function (obj) { return this._object.indexOf(obj) },
// 獲取包含的精靈個數 size:
function () { return this._object.length },
// 移除全部精靈 clear:
function () { this._object.length = 0 return this } })

 

  stageweb

  舞臺管理對象,之因此不用寫成一個類是基本不會反覆生成多個舞臺實例,一個界面一個canvas就夠了。上面也提到stage具備的不少方法Sprite類都有,因此咱們能夠繼承Sprite類,又由於只用作成一個對象,因此直接實例化Sprite類就OK了,而後在這個實例中添加或重寫方法:canvas

  js/lib/stage.js數組

this.stage = new Sprite()

// 拷貝方法到stage對象中 __copy__({
// 初始化stage,傳入一個canvas dom對象 init: function (canvas) { this.canvas = canvas this.context = canvas.getContext('2d') this.width = canvas.width this.height = canvas.height return this }, // 運行,參數fps爲幀率,默認每秒24幀 run: function (fps) { fps = Number(fps) || 24 this._interval = Math.round(1000 / fps) this._starttimer() this.running = true return this }, // 中止運行 stop: function () { this.running = false this._stoptimer() return this }, running: false, __timer: null, _starttimer: function () { if (!this.__timer) this.__timer = setInterval(function (obj) { obj._drawall() }, this._interval, this) }, _stoptimer: function () { if (this.__timer) { clearInterval(this.__timer) this.__timer = null } }, // override _drawall: function () { if (this.size()) { // 清空畫布 this.context.clearRect(0, 0, this.width, this.height) Sprite.prototype._drawall.call(this, this.context) } } }, stage)

 

  這兩個東西都實現了,如今嘗試來使用它們。xcode

     其實還有一個大前提,就是你已經基本瞭解 html5 canvas的API,若是這個條件不知足能夠先去補習一下下,很簡單的幾個東西。瀏覽器

  感慨web前端這塊好象沒有特別智能如 android eclipse和ios xcode這樣的ide,對文件的引用什麼的都不是很友好,或者是我寡聞了,除了靜態語言其餘時間全是vi的可悲啊……先來調整一下以前定義的東西,在js/lib/sys.js裏再加一個工具吧,路徑添加和獲取的對象,稍稍方法咱們用來加載js文件:

this.__path__ = function () {
    var arr = []
    return {
  
        //  添加路徑
        add: function () {
            for (var i = 0, str; str = arguments[i]; ++i)
                arr.push(str)
        },

        // 獲取全部路徑,供__load__使用
        list: function () {
            return arr.slice()
        }
    }
}()

 

      修改js/etc/mtm_module.js文件吧,不用再爲每一個目錄定義一個數組了

__path__.add(
    'js/mtm/Test.js',
    'js/mtm/OtherTest.js'
)

   個性一個js/bin/main.js裏開頭調用__load__方法的參數爲:

// __path__.list() 可獲取所添加的要加載的路徑
__load__(__path__.list(), function () {})

 

  由於如今在Lib下加了兩個文件 (Sprite.js,stage.js),之後要是再加其餘類文件 的話都要手動去寫標籤太麻煩(我的感受),在js/etc/目錄下新建一個lib_module.js文件

__path__.add(
    'js/lib/Sprite.js',
    'js/lib/stage.js'
)

    痛苦的是還要在Index.html裏用標籤引用lib_module.js ……

 

  好了先來初始化stage,在main.js中加載完文件的回調函數裏寫:

__load__(__path__.list(), function () {

    var cvs = document.createElement('CANVAS'),
        doc = document.documentElement
    cvs.width = doc.clientWidth
    cvs.height = doc.clientHeight
    document.body.appendChild(cvs)

    stage.init(cvs).run() // 初始化並運行

})

 

  咱們在js/mtm/Ball.js裏寫一個例子,Ball類:

var Ball = __class__(Sprite, {

    __init__: function (color, radius) {
        Sprite.call(this)
        this.color = color || 'red'
        this.radius = radius || 20
    },

    draw: function (ctx) {
        ctx.fillStyle = this.color
        ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2, true)
        ctx.fill()
    }

})

使用這個Ball類只要生成實例,並添加到stage就OK了,在js/bin/main.js的 初始化stage完後試試吧.

var ball = new Ball()

// 設置ball的位置在stage中央
ball.x = stage.width / 2
ball.y = stage.height / 2

stage.addChild(ball)

用瀏覽器打開Index.html頁面就看到一個紅色圓球在瀏覽器中心點上了,若是一路進來都沒寫錯什麼東西的話。

  工具都基本準備完了,下去就開始一個個實現精彩的例子(有些例子不必就不實現了)。

相關文章
相關標籤/搜索