diff --git a/demo/character.js b/demo/game/character.js
similarity index 78%
rename from demo/character.js
rename to demo/game/character.js
index 7f06052..d28403b 100644
--- a/demo/character.js
+++ b/demo/game/character.js
@@ -6,7 +6,7 @@ import Matter from 'matter-js';
import {
Body,
Sprite,
-} from '../src';
+} from '../../src';
const gamepad = new Gamepad();
@@ -15,6 +15,7 @@ export default class Character extends Component {
static propTypes = {
keys: PropTypes.object,
+ onEnterBuilding: PropTypes.func,
store: PropTypes.object,
};
@@ -35,7 +36,26 @@ export default class Character extends Component {
{ x: 0, y: -0.15 },
);
Matter.Body.set(body, 'friction', 0);
- }
+ };
+
+ enterBuilding = (body) => {
+ let doorIndex = null;
+
+ const doorPositions = [...Array(6).keys()].map((a) => {
+ return [(512 * a) + 224, (512 * a) + 288];
+ });
+
+ doorPositions.forEach((dp, di) => {
+ if (body.position.x + 64 > dp[0] && body.position.x + 64 < dp[1]) {
+ doorIndex = di;
+ }
+ });
+
+ if (doorIndex !== null) {
+ Matter.Events.off(this.context.engine, 'afterUpdate', this.update);
+ this.props.onEnterBuilding(doorIndex);
+ }
+ };
update = () => {
const { keys, store } = this.props;
@@ -44,14 +64,14 @@ export default class Character extends Component {
const midPoint = Math.abs(store.stageX) + 448;
const shouldMoveStageLeft = body.position.x < midPoint && store.stageX < 0;
- const shouldMoveStageRight = body.position.x > midPoint && store.stageX > -1024;
+ const shouldMoveStageRight = body.position.x > midPoint && store.stageX > -2048;
- if (body.velocity.y === 0) {
+ if (body.velocity.y === 0 || body.velocity.y < -100) {
this.isJumping = false;
Matter.Body.set(body, 'friction', 1);
}
- if (keys && !this.isJumping) {
+ if (!this.isJumping) {
let characterState = 2;
@@ -61,6 +81,10 @@ export default class Character extends Component {
this.jump(body);
}
+ if (keys.isDown(keys.UP) || gamepad.button(0, 'button 12')) {
+ this.enterBuilding(body);
+ }
+
if (keys.isDown(keys.LEFT) || gamepad.button(0, 'button 14')) {
if (shouldMoveStageLeft) {
store.setStageX(store.stageX + 5);
@@ -128,10 +152,12 @@ export default class Character extends Component {
}
render() {
+ const x = this.props.store.characterPosition.x;
+
return (
{ this.body = b; }}
>
diff --git a/demo/game/fade.js b/demo/game/fade.js
new file mode 100644
index 0000000..4342778
--- /dev/null
+++ b/demo/game/fade.js
@@ -0,0 +1,17 @@
+import React, { PropTypes } from 'react';
+
+const Fade = (props) => (
+
+);
+
+Fade.propTypes = {
+ visible: PropTypes.bool,
+};
+
+Fade.defaultProps = {
+ visible: true,
+};
+
+export default Fade;
diff --git a/demo/demo.js b/demo/game/index.js
similarity index 73%
rename from demo/demo.js
rename to demo/game/index.js
index 868d8fc..39a6fe9 100644
--- a/demo/demo.js
+++ b/demo/game/index.js
@@ -1,26 +1,25 @@
import React, { Component } from 'react';
+import Matter from 'matter-js';
import {
Loop,
Stage,
KeyListener,
World,
-} from '../src';
+} from '../../src';
import Character from './character';
import Level from './level';
-import GameStore from './stores/game-store';
-
-import './index.css';
+import Fade from './fade';
-import Matter from 'matter-js';
+import GameStore from './stores/game-store';
-export default class Demo extends Component {
+export default class Game extends Component {
physicsInit = (engine) => {
const ground = Matter.Bodies.rectangle(
- 448 * 2, 448,
- 1024 * 2, 64,
+ 512 * 3, 448,
+ 1024 * 3, 64,
{
isStatic: true,
},
@@ -35,7 +34,7 @@ export default class Demo extends Component {
);
const rightWall = Matter.Bodies.rectangle(
- 1984, 288,
+ 3008, 288,
64, 576,
{
isStatic: true,
@@ -46,25 +45,43 @@ export default class Demo extends Component {
Matter.World.addBody(engine.world, leftWall);
Matter.World.addBody(engine.world, rightWall);
}
+
+ handleEnterBuilding = () => {
+ this.setState({
+ fade: true,
+ });
+ }
+
constructor(props) {
super(props);
+ this.state = {
+ fade: true,
+ };
this.keyListener = new KeyListener();
}
+
componentDidMount() {
+ this.setState({
+ fade: false,
+ });
+
this.keyListener.subscribe([
this.keyListener.LEFT,
this.keyListener.RIGHT,
+ this.keyListener.UP,
this.keyListener.SPACE,
]);
}
+
componentWillUnmount() {
this.keyListener.unsubscribe();
}
+
render() {
return (
-
+
@@ -72,11 +89,13 @@ export default class Demo extends Component {
store={GameStore}
/>
+
);
}
diff --git a/demo/game/level.js b/demo/game/level.js
new file mode 100644
index 0000000..61f029a
--- /dev/null
+++ b/demo/game/level.js
@@ -0,0 +1,83 @@
+import React, { Component, PropTypes } from 'react';
+import { autorun } from 'mobx';
+
+import {
+ TileMap,
+} from '../../src';
+
+import GameStore from './stores/game-store';
+
+export default class Level extends Component {
+
+ static contextTypes = {
+ scale: PropTypes.number,
+ };
+
+ constructor(props) {
+ super(props);
+
+ this.state = {
+ stageX: 0,
+ };
+ }
+
+ componentDidMount() {
+ this.cameraWatcher = autorun(() => {
+ const targetX = Math.round(GameStore.stageX * this.context.scale);
+ this.setState({
+ stageX: targetX,
+ });
+ });
+ }
+
+ componentWillReceiveProps(nextProps, nextContext) {
+ const targetX = Math.round(GameStore.stageX * nextContext.scale);
+ this.setState({
+ stageX: targetX,
+ });
+ }
+
+ componentWillUnmount() {
+ this.cameraWatcher();
+ }
+
+ getWrapperStyles() {
+ return {
+ position: 'absolute',
+ transform: `translate(${this.state.stageX}px, 0px) translateZ(0)`,
+ transformOrigin: 'top left',
+ };
+ }
+
+ render() {
+ return (
+
+
+
+
+ );
+ }
+}
diff --git a/demo/stores/game-store.js b/demo/game/stores/game-store.js
similarity index 86%
rename from demo/stores/game-store.js
rename to demo/game/stores/game-store.js
index e83706c..a312666 100644
--- a/demo/stores/game-store.js
+++ b/demo/game/stores/game-store.js
@@ -12,8 +12,8 @@ class GameStore {
setStageX(x) {
if (x > 0) {
this.stageX = 0;
- } else if (x < -1024) {
- this.stageX = -1024;
+ } else if (x < -2048) {
+ this.stageX = -2048;
} else {
this.stageX = x;
}
diff --git a/demo/index.css b/demo/index.css
deleted file mode 100644
index 140a5d7..0000000
--- a/demo/index.css
+++ /dev/null
@@ -1,11 +0,0 @@
-html, body, #root {
- background: black;
- height: 100%;
- width: 100%;
- margin: 0;
- padding: 0;
-}
-
-* {
- box-sizing: border-box;
-}
\ No newline at end of file
diff --git a/demo/index.js b/demo/index.js
index c8aede6..3b6a4d3 100644
--- a/demo/index.js
+++ b/demo/index.js
@@ -1,8 +1,8 @@
import React from 'react';
import ReactDOM from 'react-dom';
-import Demo from './demo';
+import Presentation from './presentation';
ReactDOM.render(
-
,
+
,
document.getElementById('root')
);
diff --git a/demo/intro.js b/demo/intro.js
new file mode 100644
index 0000000..d6c94e4
--- /dev/null
+++ b/demo/intro.js
@@ -0,0 +1,64 @@
+import React, { Component, PropTypes } from 'react';
+
+import Gamepad from 'html5-gamepad';
+
+const gamepad = new Gamepad();
+
+export default class Intro extends Component {
+ static propTypes = {
+ onStart: PropTypes.func,
+ };
+
+ startUpdate = () => {
+ gamepad.update();
+ if (gamepad.button(0, 'left stick')) {
+ this.props.onStart();
+ return;
+ }
+ this.animationFrame = requestAnimationFrame(this.startUpdate);
+ }
+
+ handleKeyPress = (e) => {
+ if (e.keyCode === 13) {
+ this.props.onStart();
+ }
+ }
+
+ constructor(props) {
+ super(props);
+
+ this.state = {
+ blink: false,
+ };
+ }
+
+ componentDidMount() {
+ window.addEventListener('keypress', this.handleKeyPress);
+ this.animationFrame = requestAnimationFrame(this.startUpdate);
+ this.interval = setInterval(() => {
+ this.setState({
+ blink: !this.state.blink,
+ });
+ }, 500);
+ }
+
+ componentWillUnmount() {
+ window.removeEventListener('keypress', this.handleKeyPress);
+ cancelAnimationFrame(this.animationFrame);
+ clearInterval(this.interval);
+ }
+
+ render() {
+ return (
+
+
+
+ Press Start
+
+
+ );
+ }
+}
diff --git a/demo/level.js b/demo/level.js
deleted file mode 100644
index 1bf4ceb..0000000
--- a/demo/level.js
+++ /dev/null
@@ -1,80 +0,0 @@
-import React, { Component, PropTypes } from 'react';
-import { autorun } from 'mobx';
-
-import {
- TileMap,
-} from '../src';
-
-import GameStore from './stores/game-store';
-
-export default class Level extends Component {
-
- static contextTypes = {
- scale: PropTypes.number,
- };
-
- constructor(props) {
- super(props);
-
- this.state = {
- stageX: 0,
- };
- }
-
- componentDidMount() {
- this.cameraWatcher = autorun(() => {
- const targetX = Math.round(GameStore.stageX * this.context.scale);
- this.setState({
- stageX: targetX,
- });
- });
- }
-
- componentWillUnmount() {
- this.cameraWatcher();
- }
-
- getWrapperStyles() {
- return {
- position: 'absolute',
- transform: `translate(${this.state.stageX}px, 0px) translateZ(0)`,
- transformOrigin: 'top left',
- };
- }
-
- render() {
- return (
-
-
-
- );
- }
-}
diff --git a/demo/presentation.js b/demo/presentation.js
new file mode 100644
index 0000000..0d756b7
--- /dev/null
+++ b/demo/presentation.js
@@ -0,0 +1,32 @@
+import React, { Component } from 'react';
+
+import Intro from './intro';
+import Game from './game';
+
+export default class Presentation extends Component {
+ handleStart = () => {
+ this.setState({
+ mode: 1,
+ });
+ }
+ constructor(props) {
+ super(props);
+
+ this.state = {
+ mode: 0,
+ };
+ }
+ render() {
+ let componentToRender;
+ switch (this.state.mode) {
+ case 0: {
+ componentToRender =
;
+ break;
+ }
+ case 1: {
+ componentToRender = ;
+ }
+ }
+ return componentToRender;
+ }
+}
diff --git a/package.json b/package.json
index aff9f77..f77046d 100644
--- a/package.json
+++ b/package.json
@@ -20,9 +20,8 @@
},
"author": "Ken Wheeler",
"license": "MIT",
- "repository": "https://github.com/FormidableLabs/react-music",
+ "repository": "https://github.com/FormidableLabs/react-game-kit",
"dependencies": {
- "html5-gamepad": "^0.1.4",
"matter-js": "^0.10.0"
},
"peerDependencies": {
@@ -32,6 +31,7 @@
"devDependencies": {
"babel-cli": "^6.10.1",
"babel-core": "^6.10.4",
+ "html5-gamepad": "^0.1.4",
"babel-eslint": "^6.1.2",
"babel-loader": "^6.2.4",
"babel-plugin-transform-decorators-legacy": "^1.3.4",
diff --git a/public/assets/8BITWONDERNominal.eot b/public/assets/8BITWONDERNominal.eot
new file mode 100644
index 0000000..e2c9e2a
Binary files /dev/null and b/public/assets/8BITWONDERNominal.eot differ
diff --git a/public/assets/8BITWONDERNominal.ttf b/public/assets/8BITWONDERNominal.ttf
new file mode 100644
index 0000000..6d9b397
Binary files /dev/null and b/public/assets/8BITWONDERNominal.ttf differ
diff --git a/public/assets/8BITWONDERNominal.woff b/public/assets/8BITWONDERNominal.woff
new file mode 100644
index 0000000..3973ff5
Binary files /dev/null and b/public/assets/8BITWONDERNominal.woff differ
diff --git a/public/assets/background.png b/public/assets/background.png
deleted file mode 100644
index 9dbd5eb..0000000
Binary files a/public/assets/background.png and /dev/null differ
diff --git a/public/assets/boardwalktile.png b/public/assets/boardwalktile.png
new file mode 100644
index 0000000..ed34ef6
Binary files /dev/null and b/public/assets/boardwalktile.png differ
diff --git a/public/assets/buildings.png b/public/assets/buildings.png
new file mode 100644
index 0000000..740ff17
Binary files /dev/null and b/public/assets/buildings.png differ
diff --git a/public/assets/intro.png b/public/assets/intro.png
new file mode 100644
index 0000000..f375935
Binary files /dev/null and b/public/assets/intro.png differ
diff --git a/public/index.css b/public/index.css
index e69de29..3064f2f 100644
--- a/public/index.css
+++ b/public/index.css
@@ -0,0 +1,55 @@
+@font-face {
+ font-family: '8BIT WONDER';
+ src: url('assets/8BITWONDERNominal.eot');
+ src: url('assets/8BITWONDERNominal.eot?#iefix') format('embedded-opentype'),
+ url('assets/8BITWONDERNominal.woff') format('woff'),
+ url('assets/8BITWONDERNominal.ttf') format('truetype');
+ font-weight: normal;
+ font-style: normal;
+}
+
+html, body, #root {
+ background: black;
+ height: 100%;
+ width: 100%;
+ margin: 0;
+ padding: 0;
+ color: white;
+}
+
+.intro {
+ margin: auto;
+ width: 100%;
+ max-width: 1024px;
+ display: block;
+}
+
+.start {
+ font-family: '8BIT WONDER';
+ display: block;
+ width: 400px;
+ font-size: 24px;
+ margin: -1% auto 0px;
+ text-align: center;
+ color: white;
+}
+
+.fade {
+ position: absolute;
+ top: 0;
+ left: 0;
+ bottom: 0;
+ right: 0;
+ background: black;
+ -webkit-transition: 1s opacity linear;
+ transition: 1s opacity linear;
+ opacity: 0;
+}
+
+.fade.active {
+ opacity: 1;
+}
+
+* {
+ box-sizing: border-box;
+}
\ No newline at end of file
diff --git a/src/components/body.js b/src/components/body.js
index ccab375..1fe57ca 100644
--- a/src/components/body.js
+++ b/src/components/body.js
@@ -31,7 +31,7 @@ export default class Body extends Component {
}
componentWillUnmount() {
- World.removeBody(this.context.engine.world, this.body);
+ World.remove(this.context.engine.world, this.body);
}
getChildContext() {
diff --git a/src/components/sprite.js b/src/components/sprite.js
index e140309..4e966b8 100644
--- a/src/components/sprite.js
+++ b/src/components/sprite.js
@@ -9,6 +9,7 @@ export default class Sprite extends Component {
src: PropTypes.string,
state: PropTypes.number,
states: PropTypes.array,
+ style: PropTypes.object,
ticksPerFrame: PropTypes.number,
tileHeight: PropTypes.number,
tileWidth: PropTypes.number,
@@ -38,22 +39,12 @@ export default class Sprite extends Component {
this.state = {
currentStep: 0,
- src: null,
};
}
componentDidMount() {
- const image = new Image();
- image.onload = () => {
- this.setState({
- src: this.props.src,
- });
-
- const animate = this.animate.bind(this, this.props);
- this.loopID = this.context.loop.subscribe(animate);
- };
-
- image.src = this.props.src;
+ const animate = this.animate.bind(this, this.props);
+ this.loopID = this.context.loop.subscribe(animate);
}
componentWillReceiveProps(nextProps) {
@@ -105,7 +96,6 @@ export default class Sprite extends Component {
return {
position: 'absolute',
transform: `translate(-${left}px, -${top}px)`,
- visibility: this.state.src ? 'visible' : 'hidden',
};
}
@@ -123,10 +113,10 @@ export default class Sprite extends Component {
render() {
return (
-
+
);
diff --git a/src/components/stage.js b/src/components/stage.js
index 121552f..38be0d3 100644
--- a/src/components/stage.js
+++ b/src/components/stage.js
@@ -59,10 +59,7 @@ export default class Stage extends Component {
}
getScale() {
- const { container } = this;
- const { dimensions } = this.state;
-
- const [vwidth, vheight] = dimensions;
+ const [vwidth, vheight] = this.state.dimensions;
const { height, width } = this.props;
let targetWidth;
@@ -79,7 +76,7 @@ export default class Stage extends Component {
targetScale = vwidth / width;
}
- if (!container) {
+ if (!this.container) {
return {
height,
width,
@@ -119,7 +116,7 @@ export default class Stage extends Component {
render() {
return (
{ this.container = c; }}>
-
diff --git a/src/components/tile-map.js b/src/components/tile-map.js
index 68e27a6..e2ec93f 100644
--- a/src/components/tile-map.js
+++ b/src/components/tile-map.js
@@ -10,6 +10,7 @@ export default class TileMap extends Component {
rows: PropTypes.number,
scale: PropTypes.number,
src: PropTypes.string,
+ style: PropTypes.object,
tileSize: PropTypes.number,
};
@@ -68,7 +69,6 @@ export default class TileMap extends Component {
}
getTileData(row, column, index) {
- const { scale } = this.context;
const { tileSize } = this.props;
const size = tileSize;
@@ -135,7 +135,7 @@ export default class TileMap extends Component {
render() {
const layers = this.generateMap();
return (
-
+
{ layers.map((layer, index) => {
return (
diff --git a/src/utils/shallow-equal.js b/src/utils/shallow-equal.js
index 545e937..198de82 100644
--- a/src/utils/shallow-equal.js
+++ b/src/utils/shallow-equal.js
@@ -8,20 +8,20 @@ export default function shallowEqual(objA, objB) {
return false;
}
- var keysA = Object.keys(objA);
- var keysB = Object.keys(objB);
+ let keysA = Object.keys(objA);
+ let keysB = Object.keys(objB);
if (keysA.length !== keysB.length) {
return false;
}
// Test for A's keys different from B.
- var bHasOwnProperty = Object.prototype.hasOwnProperty.bind(objB);
- for (var i = 0; i < keysA.length; i++) {
+ let bHasOwnProperty = Object.prototype.hasOwnProperty.bind(objB);
+ for (let i = 0; i < keysA.length; i++) {
if (!bHasOwnProperty(keysA[i]) || objA[keysA[i]] !== objB[keysA[i]]) {
return false;
}
}
return true;
-}
\ No newline at end of file
+}
diff --git a/webpack.config.dev.js b/webpack.config.dev.js
index 6cd3c84..7b5fd28 100644
--- a/webpack.config.dev.js
+++ b/webpack.config.dev.js
@@ -12,6 +12,11 @@ module.exports = {
},
plugins: [
new webpack.NoErrorsPlugin(),
+ new webpack.DefinePlugin({
+ 'process.env': {
+ NODE_ENV: JSON.stringify('production'),
+ },
+ }),
],
module: {
loaders: [{