Commit 86c4d69b authored by Chen Jiping's avatar Chen Jiping

perf:完成开发

parent 8a51c964
...@@ -128,5 +128,8 @@ ...@@ -128,5 +128,8 @@
} }
} }
}, },
"defaultProject": "ng-template-generator" "defaultProject": "ng-template-generator",
} "cli": {
"analytics": "29e14fb6-b14a-4775-987f-2ceb56e73fa0"
}
}
\ No newline at end of file
import { Obj } from './ObjBean';
export class ExercisesBean extends Obj {
answerArr : Array<AnswerBean> = [];
rightAnswer : AnswerBean;
}
export class AnswerBean extends Obj {
/**类型:T-文本, P - 图片 */
contentType = 'T';
/**正确答案:0-否,1-是 */
isRight = '0';
}
export function getDefaultExercises(){
const exercises = new ExercisesBean();
exercises.rightAnswer = getDefaultAnswer();
exercises.rightAnswer.isRight = "1";
exercises.answerArr = [];
return exercises;
}
export function getDefaultAnswer(){
const answer = new AnswerBean();
return answer;
}
\ No newline at end of file
export class Obj{
/**音频材料 */
audioUrl: String;
/**图片材料 */
picUrl:String;
val : String;
}
\ No newline at end of file
<div class="model-content"> <div class="model-content">
<div nz-row>
<div nz-col nzOffset='4'>
<div style="position: absolute; left: 200px; top: 100px; width: 800px;"> <h1 nz-title>课程练习内容编辑</h1>
</div>
<input type="text" nz-input [(ngModel)]="item.text" (blur)="save()"> </div>
<div nz-row>
<app-upload-image-with-preview <div nz-col [nzSpan]="20" nzOffset="2">
[picUrl]="item.pic_url" <nz-form-item>
(imageUploaded)="onImageUploadSuccess($event, 'pic_url')" <nz-form-label [nzSpan]="6"> 问题音频:</nz-form-label>
></app-upload-image-with-preview> <nz-form-control [nzSpan]="12">
<app-audio-recorder [audioUrl]="item.audioUrl"
<app-audio-recorder (audioUploaded)="onAudioUploadSuccess($event, item, 'audioUrl')">
[audioUrl]="item.audio_url" </app-audio-recorder>
(audioUploaded)="onAudioUploadSuccess($event, 'audio_url')" </nz-form-control>
></app-audio-recorder> </nz-form-item>
<app-custom-hot-zone></app-custom-hot-zone> </div>
<app-upload-video></app-upload-video> </div>
<app-lesson-title-config></app-lesson-title-config> <div nz-col [nzSpan]="20" nzOffset="2">
<h5>正确答案</h5>
<nz-form-item>
<nz-form-label [nzSpan]="6"> 音频:</nz-form-label>
<nz-form-control [nzSpan]="12">
<app-audio-recorder [audioUrl]="item.rightAnswer.audioUrl"
(audioUploaded)="onAudioUploadSuccess($event, item.rightAnswer, 'audioUrl')">
</app-audio-recorder>
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-label [nzSpan]="6" >内容形式</nz-form-label>
<nz-form-control [nzSpan]="6">
<nz-radio-group [(ngModel)]="item.rightAnswer.contentType" (ngModelChange)="setContentType($event, item.rightAnswer)">
<label nz-radio nzValue="T">文字</label>
<label nz-radio nzValue="P">图片</label>
</nz-radio-group>
</nz-form-control>
</nz-form-item>
<div *ngIf="item.rightAnswer.contentType == 'T'">
<nz-form-item>
<nz-form-label [nzSpan]="6" >文本</nz-form-label>
<nz-form-control [nzSpan]="6">
<input nz-input type="text" placeholder="请录入内容" [(ngModel)]="item.rightAnswer.val" (blur)="save()">
</nz-form-control>
</nz-form-item>
</div>
<div *ngIf="item.rightAnswer.contentType == 'P'">
<nz-form-item>
<nz-form-label [nzSpan]="6">图片</nz-form-label>
<nz-form-control [nzSpan]="6">
<app-upload-image-with-preview
style="width: 100%"
[picUrl]="item.rightAnswer.picUrl"
(imageUploaded)="onImageUploadSuccess($event, item.rightAnswer, 'picUrl')"
></app-upload-image-with-preview>
</nz-form-control>
</nz-form-item>
</div>
</div> </div>
</div> <div nz-col [nzSpan]="20" nzOffset="2">
<h5>备选答案</h5>
\ No newline at end of file <div *ngFor="let data of item.answerArr;let j = index" class="card-item" style="padding: 0.5vw;">
<div class="border">
<nz-divider nzText="备选答案-{{j+1}}" nzOrientation="left"></nz-divider>
<nz-form-item>
<button style="margin: 10px;" nz-button nzType="danger"
(click)="deleteAnswer(item, 'answerArr', j)">
<span>删除</span>
</button>
</nz-form-item>
<nz-form-item>
<nz-form-label [nzSpan]="6" nzFor="data.audioUrl"> 音频:</nz-form-label>
<nz-form-control [nzSpan]="12">
<app-audio-recorder [audioUrl]="data.audioUrl"
(audioUploaded)="onAudioUploadSuccess($event, data, 'audioUrl')">
</app-audio-recorder>
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-label [nzSpan]="6" >内容形式</nz-form-label>
<nz-form-control [nzSpan]="6">
<nz-radio-group [(ngModel)]="data.contentType" (ngModelChange)="setContentType($event, data)">
<label nz-radio nzValue="T">文字</label>
<label nz-radio nzValue="P">图片</label>
</nz-radio-group>
</nz-form-control>
</nz-form-item>
<div *ngIf="data.contentType == 'T'">
<nz-form-item>
<nz-form-label [nzSpan]="6" >文本</nz-form-label>
<nz-form-control [nzSpan]="6">
<input nz-input type="text" placeholder="请录入内容" [(ngModel)]="data.val" (blur)="save()">
</nz-form-control>
</nz-form-item>
</div>
<div *ngIf="data.contentType == 'P'">
<nz-form-item>
<nz-form-label [nzSpan]="6">图片</nz-form-label>
<nz-form-control [nzSpan]="6">
<app-upload-image-with-preview
style="width: 100%"
[picUrl]="data.picUrl"
(imageUploaded)="onImageUploadSuccess($event, data, 'picUrl')"
></app-upload-image-with-preview>
</nz-form-control>
</nz-form-item>
</div>
</div>
</div>
<hr>
<div id='listen-anchor'>
<nz-form-item>
<nz-form-label [nzSpan]="6" >操作</nz-form-label>
<nz-form-control [nzSpan]="6">
<button nz-button nzType="dashed" class="add-btn" id="add-btn" (click)="addAnswer(item, 'answerArr')">
<i nz-icon nzType="plus-circle" nzTheme="outline"></i>添加
</button>
</nz-form-control>
</nz-form-item>
</div>
</div>
</div>
\ No newline at end of file
import {Component, EventEmitter, Input, OnDestroy, OnChanges, OnInit, Output, ApplicationRef, ChangeDetectorRef} from '@angular/core'; import {Component, EventEmitter, Input, OnDestroy, OnChanges, OnInit, Output, ApplicationRef, ChangeDetectorRef} from '@angular/core';
import { getDefaultAnswer, getDefaultExercises } from '../bean/ExercisesBean';
...@@ -10,7 +11,7 @@ import {Component, EventEmitter, Input, OnDestroy, OnChanges, OnInit, Output, Ap ...@@ -10,7 +11,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 = "LST-05";
// 储存对象 // 储存对象
item; item;
...@@ -22,7 +23,7 @@ export class FormComponent implements OnInit, OnChanges, OnDestroy { ...@@ -22,7 +23,7 @@ export class FormComponent implements OnInit, OnChanges, OnDestroy {
ngOnInit() { ngOnInit() {
this.item = {}; this.item = getDefaultExercises();
// 获取存储的数据 // 获取存储的数据
(<any> window).courseware.getData((data) => { (<any> window).courseware.getData((data) => {
...@@ -58,19 +59,19 @@ export class FormComponent implements OnInit, OnChanges, OnDestroy { ...@@ -58,19 +59,19 @@ export class FormComponent implements OnInit, OnChanges, OnDestroy {
* 储存图片数据 * 储存图片数据
* @param e * @param e
*/ */
onImageUploadSuccess(e, key) { onImageUploadSuccess(e, item, key) {
this.item[key] = e.url; item[key] = e.url;
this.save(); this.save();
} }
/** /**
* 储存音频数据 * 储存音频数据
* @param e * @param e
*/ */
onAudioUploadSuccess(e, key) { onAudioUploadSuccess(e, item, key) {
this.item[key] = e.url; item[key] = e.url;
this.save(); this.save();
} }
...@@ -93,5 +94,35 @@ export class FormComponent implements OnInit, OnChanges, OnDestroy { ...@@ -93,5 +94,35 @@ export class FormComponent implements OnInit, OnChanges, OnDestroy {
}, 1); }, 1);
} }
deleteAnswer(item, key, index){
if (index !== -1) {
item[key].splice(index, 1);
item[key] = [...item[key]];
this.save();
}
}
addAnswer(item, key){
let answer = getDefaultAnswer();
item[key] = [...item[key], answer];
this.save();
}
setContentType(e, item){
item['contentType'] = e;
if("T" == e){
item['picUrl'] = "";
}
else if("P" == e){
item['val'] = "";
}
this.save();
}
} }
import {
MySprite, tweenChange,
ShapeRect
} from './Unit';
export class AudioAnimation {
private x = 0;
private y = 0;
images = new Map();
bg: ShapeRect;
playPic1;
playPic2;
playPic3;
playPic4;
curAudio;
playing = false;
hideFlag = true;
/**
* 设置播放帧图片
* @param images
*/
constructor(images) {
this.images = images;
}
setXY(x, y) {
this.x = x;
this.y = y;
}
/**
* 初始化图
* @param parent 图片显示父对象
* @param show 是否直接显示
*/
initPic(parent, show: boolean) {
if (!parent) {
return;
}
const bg = new ShapeRect();
const getAudioPic = (index) => {
const playPic = new MySprite();
playPic.init(this.images.get("btn_laba" + index));
playPic.alpha = 0;
playPic.x = playPic.getBoundingBox().width / 2;
playPic.y = playPic.getBoundingBox().height / 2;
bg.addChild(playPic);
return playPic;
};
const playPic1 = getAudioPic(1);
if (show) {
playPic1.alpha = 1;
this.hideFlag = false;
}
else {
playPic1.alpha = 0;
this.hideFlag = true;
}
this.playPic1 = playPic1;
const playPic2 = getAudioPic(2);
this.playPic2 = playPic2;
const playPic3 = getAudioPic(3);
this.playPic3 = playPic3;
const playPic4 = getAudioPic(4);
this.playPic4 = playPic4;
bg.setSize(playPic1.getBoundingBox().width, playPic1.getBoundingBox().height);
bg.alpha = 0;
this.bg = bg;
bg.x = this.x;
bg.y = this.y;
if (parent instanceof Array) {
parent.push(bg);
}
else {
parent.addChild(bg);
}
}
/**
* 显示播放状态
*/
showPlayStauts() {
this.hideFlag = false;
const setPause = () => {
if (this.hideFlag) {
this.playPic1.alpha = 0;
}
else {
this.playPic1.alpha = 1;
}
this.playPic2.alpha = 0;
this.playPic3.alpha = 0;
this.playPic4.alpha = 0;
}
const show1 = () => {
if (this.playing) {
this.playPic1.alpha = 0;
this.playPic2.alpha = 1;
this.playPic3.alpha = 0;
this.playPic4.alpha = 0;
setTimeout(() => {
show2();
}, 500);
}
else {
setPause();
}
};
const show2 = () => {
if (this.playing) {
this.playPic1.alpha = 0;
this.playPic2.alpha = 0;
this.playPic3.alpha = 1;
this.playPic4.alpha = 0;
setTimeout(() => {
show3();
}, 500);
}
else {
setPause();
}
};
const show3 = () => {
if (this.playing) {
this.playPic1.alpha = 0;
this.playPic2.alpha = 0;
this.playPic3.alpha = 0;
this.playPic4.alpha = 1;
setTimeout(() => {
show4();
}, 500);
}
else {
setPause();
}
};
const show4 = () => {
if (this.playing) {
this.playPic1.alpha = 1;
this.playPic2.alpha = 0;
this.playPic3.alpha = 0;
this.playPic4.alpha = 0;
setTimeout(() => {
show1();
}, 500);
}
else {
setPause();
}
};
show1();
}
/**
*
* @param audio 播放音频
* @param callback
*/
playAudio(audio, callback = null) {
//console.log(audio);
if (!audio) {
return;
}
this.curAudio = audio;
audio.onended = () => {
this.playing = false;
if (callback) {
callback();
}
};
audio.play();
this.playing = true;
this.showPlayStauts();
}
/**
*
* @param reset 是否重置
* @param callback 暂停后执行方法
*/
pauseAudio(reset = false, callback = null) {
const audio = this.curAudio;
if (audio) {
this.playing = false;
if (reset) {
audio.currentTime = 0;
}
audio.pause();
if (callback) {
callback();
}
}
}
/**
* 隐藏音频播放动画
* @param reset 是否重置
*/
hide(reset = false) {
this.hideFlag = true;
this.pauseAudio(reset);
this.playPic1.alpha = 0;
this.playPic2.alpha = 0;
this.playPic3.alpha = 0;
this.playPic4.alpha = 0;
}
/**
* 显示播放动画
*/
show() {
this.hideFlag = false;
this.playPic1.alpha = 1;
this.playPic2.alpha = 0;
this.playPic3.alpha = 0;
this.playPic4.alpha = 0;
}
}
\ No newline at end of file
/**
*
* @param audio 音频
* @param now true-重新开始播放,flase-继续播放
* @param callback
*/
export function playAudio(audio, now = false, callback = null) {
if (audio) {
if (now) {
audio.pause();
audio.currentTime = 0;
}
if (callback) {
audio.onended = () => {
callback();
};
}
audio.play();
}
}
/**
* 暂停播放音频
* @param audio 音频
* @param reset 暂停是否重置:true-是,false-否
* @param callback
*/
export function pauseAudio(audio, reset = false, callback = null) {
if (audio) {
if (reset) {
audio.currentTime = 0;
}
audio.pause();
if (callback) {
callback();
}
}
}
\ No newline at end of file
import { Item } from './Item';
import { MySprite, tweenChange } from './Unit';
import { playAudio } from './AudioUtil';
export class Button extends Item{
btnPic : MySprite;
private _outX = 0;
set outX(v){
this._outX =v ;
}
get outX(){
return this._outX;
}
private _outY = 0;
set outY(v){
this._outY =v ;
}
get outY(){
return this._outY;
}
init(picName){
const btnPic = this.getPic(picName);
this.width = btnPic.width;
this.height = btnPic.height;
btnPic.x = this.x;
btnPic.y = this.y;
this.btnPic = btnPic;
}
click(callback = null){
playAudio(this.audioObj['click'], true);
//放大
tweenChange(this.btnPic, {scaleX: this.scaleX * 1.3, scaleY : this.scaleY * 1.3}, 0.1, ()=>{
//恢复
tweenChange(this.btnPic, {scaleX: this.scaleX, scaleY : this.scaleY}, 0.1, ()=>{
//移出
tweenChange(this.btnPic, {x : this.outX, y:this.outY}, 0.3, ()=>{
if(callback){
callback();
}
})
});
})
}
show(callback = null){
this.btnPic.x = this.x;
this.btnPic.y = this.y;
this.btnPic.visible = true;
if(callback){
callback();
}
}
}
\ No newline at end of file
import { Label, MySprite, ShapeRect } from './Unit';
export class Card {
images;
mapScale = 1;
bg: ShapeRect;
initX = 0;
initY = 0;
toX = 0;
toY = 0;
canClick = false;
curAnswer = null;
bgPic: MySprite;
bgWord: MySprite;
h = 0;
canHit = false;
endFlag = false;
init(images, mapScale = 1) {
this.mapScale = mapScale;
this.images = images;
const bg = new ShapeRect();
bg.alpha = 0;
this.bg = bg;
const pic = new MySprite();
pic.init(this.images.get('bg_ip'));
pic.setScaleXY(mapScale);
bg.setSize(pic.getBoundingBox().width, pic.getBoundingBox().height);
pic.x = bg.width / 2;
pic.y = bg.height / 2;
bg.addChild(pic);
this.initPic();
this.canClick = false;
this.h = bg.height;
}
private initPic() {
const bgPic = new MySprite();
bgPic.init(this.images.get('bg_pic'));
bgPic.setScaleXY(this.mapScale);
bgPic.x = this.bg.width / 2;
bgPic.y = - bgPic.getBoundingBox().height / 2 + 15 * this.mapScale;
this.bgPic = bgPic;
this.bg.addChild(bgPic);
this.bgPic.visible = false;
const bgWord = new MySprite();
bgWord.init(this.images.get('bg_word'));
bgWord.setScaleXY(this.mapScale);
bgWord.x = this.bg.width / 2;
bgWord.y = - bgWord.getBoundingBox().height / 2 + 15 * this.mapScale;
this.bgWord = bgWord;
this.bg.addChild(bgWord);
this.bgWord.visible = false;
}
showNext(answer, callback = null) {
this.curAnswer = answer;
if (!answer) {
if (callback) {
callback();
}
}
this.bgPic.removeChildren();
this.bgWord.removeChildren();
this.bgPic.visible = false;
this.bgWord.visible = false;
const setMaxScale = (target: MySprite, maxW, maxH) => {
const sx = maxW / target.width;
const sy = maxH / target.height;
const s = Math.min(sx, sy);
target.setScaleXY(Math.round(s * 1000) / 1000);
}
if (answer.contentType == 'P') {
this.bgPic.visible = true;
const pic = new MySprite();
pic.init(this.images.get(answer.picUrl));
pic.x = 0;
pic.y = 0;
setMaxScale(pic, 230, 172);
this.bgPic.addChild(pic);
this.h = this.bgPic.getBoundingBox().height;
}
else if (answer.contentType == 'T') {
this.bgWord.visible = true;
const label = new Label();
label.text = answer.val;
label.fontSize = 70;
label.fontName = 'MMTextBook-Bold';
label.textAlign = 'center';
label.fontColor = '#18408d';
label.setMaxSize(320);
label.y = 0;
label.x = 0;
this.bgWord.addChild(label);
this.h = this.bgWord.getBoundingBox().height;
}
}
}
\ No newline at end of file
import { MySprite, ShapeRect } from './Unit';
interface AirWindow extends Window {
air: any;
curCtx: any;
}
declare let window: AirWindow;
export class Item {
/**图片集合 */
images;
audioObj;
_scaleX = 1;
_scaleY = 1;
ctx;
_width = 0;
_height = 0;
_x = 0;
_y = 0;
bg: ShapeRect;
constructor(images, audioObj, scaleX = 1, scaleY = 1, ctx = null) {
this.images = images;
this.audioObj = audioObj;
this._scaleX = scaleX;
this._scaleY = scaleY;
if (!ctx) {
this.ctx = window.curCtx;
} else {
this.ctx = ctx;
}
}
set width(width) {
this._width = width * this.scaleX;
if(this.bg){
this.bg.width = this._width;
}
}
get width() {
return this._width;
}
set height(height) {
this._height = height * this.scaleY;
if(this.bg){
this.bg.height = this._height;
}
}
get height() {
return this._height;
}
set scaleX(v) {
this._scaleX = v;
}
get scaleX() {
return this._scaleX;
}
set scaleY(v) {
this._scaleY = v;
}
get scaleY() {
return this._scaleY;
}
set x(x) {
this._x = x;
if (this.bg) {
this.bg.x = this._x;
}
}
get x() {
return this._x;
}
set y(y) {
this._y = y;
if (this.bg) {
this.bg.y = this._y;
}
}
get y() {
return this._y;
}
getPic(picName, anchorX: number = 0.5, anchorY: number = 0.5) {
const pic = new MySprite();
pic.init(this.images.get(picName), anchorX, anchorY);
pic.scaleX = this.scaleX;
pic.scaleY = this.scaleY;
pic.x = 0;
pic.y = 0;
return pic;
}
checkClickTarget(target, mx: number, my: number) {
const rect = target.getBoundingBox();
if (this.checkPointInRect(mx, my, rect)) {
return true;
}
return false;
}
checkPointInRect(x, y, rect) {
if (x >= rect.x && x <= rect.x + rect.width) {
if (y >= rect.y && y <= rect.y + rect.height) {
return true;
}
}
return false;
}
}
export function setScale(pW: number, pH: number, child) {
let width = child.width;
let height = child.height;
let sx = pW / width;
let sy = pH / height;
let scale = Math.min(sx, sy);
if (scale < 1) {
child.setScaleXY(scale);
}
}
\ No newline at end of file
...@@ -17,3 +17,8 @@ ...@@ -17,3 +17,8 @@
src: url("../../assets/font/BRLNSDB.TTF") ; src: url("../../assets/font/BRLNSDB.TTF") ;
} }
@font-face
{
font-family: 'MMTextBook-Bold';
src: url("../../assets/font/MMTextBook-Bold.otf") ;
}
\ No newline at end of file
import {Component, ElementRef, ViewChild, OnInit, Input, OnDestroy, HostListener} from '@angular/core'; import { Component, ElementRef, ViewChild, OnInit, Input, OnDestroy, HostListener } from '@angular/core';
import { import {
hideItem,
Label, Label,
MySprite, tweenChange, moveItem,
MySprite, randomSortByArr, removeItemFromArr, ShapeRect, tweenChange,
} from './Unit'; } from './Unit';
import {res, resAudio} from './resources'; import { res, resAudio } from './resources';
import {Subject} from 'rxjs'; import { Subject } from 'rxjs';
import {debounceTime} from 'rxjs/operators'; import { debounceTime } from 'rxjs/operators';
import TWEEN from '@tweenjs/tween.js'; import TWEEN from '@tweenjs/tween.js';
import { Button } from './Button';
import { AudioAnimation } from './AudioAnimation';
import { Card } from './Card';
...@@ -22,8 +27,8 @@ import TWEEN from '@tweenjs/tween.js'; ...@@ -22,8 +27,8 @@ import TWEEN from '@tweenjs/tween.js';
}) })
export class PlayComponent implements OnInit, OnDestroy { 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;
// 数据 // 数据
data; data;
...@@ -52,22 +57,40 @@ export class PlayComponent implements OnInit, OnDestroy { ...@@ -52,22 +57,40 @@ export class PlayComponent implements OnInit, OnDestroy {
audioObj = {}; audioObj = {};
renderArr; renderArr;
endRenderArr = [];
mapScale = 1; mapScale = 1;
canvasLeft; canvasLeft;
canvasTop; canvasTop;
saveKey = 'test_0011'; saveKey = 'LST-05';
btnLeft;
btnRight;
pic1;
pic2;
canTouch = true; canTouch = true;
curPic; answerArr = [];
answerArr2 = [];
mask: ShapeRect;
btnStart: Button;
btnRestart: Button;
audioAni: AudioAnimation;
cardArr = [];
holePosArr = [];
holeExistArr = [];
cardExistArr = [];
gameEndFlag = false;
showCardTimeIdArr = [];
@HostListener('window:resize', ['$event']) @HostListener('window:resize', ['$event'])
onResize(event) { onResize(event) {
...@@ -80,7 +103,7 @@ export class PlayComponent implements OnInit, OnDestroy { ...@@ -80,7 +103,7 @@ export class PlayComponent implements OnInit, OnDestroy {
this.data = {}; this.data = {};
// 获取数据 // 获取数据
const getData = (<any> window).courseware.getData; const getData = (<any>window).courseware.getData;
getData((data) => { getData((data) => {
if (data && typeof data == 'object') { if (data && typeof data == 'object') {
...@@ -432,10 +455,7 @@ export class PlayComponent implements OnInit, OnDestroy { ...@@ -432,10 +455,7 @@ export class PlayComponent implements OnInit, OnDestroy {
*/ */
initDefaultData() { 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';
}
} }
...@@ -444,8 +464,17 @@ export class PlayComponent implements OnInit, OnDestroy { ...@@ -444,8 +464,17 @@ export class PlayComponent implements OnInit, OnDestroy {
*/ */
initImg() { initImg() {
this.addUrlToImages(this.data.pic_url); if (this.data.rightAnswer && this.data.rightAnswer.picUrl) {
this.addUrlToImages(this.data.pic_url_2); this.addUrlToImages(this.data.rightAnswer.picUrl);
}
for (let i = 0; i < this.data.answerArr.length; ++i) {
let answer = this.data.answerArr[i];
if (answer.picUrl) {
this.addUrlToImages(answer.picUrl);
}
}
} }
...@@ -454,13 +483,26 @@ export class PlayComponent implements OnInit, OnDestroy { ...@@ -454,13 +483,26 @@ export class PlayComponent implements OnInit, OnDestroy {
*/ */
initAudio() { initAudio() {
// 音频资源 this.rawAudios.forEach((item, key) => {
this.addUrlToAudioObj(this.data.audio_url); // 音效
this.addUrlToAudioObj(this.data.audio_url_2); this.addUrlToAudioObj(key, this.rawAudios.get(key));
})
// 音效 if (this.data.audioUrl) {
this.addUrlToAudioObj('click', this.rawAudios.get('click'), 0.3); this.addUrlToAudioObj(this.data.audioUrl);
}
if (this.data.rightAnswer && this.data.rightAnswer.audioUrl) {
this.addUrlToAudioObj(this.data.rightAnswer.audioUrl);
}
for (let i = 0; i < this.data.answerArr.length; ++i) {
let answer = this.data.answerArr[i];
if (answer.audioUrl) {
this.addUrlToAudioObj(answer.audioUrl);
}
}
} }
...@@ -475,205 +517,529 @@ export class PlayComponent implements OnInit, OnDestroy { ...@@ -475,205 +517,529 @@ export class PlayComponent implements OnInit, OnDestroy {
const s = Math.min(sx, sy); const s = Math.min(sx, sy);
this.mapScale = s; this.mapScale = s;
// this.mapScale = sx; this.renderArr = [];
// this.mapScale = sy;
this.endRenderArr = [];
this.renderArr = []; this.canTouch = false;
this.answerArr = [];
this.cardArr = [];
this.holePosArr = [];
this.gameEndFlag = false;
this.answerArr.push(this.data.rightAnswer);
this.answerArr.push(...this.data.answerArr);
this.answerArr2.push(...this.answerArr);
this.holeExistArr = [];
this.cardExistArr = [];
console.log(this.showCardTimeIdArr);
if (this.showCardTimeIdArr) {
this.showCardTimeIdArr.forEach((showCardTimeId) => {
clearTimeout(showCardTimeId);
});
}
this.showCardTimeIdArr = [];
}
createPic(key) {
const pic = new MySprite();
pic.init(this.images.get(key));
pic.setScaleXY(this.mapScale);
return pic;
} }
getMask() {
const mask = new ShapeRect();
mask.setSize(this.canvasWidth, this.canvasHeight);
mask.fillColor = '#000000';
mask.alpha = 0.7;
this.mask = mask;
}
/** /**
* 初始化试图 * 初始化试图
*/ */
initView() { initView() {
this.initBg();
this.initPic(); this.initPic();
this.initBottomPart(); this.initBtn();
this.initCard();
this.canTouch = true;
} }
initBottomPart() { initBg() {
const btnLeft = new MySprite(); const bg = this.createPic('bg');
btnLeft.init(this.images.get('btn_left')); bg.x = this.canvasWidth / 2;
btnLeft.x = this.canvasWidth - 150 * this.mapScale; bg.y = this.canvasHeight / 2;
btnLeft.y = this.canvasHeight - 100 * this.mapScale; bg.setScaleXY(Math.max(this.canvasWidth / bg.width, this.canvasHeight / bg.height));
btnLeft.setScaleXY(this.mapScale); this.renderArr.push(bg);
}
this.renderArr.push(btnLeft); initPic() {
const audioAni = new AudioAnimation(this.images);
audioAni.setXY(this.canvasWidth - 120 * this.mapScale, this.canvasHeight - 120 * this.mapScale);
audioAni.initPic(this.renderArr, true);
audioAni.bg.setScaleXY(this.mapScale);
audioAni.bg['renderZ'] = 100;
this.audioAni = audioAni;
const bg_behind = this.createPic('bg_behind');
bg_behind.x = this.canvasWidth / 2;
bg_behind.y = this.canvasHeight - 170 * this.mapScale;
this.renderArr.push(bg_behind);
bg_behind['renderZ'] = 10;
const bg_front = this.createPic('bg_front');
bg_front.x = this.canvasWidth / 2 - 10 * this.mapScale;
bg_front.y = this.canvasHeight - 30 * this.mapScale;
this.renderArr.push(bg_front);
bg_front['renderZ'] = 20;
}
this.btnLeft = btnLeft; initBtn() {
this.getMask();
this.endRenderArr.push(this.mask);
const btnRight = new MySprite(); const btnStart = new Button(this.images, this.audioObj, this.mapScale, this.mapScale);
btnRight.init(this.images.get('btn_right')); btnStart.x = this.canvasWidth / 2;
btnRight.x = this.canvasWidth - 50 * this.mapScale; btnStart.y = this.canvasHeight / 2;
btnRight.y = this.canvasHeight - 100 * this.mapScale; btnStart.outY = btnStart.y;
btnRight.setScaleXY(this.mapScale); btnStart.init('btn_start');
btnStart.outX = this.canvasWidth + btnStart.width;
this.btnStart = btnStart;
this.endRenderArr.push(btnStart.btnPic);
this.renderArr.push(btnRight); const btnRestart = new Button(this.images, this.audioObj, this.mapScale, this.mapScale);
btnRestart.y = this.canvasHeight / 2;
btnRestart.x = this.canvasWidth + 300 * this.mapScale;
btnRestart.outY = btnRestart.y;
btnRestart.init('btn_restart');
btnRestart.outX = this.canvasWidth + btnRestart.width;
this.btnRestart = btnRestart;
this.endRenderArr.push(btnRestart.btnPic);
this.btnRight = btnRight;
} }
initPic() {
const maxW = this.canvasWidth * 0.7;
const pic1 = new MySprite(); mapDown(event) {
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); if (!this.canTouch) {
this.pic1 = pic1; return;
}
if (this.checkClickTarget(this.btnStart.btnPic)) {
const label1 = new Label(); hideItem(this.mask, 0.5);
label1.text = this.data.text;
label1.textAlign = 'center';
label1.fontSize = 50;
label1.fontName = 'BRLNSDB';
label1.fontColor = '#ffffff';
pic1.addChild(label1); this.btnStart.click(() => {
this.initGame();
});
return;
}
if (this.checkClickTarget(this.btnRestart.btnPic)) {
this.gameEndFlag = false;
const pic2 = new MySprite(); hideItem(this.mask, 0.5);
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.btnRestart.click(() => {
this.pic2 = pic2;
this.curPic = pic1; this.initGame();
} })
this.playAudio('click');
btnLeftClicked() { return;
}
this.lastPage(); if (this.audioAni && this.checkClickTarget(this.audioAni.bg)) {
}
if (this.audioAni.playing) {
this.audioAni.pauseAudio();
}
else {
this.audioAni.playAudio(this.audioObj[this.data.audioUrl]);
}
return;
}
for (let i = 0; i < this.cardArr.length; i++) {
let card = this.cardArr[i];
if (this.checkClickTarget(card.bg) || this.checkClickTarget(card.bgPic) || this.checkClickTarget(card.bgWord)) {
this.clickCard(card);
return;
}
}
btnRightClicked() {
this.nextPage();
} }
lastPage() { mapMove(event) {
if (this.curPic == this.pic1) { }
return;
}
this.canTouch = false; mapUp(event) {
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;
});
} }
nextPage() {
if (this.curPic == this.pic2) {
return;
}
this.canTouch = false; update() {
// ----------------------------------------------------------
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.endRenderArr);
}
const moveLen = this.canvasWidth; sortRenderZ(arr) {
tweenChange(this.pic1, {x: this.pic1.x - moveLen}, 1); arr.sort((a, b) => {
tweenChange(this.pic2, {x: this.pic2.x - moveLen}, 1, () => { if (!a.renderZ) a.renderZ = 0;
this.canTouch = true; if (!b.renderZ) b.renderZ = 0;
this.curPic = this.pic2;
return a.renderZ - b.renderZ;
}); });
} }
pic1Clicked() { initCard() {
this.playAudio(this.data.audio_url);
this.cleanOldCard();
this.cardArr = [];
this.holePosArr = [];
const edge = 30 * this.mapScale;
const rightNum = Math.ceil(Math.random() * 3);
const idArr = randomSortByArr([1, 2, 3]);
idArr.length = rightNum;
let card = new Card();
card.init(this.images, this.mapScale);
card.bg.x = 450 * this.mapScale;
card.bg.y = this.canvasHeight - 40 * this.mapScale;
card.bg['renderZ'] = 8;
card['id'] = 0;
this.renderArr.push(card.bg);
this.holePosArr.push({ x: card.bg.x, y: card.bg.y, z: 8 });
this.cardArr.push(card);
card = new Card();
card.init(this.images, this.mapScale);
card.bg.x = 850 * this.mapScale;
card.bg.y = this.canvasHeight - 50 * this.mapScale;
card.bg['renderZ'] = 9;
card['id'] = 1;
this.renderArr.push(card.bg);
this.holePosArr.push({ x: card.bg.x, y: card.bg.y, z: 9 });
this.cardArr.push(card);
card.showNext(this.answerArr[1]);
card = new Card();
card.init(this.images, this.mapScale);
card.bg.x = 260 * this.mapScale;
card.bg.y = this.canvasHeight + 110 * this.mapScale;
card.bg['renderZ'] = 19;
card['id'] = 1;
this.renderArr.push(card.bg);
this.holePosArr.push({ x: card.bg.x, y: card.bg.y, z: 19 });
this.cardArr.push(card);
this.sortRenderZ(this.renderArr);
} }
pic2Clicked() { cleanOldCard() {
this.playAudio(this.data.audio_url_2); if (this.cardArr && this.cardArr.length > 0) {
for (let i = 0; i < this.cardArr.length; i++) {
clearTimeout(this.cardArr[i].timeId);
if (this.cardArr[i].tween) {
this.cardArr[i].tween.stop();
}
}
}
if (this.cardArr) {
for (let i = 0; i < this.cardArr.length; i++) {
removeItemFromArr(this.renderArr, this.cardArr[i]);
}
}
} }
initGame() {
this.gameEndFlag = false;
this.answerArr = randomSortByArr(this.answerArr2);
mapDown(event) { this.answerArr.forEach((val) => {
val.endFlag = false;
})
if (!this.canTouch) { const exAudio = this.audioObj[this.data.audioUrl];
return; this.audioAni.playAudio(exAudio, true);
}
this.showCard();
if ( this.checkClickTarget(this.btnLeft) ) { }
this.btnLeftClicked();
getAnswer(callback) {
if (this.answerArr.length <= 0) {
setTimeout(() => {
this.getAnswer(callback);
}, 20);
return; return;
} }
if ( this.checkClickTarget(this.btnRight) ) { let answer = this.answerArr.shift();
this.btnRightClicked();
callback(answer);
}
getRandomItemFromArr(arr) {
if (!arr) {
return; return;
} }
if ( this.checkClickTarget(this.pic1) ) { let length = arr.length;
this.pic1Clicked();
let index = Math.ceil(Math.random() * 100000000) % length;
return arr[index];
}
showCard() {
if (this.gameEndFlag) {
return; return;
} }
if ( this.checkClickTarget(this.pic2) ) { if (this.holeExistArr.length >= 2) {
this.pic2Clicked();
return; return;
} }
this.getAnswer((answer) => {
const holeArr = [0, 1, 2];
for (let i = 0; i < this.holeExistArr.length; i++) {
removeItemFromArr(holeArr, this.holeExistArr[i]);
}
let tmp = Math.floor(holeArr.length * Math.random());
const holeIndex = holeArr[tmp];
const pos = this.holePosArr[holeIndex];
const cardIndexArr = [0, 1, 2];
for (let i = 0; i < this.cardExistArr.length; i++) {
removeItemFromArr(cardIndexArr, this.cardExistArr[i]);
}
for (let i = 0; i < cardIndexArr.length; i++) {
const cardIndex = cardIndexArr[i];
if (cardIndex) {
const card = this.cardArr[cardIndex];
if (card.canHit) {
cardIndexArr.splice(i, 1);
i--;
}
}
}
if (cardIndexArr.length == 0) {
return;
}
tmp = Math.floor(cardIndexArr.length * Math.random());
const cardIndex = cardIndexArr[tmp];
const card = this.cardArr[cardIndex];
card.bg.x = pos.x;
card.bg.y = pos.y;
card.holeId = holeIndex;
card.id = cardIndex;
card.baseY = pos.y;
card.targetY = pos.y - card.bg.height - 20 * this.mapScale;
card.bg.renderZ = pos.z;
this.sortRenderZ(this.renderArr);
card.showNext(answer);
this.cardUp(card);
this.holeExistArr.push(holeIndex);
this.cardExistArr.push(cardIndex);
let showCardTimeId = setTimeout(() => {
// console.log(' in timeout')
this.showCard();
removeItemFromArr(this.showCardTimeIdArr, showCardTimeId);
}, 500 + 1500 * Math.random());
this.showCardTimeIdArr.push(showCardTimeId);
});
} }
mapMove(event) { cardUp(card) {
card.canHit = true;
const tween = moveItem(card.bg, card.bg.x, card.targetY, 0.5 + 0.2 * Math.random(), () => {
card.timeId = setTimeout(() => {
card.timeId = null;
this.cardDown(card);
}, 300 + 1200 * Math.random());
}, TWEEN.Easing.Cubic.Out);
card.tween = tween;
} }
mapUp(event) { cardDown(card, time = 0.8) {
const tween = moveItem(card.bg, card.bg.x, card.baseY, time, () => {
card.canHit = false;
if (!card.curAnswer.endFlag) {
removeItemFromArr(this.cardExistArr, card.id);
} else {
this.checkGameEnd(card.curAnswer);
}
removeItemFromArr(this.holeExistArr, card.holeId);
this.answerArr.push(card.curAnswer);
if (this.holeExistArr.length <= 1) {
this.showCard();
}
}, TWEEN.Easing.Cubic.Out);
card.tween = tween;
} }
clickCard(card) {
if (!card.canHit) {
return;
}
if (card.tween) {
card.tween.stop();
}
if (card.timeId) {
clearTimeout(card.timeId);
card.timeId = null;
}
update() { if (card.curAnswer.isRight == '1') {
// ---------------------------------------------------------- this.playAudio('right', true);
this.animationId = window.requestAnimationFrame(this.update.bind(this));
// 清除画布内容 card.curAnswer.endFlag = true;
this.ctx.clearRect(0, 0, this.canvasWidth, this.canvasHeight);
// tween 更新动画
TWEEN.update();
// ----------------------------------------------------------
this.playAudio(card.curAnswer.audioUrl, true);
} else {
this.playAudio('wrong', true);
}
card.canHit = false;
this.cardDown(card, 0.35);
this.updateArr(this.renderArr); }
checkGameEnd(answer) {
if (answer.endFlag) {
this.showEnd();
}
} }
showEnd() {
this.audioAni.pauseAudio();
for (let i = 0; i < this.cardArr.length; i++) {
this.cardArr[i].bg.childDepandAlpha = true;
hideItem(this.cardArr[i].bg, 0.3);
}
this.gameEndFlag = true;
this.canTouch = false;
tweenChange(this.mask, { alpha: 0.7 }, 0.5, () => {
moveItem(this.btnRestart.btnPic, this.canvasWidth / 2, this.btnRestart.y, 0.5, () => {
this.canTouch = true;
this.holeExistArr = [];
this.cardExistArr = [];
this.initCard();
}, TWEEN.Easing.Cubic.Out);
});
}
} }
const res = [ const res = [
// ['bg', "assets/play/bg.jpg"], ['btn_laba1', "assets/play/btn_laba1.png"],
['btn_left', "assets/play/btn_left.png"], ['btn_laba2', "assets/play/btn_laba2.png"],
['btn_right', "assets/play/btn_right.png"], ['btn_laba3', "assets/play/btn_laba3.png"],
// ['text_bg', "assets/play/text_bg.png"], ['btn_laba4', "assets/play/btn_laba4.png"],
['bg', "assets/play/bg.png"],
['bg_behind', "assets/play/bg_behind.png"],
['bg_front', "assets/play/bg_front.png"],
['bg_ip', "assets/play/bg_ip.png"],
['bg_pic', "assets/play/bg_pic.png"],
['bg_word', "assets/play/bg_word.png"],
['btn_restart', "assets/play/btn_restart.png"],
['btn_start', "assets/play/btn_start.png"],
]; ];
...@@ -12,7 +22,8 @@ const res = [ ...@@ -12,7 +22,8 @@ const res = [
const resAudio = [ const resAudio = [
['click', "assets/play/music/click.mp3"], ['click', "assets/play/music/click.mp3"],
['right', "assets/play/music/right.mp3"],
['wrong', "assets/play/music/wrong.mp3"]
]; ];
export {res, resAudio}; export {res, resAudio};
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