Commit 0fe5f9bf authored by Li Mingzhe's avatar Li Mingzhe

feat: 首次提交

parent 8a51c964
<div class="model-content"> <div class="model-content">
<div style="padding: 30px">
<div style="position: absolute; left: 200px; top: 100px; width: 800px;"> <div style="display: flex; align-items: center; ">
<h2> 题干类型: </h2>
<nz-radio-group [(ngModel)]="item.questionType" style="margin-left: 20px; margin-top: -11px" (ngModelChange)="save()">
<label nz-radio nzValue="text">文本</label>
<label nz-radio nzValue="pic">图片</label>
<label nz-radio nzValue="audio">音频</label>
<label nz-radio nzValue="video">视频</label>
</nz-radio-group>
</div>
<input type="text" nz-input [(ngModel)]="item.text" (blur)="save()"> <div style="width: 700px">
<div *ngIf="item.questionType == 'text'">
<input type="text" nz-input [(ngModel)]="item.text" (blur)="save()">
</div>
<app-upload-image-with-preview <div *ngIf="item.questionType == 'pic'" style="width: 80%">
[picUrl]="item.pic_url" <app-upload-image-with-preview
(imageUploaded)="onImageUploadSuccess($event, 'pic_url')" [picUrl]="item.pic_url"
></app-upload-image-with-preview> (imageUploaded)="onImageUploadSuccess($event, 'pic_url')"
></app-upload-image-with-preview>
</div>
<app-audio-recorder <div *ngIf="item.questionType == 'audio'">
[audioUrl]="item.audio_url" <app-audio-recorder
(audioUploaded)="onAudioUploadSuccess($event, 'audio_url')" [audioUrl]="item.audio_url"
></app-audio-recorder> (audioUploaded)="onAudioUploadSuccess($event, 'audio_url')"
<app-custom-hot-zone></app-custom-hot-zone> ></app-audio-recorder>
<app-upload-video></app-upload-video> </div>
<app-lesson-title-config></app-lesson-title-config>
<div *ngIf="item.questionType == 'video'">
<app-upload-video
(videoUploaded)="onVideoUploadSuccess($event)"
[item]="item"
[videoUrl]="item.video_url"></app-upload-video>
</div>
</div>
<nz-divider style=" margin-top: 80px; margin-bottom: 80px;"></nz-divider>
<div style="display: flex; align-items: center;">
<h2> 答案类型: </h2>
<nz-radio-group [(ngModel)]="item.answerType" style="margin-left: 20px; margin-top: -11px" (ngModelChange)="save()">
<label nz-radio nzValue="text">文本</label>
<label nz-radio nzValue="pic">图片</label>
</nz-radio-group>
</div>
<div *ngFor="let it of item.answerArr; let i = index">
<div style="margin-bottom: 30px; width : 500px; border: 1px solid #ccc; border-radius: 10px; padding: 5px;">
<span> 答案{{i+1}}: </span>
<nz-radio-group style="margin-left: 20px; margin-bottom: 5px;" [(ngModel)]="it.answerRight" (ngModelChange)="save()">
<label nz-radio nzValue="0">错误</label>
<label nz-radio nzValue="1">正确</label>
<button style="margin-left: 200px" nz-button nzType="danger" nzsize="small" (click)="deleteAnswer(i)">删除</button>
</nz-radio-group>
<input *ngIf="item.answerType == 'text'" type="text" nz-input [(ngModel)]="it.text" (blur)="save()">
<app-upload-image-with-preview
*ngIf="item.answerType == 'pic'"
[picUrl]="it.pic_url"
(imageUploaded)="onImageUploadSuccess($event, 'pic_url', it)"
></app-upload-image-with-preview>
</div>
</div>
</div>
<div *ngIf="item.answerArr.length < 4" style="padding: 30px;" (click)="addAnswer()">
<button nz-button nzType="dashed" style="width: 200px; height: 100px; margin-top: -30px">添加答案</button>
</div> </div>
</div> </div>
\ No newline at end of file
...@@ -10,7 +10,7 @@ import {Component, EventEmitter, Input, OnDestroy, OnChanges, OnInit, Output, Ap ...@@ -10,7 +10,7 @@ import {Component, EventEmitter, Input, OnDestroy, OnChanges, OnInit, Output, Ap
export class FormComponent implements OnInit, OnChanges, OnDestroy { export class FormComponent implements OnInit, OnChanges, OnDestroy {
// 储存数据用 // 储存数据用
saveKey = "test_0011"; saveKey = "pu06";
// 储存对象 // 储存对象
item; item;
...@@ -23,7 +23,6 @@ export class FormComponent implements OnInit, OnChanges, OnDestroy { ...@@ -23,7 +23,6 @@ export class FormComponent implements OnInit, OnChanges, OnDestroy {
ngOnInit() { ngOnInit() {
this.item = {}; this.item = {};
// 获取存储的数据 // 获取存储的数据
(<any> window).courseware.getData((data) => { (<any> window).courseware.getData((data) => {
...@@ -51,6 +50,33 @@ export class FormComponent implements OnInit, OnChanges, OnDestroy { ...@@ -51,6 +50,33 @@ export class FormComponent implements OnInit, OnChanges, OnDestroy {
init() { init() {
if (!this.item.questionType) {
this.item.questionType = 'text';
this.item.answerType = 'text';
this.item.answerArr = [];
// for (let i = 0; i < 4; i++) {
// this.item.answerArr.push({
// text: '',
// pic_url: '',
// answerRight: '0',
// });
// }
}
}
deleteAnswer(i) {
this.item.answerArr.splice(i, 1);
this.save();
}
addAnswer() {
this.item.answerArr.push({
text: '',
pic_url: '',
answerRight: '0',
});
this.save();
} }
...@@ -58,10 +84,13 @@ export class FormComponent implements OnInit, OnChanges, OnDestroy { ...@@ -58,10 +84,13 @@ export class FormComponent implements OnInit, OnChanges, OnDestroy {
* 储存图片数据 * 储存图片数据
* @param e * @param e
*/ */
onImageUploadSuccess(e, key) { onImageUploadSuccess(e, key, item = null) {
this.item[key] = e.url; if (!item) {
this.save(); item = this.item;
}
item[key] = e.url;
this.save();
} }
/** /**
...@@ -75,6 +104,10 @@ export class FormComponent implements OnInit, OnChanges, OnDestroy { ...@@ -75,6 +104,10 @@ export class FormComponent implements OnInit, OnChanges, OnDestroy {
} }
onVideoUploadSuccess(e) {
this.item.video_url = e.url;
this.save();
}
/** /**
* 储存数据 * 储存数据
......
...@@ -4,6 +4,7 @@ import TWEEN from '@tweenjs/tween.js'; ...@@ -4,6 +4,7 @@ import TWEEN from '@tweenjs/tween.js';
interface AirWindow extends Window { interface AirWindow extends Window {
air: any; air: any;
curCtx: any; curCtx: any;
curImages: any;
} }
declare let window: AirWindow; declare let window: AirWindow;
...@@ -36,7 +37,6 @@ class Sprite { ...@@ -36,7 +37,6 @@ class Sprite {
export class MySprite extends Sprite { export class MySprite extends Sprite {
_width = 0; _width = 0;
...@@ -69,6 +69,13 @@ export class MySprite extends Sprite { ...@@ -69,6 +69,13 @@ export class MySprite extends Sprite {
img; img;
_z = 0; _z = 0;
_showRect;
_bitmapFlag = false;
_offCanvas;
_offCtx;
init(imgObj = null, anchorX: number = 0.5, anchorY: number = 0.5) { init(imgObj = null, anchorX: number = 0.5, anchorY: number = 0.5) {
...@@ -87,6 +94,10 @@ export class MySprite extends Sprite { ...@@ -87,6 +94,10 @@ export class MySprite extends Sprite {
} }
setShowRect(rect) {
this._showRect = rect;
}
setShadow(offX, offY, blur, color = 'rgba(0, 0, 0, 0.3)') { setShadow(offX, offY, blur, color = 'rgba(0, 0, 0, 0.3)') {
...@@ -103,6 +114,8 @@ export class MySprite extends Sprite { ...@@ -103,6 +114,8 @@ export class MySprite extends Sprite {
} }
update($event = null) { update($event = null) {
if (!this.visible && this.childDepandVisible) { if (!this.visible && this.childDepandVisible) {
return; return;
...@@ -139,21 +152,21 @@ export class MySprite extends Sprite { ...@@ -139,21 +152,21 @@ export class MySprite extends Sprite {
//
if (this._radius) { // if (this._radius) {
//
const r = this._radius; // const r = this._radius;
const w = this.width; // const w = this.width;
const h = this.height; // const h = this.height;
//
this.ctx.lineTo(-w / 2, h / 2); // 创建水平线 // 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 + 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, -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 - 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, h / 2 - r, r);
//
this.ctx.clip(); // this.ctx.clip();
} // }
} }
...@@ -176,10 +189,14 @@ export class MySprite extends Sprite { ...@@ -176,10 +189,14 @@ export class MySprite extends Sprite {
if (this.img) { if (this.img) {
this.ctx.drawImage(this.img, this._offX, this._offY);
}
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 {
this.ctx.drawImage(this.img, this._offX, this._offY);
}
}
} }
...@@ -257,6 +274,13 @@ export class MySprite extends Sprite { ...@@ -257,6 +274,13 @@ export class MySprite extends Sprite {
} }
} }
set bitmapFlag(v) {
this._bitmapFlag = v;
}
get bitmapFlag() {
return this._bitmapFlag;
}
set alpha(v) { set alpha(v) {
this._alpha = v; this._alpha = v;
if (this.childDepandAlpha) { if (this.childDepandAlpha) {
...@@ -305,7 +329,6 @@ export class MySprite extends Sprite { ...@@ -305,7 +329,6 @@ export class MySprite extends Sprite {
getBoundingBox() { getBoundingBox() {
const getParentData = (item) => { const getParentData = (item) => {
let px = item.x; let px = item.x;
...@@ -343,11 +366,6 @@ export class MySprite extends Sprite { ...@@ -343,11 +366,6 @@ export class MySprite extends Sprite {
const width = this.width * Math.abs(data.sx); const width = this.width * Math.abs(data.sx);
const height = this.height * Math.abs(data.sy); 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}; return {x, y, width, height};
} }
...@@ -758,7 +776,8 @@ export class RichTextOld extends Label { ...@@ -758,7 +776,8 @@ export class RichTextOld extends Label {
export class RichText extends Label { export class RichText extends Label {
disH = 30; disH = 30;
offW = 10;
constructor(ctx?: any) { constructor(ctx?: any) {
super(ctx); super(ctx);
...@@ -788,7 +807,7 @@ export class RichText extends Label { ...@@ -788,7 +807,7 @@ export class RichText extends Label {
const chr = this.text.split(' '); const chr = this.text.split(' ');
let temp = ''; let temp = '';
const row = []; const row = [];
const w = selfW - 80; const w = selfW - this.offW * 2;
const disH = (this.fontSize + this.disH) * this.scaleY; const disH = (this.fontSize + this.disH) * this.scaleY;
...@@ -1020,7 +1039,7 @@ export class MyAnimation extends MySprite { ...@@ -1020,7 +1039,7 @@ export class MyAnimation extends MySprite {
loop = false; loop = false;
playEndFunc; playEndFunc;
delayPerUnit = 1; delayPerUnit = 0.07;
restartFlag = false; restartFlag = false;
reverseFlag = false; reverseFlag = false;
...@@ -1109,8 +1128,9 @@ export class MyAnimation extends MySprite { ...@@ -1109,8 +1128,9 @@ export class MyAnimation extends MySprite {
this.frameArr[this.frameIndex].visible = true; this.frameArr[this.frameIndex].visible = true;
if (this.playEndFunc) { if (this.playEndFunc) {
this.playEndFunc(); const func = this.playEndFunc;
this.playEndFunc = null; this.playEndFunc = null;
func();
} }
} }
...@@ -1200,7 +1220,7 @@ export function tweenChange(item, obj, time = 0.8, callBack = null, easing = nul ...@@ -1200,7 +1220,7 @@ export function tweenChange(item, obj, time = 0.8, callBack = null, easing = nul
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); const tween = new TWEEN.Tween(item).to({ rotation }, time * 1000);
...@@ -1208,7 +1228,14 @@ export function rotateItem(item, rotation, time = 0.8, callBack = null, easing = ...@@ -1208,7 +1228,14 @@ export function rotateItem(item, rotation, time = 0.8, callBack = null, easing =
tween.onComplete(() => { tween.onComplete(() => {
callBack(); 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) { if (easing) {
tween.easing(easing); tween.easing(easing);
} }
...@@ -1525,10 +1552,15 @@ export function formatTime(fmt, date) { ...@@ -1525,10 +1552,15 @@ export function formatTime(fmt, date) {
return fmt; return fmt;
} }
export function getMinScale(item, maxLen) { export function getMinScale(item, maxW, maxH = null) {
const sx = maxLen / item.width; if (!maxH) {
const sy = maxLen / item.height; maxH = maxW;
}
const sx = maxW / item.width;
const sy = maxH / item.height;
const minS = Math.min(sx, sy); const minS = Math.min(sx, sy);
return minS; return minS;
} }
...@@ -1571,6 +1603,46 @@ export function jelly(item, time = 0.7) { ...@@ -1571,6 +1603,46 @@ export function jelly(item, time = 0.7) {
run(); 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) { export function showPopParticle(img, pos, parent, num = 20, minLen = 40, maxLen = 80, showTime = 0.4) {
...@@ -1672,5 +1744,41 @@ export function shake(item, time = 0.5, callback = null, rate = 1) { ...@@ -1672,5 +1744,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 -------------------- // --------------- custom class --------------------
...@@ -13,7 +13,7 @@ ...@@ -13,7 +13,7 @@
@font-face @font-face
{ {
font-family: 'BRLNSDB'; font-family: 'MMTextBook-Bold';
src: url("../../assets/font/BRLNSDB.TTF") ; src: url("../../assets/font/MMTextBook-Bold.otf") ;
} }
<div style="display: none">
<video [src]="data.video_url" #videoNode></video>
</div>
<div class="game-container" #wrap> <div class="game-container" #wrap>
<canvas id="canvas" #canvas></canvas> <canvas id="canvas" #canvas></canvas>
</div> </div>
<label style="position: absolute; top: 0px; opacity: 0; font-family: 'MMTextBook-Bold'">1</label>
import {Component, ElementRef, ViewChild, OnInit, Input, OnDestroy, HostListener} from '@angular/core';
import { import {
Label, ApplicationRef,
MySprite, tweenChange, ChangeDetectorRef,
Component,
ElementRef,
HostListener,
OnDestroy,
OnInit,
ViewChild
} from '@angular/core';
import {
createSprite,
formatTime,
getMaxScale,
getMinScale, jelly, jellyPop,
Label, moveItem,
MySprite,
MyVideo, removeItemFromArr,
RichText, rotateItem,
shake, ShapeRect,
tweenChange,
} from './Unit'; } from './Unit';
import {res, resAudio} from './resources'; import {res, resAudio} from './resources';
...@@ -13,8 +29,6 @@ import {debounceTime} from 'rxjs/operators'; ...@@ -13,8 +29,6 @@ import {debounceTime} from 'rxjs/operators';
import TWEEN from '@tweenjs/tween.js'; import TWEEN from '@tweenjs/tween.js';
@Component({ @Component({
selector: 'app-play', selector: 'app-play',
templateUrl: './play.component.html', templateUrl: './play.component.html',
...@@ -25,6 +39,8 @@ export class PlayComponent implements OnInit, OnDestroy { ...@@ -25,6 +39,8 @@ export class PlayComponent implements OnInit, OnDestroy {
@ViewChild('canvas', {static: true }) canvas: ElementRef; @ViewChild('canvas', {static: true }) canvas: ElementRef;
@ViewChild('wrap', {static: true }) wrap: ElementRef; @ViewChild('wrap', {static: true }) wrap: ElementRef;
@ViewChild('videoNode', {static: true }) videoNode: ElementRef;
// 数据 // 数据
data; data;
...@@ -57,17 +73,26 @@ export class PlayComponent implements OnInit, OnDestroy { ...@@ -57,17 +73,26 @@ export class PlayComponent implements OnInit, OnDestroy {
canvasLeft; canvasLeft;
canvasTop; canvasTop;
saveKey = 'test_0011'; saveKey = 'pu06';
btnLeft;
btnRight;
pic1;
pic2;
canTouch = true; canTouch = true;
curPic; private oven: MySprite;
private ovenBg: MySprite;
private curAudio: any;
private progressBarBg ;
private currentTime: number;
private isClickedProgress: boolean;
private allBtns: any;
private curVideo: MyVideo;
private videoBtn: MySprite;
private answerArr: any;
private ovenLight: MySprite;
private petalTime: number;
private showPetalFlag: boolean;
private endPageArr: any;
@HostListener('window:resize', ['$event']) @HostListener('window:resize', ['$event'])
onResize(event) { onResize(event) {
...@@ -86,7 +111,7 @@ export class PlayComponent implements OnInit, OnDestroy { ...@@ -86,7 +111,7 @@ export class PlayComponent implements OnInit, OnDestroy {
if (data && typeof data == 'object') { if (data && typeof data == 'object') {
this.data = data; this.data = data;
} }
// console.log('data:' , data); console.log('data:' , data);
// 初始化 各事件监听 // 初始化 各事件监听
this.initListener(); this.initListener();
...@@ -141,6 +166,7 @@ export class PlayComponent implements OnInit, OnDestroy { ...@@ -141,6 +166,7 @@ export class PlayComponent implements OnInit, OnDestroy {
this.canvas.nativeElement.height = this.canvasHeight; this.canvas.nativeElement.height = this.canvasHeight;
window['curCtx'] = this.ctx; window['curCtx'] = this.ctx;
window['curImages'] = this.images;
} }
...@@ -270,7 +296,7 @@ export class PlayComponent implements OnInit, OnDestroy { ...@@ -270,7 +296,7 @@ export class PlayComponent implements OnInit, OnDestroy {
} }
playAudio(key, now = false, callback = null) { playAudio(key, now = true, callback = null) {
const audio = this.audioObj[key]; const audio = this.audioObj[key];
if (audio) { if (audio) {
...@@ -313,6 +339,15 @@ export class PlayComponent implements OnInit, OnDestroy { ...@@ -313,6 +339,15 @@ export class PlayComponent implements OnInit, OnDestroy {
pr.push(a); pr.push(a);
}); });
// if (this.videoNode && this.videoNode.nativeElement) {
// const a = this.preloadVideo(this.videoNode.nativeElement)
// .then(() => {
// console.log('video load end');
// })
// .catch(err => console.log(err));
// pr.push(a);
// }
return Promise.all(pr); return Promise.all(pr);
} }
...@@ -340,6 +375,19 @@ export class PlayComponent implements OnInit, OnDestroy { ...@@ -340,6 +375,19 @@ export class PlayComponent implements OnInit, OnDestroy {
}); });
} }
preloadVideo(video) {
return new Promise((resolve, reject) => {
video.addEventListener('canplay', () => {
console.log('video canplay');
resolve();
})
video.addEventListener('error', (e) => {
console.log('video error: ', e);
reject();
})
video.load();
});
}
renderAfterResize() { renderAfterResize() {
this.canvasWidth = this.wrap.nativeElement.clientWidth; this.canvasWidth = this.wrap.nativeElement.clientWidth;
...@@ -350,7 +398,6 @@ export class PlayComponent implements OnInit, OnDestroy { ...@@ -350,7 +398,6 @@ export class PlayComponent implements OnInit, OnDestroy {
checkClickTarget(target) { checkClickTarget(target) {
const rect = target.getBoundingBox(); const rect = target.getBoundingBox();
...@@ -421,6 +468,7 @@ export class PlayComponent implements OnInit, OnDestroy { ...@@ -421,6 +468,7 @@ export class PlayComponent implements OnInit, OnDestroy {
// ======================================================编写区域========================================================================== // ======================================================编写区域==========================================================================
...@@ -436,6 +484,32 @@ export class PlayComponent implements OnInit, OnDestroy { ...@@ -436,6 +484,32 @@ export class PlayComponent implements OnInit, OnDestroy {
this.data.pic_url = 'assets/play/default/pic.jpg'; this.data.pic_url = 'assets/play/default/pic.jpg';
this.data.pic_url_2 = 'assets/play/default/pic.jpg'; this.data.pic_url_2 = 'assets/play/default/pic.jpg';
} }
if (!this.data.questionType) {
this.data = {
answerArr: [
{
answerRight: "1",
text: "This option is correct."
},
{
answerRight: "0",
text: "This option is wrong."
},
{
answerRight: "0",
text: "This option is wrong."
},
{
answerRight: "1",
text: "This option is correct."
}
],
answerType: "text",
questionType: "text",
text: "This is a test question."
}
}
} }
...@@ -445,7 +519,10 @@ export class PlayComponent implements OnInit, OnDestroy { ...@@ -445,7 +519,10 @@ export class PlayComponent implements OnInit, OnDestroy {
initImg() { initImg() {
this.addUrlToImages(this.data.pic_url); this.addUrlToImages(this.data.pic_url);
this.addUrlToImages(this.data.pic_url_2);
this.data.answerArr.forEach(( item ) => {
this.addUrlToImages(item.pic_url);
});
} }
...@@ -456,15 +533,15 @@ export class PlayComponent implements OnInit, OnDestroy { ...@@ -456,15 +533,15 @@ export class PlayComponent implements OnInit, OnDestroy {
// 音频资源 // 音频资源
this.addUrlToAudioObj(this.data.audio_url); this.addUrlToAudioObj(this.data.audio_url);
this.addUrlToAudioObj(this.data.audio_url_2);
// 音效 // 音效
this.addUrlToAudioObj('click', this.rawAudios.get('click'), 0.3); this.addUrlToAudioObj('wrong', this.rawAudios.get('wrong'), 1);
this.addUrlToAudioObj('right', this.rawAudios.get('right'), 0.5);
this.addUrlToAudioObj('finish', this.rawAudios.get('finish'), 0.5);
} }
/** /**
* 初始化数据 * 初始化数据
*/ */
...@@ -481,8 +558,11 @@ export class PlayComponent implements OnInit, OnDestroy { ...@@ -481,8 +558,11 @@ export class PlayComponent implements OnInit, OnDestroy {
this.renderArr = []; this.renderArr = [];
this.currentTime = 0;
this.allBtns = [];
this.answerArr = [];
this.endPageArr = [];
} }
...@@ -492,188 +572,675 @@ export class PlayComponent implements OnInit, OnDestroy { ...@@ -492,188 +572,675 @@ export class PlayComponent implements OnInit, OnDestroy {
*/ */
initView() { initView() {
this.initBg();
this.initQuestion();
this.initAnswer();
}
mapDown(event) {
this.initPic(); if (!this.canTouch) {
return;
}
this.initBottomPart();
if (this.data.questionType == 'video' && this.checkClickTarget(this.ovenBg)) {
this.clickedVideo();
return;
}
for (let i = 0; i < this.answerArr.length; i++) {
if (this.checkClickTarget(this.answerArr[i])) {
this.clickedAnswer(this.answerArr[i]);
return;
}
}
// ------- 播放器 --------
if (this.curAudio) {
if (this.checkClickTarget(this.progressBarBg)) {
this.isClickedProgress = true;
this.touchDownProgressBar(this.progressBarBg);
return;
}
if (this.checkClickTarget(this.curAudio.playBtn)) {
this.touchDownAudioBtn(this.curAudio);
return;
}
}
// ------------------------
} }
initBottomPart() { mapMove(event) {
if (!this.isClickedProgress) {
return;
}
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;
btnLeft.setScaleXY(this.mapScale); this.touchDownProgressBar(this.progressBarBg);
}
this.renderArr.push(btnLeft); mapUp(event) {
this.btnLeft = btnLeft;
this.isClickedProgress = false;
}
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);
this.renderArr.push(btnRight); update() {
this.btnRight = btnRight; // ----------------------------------------------------------
this.animationId = window.requestAnimationFrame(this.update.bind(this));
// 清除画布内容
this.ctx.clearRect(0, 0, this.canvasWidth, this.canvasHeight);
// tween 更新动画
TWEEN.update();
// ----------------------------------------------------------
this.updateArr(this.renderArr);
this.updateArr(this.endPageArr);
this.updateTime();
} }
initPic() { private updateTime() {
if (!this.isClickedProgress && this.curAudio) {
const progress = this.curAudio.currentTime / this.curAudio.duration;
this.setAudioProgress(this.progressBarBg, progress);
}
}
const maxW = this.canvasWidth * 0.7;
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;
const label1 = new Label();
label1.text = this.data.text;
label1.textAlign = 'center';
label1.fontSize = 50;
label1.fontName = 'BRLNSDB';
label1.fontColor = '#ffffff';
pic1.addChild(label1); private createPlayPauseButton(playKey, pauseKey) {
const button = createSprite(playKey);
const btnPause = createSprite(pauseKey);
this.hide(btnPause);
button.addChild(btnPause);
this.curAudio.playBtn = button;
this.curAudio.stopBtn = btnPause;
return button;
}
private createProgressBar(barTopKey, barBottomKey, barBtnKey) {
const container = new MySprite();
const progressBarBg = createSprite(barBottomKey);
progressBarBg.anchorX = 0;
this.progressBarBg = progressBarBg;
const progressBarPlayed = createSprite(barTopKey);
progressBarPlayed.anchorX = 0;
progressBarBg['bar'] = progressBarPlayed;
container['bar'] = progressBarPlayed;
const btn = createSprite(barBtnKey)
btn.y = -3;
progressBarBg['btn'] = btn;
const currentTime = this.createTime();
currentTime.text = formatTime('mm:ss', new Date(this.currentTime * 1000));
currentTime.refreshSize();
currentTime.x = 0;
currentTime.y = 30;
progressBarBg['timeLabel'] = currentTime;
const totalTime = this.createTime();
totalTime.text = formatTime('mm:ss', new Date(this.curAudio.duration * 1000));
totalTime.refreshSize();
totalTime.x = progressBarBg.width - totalTime.width;
totalTime.y = currentTime.y;
container.addChild(progressBarBg);
container.addChild(progressBarPlayed);
container.addChild(btn);
container.addChild(currentTime)
container.addChild(totalTime)
return container;
}
private createTime() {
const label = new Label();
label.fontSize = 22;
label.fontColor = '#c7edc8';
label.fontName = 'MMTextBook-Bold';
// label.setShadow(1, 1, 2, '#000000')
return label;
}
const pic2 = new MySprite(); private setAudioProgress(target: any, progress: number) {
pic2.init(this.images.get(this.data.pic_url_2)); target.btn.x = target.width * progress;
pic2.x = this.canvasWidth / 2 + this.canvasWidth;
pic2.y = this.canvasHeight / 2;
pic2.setScaleXY(maxW / pic2.width);
this.renderArr.push(pic2); const showRect = {x: 0, y: 0, width: target.bar.width * progress, height: target.bar.height};
this.pic2 = pic2;
this.curPic = pic1; target.bar.setShowRect(showRect);
this.currentTime = Math.floor(progress * this.curAudio.duration);
target.timeLabel.text = formatTime('mm:ss', new Date(this.currentTime * 1000));
} }
private touchDownProgressBar(target) {
this.setAudioState(this.curAudio, false);
btnLeftClicked() { const rect = target.getBoundingBox();
const sx = rect.width / target.width;
const tmpW = (this.mx - rect.x) / sx;
if (tmpW >= 0 && tmpW <= target.width) {
const progress = tmpW / target.width;
this.curAudio.currentTime = progress * this.curAudio.duration;
this.setAudioProgress(target, progress);
}
}
this.lastPage(); private setAudioState(audio: any, isPlay: boolean) {
if (isPlay) {
this.hide(audio.playBtn);
this.show(audio.stopBtn);
audio.play();
} else {
this.hide(audio.stopBtn);
this.show(audio.playBtn);
audio.pause();
}
} }
btnRightClicked() { private hide(element: MySprite) {
element.alpha = 0;
}
private show(element: MySprite) {
element.alpha = 1;
}
this.nextPage(); private touchDownAudioBtn(audio) {
if (audio.paused) {
audio.play();
this.setAudioState(audio, true);
} else {
audio.pause();
this.setAudioState(audio, false);
}
} }
lastPage() {
if (this.curPic == this.pic1) {
return;
private initBg() {
const bg = createSprite('bg');
bg.setScaleXY(getMaxScale(bg, this.canvasWidth, this.canvasHeight));
bg.x = this.canvasWidth / 2;
bg.y = this.canvasHeight - bg.height / 2 * bg.scaleY;
this.renderArr.push(bg);
const oven = createSprite('oven');
oven.setScaleXY(this.mapScale);
oven.x = this.canvasWidth / 2;
oven.y = this.canvasHeight - oven.height / 2 * oven.scaleY - 10 * this.mapScale;
this.oven = oven;
this.renderArr.push(oven);
const ovenBg = createSprite('question_text_bg');
ovenBg.x = 0.6;
ovenBg.y = -110;
ovenBg.setScaleXY(1.01);
this.oven.addChild(ovenBg, -1);
this.ovenBg = ovenBg;
const light = createSprite('light');
oven.addChild(light);
light.anchorY = 0;
light.alpha = 0;
light.y = -oven.height / 2 + 62;
this.ovenLight = light;
}
private initQuestion() {
switch (this.data.questionType) {
case 'text':
this.initQuestionText();
break;
case 'pic':
this.initQuestionPic();
break;
case 'audio':
this.initQuestionAudio();
break;
case 'video':
this.initQuestionVideo();
break;
} }
}
this.canTouch = false; private initQuestionText() {
const questionLabel = new RichText();
questionLabel.text = this.data.text;
questionLabel.width = this.ovenBg.width * 0.98;
questionLabel.x = -questionLabel.width / 2;
questionLabel.y = -28;
questionLabel.fontColor = '#f6dc92';
questionLabel.fontName = 'MMTextBook-Bold';
questionLabel.disH = 5;
questionLabel.fontSize = 50;
this.ovenBg.addChild(questionLabel);
}
const moveLen = this.canvasWidth; private initQuestionPic() {
tweenChange(this.pic1, {x: this.pic1.x + moveLen}, 1); const questionPic = createSprite(this.data.pic_url);
tweenChange(this.pic2, {x: this.pic2.x + moveLen}, 1, () => { questionPic.setScaleXY(getMinScale(questionPic, this.ovenBg.width, this.ovenBg.height));
this.canTouch = true; this.ovenBg.addChild(questionPic);
this.curPic = this.pic1; }
});
private initQuestionAudio() {
const res = {
btnPlay: 'btn_play',
btnPause: 'btn_pause',
barTop: 'bar_top',
barBottom: 'bar_bottom',
barBtn: 'bar_btn',
};
this.initAudioPlayer(res);
} }
nextPage() { private initQuestionVideo() {
if (this.curPic == this.pic2) { const video = new MyVideo();
return;
const initVideoAndBtn = () => {
console.log('in initSize');
video.initVideoElement(this.videoNode.nativeElement);
video.setScaleXY(getMinScale(video, this.ovenBg.width, this.ovenBg.height));
video.x = -video.width / 2 * video.scaleX;
video.y = -video.height / 2 * video.scaleY;
video.element.removeEventListener('canplaythrough', initVideoAndBtn);
if (this.videoBtn) {
this.videoBtn.x = video.width / 2;
this.videoBtn.y = video.height / 2;
}
};
initVideoAndBtn();
video.element.onended = () => {
this.videoBtn.visible = true;
video.element.currentTime = 0;
this.refreshVideoState(video.element, true);
} }
this.canTouch = false; this.curVideo = video;
this.ovenBg.addChild(video);
const videoBtn = this.createVideoBtn();
videoBtn.x = video.width / 2;
videoBtn.y = video.height / 2;
video.addChild(videoBtn);
this.videoBtn = videoBtn;
video.element.src = this.data.video_url;
video.element.load();
video.element.addEventListener('canplaythrough', initVideoAndBtn);
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;
});
} }
pic1Clicked() { initAudioPlayer(res) {
this.playAudio(this.data.audio_url); this.curAudio = this.audioObj[this.data.audio_url];
this.curAudio.onended = () => {
this.setAudioState(this.curAudio, false);
this.curAudio.currentTime = 0;
}
const playerCake = createSprite('player_cake');
this.oven.addChild(playerCake);
playerCake.y = -85;
const audioPlayer = this.createAudioPlayer(res);
audioPlayer.y = 10;
playerCake.addChild(audioPlayer);
this.setAudioProgress(this.progressBarBg, 0);
return audioPlayer;
}
private createAudioPlayer(res) {
const audioPlayer = new MySprite();
const playBtn = this.createPlayPauseButton(res.btnPlay, res.btnPause);
playBtn.x = 0;
playBtn.y = -120;
audioPlayer.addChild(playBtn);
audioPlayer['playBtn'] = playBtn;
const progressBarContainer = this.createProgressBar(res.barTop, res.barBottom, res.barBtn);
progressBarContainer.x = -this.progressBarBg.width / 2;
progressBarContainer.y = 80;
audioPlayer.addChild(progressBarContainer);
return audioPlayer;
} }
pic2Clicked() { private createVideoBtn() {
this.playAudio(this.data.audio_url_2); const btn = createSprite('video_play');
const pauseBtn = createSprite('video_pause');
pauseBtn.alpha = 0;
btn['pauseBtn'] = pauseBtn;
btn.addChild(pauseBtn);
return btn;
} }
private clickedVideo() {
if (this.videoBtn.visible) {
this.videoBtn.visible = false;
} else {
this.videoBtn.visible = true;
}
const videoElement = this.curVideo.element;
if (videoElement.paused) {
videoElement.play();
this.refreshVideoState(videoElement);
} else {
videoElement.pause();
this.refreshVideoState(videoElement);
}
}
private refreshVideoState(video, isPlay = null) {
if (isPlay == null) {
isPlay = !video.paused;
}
if (isPlay) {
this.hide(this.videoBtn['pauseBtn']);
this.show(this.videoBtn);
} else {
this.hide(this.videoBtn);
this.show(this.videoBtn['pauseBtn']);
}
}
private initAnswer() {
if (this.data.answerType == 'text') {
this.initTextAnswer();
} else {
this.initPicAnswer();
}
}
mapDown(event) { private initTextAnswer() {
if (!this.canTouch) { const offX = 620 * this.mapScale;
return; const offY = 150 * this.mapScale;
const baseX = this.canvasWidth / 2 - offX / 2;
let baseY = this.canvasHeight - 230 * this.mapScale;
if (this.data.answerArr.length < 3) {
baseY += offY / 2;
} }
if ( this.checkClickTarget(this.btnLeft) ) { for (let i = 0; i < this.data.answerArr.length; i++) {
this.btnLeftClicked(); const textAnswer = this.createAnswerText(this.data.answerArr[i], i + 1);
return; this.answerArr.push(textAnswer);
textAnswer.x = baseX + (i % 2) * offX;
textAnswer.y = baseY;
if (i % 2 === 1) {
baseY += offY;
}
} }
}
if ( this.checkClickTarget(this.btnRight) ) { private initPicAnswer() {
this.btnRightClicked();
return; const answerNum = this.data.answerArr.length;
const disW = 10 * this.mapScale;
const picW = 300 * this.mapScale;
const baseX = this.canvasWidth / 2 - (picW * answerNum + disW * (answerNum - 1)) / 2 + picW / 2 ;
const baseY = this.canvasHeight - 150 * this.mapScale;
for (let i = 0; i < this.data.answerArr.length; i++) {
const textAnswer = this.createAnswerPic(this.data.answerArr[i], i + 1);
this.answerArr.push(textAnswer);
textAnswer.x = baseX + i * (picW + disW);
textAnswer.y = baseY;
} }
}
if ( this.checkClickTarget(this.pic1) ) { private createAnswerText(answerData: any, id) {
this.pic1Clicked(); const textBg = createSprite('text_bg');
return; textBg.setScaleXY(this.mapScale);
this.renderArr.push(textBg);
const textId = createSprite('text_' + id);
textBg.addChild(textId);
textId.x = -textBg.width / 2 + 29;
textId.y = -42;
const label = new Label();
label.text = answerData.text;
label.fontColor = '#393158';
label.fontSize = 50;
label.fontName = 'MMTextBook-Bold';
label.textAlign = 'center';
label.setMaxSize(textBg.width * 0.86);
label.refreshSize();
label.y = 9;
label.x = 12;
textBg.addChild(label);
textBg['answerRight'] = answerData.answerRight === '1' ? true : false;
if (textBg['answerRight']) {
const rightIcon = createSprite('text_bg_right');
textBg.addChild(rightIcon, -1);
rightIcon.x = 8.3;
rightIcon.y = 12;
rightIcon.alpha = 0;
textBg['rightIcon'] = rightIcon;
} }
if ( this.checkClickTarget(this.pic2) ) { return textBg;
this.pic2Clicked(); }
return;
private clickedAnswer(answerArrElement: any) {
if (answerArrElement.answerRight) {
this.showAnswerRight(answerArrElement);
} else {
this.showAnswerWrong(answerArrElement);
} }
}
private showAnswerRight(answerArrElement: any) {
tweenChange(answerArrElement['rightIcon'], {alpha: 1}, 0.5, () => {
this.checkGameEnd();
});
this.playAudio('right');
this.showOvenLight();
} }
mapMove(event) { private showAnswerWrong(answerArrElement: any) {
shake(answerArrElement);
this.playAudio('wrong');
}
private checkGameEnd() {
for (let i = 0; i < this.answerArr.length; i++) {
if (this.answerArr[i].rightIcon && this.answerArr[i].rightIcon.alpha == 0) {
return;
}
}
this.gameEnd();
} }
mapUp(event) { private showOvenLight() {
if (this.ovenLight['tween']) {
this.ovenLight['tween'].stop();
}
this.ovenLight['tween'] = tweenChange(this.ovenLight, {alpha: 1}, 0.7, () => {
this.ovenLight['tween'] = tweenChange(this.ovenLight, {alpha: 0}, 0.7, () => {
}, TWEEN.Easing.Cubic.Out);
}, TWEEN.Easing.Cubic.Out);
} }
private createAnswerPic(data: any, id: number) {
const picBg = createSprite('pic_bg');
picBg.setScaleXY(this.mapScale);
this.renderArr.push(picBg);
const picIcon = createSprite('pic_icon');
picBg.addChild(picIcon);
picIcon.x = -picBg.width / 2 + 30;
picIcon.y = -picBg.height / 2 + 20;
const textId = createSprite('text_' + id);
picIcon.addChild(textId);
// textId.x = -picBg.width / 2 + 27;
textId.y = -12;
const maxW = 225;
const maxH = 140;
const pic = createSprite(data.pic_url);
pic.setScaleXY(getMinScale(pic, maxW, maxH));
pic.y = -6.5;
pic.x = 1;
picBg.addChild(pic);
picBg['answerRight'] = data.answerRight === '1' ? true : false;
if (picBg['answerRight']) {
const rightIcon = createSprite('pic_bg_right');
picBg.addChild(rightIcon, -1);
rightIcon.x = 0;
rightIcon.y = -6.5;
rightIcon.alpha = 0;
picBg['rightIcon'] = rightIcon;
}
return picBg;
}
update() {
// ---------------------------------------------------------- private gameEnd() {
this.animationId = window.requestAnimationFrame(this.update.bind(this));
// 清除画布内容
this.ctx.clearRect(0, 0, this.canvasWidth, this.canvasHeight);
// tween 更新动画
TWEEN.update();
// ----------------------------------------------------------
this.showEndPetal();
this.showCakeAnima();
this.canTouch = false;
}
this.updateArr(this.renderArr); showEndPetal() {
this.setMaskLayer();
console.log('showEndPetal');
this.petalTime = 0;
this.showPetalFlag = true;
this.addPetal();
this.playAudio('finish');
(<any> window).courseware.sendEvent('gameEnd');
setTimeout(() => {
this.showPetalFlag = false;
}, 6000);
} }
setMaskLayer() {
const shapeRect = new ShapeRect();
shapeRect.fillColor = '#000000';
shapeRect.width = this.canvasWidth;
shapeRect.height = this.canvasHeight;
shapeRect.alpha = 0.5;
this.endPageArr = [shapeRect];
}
addPetal() {
if (!this.showPetalFlag) {
return;
}
const petal = this.getPetal();
this.endPageArr.push(petal);
moveItem(petal, petal.x, this.canvasHeight + petal.height * petal.scaleY, petal['time'], () => {
removeItemFromArr(this.endPageArr, petal);
});
rotateItem(petal, petal['tr'], petal['time']);
setTimeout(() => {
this.addPetal();
}, 0 + this.petalTime);
this.petalTime += 5;
}
getPetal() {
const petal = new MySprite();
const id = Math.ceil( Math.random() * 6 );
petal.init(this.images.get('petal_' + id));
const randomS = (Math.random() * 0.4 + 0.6) * this.mapScale;
petal.setScaleXY(randomS);
const randomR = Math.random() * 360;
petal.rotation = randomR;
const randomX = Math.random() * this.canvasWidth;
petal.x = randomX;
petal.y = -petal.height / 2 * petal.scaleY;
const randomT = 1 + Math.random() * 3;
petal['time'] = randomT;
let randomTR = 360 * Math.random(); // - 180;
if (Math.random() < 0.5) { randomTR *= -1; }
petal['tr'] = randomTR;
return petal;
}
private showCakeAnima() {
const cake = createSprite('finish_cake');
cake.x = this.canvasWidth / 2;
cake.y = this.canvasHeight / 2;
cake.setScaleXY(this.mapScale);
this.endPageArr.push(cake);
const light = createSprite('finish_light');
cake.addChild(light, -1);
rotateItem(light, 180, 4, null, null, true);
jellyPop(cake, 1);
}
} }
const res = [ const res = [
// ['bg', "assets/play/bg.jpg"], ['bg', "assets/play/bg.png"],
['btn_left', "assets/play/btn_left.png"], ['oven', "assets/play/oven.png"],
['btn_right', "assets/play/btn_right.png"], ['question_text_bg', "assets/play/question_text_bg.png"],
// ['text_bg', "assets/play/text_bg.png"], ['light', "assets/play/light.png"],
['btn_play', "assets/play/player/btn_play.png"],
['btn_pause', "assets/play/player/btn_pause.png"],
['bar_top', "assets/play/player/bar_top.png"],
['bar_bottom', "assets/play/player/bar_bottom.png"],
['bar_btn', "assets/play/player/bar_btn.png"],
['player_cake', "assets/play/player/cake.png"],
['video_pause', "assets/play/video_pause.png"],
['video_play', "assets/play/video_play.png"],
['text_bg', "assets/play/text_bg.png"],
['text_bg_right', "assets/play/text_bg_right.png"],
['text_1', "assets/play/text_1.png"],
['text_2', "assets/play/text_2.png"],
['text_3', "assets/play/text_3.png"],
['text_4', "assets/play/text_4.png"],
['pic_bg', "assets/play/pic_bg.png"],
['pic_icon', "assets/play/pic_icon.png"],
['pic_bg_right', "assets/play/pic_bg_right.png"],
['finish_light', "assets/play/finish_light.png"],
['finish_cake', "assets/play/finish_cake.png"],
['petal_1', "assets/play/particle/1.png"],
['petal_2', "assets/play/particle/2.png"],
['petal_3', "assets/play/particle/3.png"],
['petal_4', "assets/play/particle/4.png"],
['petal_5', "assets/play/particle/5.png"],
['petal_6', "assets/play/particle/6.png"],
]; ];
...@@ -11,7 +46,9 @@ const res = [ ...@@ -11,7 +46,9 @@ const res = [
const resAudio = [ const resAudio = [
['click', "assets/play/music/click.mp3"], ['wrong', "assets/play/music/wrong.mp3"],
['right', "assets/play/music/right.mp3"],
['finish', "assets/play/music/finish.mp3"],
]; ];
......
File mode changed from 100644 to 100755
src/assets/play/text_bg.png

293 Bytes | W: | H:

src/assets/play/text_bg.png

5.6 KB | W: | H:

src/assets/play/text_bg.png
src/assets/play/text_bg.png
src/assets/play/text_bg.png
src/assets/play/text_bg.png
  • 2-up
  • Swipe
  • Onion skin
This source diff could not be displayed because it is too large. You can view the blob instead.
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