11import React , { Component } from 'react' ;
22import PropTypes from 'prop-types' ;
33
4- import Matter , { Engine , Events } from 'matter-js' ;
4+ import Matter , { Render , Engine , Events } from 'matter-js' ;
55
66export default class World extends Component {
77 static propTypes = {
@@ -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
@@ -46,6 +55,94 @@ export default class World extends Component {
4655 this . lastTime = currTime ;
4756 } ;
4857
58+ onInit = ( ...args ) => {
59+ if ( this . props . debug ) {
60+ this . setupDebugRenderer ( ) ;
61+ }
62+
63+ this . props . onInit ( ...args ) ;
64+ } ;
65+
66+ stopDebugRendering = ( ) => {
67+ if ( this . _render ) {
68+ Render . stop ( this . _render ) ;
69+ delete this . _render ;
70+ }
71+ } ;
72+
73+ getDebugProps = ( ) => {
74+ const debugProps = Object . assign (
75+ {
76+ offset : { } ,
77+ // transparent background to see sprites, etc, in the world
78+ background : 'rgba(0, 0, 0, 0)' ,
79+ } ,
80+ this . props . debug || { }
81+ ) ;
82+
83+ debugProps . offset = Object . assign (
84+ {
85+ x : 0 ,
86+ y : 0 ,
87+ } ,
88+ debugProps . offset
89+ ) ;
90+
91+ return debugProps ;
92+ } ;
93+
94+ setupDebugRenderer = ( ) => {
95+
96+ if ( ! this . _debugRenderElement ) {
97+ return ;
98+ }
99+
100+ const { renderWidth, renderHeight, scale } = this . context ;
101+ const { offset, background } = this . getDebugProps ( ) ;
102+
103+ const width = renderWidth / scale ;
104+ const height = renderHeight / scale ;
105+
106+ this . _render = Render . create ( {
107+ canvas : this . _debugRenderElement ,
108+ // Auto-zoom the canvas to the correct game area
109+ bounds : {
110+ min : {
111+ x : offset . x ,
112+ y : offset . y ,
113+ } ,
114+ max : {
115+ x : offset . x + width ,
116+ y : offset . y + height ,
117+ } ,
118+ } ,
119+ options : {
120+ wireframeBackground : background ,
121+ width : renderWidth ,
122+ height : renderHeight ,
123+ } ,
124+ } ) ;
125+
126+ // Setting this as part of `.create` crashes Chrome during a deep clone. :/
127+ // My guess: a circular reference
128+ this . _render . engine = this . engine ;
129+
130+ Render . run ( this . _render ) ;
131+ } ;
132+
133+ getCanvasRef = ( element ) => {
134+
135+ this . _debugRenderElement = element ;
136+
137+ if ( element ) {
138+ if ( ! this . _render ) {
139+ this . setupDebugRenderer ( ) ;
140+ }
141+ } else {
142+ this . stopDebugRendering ( ) ;
143+ }
144+ } ;
145+
49146 constructor ( props ) {
50147 super ( props ) ;
51148
@@ -65,11 +162,42 @@ export default class World extends Component {
65162 if ( gravity !== this . props . gravity ) {
66163 this . engine . world . gravity = gravity ;
67164 }
165+
166+ if ( ! nextProps . debug ) {
167+ this . stopDebugRendering ( ) ;
168+ }
169+ }
170+
171+ componentDidUpdate ( ) {
172+ if ( this . props . debug && this . _render ) {
173+
174+ const { renderWidth, renderHeight, scale } = this . context ;
175+
176+ const { offset } = this . getDebugProps ( ) ;
177+
178+ // When context changes (eg; `scale` due to a window resize),
179+ // re-calculate the world stage
180+ this . _render . options . width = renderWidth ;
181+ this . _render . options . height = renderHeight ;
182+
183+ this . _render . bounds = {
184+ min : {
185+ x : offset . x ,
186+ y : offset . y ,
187+ } ,
188+ max : {
189+ x : offset . x + ( renderWidth / scale ) ,
190+ y : offset . y + ( renderHeight / scale ) ,
191+ } ,
192+ } ;
193+
194+ Render . world ( this . _render ) ;
195+ }
68196 }
69197
70198 componentDidMount ( ) {
71199 this . loopID = this . context . loop . subscribe ( this . loop ) ;
72- this . props . onInit ( this . engine ) ;
200+ this . onInit ( this . engine ) ;
73201 Events . on ( this . engine , 'afterUpdate' , this . props . onUpdate ) ;
74202 Events . on ( this . engine , 'collisionStart' , this . props . onCollision ) ;
75203 }
@@ -78,6 +206,7 @@ export default class World extends Component {
78206 this . context . loop . unsubscribe ( this . loopID ) ;
79207 Events . off ( this . engine , 'afterUpdate' , this . props . onUpdate ) ;
80208 Events . off ( this . engine , 'collisionStart' , this . props . onCollision ) ;
209+ this . stopDebugRendering ( ) ;
81210 }
82211
83212 getChildContext ( ) {
@@ -95,9 +224,26 @@ export default class World extends Component {
95224 width : '100%' ,
96225 } ;
97226
227+ const { renderWidth, renderHeight, scale } = this . context ;
228+
229+ let debugRenderTarget = false ;
230+
231+ if ( this . props . debug ) {
232+ debugRenderTarget = (
233+ < canvas
234+ key = "debug-render-target"
235+ style = { { position : 'relative' } }
236+ width = { renderWidth }
237+ height = { renderHeight }
238+ ref = { this . getCanvasRef }
239+ />
240+ ) ;
241+ }
242+
98243 return (
99244 < div style = { defaultStyles } >
100245 { this . props . children }
246+ { debugRenderTarget }
101247 </ div >
102248 ) ;
103249 }
0 commit comments