Skip to content

Commit

Permalink
Merge branch 'development'
Browse files Browse the repository at this point in the history
  • Loading branch information
jeffreylanters committed Nov 17, 2017
2 parents 0340390 + e819cab commit f1d2a49
Show file tree
Hide file tree
Showing 15 changed files with 444 additions and 293 deletions.
2 changes: 1 addition & 1 deletion .babelrc
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
{
"presets": ["es2015"]
"presets": ["env"]
}
158 changes: 106 additions & 52 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,94 +1,148 @@
# react-unity-webgl
Easy to use Unity 5.6 or newer (also Unity 2017 or newer) WebGL player component for your React application. Embed your Unity application in your react application for writing interactive interfaces with two way Unity and react communication.
# React Unity WebGL
When building content for the web, you might need to communicate with other elements on React Application. Or you might want to implement functionality using Web APIs which [Unity](https://unity3d.com) does not currently expose by default. In both cases, you need to directly interface with the browser’s JavaScript engine. React Unity WebGL provides an easy library for Unity 5.6 / 2017 or newer with different methods to do this.

<img src="http://react-etc.net/files/2016-07/logo-578x270.png" height="50px"/> <img src="http://gamepadable.com/wp-content/uploads/2016/01/Official_unity_logo.png" height="50px"/>

# installation
Install using npm. Make sure you download the version matching with your Unity version. I try to update this plugin in case of need as fast as possible. Check the [releases on GitHub](https://github.com/jeffreylanters/react-unity-webgl/releases) for the corresponding version.




# Installation
Install using npm. Make sure you download the release matching with your Unity version. I try to update this plugin in case of need as fast as possible. Check the [releases on GitHub](https://github.com/jeffreylanters/react-unity-webgl/releases) for the corresponding version.

```sh
# example
$ npm install --save react-unity-webgl
```

# usage
To get stated import the Unity component from 'react-unity-webgl'. Once imported you can use the Unity component to load in your Unity content. Place the Unity tag along with a src to the json file Unity exported.

> ### Notice
> Don't forget to add a script tag to load the `UnityLoader.js` file, exported by Unity in your base html file.



# Usage
To get started import the default Unity class from react-unity-webgl.

```js
import React, { Component } from 'react';
import { Unity } from 'react-unity-webgl';

export class App extends Component {
render() {
return (<div className="app">
<Unity src="Build/myGame.json" />
</div>)
import React from 'react';
import Unity from 'react-unity-webgl';

export class App extends React.Component {
render () {
return <Unity
src='Build/myGame.json'
loader='Build/UnityLoader.js' />
}
}
```

## optional attributes
## Optional attributes

```js
// Overruling the module
<Unity src="Build/myGame.json" module={this.myCustomModule} />
<Unity ... module={ this.myCustomModule } />
```

# communication
Unity allows you to send Javascript messages to the Unity content. In order to do so using React you have to import the Message function from 'react-unity-webgl'. The first parameter is the target game object name, the next is the method name, and the last is a optional parameter value.




# Calling Unity scripts functions from JavaScript in React
Sometimes you need to send some data or notification to the Unity script from the browser’s JavaScript. The recommended way of doing it is to call methods on GameObjects in your content. To get started import the function SendMessage from react-unity-webgl.

```js
SendMessage (objectName, methodName, value);
```

Where objectName is the name of an object in your scene; methodName is the name of a method in the script, currently attached to that object; value can be a string, a number, or can be empty. For example:
```js
import React, { Component } from 'react';
import { Message } from 'react-unity-webgl'
import React from 'react';
import { SendMessage } from 'react-unity-webgl';

export class Menu extends Component {
onClick () {
Message ("myGameObjectName", "myMethodName", "paramterValue");
export class App extends React.Component {
spawnEnemy (count) {
SendMessage ('SpawnBehaviour', 'SpawnEnemies', count);
}
render () {
return <div onClick={ this.spawnEnemy.bind(this, 5) }>
Click to Spawn 5 Enemies</div>
}
render() {
return (<div className="menu">
<div onClick={this.onClick.bind(this)}>
Click me
</div>
</div>)
}
```
While in Unity, for example:
```cs
using UnityEngine;

public class SpawnController: MonoBehaviour {
public void SpawnEnemies (int count) {
Debug.Log (string.Format ("Spawning {0} enemies", count));
}
}
```

# styling
The player will be injected in the a component with the className "unity-container". To style to player use the following sass styling. To style the loader you can style the component with the className "unity-loader". See the example below.




# Calling JavaScript functions within React from Unity scripts
We also allow you to call JavaScript functions within React from the Unity Content. To get started import the function RegisterExternalListener from react-unity-webgl.
```js
RegisterExternalListener (methodName, callback);
```
Where methodName is the name of a method in the script, this method will be binded to the current browser window so Unity can refer to it; callback canwill be a function, which takes one parameter with the value passed by your content. Note that it is recommended to register the callbacks before loading the Unity content. For example:
```js
import React from 'react';
import { RegisterExternalListener } from 'react-unity-webgl';

export class App extends React.Component {
constructor () {
RegisterExternalListener ('OpenMenu', this.openMenu.bind (this));
}
openMenu (menuId) {
console.log (`opening menu with id ${menuId$}`);
}
}
```
While in Unity, for example:
```cs
using UnityEngine;

public class MenuController: MonoBehaviour {
[DllImport("__Internal")]
private static extern void OpenMenu (string menuId);
public void OpenReactMenuById (string menuId) {
OpenMenu (menuId);
}
}
```
Simple numeric types can be passed to JavaScript in function parameters without requiring any conversion. Other data types will be passed as a pointer in the emscripten heap (which is really just a big array in JavaScript). For strings, you can use the Pointer_stringify helper function to convert to a JavaScript string. To return a string value you need to call _malloc_ to allocate some memory and the writeStringToMemory helper function to write a JavaScript string to it. If the string is a return value, then the il2cpp runtime will take care of freeing the memory for you. For arrays of primitive types, emscripten provides different ArrayBufferViews into it’s heap for different sizes of integer, unsigned integer or floating point representations of memory: HEAP8, HEAPU8, HEAP16, HEAPU16, HEAP32, HEAPU32, HEAPF32, HEAPF64. To access a texture in WebGL, emscripten provides the GL.textures array which maps native texture IDs from Unity to WebGL texture objects. WebGL functions can be called on emscripten’s WebGL context, GLctx.

Legacy ways of calling JavaScript code from Unity. You can use the Application.ExternalCall () and Application.ExternalEval () functions to invoke JavaScript code on the embedding web page. Note that expressions are evaluated in the local scope of the build. If you would like to execute JavaScript code in the global scope, see the Code Visibility section below.





# Styling
The following hierarchy will be applied to the React Unity WebGL component. Feel free to apply any styles to the component.

```scss
.unity {
.unity-container {
canvas {

/* don't forget to set my width and height! */
}
}
.unity-loader {
.bar {
.fill {
.loading-bar {
.loading-fill {
/* the width will be set by the component */
}
}
}
}
```

# html example
```html
<!DOCTYPE html>
<html lang="nl">
<head>
<title>My Unity Game</title>
</head>
<body>
<div id="app"></div>
</body>
<script src="Build/UnityLoader.js"></script>
<script src="compiled/bundle.js"></script>
</html>
```




# Contributing
When contributing to this repository, please first discuss the change you wish to make via issue, email, or any other method with the owners of this repository before making a change. Before commiting, please compile your code using `npm run compile` and open a pull request. Thank you very much!
18 changes: 18 additions & 0 deletions lib/RegisterExternalListener.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
"use strict";

Object.defineProperty(exports, "__esModule", {
value: true
});
exports.RegisterExternalListener = RegisterExternalListener;
/**
* Registers a listener to this window. When a message is sent
* from Unity using 'CallExternal', the listener will forward it
* into your React Application.
* @param {string} functionName
* @param {function} callback
*/
function RegisterExternalListener(functionName, callback) {
window[functionName] = function (paramterValue) {
callback(paramterValue);
};
}
22 changes: 22 additions & 0 deletions lib/SendMessage.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
'use strict';

Object.defineProperty(exports, "__esModule", {
value: true
});
exports.SendMessage = SendMessage;

var _Unity = require('./Unity');

/**
* Sends a message to the Unity content. This works the same
* as Unity's internal 'SendMessage' system. The paramaterValue
* is an optional field.
* @param {string} gameObjectName
* @param {string} methodName
* @param {object} paramterValue
*/
function SendMessage(gameObjectName, methodName, paramterValue) {
if (typeof paramterValue === 'undefined') paramterValue = '';

if (typeof _Unity.UnityInstance !== 'undefined') _Unity.UnityInstance.SendMessage(gameObjectName, methodName, paramterValue);else console.warn('Wait for Unity to be instantiated before sending a message to \'' + gameObjectName + '\'');
}
114 changes: 114 additions & 0 deletions lib/Unity.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
'use strict';

Object.defineProperty(exports, "__esModule", {
value: true
});

var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();

var _react = require('react');

var _react2 = _interopRequireDefault(_react);

var _UnityLoaderService = require('./UnityLoaderService');

var _UnityLoaderService2 = _interopRequireDefault(_UnityLoaderService);

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }

function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }

function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }

var Unity = function (_Component) {
_inherits(Unity, _Component);

function Unity(props) {
_classCallCheck(this, Unity);

var _this = _possibleConstructorReturn(this, (Unity.__proto__ || Object.getPrototypeOf(Unity)).call(this, props));

_this.state = {
progress: 0,
loaded: false,
error: null
};
_this.unityLoaderService = new _UnityLoaderService2.default();
return _this;
}

_createClass(Unity, [{
key: 'componentDidMount',
value: function componentDidMount() {
this.instantiate();
}
}, {
key: 'instantiate',
value: function instantiate() {
var _this2 = this;

var error = null;

if (typeof this.props.loader === 'undefined') error = 'Please provide Unity with a path to the UnityLoader in the loader prop.';
if (typeof this.props.src === 'undefined') error = 'Please provide Unity with a path to a valid JSON in the src prop.';

if (error !== null) {
console.error(error);
this.setState({ error: error });
} else {
this.unityLoaderService.append(this.props.loader).then(function () {
module.exports.UnityInstance = UnityLoader.instantiate('unity-container', _this2.props.src, {
onProgress: function onProgress(gameInstance, progress) {
_this2.setState({
loaded: progress === 1,
progress: progress
});
},
Module: _this2.props.module
});
});
}
}
}, {
key: 'render',
value: function render() {
if (this.state.error !== null) {
return _react2.default.createElement(
'div',
{ className: 'unity' },
_react2.default.createElement(
'b',
null,
'React-Unity-Webgl error'
),
' ',
this.state.error
);
}
return _react2.default.createElement(
'div',
{ className: 'unity' },
_react2.default.createElement(
'div',
null,
_react2.default.createElement('div', { className: 'unity-container', id: 'unity-container' })
),
this.state.loaded === false && _react2.default.createElement(
'div',
{ className: 'unity-loader' },
_react2.default.createElement(
'div',
{ className: 'bar' },
_react2.default.createElement('div', { className: 'fill', style: { width: this.state.progress * 100 + '%' } })
)
)
);
}
}]);

return Unity;
}(_react.Component);

exports.default = Unity;
Loading

0 comments on commit f1d2a49

Please sign in to comment.