diff --git a/src/app/play/Unit.ts b/src/app/play/Unit.ts index 4a84782db4c8f7a50a9e45a2bd7e50d7f32d2f0c..b78f3f2c65d4e7535cb12b7da1dff9bb746eb0d2 100644 --- a/src/app/play/Unit.ts +++ b/src/app/play/Unit.ts @@ -4,6 +4,7 @@ import TWEEN from '@tweenjs/tween.js'; interface AirWindow extends Window { air: any; curCtx: any; + curImages: any; } declare let window: AirWindow; @@ -36,7 +37,6 @@ class Sprite { - export class MySprite extends Sprite { _width = 0; @@ -69,6 +69,16 @@ export class MySprite extends Sprite { img; _z = 0; + _showRect; + + + _bitmapFlag = false; + _offCanvas; + _offCtx; + isCircleStyle = false; // 切æˆåœ†å½¢ + parent; + _maskSpr; + init(imgObj = null, anchorX: number = 0.5, anchorY: number = 0.5) { @@ -79,7 +89,6 @@ export class MySprite extends Sprite { this.width = this.img.width; this.height = this.img.height; - } this.anchorX = anchorX; @@ -87,8 +96,11 @@ export class MySprite extends Sprite { } - setShadow(offX, offY, blur, color = 'rgba(0, 0, 0, 0.3)') { + setShowRect(rect) { + this._showRect = rect; + } + setShadow(offX, offY, blur, color = 'rgba(0, 0, 0, 0.3)') { this._shadowFlag = true; this._shadowColor = color; @@ -102,6 +114,19 @@ export class MySprite extends Sprite { this._radius = r; } + setMaskSpr(spr) { + this._maskSpr = spr; + this._createOffCtx(); + } + + _createOffCtx() { + if (!this._offCtx) { + this._offCanvas = document.createElement('canvas'); // 创建一个新的canvas + this.width = this._offCanvas.width = this.width; // 创建一个æ£å¥½åŒ…裹ä½ä¸€ä¸ªç²’åcanvas + this.height = this._offCanvas.height = this.height; + this._offCtx = this._offCanvas.getContext('2d'); + } + } update($event = null) { if (!this.visible && this.childDepandVisible) { @@ -137,7 +162,22 @@ export class MySprite extends Sprite { this.ctx.transform(1, this.skewX, this.skewY, 1, 0, 0); + } + + drawSelf() { + + if (this._shadowFlag) { + this.ctx.shadowOffsetX = this._shadowOffsetX; + this.ctx.shadowOffsetY = this._shadowOffsetY; + this.ctx.shadowBlur = this._shadowBlur; + this.ctx.shadowColor = this._shadowColor; + } else { + this.ctx.shadowOffsetX = 0; + this.ctx.shadowOffsetY = 0; + this.ctx.shadowBlur = null; + this.ctx.shadowColor = null; + } if (this._radius) { @@ -146,45 +186,68 @@ export class MySprite extends Sprite { const w = this.width; const h = this.height; - this.ctx.lineTo(-w / 2, h / 2); // 创建水平线 - this.ctx.arcTo(-w / 2, -h / 2, -w / 2 + r, -h / 2, r); - this.ctx.arcTo(w / 2, -h / 2, w / 2, -h / 2 + r, r); - this.ctx.arcTo(w / 2, h / 2, w / 2 - r, h / 2, r); - this.ctx.arcTo(-w / 2, h / 2, -w / 2, h / 2 - r, r); + this.ctx.beginPath() + this._roundRect(-w / 2, - h / 2, w, h, r * 1 || 0); + this.ctx.clip(); + } + if (this.isCircleStyle) { + this.ctx.beginPath() + this.ctx.arc(0, 0, Math.max(this.width, this.height) / 2, 0, Math.PI * 2, false); // 圆形 this.ctx.clip(); } - } - drawSelf() { + if (this.img) { + if (this._showRect) { + const rect = this._showRect; + this.ctx.drawImage(this.img, rect.x, rect.y, rect.width, rect.height, this._offX + rect.x, this._offY + rect.y, rect.width, rect.height); + } else { + if (this._offCtx) { + this._offScreenRender(); + } else { + this.ctx.drawImage(this.img, this._offX, this._offY); + } + } + } + } - if (this._shadowFlag) { + _offScreenRender() { - this.ctx.shadowOffsetX = this._shadowOffsetX; - this.ctx.shadowOffsetY = this._shadowOffsetY; - this.ctx.shadowBlur = this._shadowBlur; - this.ctx.shadowColor = this._shadowColor; - } else { - this.ctx.shadowOffsetX = 0; - this.ctx.shadowOffsetY = 0; - this.ctx.shadowBlur = null; - this.ctx.shadowColor = null; - } + this._offCtx.save(); + this._offCtx.clearRect(0, 0, this.width, this.height); - if (this.img) { - this.ctx.drawImage(this.img, this._offX, this._offY); + this._offCtx.drawImage(this.img, 0, 0); + if (this._maskSpr) { + this._offCtx.globalCompositeOperation = 'destination-in'; + this._offCtx.drawImage(this._maskSpr.img, this._maskSpr.x + this._maskSpr._offX - this._offX , this._maskSpr.y + this._maskSpr._offY - this._offY); } + this.ctx.drawImage(this._offCanvas, this._offX, this._offY); + this._offCtx.restore(); + } + _roundRect(x, y, w, h, r) { + const min_size = Math.min(w, h); + if (r > min_size / 2) r = min_size / 2; + // 开始绘制 + const ctx = this.ctx; + ctx.beginPath(); + ctx.moveTo(x + r, y); + ctx.arcTo(x + w, y, x + w, y + h, r); + ctx.arcTo(x + w, y + h, x, y + h, r); + ctx.arcTo(x, y + h, x, y, r); + ctx.arcTo(x, y, x + w, y, r); + ctx.closePath(); } - updateChildren() { + + updateChildren() { if (this.children.length <= 0) { return; } @@ -257,6 +320,13 @@ export class MySprite extends Sprite { } } + + set bitmapFlag(v) { + this._bitmapFlag = v; + } + get bitmapFlag() { + return this._bitmapFlag; + } set alpha(v) { this._alpha = v; if (this.childDepandAlpha) { @@ -305,7 +375,6 @@ export class MySprite extends Sprite { getBoundingBox() { - const getParentData = (item) => { let px = item.x; @@ -343,11 +412,6 @@ export class MySprite extends Sprite { const width = this.width * Math.abs(data.sx); const height = this.height * Math.abs(data.sy); - // const x = this.x + this._offX * Math.abs(this.scaleX); - // const y = this.y + this._offY * Math.abs(this.scaleY); - // const width = this.width * Math.abs(this.scaleX); - // const height = this.height * Math.abs(this.scaleY); - return {x, y, width, height}; } @@ -758,7 +822,8 @@ export class RichTextOld extends Label { export class RichText extends Label { - disH = 30; + disH = 30; + offW = 10; constructor(ctx?: any) { super(ctx); @@ -788,7 +853,7 @@ export class RichText extends Label { const chr = this.text.split(' '); let temp = ''; const row = []; - const w = selfW - 80; + const w = selfW - this.offW * 2; const disH = (this.fontSize + this.disH) * this.scaleY; @@ -964,28 +1029,28 @@ export class ShapeRectNew extends MySprite { ctx.save(); ctx.beginPath(0); // 从å³ä¸‹è§’顺时针绘制,弧度从0到1/2PI - ctx.arc(width - radius, height - radius, radius, 0, Math.PI / 2); + ctx.arc(width - radius + this._offX, height - radius + this._offY, radius, 0, Math.PI / 2); // 矩形下边线 - ctx.lineTo(radius, height); + ctx.lineTo(radius + this._offX, height + this._offY); // 左下角圆弧,弧度从1/2PI到PI - ctx.arc(radius, height - radius, radius, Math.PI / 2, Math.PI); + ctx.arc(radius + this._offX, height - radius + this._offY, radius, Math.PI / 2, Math.PI); // 矩形左边线 - ctx.lineTo(0, radius); + ctx.lineTo(0 + this._offX, radius + this._offY); // 左上角圆弧,弧度从PI到3/2PI - ctx.arc(radius, radius, radius, Math.PI, Math.PI * 3 / 2); + ctx.arc(radius + this._offX, radius + this._offY, radius, Math.PI, Math.PI * 3 / 2); // 上边线 - ctx.lineTo(width - radius, 0); + ctx.lineTo(width - radius + this._offX, 0 + this._offY); // å³ä¸Šè§’圆弧 - ctx.arc(width - radius, radius, radius, Math.PI * 3 / 2, Math.PI * 2); + ctx.arc(width - radius + this._offX, radius + this._offY, radius, Math.PI * 3 / 2, Math.PI * 2); // å³è¾¹çº¿ - ctx.lineTo(width, height - radius); + ctx.lineTo(width + this._offX, height - radius + this._offY); ctx.closePath(); if (this.fill) { @@ -1020,7 +1085,7 @@ export class MyAnimation extends MySprite { loop = false; playEndFunc; - delayPerUnit = 1; + delayPerUnit = 0.07; restartFlag = false; reverseFlag = false; @@ -1109,8 +1174,9 @@ export class MyAnimation extends MySprite { this.frameArr[this.frameIndex].visible = true; if (this.playEndFunc) { - this.playEndFunc(); + const func = this.playEndFunc; this.playEndFunc = null; + func(); } } @@ -1177,6 +1243,14 @@ export class MyAnimation extends MySprite { export function tweenChange(item, obj, time = 0.8, callBack = null, easing = null, update = null) { + const tween = createTween(item, obj, time, callBack, easing, update) + tween.start(); + + return tween; +} + +export function createTween(item, obj, time = 0.8, callBack = null, easing = null, update = null) { + const tween = new TWEEN.Tween(item).to(obj, time * 1000); if (callBack) { @@ -1192,15 +1266,28 @@ export function tweenChange(item, obj, time = 0.8, callBack = null, easing = nul update(a, b); }); } - - tween.start(); return tween; } +export function tweenQueue(arr) { + + const showOneTween = () => { + const tween = arr.shift(); + if (arr.length > 0) { + tween.onComplete( () => { + showOneTween(); + }); + } + tween.start(); + }; + + showOneTween(); +} + -export function rotateItem(item, rotation, time = 0.8, callBack = null, easing = null) { +export function rotateItem(item, rotation, time = 0.8, callBack = null, easing = null, loop = false) { const tween = new TWEEN.Tween(item).to({ rotation }, time * 1000); @@ -1208,7 +1295,14 @@ export function rotateItem(item, rotation, time = 0.8, callBack = null, easing = tween.onComplete(() => { callBack(); }); + } else if (loop) { + const speed = (rotation - item.rotation) / time; + tween.onComplete(() => { + item.rotation %= 360; + rotateItem(item, item.rotation + speed * time, time, null, easing, true); + }); } + if (easing) { tween.easing(easing); } @@ -1491,7 +1585,7 @@ export function getPosDistance(sx, sy, ex, ey) { return len; } -export function delayCall(callback, second) { +export function delayCall(second, callback) { const tween = new TWEEN.Tween(this) .delay(second * 1000) .onComplete(() => { @@ -1525,10 +1619,15 @@ export function formatTime(fmt, date) { return fmt; } -export function getMinScale(item, maxLen) { - const sx = maxLen / item.width; - const sy = maxLen / item.height; +export function getMinScale(item, maxW, maxH = null) { + if (!maxH) { + maxH = maxW; + } + + const sx = maxW / item.width; + const sy = maxH / item.height; const minS = Math.min(sx, sy); + return minS; } @@ -1571,6 +1670,46 @@ export function jelly(item, time = 0.7) { run(); } +export function jellyPop(item, time) { + + if (item.jellyTween) { + TWEEN.remove(item.jellyTween); + } + + const t = time / 6; + const baseSX = item.scaleX; + const baseSY = item.scaleY; + let index = 0; + + const run = () => { + if (index >= arr.length) { + item.jellyTween = null; + return; + } + const data = arr[index]; + const t = tweenChange(item, {scaleX: data[0], scaleY: data[1]}, data[2], () => { + index ++; + run(); + }, TWEEN.Easing.Sinusoidal.InOut); + item.jellyTween = t; + }; + + + const arr = [ + [baseSX * 1.3, baseSY * 1.3, t], + [baseSX * 0.85, baseSY * 0.85, t * 1], + [baseSX * 1.1, baseSY * 1.1, t * 1], + [baseSX * 0.95, baseSY * 0.95, t * 1], + [baseSX * 1.02, baseSY * 1.02, t * 1], + [baseSX * 1, baseSY * 1, t * 1], + ]; + + + item.setScaleXY(0); + run(); + +} + export function showPopParticle(img, pos, parent, num = 20, minLen = 40, maxLen = 80, showTime = 0.4) { @@ -1672,5 +1811,41 @@ export function shake(item, time = 0.5, callback = null, rate = 1) { } +export function getMaxScale(item, maxW, maxH) { + const sx = maxW / item.width; + const sy = maxH / item.height; + const maxS = Math.max(sx, sy); + return maxS; +} + +export function createSprite(key) { + const image = window.curImages; + const spr = new MySprite(); + spr.init(image.get(key)); + return spr; +} + +export class MyVideo extends MySprite { + + element; + + initVideoElement(videoElement) { + + this.element = videoElement; + this.width = this.element.videoWidth; + this.height = this.element.videoHeight; + + this.element.currentTime = 0.01; + } + + + drawSelf() { + super.drawSelf(); + + this.ctx.drawImage(this.element, 0, 0, this.width, this.height); + } +} + + // --------------- custom class -------------------- diff --git a/src/app/play/play.component.ts b/src/app/play/play.component.ts index f4b8a863d45aa9f51852483802422d4dfacce939..722f061f157a6447b2ffe05ba064b845a7fc5085 100644 --- a/src/app/play/play.component.ts +++ b/src/app/play/play.component.ts @@ -108,6 +108,16 @@ export class PlayComponent implements OnInit, OnDestroy { ngOnDestroy() { window['curCtx'] = null; window.cancelAnimationFrame(this.animationId); + this.cleanAudio(); + } + + + cleanAudio() { + if (this.audioObj) { + for (const key in this.audioObj) { + this.audioObj[key].pause(); + } + } } @@ -141,6 +151,7 @@ export class PlayComponent implements OnInit, OnDestroy { this.canvas.nativeElement.height = this.canvasHeight; window['curCtx'] = this.ctx; + window['curImages'] = this.images; } diff --git a/tslint.json b/tslint.json index 4fcb4b1d413f773db7ea534e2c9d6d29436a819a..92190299d54a20a69f1f724335455dae4ce7a698 100644 --- a/tslint.json +++ b/tslint.json @@ -92,7 +92,8 @@ "variable-name": false, "no-unused-expression": false, - "align": false + "align": false, + "no-string-literal": false }, "rulesDirectory": [ "codelyzer"