Commit 0a66d553 authored by limingzhe's avatar limingzhe

feat: 首次提交

parent 8a51c964
<div class="model-content">
<div style="padding: 20px">
<div style="position: absolute; left: 200px; top: 100px; width: 800px;">
<input type="text" nz-input [(ngModel)]="item.text" (blur)="save()">
<div style="width: 700px">
<app-upload-image-with-preview
[picUrl]="item.pic_url"
(imageUploaded)="onImageUploadSuccess($event, 'pic_url')"
></app-upload-image-with-preview>
<nz-divider nzText="课程标题" nzOrientation="left"></nz-divider>
<nz-form-label nzFor="t_val1">标题1</nz-form-label>
<input style="width: 80%; margin-bottom: 0.5vw" type="text" nz-input placeholder="" [(ngModel)]="item.title.t_val1" (blur)="save()">
<br><nz-form-label nzFor="t_val2">标题2</nz-form-label>
<input style="width: 80%; margin-bottom: 0.5vw" type="text" nz-input placeholder="" [(ngModel)]="item.title.t_val2" (blur)="save()">
<nz-form-control [nzSpan]="6">
<app-audio-recorder id="item.title.audio_url" [audioUrl]="item.title.audio_url"
(audioUploaded)="onAudioUploadSuccess($event, 'audio_url', item.title)">
</app-audio-recorder>
</nz-form-control>
<app-audio-recorder
[audioUrl]="item.audio_url"
(audioUploaded)="onAudioUploadSuccess($event, 'audio_url')"
></app-audio-recorder>
<app-custom-hot-zone></app-custom-hot-zone>
<app-upload-video></app-upload-video>
<app-lesson-title-config></app-lesson-title-config>
</div>
<div style="margin-top: 80px"></div>
<nz-divider nzText="单词" nzOrientation="left"></nz-divider>
<div *ngFor="let it of item.picArr; let i = index" style="padding: 10px; border: 1px solid #ccc; border-radius: 10px; width: 270px; margin-bottom: 20px">
<div style=" display: flex; align-items: center;">
<div style="width: 200px; margin-right: 10px; display: flex; justify-content: center; flex-direction: column">
<h4>单词-{{i+1}}: </h4>
<input type="text" nz-input [(ngModel)]="it.text" (blur)="save()">
<app-audio-recorder
style="margin-top: 5px"
[audioUrl]="it.audio_url"
(audioUploaded)="onAudioUploadSuccess($event, 'audio_url', it)"
></app-audio-recorder>
<button style="width: 150px; margin-top: 5px" nz-button nzType="danger" (click)="deletePic(i)">
删除
</button>
</div>
</div>
</div>
<div *ngIf="item.picArr.length < 10">
<button style="width: 180px; height: 70px;" nz-button nzType="dashed" (click)="addPic()">
<i nz-icon nzType="plus-circle" nzTheme="outline"></i>
添加单词
</button>
</div>
<div style="margin-top: 80px"></div>
<nz-divider nzText="格子" nzOrientation="left"></nz-divider>
<div style="margin-top: 10px; display: flex">
<div *ngFor="let oneRow of item.grid; let x = index" >
<div *ngFor="let oneGrid of oneRow; let y = index" style="padding: 2px;">
<input style="width: 38px" [maxLength]="1" type="text" nz-input [(ngModel)]="oneGrid.text" (blur)="save()" >
</div>
</div>
</div>
</div>
</div>
\ No newline at end of file
......@@ -10,7 +10,7 @@ import {Component, EventEmitter, Input, OnDestroy, OnChanges, OnInit, Output, Ap
export class FormComponent implements OnInit, OnChanges, OnDestroy {
// 储存数据用
saveKey = "test_0011";
saveKey = 'ym_3_29';
// 储存对象
item;
......@@ -30,6 +30,7 @@ export class FormComponent implements OnInit, OnChanges, OnDestroy {
if (data) {
this.item = data;
}
console.log('data:', data);
this.init();
this.changeDetectorRef.markForCheck();
......@@ -50,7 +51,19 @@ export class FormComponent implements OnInit, OnChanges, OnDestroy {
init() {
if (!this.item.logicX) {
this.item.logicX = 13;
}
if (!this.item.logicY) {
this.item.logicY = 9;
}
if (!this.item.picArr) {
this.item.picArr = [];
}
if (!this.item.title) {
this.item.title = {};
}
this.gridSizeSave();
}
......@@ -58,9 +71,11 @@ export class FormComponent implements OnInit, OnChanges, OnDestroy {
* 储存图片数据
* @param e
*/
onImageUploadSuccess(e, key) {
this.item[key] = e.url;
onImageUploadSuccess(e, key, item = null) {
if (item == null) {
item = this.item;
}
item[key] = e.url;
this.save();
}
......@@ -68,9 +83,64 @@ export class FormComponent implements OnInit, OnChanges, OnDestroy {
* 储存音频数据
* @param e
*/
onAudioUploadSuccess(e, key) {
onAudioUploadSuccess(e, key, item = null) {
console.log(' key, item:', item);
if (item == null) {
item = this.item;
}
item[key] = e.url;
this.save();
}
addPic() {
console.log(' in add Pic');
if (!this.item.picArr) {
this.item.picArr = [];
}
this.item.picArr.push(
{
text: '',
audio_url: '',
pic_url: ''
}
)
this.save();
}
deletePic(index) {
this.item.picArr.splice(index, 1);
this.save();
}
gridSizeSave() {
console.log(' in gridSizeSave')
if (!this.item.grid) {
this.item.grid = [];
}
const w = Number(this.item.logicX);
const h = Number(this.item.logicY);
this.item.grid.length = w;
for (let i = 0; i < w; i ++) {
if (!this.item.grid[i]) {
this.item.grid[i] = [];
}
this.item.grid[i].length = h;
for (let j = 0; j < h; j++) {
if (!this.item.grid[i][j]) {
this.item.grid[i][j] = {};
}
}
}
this.item[key] = e.url;
this.save();
}
......
......@@ -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};
}
......@@ -521,6 +585,8 @@ export class Label extends MySprite {
_outLineColor;
constructor(ctx = null) {
super(ctx);
this.init();
......@@ -638,6 +704,22 @@ export class Label extends MySprite {
}
getBoundingBox(): { x: any; width: number; y: any; height: number } {
const rect = super.getBoundingBox();
rect.y += this.anchorY * rect.height - rect.height / 2;
if (this.textAlign == 'left') {
rect.x += this.anchorX * rect.width;
}
if (this.textAlign == 'center') {
rect.x += this.anchorX * rect.width - rect.width / 2;
}
if (this.textAlign == 'right') {
rect.x += this.anchorX * rect.width - rect.width;
}
return rect;
}
drawSelf() {
super.drawSelf();
this.drawText();
......@@ -758,7 +840,8 @@ export class RichTextOld extends Label {
export class RichText extends Label {
disH = 30;
disH = 30;
offW = 10;
constructor(ctx?: any) {
super(ctx);
......@@ -788,7 +871,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 +1047,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 +1103,7 @@ export class MyAnimation extends MySprite {
loop = false;
playEndFunc;
delayPerUnit = 1;
delayPerUnit = 0.07;
restartFlag = false;
reverseFlag = false;
......@@ -1109,8 +1192,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 +1261,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 +1284,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 +1313,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 +1603,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 +1637,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,9 +1688,49 @@ export function jelly(item, time = 0.7) {
run();
}
export function jellyPop(item, time) {
if (item.jellyTween) {
TWEEN.remove(item.jellyTween);
}
export function showPopParticle(img, pos, parent, num = 20, minLen = 40, maxLen = 80, showTime = 0.4) {
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, mapScale = 1) {
for (let i = 0; i < num; i ++) {
......@@ -1587,7 +1744,7 @@ export function showPopParticle(img, pos, parent, num = 20, minLen = 40, maxLen
const randomR = 360 * Math.random();
particle.rotation = randomR;
const randomS = 0.3 + Math.random() * 0.7;
const randomS = (0.3 + Math.random() * 0.7) * mapScale;
particle.setScaleXY(randomS * 0.3);
const randomX = Math.random() * 20 - 10;
......@@ -1672,5 +1829,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 --------------------
......@@ -12,8 +12,27 @@
@font-face
{
font-family: 'BRLNSDB_1';
src: url("../../assets/font/BRLNSDB_1.TTF") ;
}@font-face
{
font-family: 'BRLNSDB';
src: url("../../assets/font/BRLNSDB.TTF") ;
}
@font-face
{
font-family: 'FUTURAB';
src: url("../../assets/font/FUTURAB.TTF") ;
}
@font-face
{
font-family: 'GOTHICB_1';
src: url("../../assets/font/GOTHICB_1.TTF") ;
}
@font-face
{
font-family: 'FZLSJW';
src: url("../../assets/font/FZLSJW.TTF") ;
}
<div class="game-container" #wrap>
<canvas id="canvas" #canvas></canvas>
</div>
<label style="font-family: 'BRLNSDB_1'; opacity: 0; position: absolute; top: 0px">1</label>
<label style="font-family: 'BRLNSDB'; opacity: 0; position: absolute; top: 0px">1</label>
<label style="font-family: 'FUTURAB'; opacity: 0; position: absolute; top: 0px">1</label>
<label style="font-family: 'GOTHICB_1'; opacity: 0; position: absolute; top: 0px">1</label>
<label style="font-family: 'FZLSJW'; opacity: 0; position: absolute; top: 0px">1</label>
import {Component, ElementRef, ViewChild, OnInit, Input, OnDestroy, HostListener} from '@angular/core';
import {
createSprite, delayCall, getAngleByPos, getPosDistance,
Label,
MySprite, tweenChange,
MySprite, randomSortByArr, removeItemFromArr, ShapeRect, ShapeRectNew, showPopParticle, tweenChange,
} from './Unit';
import {res, resAudio} from './resources';
import {Subject} from 'rxjs';
import {debounceTime} from 'rxjs/operators';
import {debounceTime, max} from 'rxjs/operators';
import TWEEN from '@tweenjs/tween.js';
......@@ -57,7 +58,7 @@ export class PlayComponent implements OnInit, OnDestroy {
canvasLeft;
canvasTop;
saveKey = 'test_0011';
saveKey = 'ym_3_29';
btnLeft;
......@@ -68,6 +69,23 @@ export class PlayComponent implements OnInit, OnDestroy {
canTouch = true;
curPic;
private title1: Label;
private t1Bg: any;
private title2: Label;
private bgRect: ShapeRect;
private gridBg: any;
private gridObj: {};
private wordArr: any;
private curStrip: any;
private startGrid: any;
private endGrid: any;
private curWord: any;
private curGridSprArr: any[];
private stripColorArr: any[];
private stripColodId: 0;
private timeId: NodeJS.Timeout;
private isShowBallon: boolean;
private particleLayer: any;
@HostListener('window:resize', ['$event'])
onResize(event) {
......@@ -86,7 +104,7 @@ export class PlayComponent implements OnInit, OnDestroy {
if (data && typeof data == 'object') {
this.data = data;
}
// console.log('data:' , data);
console.log('data:' , data);
// 初始化 各事件监听
this.initListener();
......@@ -108,6 +126,17 @@ export class PlayComponent implements OnInit, OnDestroy {
ngOnDestroy() {
window['curCtx'] = null;
window.cancelAnimationFrame(this.animationId);
this.cleanAudio();
clearTimeout(this.timeId);
}
cleanAudio() {
if (this.audioObj) {
for (const key in this.audioObj) {
this.audioObj[key].pause();
}
}
}
......@@ -141,6 +170,7 @@ export class PlayComponent implements OnInit, OnDestroy {
this.canvas.nativeElement.height = this.canvasHeight;
window['curCtx'] = this.ctx;
window['curImages'] = this.images;
}
......@@ -270,7 +300,7 @@ export class PlayComponent implements OnInit, OnDestroy {
}
playAudio(key, now = false, callback = null) {
playAudio(key, now = true, callback = null) {
const audio = this.audioObj[key];
if (audio) {
......@@ -432,9 +462,13 @@ export class PlayComponent implements OnInit, OnDestroy {
*/
initDefaultData() {
if (!this.data.pic_url) {
this.data.pic_url = 'assets/play/default/pic.jpg';
this.data.pic_url_2 = 'assets/play/default/pic.jpg';
if (!this.data.grid) {
const strData = '{"logicX":10,"logicY":10,"grid":[[{},{},{},{},{},{},{},{},{},{}],[{},{},{},{},{},{},{},{},{},{}],[{},{},{},{"text":"a"},{"text":"a"},{},{},{},{},{}],[{},{},{},{"text":"b"},{"text":"p"},{},{},{},{},{}],[{},{},{},{"text":"c"},{"text":"p"},{"text":"d"},{},{},{},{}],[{},{},{},{},{"text":"l"},{"text":"e"},{},{},{},{}],[{},{},{},{},{"text":"e"},{"text":"f"},{},{},{},{}],[{},{},{},{},{},{},{},{},{},{}],[{},{},{},{},{},{},{},{},{},{}],[{},{},{},{},{},{},{},{},{},{}]],"picArr":[{"text":"apple","audio_url":"assets/play/default/apple.mp3","pic_url":"assets/play/default/apple.png"}]}'
this.data = JSON.parse(strData);
this.data.title = {
t_val1: "C",
t_val2: "Read, find and circle."
};
}
}
......@@ -455,11 +489,19 @@ export class PlayComponent implements OnInit, OnDestroy {
initAudio() {
// 音频资源
this.addUrlToAudioObj(this.data.audio_url);
this.addUrlToAudioObj(this.data.audio_url_2);
this.addUrlToAudioObj(this.data.title.audio_url);
this.data.picArr.forEach((item) => {
this.addUrlToAudioObj(item.audio_url);
})
// 音效
this.addUrlToAudioObj('click', this.rawAudios.get('click'), 0.3);
this.addUrlToAudioObj('right', this.rawAudios.get('right'), 1);
this.addUrlToAudioObj('wrong', this.rawAudios.get('wrong'), 0.5);
this.addUrlToAudioObj('click', this.rawAudios.get('click'), 0.2);
this.addUrlToAudioObj('pop', this.rawAudios.get('pop'), 0.7);
this.addUrlToAudioObj('finish', this.rawAudios.get('finish'), 0.3);
}
......@@ -481,7 +523,20 @@ export class PlayComponent implements OnInit, OnDestroy {
this.renderArr = [];
const colorArr = [
'#ee393c',
'#9500ee',
'#3821fb',
'#4e9312',
'#fe6702',
'#17d8c8',
'#f5c001',
'#0095ff',
'#ed2e9c',
'#b65f15',
];
this.stripColorArr = randomSortByArr(colorArr);
this.stripColodId = 0;
}
......@@ -493,187 +548,565 @@ export class PlayComponent implements OnInit, OnDestroy {
initView() {
this.initPic();
this.initBg();
this.initTitle();
this.initWords();
this.initGrid();
this.initParticleLayer();
// this.initPic();
this.initBottomPart();
// this.initBottomPart();
}
initBottomPart() {
initBg() {
// 背景
const bg = new ShapeRect();
bg.setSize(this.canvasWidth, this.canvasHeight);
bg.fillColor = '#ffdb84';
this.renderArr.push(bg);
const bgRect2 = new ShapeRect();
bgRect2.setSize(57, 65);
bgRect2.fillColor = '#fdcd00';
const sx2 = this.canvasWidth / this.canvasBaseW;
bgRect2.setScaleXY(sx2);
bgRect2.x = 65 * sx2;
this.t1Bg = bgRect2;
this.renderArr.push(bgRect2);
const letterbg = new ShapeRectNew();
letterbg.setSize(923, 600, 20);
letterbg.setScaleXY(this.mapScale);
letterbg.fillColor = '#fdf8e9';
letterbg.x = this.canvasWidth - letterbg.width * letterbg.scaleX - 90 * this.mapScale;
letterbg.y = this.canvasHeight - letterbg.height * letterbg.scaleY - 30 * this.mapScale;
letterbg.setShadow(0, 5, 7, 'rgba(0, 0, 0, 0.4)');
// letterbg.setShadow()
this.renderArr.push(letterbg);
this.gridBg = letterbg;
// const gridBg = createSprite('grid_bg');
// this.bgRight.addChild(gridBg, -2);
// gridBg.x = this.gridBg.x;
// gridBg.y = this.gridBg.y;
const stripLayer = createSprite('');
this.gridBg.addChild(stripLayer);
this.gridBg['stripLayer'] = stripLayer;
// this.gridBg = gridBg;
}
const btnLeft = new MySprite();
btnLeft.init(this.images.get('btn_left'));
btnLeft.x = this.canvasWidth - 150 * this.mapScale;
btnLeft.y = this.canvasHeight - 100 * this.mapScale;
initTitle() {
//小标题
console.log("title" + this.data);
this.title1 = new Label();
this.title1.text = this.data.title.t_val1;
this.title1.fontName = 'BRLNSDB';
this.title1.fontColor = '#ab5b22';
this.title1.fontSize = 55;
this.title1.textAlign = 'center';
this.title1.refreshSize();
this.t1Bg.addChild(this.title1);
this.title1.setMaxSize(52);
this.title1.x = this.t1Bg.width / 2;
this.title1.y = this.t1Bg.height / 2;
//大标题
const bgRect = new ShapeRect();
bgRect.setSize(1000, 60);
bgRect.init();
bgRect.fillColor = '#F7CB47';
bgRect.alpha = 0;
this.title2 = new Label();
this.title2.text = this.data.title.t_val2;
this.title2.fontName = 'FUTURAB';
this.title2.fontColor = '#040404';
this.title2.fontSize = 32 * this.t1Bg.scaleX;
this.title2.textAlign = 'left';
this.title2.setMaxSize(1000);
this.title2.x = this.t1Bg.x + (this.t1Bg.width + 10) * this.t1Bg.scaleX;
this.title2.y = this.t1Bg.y + (this.t1Bg.height / 2 + 8) * this.t1Bg.scaleY;
this.title2.refreshSize();
this.renderArr.push(this.title2);
this.renderArr.push(bgRect);
this.bgRect = bgRect;
btnLeft.setScaleXY(this.mapScale);
}
this.renderArr.push(btnLeft);
this.btnLeft = btnLeft;
mapDown(event) {
const btnRight = new MySprite();
btnRight.init(this.images.get('btn_right'));
btnRight.x = this.canvasWidth - 50 * this.mapScale;
btnRight.y = this.canvasHeight - 100 * this.mapScale;
btnRight.setScaleXY(this.mapScale);
if (!this.canTouch) {
return;
}
this.renderArr.push(btnRight);
if (this.curStrip) {
this.cleanCurStrip();
return false;
}
this.btnRight = btnRight;
}
initPic() {
for (let i = 0; i < this.wordArr.length; i++) {
if (this.checkClickTarget(this.wordArr[i])) {
this.clickedWord(this.wordArr[i]);
return;
}
}
const maxW = this.canvasWidth * 0.7;
for (let x in this.gridObj) {
for (let y in this.gridObj[x]) {
if (this.checkClickTarget(this.gridObj[x][y])) {
this.clickedGrid(this.gridObj[x][y]);
return;
}
}
}
const pic1 = new MySprite();
pic1.init(this.images.get(this.data.pic_url));
pic1.x = this.canvasWidth / 2;
pic1.y = this.canvasHeight / 2;
pic1.setScaleXY(maxW / pic1.width);
this.renderArr.push(pic1);
this.pic1 = pic1;
if (this.checkClickTarget(this.title2)) {
console.log('aaa');
this.playAudio(this.data.title.audio_url);
return;
}
}
const label1 = new Label();
label1.text = this.data.text;
label1.textAlign = 'center';
label1.fontSize = 50;
label1.fontName = 'BRLNSDB';
label1.fontColor = '#ffffff';
mapMove(event) {
if (!this.curStrip) {
return;
}
for (let x in this.gridObj) {
for (let y in this.gridObj[x]) {
if (this.checkClickTarget(this.gridObj[x][y])) {
if (this.gridObj[x][y] != this.startGrid) {
this.refreshCurStrip(this.gridObj[x][y]);
return;
}
}
}
}
}
mapUp(event) {
if (this.curStrip) {
this.checkIsWord();
this.cleanCurStrip();
}
}
pic1.addChild(label1);
update() {
// ----------------------------------------------------------
this.animationId = window.requestAnimationFrame(this.update.bind(this));
// 清除画布内容
this.ctx.clearRect(0, 0, this.canvasWidth, this.canvasHeight);
// tween 更新动画
TWEEN.update();
// ----------------------------------------------------------
const pic2 = new MySprite();
pic2.init(this.images.get(this.data.pic_url_2));
pic2.x = this.canvasWidth / 2 + this.canvasWidth;
pic2.y = this.canvasHeight / 2;
pic2.setScaleXY(maxW / pic2.width);
this.renderArr.push(pic2);
this.pic2 = pic2;
this.updateArr(this.renderArr);
this.particleLayer.update();
this.curPic = pic1;
}
btnLeftClicked() {
private initWords() {
this.wordArr = [];
const scale = this.gridBg.scaleX;
const maxWidth = 245;
const itemH = 50;
const disH = 10;
const baseX = this.gridBg.x / 2 - maxWidth / 2 * scale;
const baseY = (this.gridBg.height * this.gridBg.scaleY - (itemH + disH) * this.data.picArr.length * scale) / 2 + this.gridBg.y;
this.data.picArr.forEach((item, i) => {
const word = this.getWordBg(item, maxWidth);
word.setScaleXY(scale);
word.setShadow(0, 3, 4, 'rgba(0, 0, 0, 0.5)');
word['top'].setShadow(0, 3, 4, 'rgba(0, 0, 0, 0.5)');
word.x = baseX + (maxWidth ) / 2 * scale;
word.y = baseY + i * (disH + itemH) * scale;
this.lastPage();
this.wordArr.push(word);
this.renderArr.push(word);
});
}
btnRightClicked() {
private getWordBg(item: any, maxLen) {
const wordBg = new ShapeRectNew();
// wordBg.setSize(50, 50, 25);
wordBg.setScaleXY(this.mapScale);
wordBg.fillColor = '#a6b500';
const wordTop = new ShapeRectNew();
wordTop.alpha = 0;
wordTop.anchorX = 0.5;
wordTop.anchorY = 0.5;
wordBg['top'] = wordTop;
wordBg.addChild(wordTop);
wordBg.anchorX = 0.5;
wordBg.anchorY = 0.5;
this.nextPage();
const label = new Label();
label.text = item.text;
label.fontColor = '#fff';
label.fontName = 'BRLNSDB_1';
label.textAlign = 'center';
label.refreshSize();
const min = 100;
const minMax = Math.max(min, label.width * 1.2)
wordBg.setSize(Math.min(maxLen , minMax), 50, 25);
wordTop.setSize(Math.min(maxLen , minMax), 50, 25);
// label.x = wordBg.width / 2;
// label.y = wordBg.height / 2;
label.setMaxSize(wordBg.width * 0.9);
wordBg.addChild(label);
wordBg['data'] = item;
return wordBg;
}
lastPage() {
if (this.curPic == this.pic1) {
return;
private initGrid() {
this.gridObj = {};
const numX = Number(this.data.logicX);
const numY = Number(this.data.logicY);
const len = 56;
const dis = 8;
const baseX = -(len * numX + dis * (numX - 1)) / 2 + len / 2 + this.gridBg.width / 2;
let baseY = -(len * (numY) + dis * (numY - 1)) / 2 + len / 2 + this.gridBg.height / 2;
const grid = this.data.grid;
for (let j = 0; j < Number(this.data.logicY); j++) {
for (let i = 0; i < Number(this.data.logicX); i++) {
if (!this.gridObj[i.toString()]) {
this.gridObj[i.toString()] = {};
}
const gridData = grid[i][j];
const gridSpr = this.createGridRect(gridData, len);
gridSpr.x = baseX + i * (len + dis);
gridSpr.y = baseY;
this.gridBg.addChild(gridSpr);
gridSpr['logicX'] = i.toString();
gridSpr['logicY'] = j.toString();
this.gridObj[i.toString()][j.toString()] = gridSpr;
}
baseY += (len + dis);
}
}
this.canTouch = false;
private createGridRect(data, len) {
const grid = new MySprite();
const shapeRect = new ShapeRect();
shapeRect.setSize(len, len);
shapeRect.x = - len / 2;
shapeRect.y = - len / 2;
shapeRect.visible = false;
grid.addChild(shapeRect);
if (data.text) {
const label = new Label()
label.text = data.text;
label.setMaxSize(len * 0.9);
label.textAlign = 'center';
label.fontName = 'FZLSJW';
label.fontSize = 56;
label.fontColor = '#000';
label.y = -3;
grid.addChild(label);
grid['label'] = label;
}
grid.width = len;
grid.height = len;
grid.anchorX = 0.5;
grid.anchorY = 0.5;
grid['data'] = data;
return grid;
}
const moveLen = this.canvasWidth;
tweenChange(this.pic1, {x: this.pic1.x + moveLen}, 1);
tweenChange(this.pic2, {x: this.pic2.x + moveLen}, 1, () => {
this.canTouch = true;
this.curPic = this.pic1;
private cleanCurStrip() {
const strip = this.curStrip;
tweenChange(strip, {alpha: 0}, 0.1, () => {
strip.parent.removeChild(this.curStrip);
});
this.curStrip = null;
}
nextPage() {
private checkIsWord() {
if (this.curPic == this.pic2) {
if (this.startGrid == this.endGrid) {
if(this.startGrid.audio) {
this.startGrid.audio.play()
}
return;
}
this.canTouch = false;
const word = this.getWord();
const moveLen = this.canvasWidth;
tweenChange(this.pic1, {x: this.pic1.x - moveLen}, 1);
tweenChange(this.pic2, {x: this.pic2.x - moveLen}, 1, () => {
this.canTouch = true;
this.curPic = this.pic2;
});
}
for (let i = 0; i < this.wordArr.length; i++) {
const item = this.wordArr[i];
if (!item.isCheckEnd && item.data && word == item.data.text) {
this.showWordRight(item);
item.isCheckEnd = true;
this.checkGameEnd();
return;
}
}
pic1Clicked() {
this.playAudio(this.data.audio_url);
}
pic2Clicked() {
this.playAudio(this.data.audio_url_2);
this.playAudio('wrong');
}
private getWord() {
const startNumX = Number(this.startGrid['logicX']);
const startNumY = Number(this.startGrid['logicY']);
const endNumX = Number(this.endGrid['logicX']);
const endNumY = Number(this.endGrid['logicY']);
let subX = endNumX - startNumX;
let subY = endNumY - startNumY;
const loopNum = Math.max(Math.abs(subX), Math.abs(subY));
subX = subX / loopNum;
subY = subY / loopNum;
this.curGridSprArr = [];
let word = '';
for (let i = 0; i <= loopNum; i++) {
const logicX = (startNumX + subX * i).toString();
const logicY = (startNumY + subY * i).toString();
const gridSpr = this.gridObj[logicX][logicY];
mapDown(event) {
this.curGridSprArr.push(gridSpr);
if (!this.canTouch) {
return;
word += gridSpr['data'].text || ' ';
}
return word;
}
if ( this.checkClickTarget(this.btnLeft) ) {
this.btnLeftClicked();
return;
}
if ( this.checkClickTarget(this.btnRight) ) {
this.btnRightClicked();
return;
private checkGameEnd() {
const isGameEnd = this.wordArr.every((word) => {
return word.isCheckEnd;
});
if (isGameEnd) {
this.gameEnd();
}
}
if ( this.checkClickTarget(this.pic1) ) {
this.pic1Clicked();
private gameEnd() {
this.showBallonAnimation();
this.playAudio('finish');
}
private refreshCurStrip(endGrid) {
if (this.endGrid == endGrid) {
return;
}
if ( this.checkClickTarget(this.pic2) ) {
this.pic2Clicked();
const x1 = Number(this.startGrid['logicX']);
const y1 = Number(this.startGrid['logicY']);
const x2 = Number(endGrid['logicX']);
const y2 = Number(endGrid['logicY']);
const angle = Math.round( getAngleByPos(x1, y1, x2, y2) );
if (angle % 45 !== 0) {
return;
}
const len = getPosDistance(this.startGrid.x, this.startGrid.y, endGrid.x, endGrid.y);
this.curStrip.width = len + this.curStrip.height;
this.curStrip.rotation = angle - 90;
this.curStrip.anchorX = this.curStrip.height / 2 / this.curStrip.width;
console.log('angle: ', angle);
this.endGrid = endGrid;
}
mapMove(event) {
private clickedWord(word: any) {
this.playAudio(word.data.audio_url);
}
mapUp(event) {
private createStrip(len) {
const strip = new ShapeRectNew();
strip.setSize(len, len, len / 2);
strip.anchorX = 0.5;
strip.anchorY = 0.5;
strip.fillColor = this.stripColorArr[this.stripColodId];
strip.alpha = 0.72;
return strip;
}
private clickedGrid(gridSpr: any) {
const strip = this.createStrip(gridSpr.width * 1.05);
strip.x = gridSpr.x;
strip.y = gridSpr.y;
update() {
// console.log('gridSpr.logicX: ', gridSpr.logicX);
// console.log('gridSpr.logicY: ', gridSpr.logicY);
// ----------------------------------------------------------
this.animationId = window.requestAnimationFrame(this.update.bind(this));
// 清除画布内容
this.ctx.clearRect(0, 0, this.canvasWidth, this.canvasHeight);
// tween 更新动画
TWEEN.update();
// ----------------------------------------------------------
this.gridBg.stripLayer.addChild(strip);
this.curStrip = strip;
this.startGrid = this.endGrid = gridSpr;
this.playAudio('click');
}
private createRightStrip() {
const strip = this.curStrip;
const rightStrip = new ShapeRectNew();
rightStrip.setSize(strip.width, strip.height, strip.radius);
rightStrip.anchorX = strip.anchorX;
rightStrip.anchorY = strip.anchorY;
rightStrip.rotation = strip.rotation;
rightStrip.x = strip.x;
rightStrip.y = strip.y;
rightStrip.fillColor = this.stripColorArr[this.stripColodId];
rightStrip.alpha = 0.72;
return rightStrip;
}
this.updateArr(this.renderArr);
private changeLetterColor(item) {
this.curGridSprArr.forEach((gridSpr) => {
const label = gridSpr['label'];
tweenChange(label, {alpha: 0} , 0.3, () => {
label.fontColor = '#ffffff';
tweenChange(label, {alpha: 1}, 0.3);
});
gridSpr['audio'] = this.audioObj[item.data.audio_url];
});
}
private showWordRight(item: any) {
console.log(' in showWordRight')
const audio = this.audioObj[item.data.audio_url];
this.playAudio('right', null, () => {
if (audio) {
audio.play();
}
});
const rightStrip = this.createRightStrip();
this.gridBg.stripLayer.addChild(rightStrip);
rightStrip.alpha = 0;
tweenChange(rightStrip, {alpha: 0.72}, 0.5, () => {
}, TWEEN.Easing.Cubic.In);
this.changeLetterColor(item);
this.changeWordBgColor(item, rightStrip.fillColor);
this.stripColodId ++;
}
private changeWordBgColor(wordBg: any, fillColor) {
wordBg.top.fillColor = fillColor;
tweenChange(wordBg, {alpha: 0}, 1);
tweenChange(wordBg.top, {alpha: 1}, 0.5);
const rect = wordBg.getBoundingBox();
tweenChange(wordBg, {scaleX: 1.2 * this.mapScale, scaleY: 1.2 * this.mapScale}, 0.15, () => {
tweenChange(wordBg, {scaleX: this.mapScale, scaleY: this.mapScale}, 0.15, () => {
}, TWEEN.Easing.Cubic.In);
}, TWEEN.Easing.Cubic.Out);
setTimeout(() => {
this.playAudio('pop');
showPopParticle(this.images.get('dot'), {x: rect.x + rect.width / 2, y: rect.y + rect.height / 2}, this.particleLayer, 20, 40 * this.mapScale, 80 * this.mapScale, 0.5, this.mapScale);
}, 100);
}
private showBallonAnimation() {
this.isShowBallon = true;
this.showOneBallon();
setTimeout(() => {
this.isShowBallon = false;
}, 2700);
}
private showOneBallon() {
console.log(' in showBallonAnima');
const getBallon = () => {
const ballonId = Math.floor( Math.random() * 6 );
const ballon = createSprite('ballon_' + ballonId);
const randomS = 0.8 + 0.2 * Math.random();
ballon.setScaleXY(randomS * this.mapScale);
const randomX = this.canvasWidth * Math.random();
ballon.x = randomX;
ballon.y = this.canvasHeight + ballon.height / 2 * ballon.scaleY;
return ballon;
};
const ballon = getBallon();
this.renderArr.push(ballon);
const time = Math.floor( (1 + Math.random() * 2) * 100 ) / 100 ;
tweenChange(ballon, {y: -ballon.height / 2 * ballon.scaleY}, time, () => {
removeItemFromArr(this.renderArr, ballon);
}, TWEEN.Easing.Quadratic.In);
this.timeId = setTimeout(() => {
if (this.isShowBallon) {
this.showOneBallon();
}
}, 20 + 50 * Math.random());
}
private initParticleLayer() {
this.particleLayer = new MySprite();
}
}
const res = [
// ['bg', "assets/play/bg.jpg"],
['btn_left', "assets/play/btn_left.png"],
['btn_right', "assets/play/btn_right.png"],
// ['text_bg', "assets/play/text_bg.png"],
['dot', "assets/play/dot.png"],
['ballon_1', "assets/play/ballon/1.png"],
['ballon_2', "assets/play/ballon/2.png"],
['ballon_3', "assets/play/ballon/3.png"],
['ballon_4', "assets/play/ballon/4.png"],
['ballon_5', "assets/play/ballon/5.png"],
['ballon_6', "assets/play/ballon/6.png"],
];
......@@ -11,7 +15,12 @@ const res = [
const resAudio = [
['right', "assets/play/music/right.mp3"],
['wrong', "assets/play/music/wrong.mp3"],
['click', "assets/play/music/click.mp3"],
['pop', "assets/play/music/pop.mp3"],
['finish', "assets/play/music/finish.mp3"],
['apple', "assets/play/music/apple.mp3"],
];
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment