11import React , { Component , PropTypes } from 'react' ;
22
3- import Matter , { Engine , Events } from 'matter-js' ;
3+ import Matter , { Render , Engine , Events } from 'matter-js' ;
44
55export default class World extends Component {
66
@@ -11,6 +11,13 @@ export default class World extends Component {
1111 y : PropTypes . number ,
1212 scale : PropTypes . number ,
1313 } ) ,
14+ debug : PropTypes . shape ( {
15+ offset : PropTypes . shape ( {
16+ x : PropTypes . number ,
17+ y : PropTypes . number ,
18+ } ) ,
19+ background : PropTypes . string ,
20+ } ) ,
1421 onCollision : PropTypes . func ,
1522 onInit : PropTypes . func ,
1623 onUpdate : PropTypes . func ,
@@ -29,6 +36,8 @@ export default class World extends Component {
2936
3037 static contextTypes = {
3138 scale : PropTypes . number ,
39+ renderWidth : PropTypes . number ,
40+ renderHeight : PropTypes . number ,
3241 loop : PropTypes . object ,
3342 } ;
3443
@@ -42,6 +51,94 @@ export default class World extends Component {
4251 this . lastTime = currTime ;
4352 } ;
4453
54+ onInit = ( ...args ) => {
55+ if ( this . props . debug ) {
56+ this . setupDebugRenderer ( ) ;
57+ }
58+
59+ this . props . onInit ( ...args ) ;
60+ } ;
61+
62+ stopDebugRendering = ( ) => {
63+ if ( this . _render ) {
64+ Render . stop ( this . _render ) ;
65+ delete this . _render ;
66+ }
67+ } ;
68+
69+ getDebugProps = ( ) => {
70+ const debugProps = Object . assign (
71+ {
72+ offset : { } ,
73+ // transparent background to see sprites, etc, in the world
74+ background : 'rgba(0, 0, 0, 0)' ,
75+ } ,
76+ this . props . debug || { }
77+ ) ;
78+
79+ debugProps . offset = Object . assign (
80+ {
81+ x : 0 ,
82+ y : 0 ,
83+ } ,
84+ debugProps . offset
85+ ) ;
86+
87+ return debugProps ;
88+ } ;
89+
90+ setupDebugRenderer = ( ) => {
91+
92+ if ( ! this . _debugRenderElement ) {
93+ return ;
94+ }
95+
96+ const { renderWidth, renderHeight, scale } = this . context ;
97+ const { offset, background } = this . getDebugProps ( ) ;
98+
99+ const width = renderWidth / scale ;
100+ const height = renderHeight / scale ;
101+
102+ this . _render = Render . create ( {
103+ canvas : this . _debugRenderElement ,
104+ // Auto-zoom the canvas to the correct game area
105+ bounds : {
106+ min : {
107+ x : offset . x ,
108+ y : offset . y ,
109+ } ,
110+ max : {
111+ x : offset . x + width ,
112+ y : offset . y + height ,
113+ } ,
114+ } ,
115+ options : {
116+ wireframeBackground : background ,
117+ width : renderWidth ,
118+ height : renderHeight ,
119+ } ,
120+ } ) ;
121+
122+ // Setting this as part of `.create` crashes Chrome during a deep clone. :/
123+ // My guess: a circular reference
124+ this . _render . engine = this . engine ;
125+
126+ Render . run ( this . _render ) ;
127+ } ;
128+
129+ getCanvasRef = ( element ) => {
130+
131+ this . _debugRenderElement = element ;
132+
133+ if ( element ) {
134+ if ( ! this . _render ) {
135+ this . setupDebugRenderer ( ) ;
136+ }
137+ } else {
138+ this . stopDebugRendering ( ) ;
139+ }
140+ } ;
141+
45142 constructor ( props ) {
46143 super ( props ) ;
47144
@@ -61,11 +158,42 @@ export default class World extends Component {
61158 if ( gravity !== this . props . gravity ) {
62159 this . engine . world . gravity = gravity ;
63160 }
161+
162+ if ( ! nextProps . debug ) {
163+ this . stopDebugRendering ( ) ;
164+ }
165+ }
166+
167+ componentDidUpdate ( ) {
168+ if ( this . props . debug && this . _render ) {
169+
170+ const { renderWidth, renderHeight, scale } = this . context ;
171+
172+ const { offset } = this . getDebugProps ( ) ;
173+
174+ // When context changes (eg; `scale` due to a window resize),
175+ // re-calculate the world stage
176+ this . _render . options . width = renderWidth ;
177+ this . _render . options . height = renderHeight ;
178+
179+ this . _render . bounds = {
180+ min : {
181+ x : offset . x ,
182+ y : offset . y ,
183+ } ,
184+ max : {
185+ x : offset . x + ( renderWidth / scale ) ,
186+ y : offset . y + ( renderHeight / scale ) ,
187+ } ,
188+ } ;
189+
190+ Render . world ( this . _render ) ;
191+ }
64192 }
65193
66194 componentDidMount ( ) {
67195 this . loopID = this . context . loop . subscribe ( this . loop ) ;
68- this . props . onInit ( this . engine ) ;
196+ this . onInit ( this . engine ) ;
69197 Events . on ( this . engine , 'afterUpdate' , this . props . onUpdate ) ;
70198 Events . on ( this . engine , 'collisionStart' , this . props . onCollision ) ;
71199 }
@@ -74,6 +202,7 @@ export default class World extends Component {
74202 this . context . loop . unsubscribe ( this . loopID ) ;
75203 Events . off ( this . engine , 'afterUpdate' , this . props . onUpdate ) ;
76204 Events . off ( this . engine , 'collisionStart' , this . props . onCollision ) ;
205+ this . stopDebugRendering ( ) ;
77206 }
78207
79208 getChildContext ( ) {
@@ -91,9 +220,26 @@ export default class World extends Component {
91220 width : '100%' ,
92221 } ;
93222
223+ const { renderWidth, renderHeight, scale } = this . context ;
224+
225+ let debugRenderTarget = false ;
226+
227+ if ( this . props . debug ) {
228+ debugRenderTarget = (
229+ < canvas
230+ key = "debug-render-target"
231+ style = { { position : 'relative' } }
232+ width = { renderWidth }
233+ height = { renderHeight }
234+ ref = { this . getCanvasRef }
235+ />
236+ ) ;
237+ }
238+
94239 return (
95240 < div style = { defaultStyles } >
96241 { this . props . children }
242+ { debugRenderTarget }
97243 </ div >
98244 ) ;
99245 }
0 commit comments