Research
Security News
Quasar RAT Disguised as an npm Package for Detecting Vulnerabilities in Ethereum Smart Contracts
Socket researchers uncover a malicious npm package posing as a tool for detecting vulnerabilities in Etherium smart contracts.
react-native-game-engine
Advanced tools
Some React Native components that make it easier to construct interactive scenes using the familiar update + draw lifecycle used in the development of many games ✨
Some React Native ⚡ components that make it easier to construct interactive scenes using the familiar update
+ draw
lifecycle used in the development of many games ✨
Firstly, install the package to your project:
npm install --save react-native-game-engine
Then import the GameEngine component:
import { GameEngine } from "react-native-game-engine"
Let's code a scene that incorporates some mult-touch logic. Create a file called renderers.js
import React, { PureComponent } from "react";
import { StyleSheet, View } from "react-native";
const RADIUS = 50;
class Finger extends PureComponent {
render() {
const x = this.props.position[0] - RADIUS / 2;
const y = this.props.position[1] - RADIUS / 2;
return (
<View style={[styles.finger, { left: x, top: y }]} />
);
}
}
const styles = StyleSheet.create({
finger: {
borderColor: "#CCC",
borderWidth: 4,
borderRadius: RADIUS * 2,
width: RADIUS * 2,
height: RADIUS * 2,
backgroundColor: "pink",
position: "absolute"
}
});
export { Finger };
Next, let's code our systems in a file called systems.js
const MoveFinger = (entities, { touches }) => {
//-- I'm choosing to update the game state (entities) directly for the sake of brevity and simplicity.
//-- There's nothing stopping you from treating the game state as immutable and returning a copy..
//-- Example: return { ...entities, t.id: { UPDATED COMPONENTS }};
touches.filter(t => t.type === "move").forEach(t => {
let finger = entities[t.id];
if (finger && finger.position) {
finger.position = [
finger.position[0] + t.delta.pageX,
finger.position[1] + t.delta.pageY
];
}
});
return entities;
};
export { MoveFinger };
Finally let's bring it all together in our index.ios.js
(or index.android.js
):
import React, { PureComponent } from "react";
import { AppRegistry, StyleSheet } from "react-native";
import { GameEngine } from "react-native-game-engine";
import { Finger } from "./renderers";
import { MoveFinger } from "./systems"
export default class BestGameEver extends PureComponent {
constructor() {
super();
}
render() {
return (
<GameEngine
style={styles.container}
systems={[MoveFinger]}
entities={{
1: { position: [50, 50], renderer: <Finger />},
2: { position: [150, 150], renderer: <Finger />},
3: { position: [250, 250], renderer: <Finger />},
4: { position: [350, 450], renderer: <Finger />},
5: { position: [450, 550], renderer: <Finger />}
}}>
</GameEngine>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: "#FFF"
}
});
AppRegistry.registerComponent("BestGameEver", () => BestGameEver);
Compile and run. Each entity is a "finger" and is assigned to a particular touch id. The touch ids increase as you place more fingers on the screen. Move your fingers around the screen to move the entities. As an exercise, try add a system that will insert another finger entity into the game state when a "start" touch event is encountered. What about adding a system that removes the closest entity from the game state when a "long-press" is encountered?
React Native Game Engine
doesn't give me sensor data out of the box - what gives?This package contains only two components:
GameLoop
GameEngine
Both are standalone components. The GameLoop
is a subset of the GameEngine
and gives you access to an onUpdate
callback that fires every 16ms (or roughly 60 fps). On top of this, the GameLoop
will supply a reference to the screen (via Dimensions.get("window"))
, touch events for multiple fingers (start, end, press, long-press, move) and time + deltas. The GameLoop
is useful for simple interactive scenes, and pretty much stays out of your way.
The GameEngine
is more opinionated and is a react-friendly implementation of the [Component-Entity-Systems pattern](#building-complex-scenes-with-the-component-entity-systems pattern). It provides the same features out of the box as the GameEngine
but also includes a crude event/signalling pipeline for communcation between your game and your other React Native components. You probably want to use the GameEngine
to implement slightly more complex games and interactive scenes.
The game loop is a common pattern in game development and other interactive programs. It loosely consists of two main functions that get called over and over again: update
and draw
.
The update
function is responsible for calculating the next state of your game. It updates all of your game objects, taking into consideration physics, ai, movement, input, health/fire/damage etc. We can consider this the logic of your game.
Once the update
function has done its thing - the draw
function is responsible for taking the current state of the game and rendering it to the screen. Typically, this would include drawing characters, scenery and backgrounds, static or dynamic objects, bad guys, special effects and HUD etc.
Ideally, both functions complete within 16ms, and we start the next iteration of the loop until some loop-breaking condition is encountered: pause, quit, game over etc. This might seem like a lot of processing overhead, but unlike regular applications, games are highly interactive and ever changing. The game loop affords us full control over scenes - even when no user input or external events have fired.
A typical React Native app will only redraw itself when this.setState()
is called on a component with some new state (for lack of better words). Often times, this is a direct response to user input (button press, keystroke, swipe) or other event (websocket callback, push notificaiton etc).
This works perfectly fine (and is even ideal) for a business-oriented app - but it doesn't give the developer fine grained control to create highly interactive and dynamic scenes.
Unlike most other software, games keep moving even when the user isn’t providing input. If you sit staring at the screen, the game doesn’t freeze. Animations keep animating. Visual effects dance and sparkle. If you’re unlucky, that monster keeps chomping on your hero.
This is the first key part of a real game loop: it processes user input, but doesn’t wait for it. The loop always keeps spinning - Robert Nystrom
That said, React Native and game loops are not mutually exclusive, and we can use React Native Game Engine
to bridge the two paradigms.
Firstly, install the package to your project:
npm install --save react-native-game-engine
Then import the GameLoop component:
import { GameLoop } from "react-native-game-engine"
Let's code a basic scene with a single moveable game object. Add this into your index.ios.js
(or index.android.js
):
import React, { PureComponent } from "react";
import { AppRegistry, StyleSheet, Dimensions, View } from "react-native";
import { GameLoop } from "react-native-game-engine";
const { width: WIDTH, height: HEIGHT } = Dimensions.get("window");
const RADIUS = 25;
export default class BestGameEver extends PureComponent {
constructor() {
super();
this.state = {
x: WIDTH / 2 - RADIUS,
y: HEIGHT / 2 - RADIUS
};
}
updateHandler = ({ touches, screen, time }) => {
let move = touches.find(x => x.type === "move");
if (move) {
this.setState({
x: this.state.x + move.delta.pageX,
y: this.state.y + move.delta.pageY
});
}
};
render() {
return (
<GameLoop style={styles.container} onUpdate={this.updateHandler}>
<View style={[styles.player, { left: this.state.x, top: this.state.y }]} />
</GameLoop>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: "#FFF"
},
player: {
position: "absolute",
backgroundColor: "pink",
width: RADIUS * 2,
height: RADIUS * 2,
borderRadius: RADIUS * 2
}
});
AppRegistry.registerComponent("BestGameEver", () => BestGameEver);
BasicGameLoop
starts a timer using requestAnimationFrame(fn)
. Effectively, this is our game loop.BasicGameLoop
will call the function passed in via props.onUpdate
.updateHandler
looks for any move
touches that were made between now and the last time through the loop.this.setState()
.Nice observation! Indeed, there is none. The logic of our scene is processed in the updateHandler
function, and our drawing is handled by our component's out-of-the-box render()
function.
All we've done here is hookup a timer to a function that fires every ~16ms, and used this.setState()
to force React Native to diff the changes in our scene and send them across the bridge to the host device. React Native Game Engine
only takes care of the game timing and input processing for us.
Typically, game developers have used OOP to implement complex game objects and scenes. Each game object is instantiated from a class, and polymorphism allows code re-use and behaviors to be extended through inheritance. As class hierarchies grow, it becomes increasingly difficult to create new types of game entities without duplicating code or seriously re-thinking the entire class hierarchy.
[GameEntity]
|
|
[Vehicle]
/ | \
/ | \
/ | \
/ | \
[Terrestrial] [Marine] [Airborne]
| | |
| | |
[Tank] [Boat] [Jet]
How do we insert a new terrestrial and marine-based vehicle - say a Hovercraft - into the class hierarchy?
One way to address these problems is to favor composition over inheritance. With this approach, we break out the attributes and behaviours of our various game entities into decoupled, encapsulated and atomic components. This allows us to be really imaginative with the sorts of game entities we create because we can easily compose them with components from disparate domains and concerns.
Component entity systems are one way to organize your game entities in a composable manner. To start with, we take the common attributes (data) of our game entities and move them into siloed components. These don't have to be concrete classes, simple hash maps (or equivalent) and scalars will do - but this depends on the data you're storing.
Examples of different types of components in a hypothetical programming language.
Your game entities will be reduced to lists/arrays of components and labeled with a unique identifier. An entity's components are by no means static - you're free to update components and even add or remove them on the fly. If our favourite Italian plumber ingests a mushroom, we simple double his velocity. If our character turns into a ghost - we remove his physics component and let him walk through walls.
All entities are assigned a unique id.
Since our entities are simple data holders now, we must move all our game logic into our systems. At its core, a system is a function that processes related groups of components and is called on each iteration of the game loop. The system will extract entities that contain the necessary components it requires to run, update those entities as necessary, and wait for the next cycle. For example, we could code a "Gravity" component that calculates the force of gravity and applies it to all entities that have an acceleration AND velocity AND mass component. Entities that do not contain these components will not be affected by gravity.
The logic in a system is inherently reusable because it can be applied to all entities that meet the system's criteria.
How exactly you choose to define your components, entities and systems is up to you. You'll probably find that coming up with well-defined components and systems will take some practice - but the general pattern is conducive to refactoring and the long term benefits will outweight the costs (learning curve).
The following is a list of invaluable packages when it comes to coding interactive scenes. Please feel free to nominate others:
FAQs
Some React Native components that make it easier to construct interactive scenes using the familiar update + draw lifecycle used in the development of many games ✨
The npm package react-native-game-engine receives a total of 821 weekly downloads. As such, react-native-game-engine popularity was classified as not popular.
We found that react-native-game-engine demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Research
Security News
Socket researchers uncover a malicious npm package posing as a tool for detecting vulnerabilities in Etherium smart contracts.
Security News
Research
A supply chain attack on Rspack's npm packages injected cryptomining malware, potentially impacting thousands of developers.
Research
Security News
Socket researchers discovered a malware campaign on npm delivering the Skuld infostealer via typosquatted packages, exposing sensitive data.