閑聊js: 實現(xiàn)一個關(guān)鍵的,最小化的,非場景圖類型的精靈系統(tǒng)(上)一文中完成了精靈系統(tǒng),但是還缺乏空間變換和動畫runLoop的支持,本篇完成上述需求!
本篇目的:
- 為BLFSprite添加空間變換相關(guān)的成員變量
- 為BLFSprite添加beginRender/endRender方法,有利于變換狀態(tài)的操作
- 增加兩個精靈類:BLFGridSprite和BLFDemoSprite
- 在引擎中封裝requestAnimationFrame操作,讓引擎動起來(遇到了一點問題,花了點時間,還是this指針導(dǎo)致的問題!)
- 動起來,轉(zhuǎn)起來
精靈系統(tǒng)最大的作用是封裝動畫和渲染操作,讓我們添加空間變換方面的內(nèi)容吧!
- BLFSprite中暫時先添加平移,旋轉(zhuǎn)操作:
class BLFSprite {
constructor(name = '') {
this.typeName = "BASE";
this.name = name;
this.color = "rgba(255,0,0,1)";
//當前精靈的位置坐標
this.x = 0;
this.y = 0;
//當前精靈的旋轉(zhuǎn)角度
this.rotation = 0;
//用于移動原點偏移量
//例如rectSprite的原點在左上角,而我們想旋轉(zhuǎn)的時候以rect中心點進行,此時需要通過使用centerX,centerY進行操作
this.centerX = 0;
this.centerY = 0;
}
}
- BLFSprite中添加beginRender/endRender用于控制空間變換操作和狀態(tài):
beginRender(render) {
//將渲染器的變換矩陣歸一化
render.resetTransform();
//設(shè)置精靈的原點
if (this.x != 0 || this.y != 0)
render.translate(this.x, this.y);
//旋轉(zhuǎn)中心點的設(shè)置
if (this.rotation != 0)
if (this.centerX != 0 || this.centerY != 0) {
render.rotateAt(this.centerX, this.centerY, this.rotation);
} else
render.rotate(this.rotation);
}
endRender(render) {
//將渲染器的變換矩陣恢復(fù)原始狀態(tài)
render.resetTransform();
}
- 原來代碼BLFSprite default情況下渲染網(wǎng)格背景,現(xiàn)在使用BLFGridSprite精靈做背景,因此基類render成純虛方法,子類如要顯示,必須override!
//虛函數(shù),如有需要,子類需override
//default實現(xiàn):原本繪制背景,現(xiàn)改成純虛方法
render(render) {
}
實現(xiàn)BLFGridSprite和BLFDemoSprite:
- BLFGridSprite:
class BLFGridSprite extends BLFSprite {
constructor(name = '') {
//super([基類構(gòu)造函數(shù)參數(shù)列表])
super(name);
//this調(diào)用父類的成員屬性必須在super()調(diào)用后才ok?。。?!
this.typeName = "GridBackgroud";
}
render(render) {
render.drawGrid('black', 'white', 20, 20);
}
}
- BLFDemoSprite:
class BLFDemoSprite extends BLFSprite {
constructor(center = false, name = '') {
//super([基類構(gòu)造函數(shù)參數(shù)列表])
super(name);
//this調(diào)用父類的成員屬性必須在super()調(diào)用后才ok!?。?!
this.typeName = "DemoSprite";
this.x = 250;
this.y = 250;
this.rotateSpeed = 1;
this.rect = new Rect(0, 0, 100, 50);
this.lines = [new Point(100, 25), new Point(150, 25)];
//如果center = true
//旋轉(zhuǎn)中心為rect的中心點,否則為rect的左上角
if (center) {
this.centerX = this.rect.width * 0.5;
this.centerY = this.rect.height * 0.5;
}
}
//渲染rect
//粗線渲染朝向標記線
//細線渲染坐標軸
render(render) {
render.drawRect(this.rect, 'blue');
render.pushStates();
render.setLineState(3.0);
render.drawLine(this.lines[0].x, this.lines[0].y, this.lines[1].x, this.lines[1].y, 'green');
render.popStates();
render.drawCoords(this.rect);
}
//運動都在update中進行數(shù)值更新
update(msec) {
this.rotation += this.rotateSpeed;
}
}
在引擎中封裝requestAnimationFrame,動起來了!
//修改上一節(jié)中BLFRender中定義的run函數(shù),讓它真正的runLoop起來:
class BLFEngine2D {
run(msec) {
this.updateAll(msec);
this.renderAll();
//調(diào)用requestAnimationFrame
requestAnimationFrame((msec) => { this.run(msec) });
/*非箭頭函數(shù)解決方案
let self = this;
requestAnimationFrame(function(msec) {
self.run(msec);
});
*/
}
}
這個函數(shù)花了我一點時間,歸根結(jié)底還是經(jīng)典的this指向問題!
- DOM中,使用requestAnimationFrame進行動畫操作
- requestAnimationFrame的參數(shù)是類型為:
function animate(time)為原型的回調(diào)函數(shù) - 但是我這里為了封裝到BLFRender2D中,剛開始死活不行,原因是this指向出了問題。
- 解決this指向:箭頭函數(shù)/let self = this;這兩種方式!
測試代碼:
<script>
let canvas = document.getElementById("myCanvas");
let context = canvas.getContext('2d');
let engine = new BLFEngine2D(context);
let spr = new BLFRectSprite(new Rect(0, 0, 50, 25), "spRect");
let spr2 = new BLFDemoSprite();
spr2.x = 400; //調(diào)整位置
spr2.rotateSpeed = -1; //逆時針
engine.sprMgr.addSprite(new BLFGridSprite("background"));
engine.sprMgr.addSprite(spr);
engine.sprMgr.addSprite(spr2); //逆時針左上角旋轉(zhuǎn)
engine.sprMgr.addSprite(new BLFDemoSprite(true)); //順時針中心旋轉(zhuǎn)
//引擎進入loop
engine.run();
</script>

demoSprite.png
htmlpreview.github.io/?https://github.com/jackyblf/BLF_JS_Demos/blob/master/spritesystemtest.html
到目前為止,一個可演示用的渲染系統(tǒng)和簡單的非場景圖類型的動畫精靈系統(tǒng)已經(jīng)完成,下一篇進入:動畫、數(shù)學(xué)與碰檢篇章