Skip to content

Commit

Permalink
React Native Client (#128)
Browse files Browse the repository at this point in the history
* React Native Client

* Fixes for android and named export issues

* Add example React Native app

* Resolve boardgame.io module with local file

* add Babel alias for boardgame.io

* fix isMultiplayer prop

* add rn-cli.config.js so that bundler can find ../../packages

* Add styles and logo

* Update package name

* remove top level react-native.js

* remove debug prop from React Native client

* fix some naming inconsistencies

* react-native.test.js

* some directory restructuring

* fix rn-cli.config.js

* update readme

* add socketOpts and make RN client force websocket transport

* remove .flowconfig

* remove client.css
  • Loading branch information
chrisheninger authored and nicolodavis committed Apr 7, 2018
1 parent ccda7ab commit 5362955
Show file tree
Hide file tree
Showing 85 changed files with 12,943 additions and 17 deletions.
1 change: 1 addition & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
*.bundle.js
*.min.js
Game.md
package.json
15 changes: 15 additions & 0 deletions examples-react-native/.babelrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"presets": ["babel-preset-expo"],
"env": {
"development": {
"plugins": ["transform-react-jsx-source"]
}
},
"plugins": [
["module-resolver", {
"alias": {
"boardgame.io": "../packages"
}
}]
]
}
17 changes: 17 additions & 0 deletions examples-react-native/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# See https://help.github.com/ignore-files/ for more about ignoring files.

# expo
.expo/

# dependencies
/node_modules

# misc
.env.local
.env.development.local
.env.test.local
.env.production.local

npm-debug.log*
yarn-debug.log*
yarn-error.log*
1 change: 1 addition & 0 deletions examples-react-native/.watchmanconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{}
43 changes: 43 additions & 0 deletions examples-react-native/App.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/*
* Copyright 2018 The boardgame.io Authors.
*
* Use of this source code is governed by a MIT-style
* license that can be found in the LICENSE file or at
* https://opensource.org/licenses/MIT.
*/

import React from 'react';
import { Image, StyleSheet, View } from 'react-native';
import { Client } from 'boardgame.io/react-native';
import logo from './logo.png';

import TicTacToe from './game';
import Board from './board';

const App = Client({
game: TicTacToe,
board: Board,
});

const Singleplayer = () => (
<View style={styles.container}>
<Image source={logo} style={styles.logo} />
<App gameID="single" />
</View>
);

export default Singleplayer;

const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
},
logo: {
width: 300,
height: 90,
marginBottom: 24,
},
});
9 changes: 9 additions & 0 deletions examples-react-native/App.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import React from 'react';
import App from './App';

import renderer from 'react-test-renderer';

it('renders without crashing', () => {
const rendered = renderer.create(<App />).toJSON();
expect(rendered).toBeTruthy();
});
20 changes: 20 additions & 0 deletions examples-react-native/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Setup

1. Go to `examples/react-native`.
1. Run `npm install`.
1. Run `npm start`.

### Platform specific issues and how to fix them

#### Linux

You may have to run the following to get it to work on Linux:

```
$ sudo sysctl -w fs.inotify.max_user_instances=1024
$ sudo sysctl -w fs.inotify.max_user_watches=12288
```

#### MacOS

Install `watchman` from HomeBrew on Mac.
5 changes: 5 additions & 0 deletions examples-react-native/app.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"expo": {
"sdkVersion": "25.0.0"
}
}
166 changes: 166 additions & 0 deletions examples-react-native/board.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
/*
* Copyright 2018 The boardgame.io Authors.
*
* Use of this source code is governed by a MIT-style
* license that can be found in the LICENSE file or at
* https://opensource.org/licenses/MIT.
*/

import React from 'react';
import { StyleSheet, Text, TouchableHighlight, View } from 'react-native';
import PropTypes from 'prop-types';

class Board extends React.Component {
static propTypes = {
G: PropTypes.any.isRequired,
ctx: PropTypes.any.isRequired,
moves: PropTypes.any.isRequired,
playerID: PropTypes.string,
isActive: PropTypes.bool,
isMultiplayer: PropTypes.bool,
isConnected: PropTypes.bool,
};

onClick = id => {
if (this.isActive(id)) {
this.props.moves.clickCell(id);
}
};

isActive(id) {
if (!this.props.isActive) return false;
if (this.props.G.cells[id] !== null) return false;
return true;
}

render() {
const tbody = [];
const marker = {
'0': 'X',
'1': 'O',
};
for (let i = 0; i < 3; i++) {
const cells = [];
for (let j = 0; j < 3; j++) {
const id = 3 * i + j;
cells.push(
<TouchableHighlight
key={id}
onPress={() => this.onClick(id)}
style={[styles.cell, styles[`cell${id}`]]}
underlayColor="transparent"
>
<Text style={styles.value}>{marker[this.props.G.cells[id]]}</Text>
</TouchableHighlight>
);
}
tbody.push(
<View key={i} style={styles.row}>
{cells}
</View>
);
}

let disconnected = null;
if (this.props.isMultiplayer && !this.props.isConnected) {
disconnected = (
<Text id="disconnected" style={styles.infoText}>
Disconnected!
</Text>
);
}

let winner = null;
if (this.props.ctx.gameover !== undefined) {
winner = (
<Text id="winner" style={styles.infoText}>
Winner: {marker[this.props.ctx.gameover]}
</Text>
);
}

let player = null;
if (this.props.playerID !== null) {
player = (
<Text id="player" style={styles.infoText}>
Player: {this.props.playerID}
</Text>
);
}

return (
<View>
<View id="board">{tbody}</View>
<View style={styles.info}>
{player}
{winner}
{disconnected}
</View>
</View>
);
}
}

const styles = StyleSheet.create({
row: {
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'center',
},
cell: {
alignItems: 'center',
justifyContent: 'center',
width: 96,
height: 96,
borderWidth: 4,
borderColor: '#666',
borderStyle: 'solid',
},
value: {
fontSize: 48,
fontWeight: '700',
color: '#373748',
},
cell0: {
borderLeftColor: 'transparent',
borderTopColor: 'transparent',
},
cell1: {
borderTopColor: 'transparent',
},
cell2: {
borderTopColor: 'transparent',
borderRightColor: 'transparent',
},
cell3: {
borderLeftColor: 'transparent',
},
cell5: {
borderRightColor: 'transparent',
},
cell6: {
borderLeftColor: 'transparent',
borderBottomColor: 'transparent',
},
cell7: {
borderBottomColor: 'transparent',
},
cell8: {
borderRightColor: 'transparent',
borderBottomColor: 'transparent',
borderStyle: 'solid',
},
info: {
justifyContent: 'center',
alignItems: 'center',
height: 60,
marginTop: 24,
},
infoText: {
fontSize: 32,
fontWeight: '700',
color: '#373748',
},
});

export default Board;
68 changes: 68 additions & 0 deletions examples-react-native/game.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
/*
* Copyright 2018 The boardgame.io Authors
*
* Use of this source code is governed by a MIT-style
* license that can be found in the LICENSE file or at
* https://opensource.org/licenses/MIT.
*/

import { Game } from 'boardgame.io/core';

function IsVictory(cells) {
const positions = [
[0, 1, 2],
[3, 4, 5],
[6, 7, 8],
[0, 3, 6],
[1, 4, 7],
[2, 5, 8],
[0, 4, 8],
[2, 4, 6],
];

for (let pos of positions) {
const symbol = cells[pos[0]];
let winner = symbol;
for (let i of pos) {
if (cells[i] != symbol) {
winner = null;
break;
}
}
if (winner != null) return true;
}

return false;
}

const TicTacToe = Game({
name: 'tic-tac-toe',

setup: () => ({
cells: Array(9).fill(null),
}),

moves: {
clickCell(G, ctx, id) {
const cells = [...G.cells];

if (cells[id] === null) {
cells[id] = ctx.currentPlayer;
}

return { ...G, cells };
},
},

flow: {
movesPerTurn: 1,

endGameIf: (G, ctx) => {
if (IsVictory(G.cells)) {
return ctx.currentPlayer;
}
},
},
});

export default TicTacToe;
Binary file added examples-react-native/logo.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit 5362955

Please sign in to comment.