@@ -3,29 +3,42 @@ import { Challenge } from "../../staticData/challenges";
33import { Actor , Behaviour } from "./SceneButtons/interpreterFactory" ;
44
55class Scene {
6- iframe ( ) : HTMLIFrameElement {
7- return document . getElementById ( "sceneIframe" ) as HTMLIFrameElement
8- }
9-
10- /**
11- * Instantiates and runs pilas-engine (pilasweb) main framework.
12- * Preloads needed challenge's images.
13- * Sets up messaging events from iframe. Iframe should exist before calling this method.
14- * @param descriptor The scene descriptor
15- */
16- async load ( descriptor : Challenge [ "sceneDescriptor" ] ) {
17- await this . initializePilasWeb ( descriptor )
18- this . setChallenge ( descriptor )
19- }
6+ private isReady = false ;
207
21- setChallenge ( descriptor : Challenge [ "sceneDescriptor" ] ) {
22- const initializer = descriptor === this . sceneName ( descriptor ) ? `new ${ descriptor } ()` : descriptor
23- this . eval ( `pilas.mundo.gestor_escenas.cambiar_escena( ${ initializer } )` )
8+ async waitUntilReady ( ) : Promise < void > {
9+ while ( ! this . isReady ) {
10+ await new Promise ( res => setTimeout ( res , 50 ) ) // espera activa
2411 }
25-
26- initializePilasWeb ( descriptor : string ) {
27- return new Promise < void > ( ( resolve ) => {
28- const pilasweb = this . eval ( `
12+ }
13+
14+ currentScene ( ) : Challenge [ "sceneDescriptor" ] {
15+ return this . isReady ? this . eval ( 'pilas.mundo.gestor_escenas.escena.mapaEscena' ) : ''
16+ }
17+
18+ iframe ( ) : HTMLIFrameElement {
19+ return document . getElementById ( "sceneIframe" ) as HTMLIFrameElement
20+ }
21+
22+ /**
23+ * Instantiates and runs pilas-engine (pilasweb) main framework.
24+ * Preloads needed challenge's images.
25+ * Sets up messaging events from iframe. Iframe should exist before calling this method.
26+ * @param descriptor The scene descriptor
27+ */
28+ async load ( descriptor : Challenge [ "sceneDescriptor" ] ) {
29+ await this . initializePilasWeb ( descriptor )
30+ this . isReady = true
31+ this . setChallenge ( descriptor )
32+ }
33+
34+ setChallenge ( descriptor : Challenge [ "sceneDescriptor" ] ) {
35+ const initializer = descriptor === this . sceneName ( descriptor ) ? `new ${ descriptor } ()` : descriptor
36+ this . eval ( `pilas.mundo.gestor_escenas.cambiar_escena(${ initializer } )` )
37+ }
38+
39+ initializePilasWeb ( descriptor : string ) {
40+ return new Promise < void > ( ( resolve ) => {
41+ const pilasweb = this . eval ( `
2942 pilasengine.iniciar({
3043 ancho: 420,
3144 alto: 480,
@@ -35,68 +48,68 @@ class Scene {
3548 cargar_imagenes_estandar: false,
3649 silenciar_advertencia_de_multiples_ejecutar: true
3750 });` )
38- pilasweb . ejecutar ( )
39- pilasweb . setFPS ( 100 )
40- pilasweb . onready = resolve
41-
42- this . listenToIframeMessages ( )
43- } )
44- }
45-
46- listenToIframeMessages ( ) {
47- window . addEventListener ( "message" , ( event ) => {
48- // exercises post error messages in the form { tipo: "error", error: object }
49- // where object can be any error or { name: "ActividadError", message: "description"}
50- if ( event . data . tipo === "error" )
51- console . log ( `Pilasweb execution ended with error: ${ JSON . stringify ( event . data . error ) } ` )
52- } )
53- }
54-
55- /**
56- * Evals code on the iframe. Shouldn't be called outside the class.
57- * The idea is that the responsability of managing the scene remains on this object.
58- * @param code string with js code to run on the iframe
59- */
60- private eval ( code : string ) : any {
61- return ( this . iframe ( ) . contentWindow as any ) . eval ( code )
62- }
63-
64- private imagesToPreload ( descriptor : Challenge [ "sceneDescriptor" ] ) {
65- //Responsibiliy of the exercise's scene class
66- var images = this . eval ( `${ this . sceneName ( descriptor ) } .imagenesPreCarga()` )
67- //TODO: Some scenes (like EscapeEnYacare) don't have images to preload. They should.
68- images = images . length ? images : this . eval ( `imageList` )
69-
70- return JSON . stringify ( images )
71- }
72-
73-
74- sceneName ( sceneDescriptor : string ) : string {
75- // if descriptor is of the form new ClassName(...). The regex (\w+) captures the classname.
76- // The [1] access the first capture group
77- const name = sceneDescriptor . match ( / n e w \s + ( \w + ) \s * \( / )
78- return name ? name [ 1 ] : sceneDescriptor
79- }
80-
81- restartScene ( descriptor : Challenge [ "sceneDescriptor" ] ) {
82- this . eval ( 'pilas.reiniciar()' )
83- this . setChallenge ( descriptor )
84- }
85-
86- sceneActor ( ) : Actor {
87- return this . eval ( 'pilas.escena_actual().automata' )
88- }
89-
90- sceneReceptor ( receptor : string ) : Actor {
91- return this . eval ( `pilas.escena_actual().${ receptor } ` )
92- }
93-
94- isTheProblemSolved ( ) {
95- return this . eval ( `pilas.escena_actual().estaResueltoElProblema();` ) ;
96- }
97-
98- behaviourClass ( behaviour : string ) : Behaviour {
99- return this . eval ( `
51+ pilasweb . ejecutar ( )
52+ pilasweb . setFPS ( 100 )
53+ pilasweb . onready = resolve
54+
55+ this . listenToIframeMessages ( )
56+ } )
57+ }
58+
59+ listenToIframeMessages ( ) {
60+ window . addEventListener ( "message" , ( event ) => {
61+ // exercises post error messages in the form { tipo: "error", error: object }
62+ // where object can be any error or { name: "ActividadError", message: "description"}
63+ if ( event . data . tipo === "error" )
64+ console . log ( `Pilasweb execution ended with error: ${ JSON . stringify ( event . data . error ) } ` )
65+ } )
66+ }
67+
68+ /**
69+ * Evals code on the iframe. Shouldn't be called outside the class.
70+ * The idea is that the responsability of managing the scene remains on this object.
71+ * @param code string with js code to run on the iframe
72+ */
73+ private eval ( code : string ) : any {
74+ return ( this . iframe ( ) . contentWindow as any ) . eval ( code )
75+ }
76+
77+ private imagesToPreload ( descriptor : Challenge [ "sceneDescriptor" ] ) {
78+ //Responsibiliy of the exercise's scene class
79+ var images = this . eval ( `${ this . sceneName ( descriptor ) } .imagenesPreCarga()` )
80+ //TODO: Some scenes (like EscapeEnYacare) don't have images to preload. They should.
81+ images = images . length ? images : this . eval ( `imageList` )
82+
83+ return JSON . stringify ( images )
84+ }
85+
86+
87+ sceneName ( sceneDescriptor : string ) : string {
88+ // if descriptor is of the form new ClassName(...). The regex (\w+) captures the classname.
89+ // The [1] access the first capture group
90+ const name = sceneDescriptor . match ( / n e w \s + ( \w + ) \s * \( / )
91+ return name ? name [ 1 ] : sceneDescriptor
92+ }
93+
94+ restartScene ( descriptor : Challenge [ "sceneDescriptor" ] ) {
95+ this . eval ( 'pilas.reiniciar()' )
96+ this . setChallenge ( descriptor )
97+ }
98+
99+ sceneActor ( ) : Actor {
100+ return this . eval ( 'pilas.escena_actual().automata' )
101+ }
102+
103+ sceneReceptor ( receptor : string ) : Actor {
104+ return this . eval ( `pilas.escena_actual().${ receptor } ` )
105+ }
106+
107+ isTheProblemSolved ( ) {
108+ return this . eval ( `pilas.escena_actual().estaResueltoElProblema();` ) ;
109+ }
110+
111+ behaviourClass ( behaviour : string ) : Behaviour {
112+ return this . eval ( `
100113 var comportamiento = null;
101114
102115 if (window['${ behaviour } ']) {
@@ -111,18 +124,18 @@ class Scene {
111124
112125 comportamiento;
113126 ` )
114- }
127+ }
115128
116- evaluateExpression ( expression : string ) : boolean {
117- return this . eval ( `
129+ evaluateExpression ( expression : string ) : boolean {
130+ return this . eval ( `
118131 try {
119132 var value = pilas.escena_actual().automata.${ expression }
120133 } catch (e) {
121134 pilas.escena_actual().errorHandler.handle(e);
122135 }
123136
124137 value` )
125- }
138+ }
126139}
127140
128141export const scene = new Scene ( )
0 commit comments