Skip to content
This repository was archived by the owner on Feb 7, 2024. It is now read-only.

Commit 95e6c12

Browse files
committed
physics
1 parent e38809e commit 95e6c12

21 files changed

+667
-122
lines changed

.babelrc

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
{
22
"presets": ["es2015", "react", "stage-0"],
3-
"plugins": ["transform-flow-strip-types"]
3+
"plugins": ["transform-flow-strip-types", "transform-decorators-legacy"]
44
}

.eslintrc

+1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
"no-magic-numbers": 0
77
"no-invalid-this": 0
88
"react/sort-comp": 0
9+
"prefer-const": 0
910
"comma-dangle": [2, "always-multiline"]
1011
"jsx-quotes": [2, "prefer-double"]
1112
"quotes": [2, "single",{"allowTemplateLiterals": true}]

demo/character.js

+92-8
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,106 @@
11
import React, { Component, PropTypes } from 'react';
22

3+
import { observer } from 'mobx-react';
4+
35
import {
6+
Body,
47
Sprite,
58
} from '../src';
69

10+
import Matter from 'matter-js';
11+
12+
@observer
713
export default class Character extends Component {
14+
815
static propTypes = {
9-
state: PropTypes.number,
16+
keys: PropTypes.object,
17+
store: PropTypes.object,
18+
};
19+
20+
static contextTypes = {
21+
loop: PropTypes.object,
22+
scale: PropTypes.number,
23+
};
24+
25+
loop = () => {
26+
const { keys } = this.props;
27+
28+
if (keys) {
29+
30+
let characterState = 2;
31+
32+
if (keys.isDown(keys.LEFT)) {
33+
this.body.body.position.x -= 1;
34+
characterState = 1;
35+
} else if (keys.isDown(keys.RIGHT)) {
36+
this.body.body.position.x += 1;
37+
characterState = 0;
38+
}
39+
40+
if (keys.isDown(keys.UP)) {
41+
Matter.Body.applyForce(
42+
this.body.body,
43+
{ x: 0, y: 0 },
44+
{ x: 0, y: -0.025 },
45+
);
46+
}
47+
48+
this.props.store.setCharacterPosition(this.body.body.position);
49+
50+
this.setState({
51+
characterState,
52+
});
53+
}
54+
1055
};
56+
57+
constructor(props) {
58+
super(props);
59+
60+
this.loopID = null;
61+
62+
this.state = {
63+
characterState: 2,
64+
};
65+
}
66+
67+
componentDidMount() {
68+
this.loopID = this.context.loop.subscribe(this.loop);
69+
}
70+
71+
componentWillUnmount() {
72+
this.context.loop.unsubscribe(this.loopID);
73+
}
74+
75+
getWrapperStyles() {
76+
const { characterPosition } = this.props.store;
77+
const { scale } = this.context;
78+
const { x, y } = characterPosition;
79+
80+
return {
81+
position: 'absolute',
82+
transform: `translate(${x * scale}px, ${y * scale}px)`,
83+
transformOrigin: 'left top',
84+
};
85+
}
86+
1187
render() {
1288
return (
13-
<Sprite
14-
animating
15-
src="assets/character-sprite.png"
16-
scale={4}
17-
state={this.props.state}
18-
states={[9, 9, 0]}
19-
/>
89+
<div style={this.getWrapperStyles()}>
90+
<Body args={[
91+
0, 400, 64, 64, { inertia: Infinity }]
92+
}
93+
ref={(b) => { this.body = b; }}
94+
>
95+
<Sprite
96+
animating
97+
src="assets/character-sprite.png"
98+
scale={this.context.scale * 2}
99+
state={this.state.characterState}
100+
states={[9, 9, 0]}
101+
/>
102+
</Body>
103+
</div>
20104
);
21105
}
22106
}

demo/demo.js

+28-33
Original file line numberDiff line numberDiff line change
@@ -1,52 +1,47 @@
11
import React, { Component } from 'react';
22

33
import {
4-
Game,
5-
Keys,
4+
Loop,
5+
Camera,
6+
KeyListener,
7+
World,
68
} from '../src';
79

810
import Character from './character';
11+
import Level from './level';
12+
import GameStore from './stores/game-store';
913

1014
import './index.css';
1115

1216
export default class Demo extends Component {
13-
14-
handleInput = (e) => {
15-
switch (e.keyCode) {
16-
case '37':
17-
// left
18-
break;
19-
case '39':
20-
// right
21-
break;
22-
default:
23-
break;
24-
}
25-
};
26-
2717
constructor(props) {
2818
super(props);
29-
this.state = {
30-
character: 0,
31-
};
32-
this.handleClick = this.handleClick.bind(this);
33-
}
3419

35-
handleClick() {
36-
const state = this.state.character === 2 ? 0 : this.state.character + 1;
37-
this.setState({
38-
character: state,
39-
});
20+
this.keyListener = new KeyListener();
21+
}
22+
componentDidMount() {
23+
this.keyListener.subscribe([
24+
this.keyListener.LEFT,
25+
this.keyListener.RIGHT,
26+
this.keyListener.UP,
27+
]);
28+
}
29+
componentWillUnmount() {
30+
this.keyListener.unsubscribe();
4031
}
41-
4232
render() {
4333
return (
44-
<Game>
45-
<Keys onInput={this.handleInput} />
46-
<Character state={this.state.character}/>
47-
{this.state.character}
48-
<button style={{ marginTop: 200 }}onClick={this.handleClick} type="button">Toggle</button>
49-
</Game>
34+
<Loop>
35+
<Camera>
36+
<World>
37+
<Level />
38+
<Character
39+
store={GameStore}
40+
keys={this.keyListener}
41+
/>
42+
</World>
43+
</Camera>
44+
</Loop>
5045
);
5146
}
5247

demo/index.css

+5
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
html, body, #root {
2+
background: black;
23
height: 100%;
34
width: 100%;
45
margin: 0;
56
padding: 0;
7+
}
8+
9+
* {
10+
box-sizing: border-box;
611
}

demo/level.js

+63
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
import React, { Component } from 'react';
2+
3+
import {
4+
Body,
5+
TileMap,
6+
} from '../src';
7+
8+
export default class Level extends Component {
9+
render() {
10+
return (
11+
<TileMap
12+
{...this.props}
13+
src="assets/background.png"
14+
renderTile={(tile, src, styles) => {
15+
if (tile.index === 5) {
16+
return (
17+
<Body args={[
18+
tile.left, tile.top, tile.size, tile.size,
19+
{ isStatic: true },
20+
]}>
21+
<img
22+
style={styles}
23+
src={src}
24+
/>
25+
</Body>
26+
);
27+
} else {
28+
return (
29+
<img
30+
style={styles}
31+
src={src}
32+
/>
33+
);
34+
}
35+
}}
36+
layers={[
37+
[
38+
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
39+
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
40+
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
41+
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
42+
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
43+
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
44+
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
45+
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
46+
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
47+
],
48+
[
49+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
50+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
51+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
52+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
53+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
54+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
55+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
56+
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
57+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
58+
],
59+
]}
60+
/>
61+
);
62+
}
63+
}

demo/stores/game-store.js

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import { observable } from 'mobx';
2+
3+
class GameStore {
4+
@observable characterPosition = { x: 0, y: 0 };
5+
setCharacterPosition(position) {
6+
this.characterPosition = position;
7+
}
8+
}
9+
10+
export default new GameStore();

package.json

+4-3
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,7 @@
2222
"license": "MIT",
2323
"repository": "https://github.com/FormidableLabs/react-music",
2424
"dependencies": {
25-
"mobx": "^2.5.0",
26-
"mobx-react": "^3.5.5"
25+
"matter-js": "^0.10.0"
2726
},
2827
"peerDependencies": {
2928
"react": "^15.2.1",
@@ -34,6 +33,7 @@
3433
"babel-core": "^6.10.4",
3534
"babel-eslint": "^6.1.2",
3635
"babel-loader": "^6.2.4",
36+
"babel-plugin-transform-decorators-legacy": "^1.3.4",
3737
"babel-plugin-transform-flow-strip-types": "^6.14.0",
3838
"babel-preset-es2015": "^6.9.0",
3939
"babel-preset-react": "^6.11.1",
@@ -46,7 +46,8 @@
4646
"eslint-plugin-jsx-a11y": "^2.1.0",
4747
"eslint-plugin-react": "^6.1.2",
4848
"flow-bin": "^0.31.1",
49-
"json-loader": "^0.5.4",
49+
"mobx": "^2.5.0",
50+
"mobx-react": "^3.5.5",
5051
"postcss-loader": "^0.10.1",
5152
"react": "^15.2.1",
5253
"react-dom": "^15.2.1",

public/assets/background.png

2.48 KB
Loading

src/components/body.js

+43
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import React, { Component, PropTypes } from 'react';
2+
3+
import { World, Bodies } from 'matter-js';
4+
5+
export default class Body extends Component {
6+
7+
static propTypes = {
8+
args: PropTypes.array,
9+
children: PropTypes.any,
10+
shape: PropTypes.string,
11+
};
12+
13+
static defaultProps = {
14+
args: [0, 0, 100, 100],
15+
shape: 'rectangle',
16+
};
17+
18+
static contextTypes = {
19+
world: PropTypes.object,
20+
};
21+
22+
static childContextTypes = {
23+
body: PropTypes.object,
24+
};
25+
26+
constructor(props, context) {
27+
super(props);
28+
29+
this.body = Bodies[props.shape](...props.args);
30+
World.addBody(context.world, this.body);
31+
}
32+
33+
getChildContext() {
34+
return {
35+
body: this.body,
36+
};
37+
}
38+
39+
render() {
40+
return this.props.children;
41+
}
42+
43+
}

0 commit comments

Comments
 (0)