閑聊js: 實(shí)現(xiàn)一個關(guān)鍵的女器,最小化的,非場景圖類型的精靈系統(tǒng)(上)一文中完成了精靈系統(tǒng)住诸,但是還缺乏空間變換和動畫runLoop的支持驾胆,本篇完成上述需求!
本篇目的:
- 為BLFSprite添加空間變換相關(guān)的成員變量
- 為BLFSprite添加beginRender/endRender方法贱呐,有利于變換狀態(tài)的操作
- 增加兩個精靈類:BLFGridSprite和BLFDemoSprite
- 在引擎中封裝requestAnimationFrame操作丧诺,讓引擎動起來(遇到了一點(diǎn)問題,花了點(diǎn)時間奄薇,還是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)";
//當(dāng)前精靈的位置坐標(biāo)
this.x = 0;
this.y = 0;
//當(dāng)前精靈的旋轉(zhuǎn)角度
this.rotation = 0;
//用于移動原點(diǎn)偏移量
//例如rectSprite的原點(diǎn)在左上角劫瞳,而我們想旋轉(zhuǎn)的時候以rect中心點(diǎn)進(jìn)行废睦,此時需要通過使用centerX,centerY進(jìn)行操作
this.centerX = 0;
this.centerY = 0;
}
}
- BLFSprite中添加beginRender/endRender用于控制空間變換操作和狀態(tài):
beginRender(render) {
//將渲染器的變換矩陣歸一化
render.resetTransform();
//設(shè)置精靈的原點(diǎn)
if (this.x != 0 || this.y != 0)
render.translate(this.x, this.y);
//旋轉(zhuǎn)中心點(diǎ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實(shí)現(xiàn):原本繪制背景搞监,現(xiàn)改成純虛方法
render(render) {
}
實(shí)現(xiàn)BLFGridSprite和BLFDemoSprite:
- BLFGridSprite:
class BLFGridSprite extends BLFSprite {
constructor(name = '') {
//super([基類構(gòu)造函數(shù)參數(shù)列表])
super(name);
//this調(diào)用父類的成員屬性必須在super()調(diào)用后才okV媪酢!5媸汀茫船!
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)用后才okH谎邸>洹G巧贰空骚!
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的中心點(diǎn),否則為rect的左上角
if (center) {
this.centerX = this.rect.width * 0.5;
this.centerY = this.rect.height * 0.5;
}
}
//渲染rect
//粗線渲染朝向標(biāo)記線
//細(xì)線渲染坐標(biāo)軸
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);
}
//運(yùn)動都在update中進(jìn)行數(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ù)花了我一點(diǎn)時間,歸根結(jié)底還是經(jīng)典的this指向問題屏镊!
- DOM中而芥,使用requestAnimationFrame進(jìn)行動畫操作
- 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)
//引擎進(jìn)入loop
engine.run();
</script>
htmlpreview.github.io/?https://github.com/jackyblf/BLF_JS_Demos/blob/master/spritesystemtest.html
到目前為止沼溜,一個可演示用的渲染系統(tǒng)和簡單的非場景圖類型的動畫精靈系統(tǒng)已經(jīng)完成平挑,下一篇進(jìn)入:動畫、數(shù)學(xué)與碰檢篇章