diff --git a/.eslintrc.js b/.eslintrc.js
new file mode 100644
index 0000000..16dadd1
--- /dev/null
+++ b/.eslintrc.js
@@ -0,0 +1,30 @@
+module.exports = {
+ env: {
+ browser: true,
+ es2021: true,
+ },
+ extends: [
+ "eslint:recommended",
+ "plugin:@typescript-eslint/recommended",
+ "plugin:react/recommended",
+ ],
+ overrides: [
+ {
+ env: {
+ node: true,
+ },
+ files: [".eslintrc.{js,cjs}"],
+ parserOptions: {
+ sourceType: "script",
+ },
+ },
+ ],
+ parser: "@typescript-eslint/parser",
+ parserOptions: {
+ ecmaVersion: "latest",
+ sourceType: "module",
+ },
+ plugins: ["@typescript-eslint", "react"],
+ rules: {},
+ ignorePatterns: ["*.d.ts"],
+};
diff --git a/.gitignore b/.gitignore
index d0637c2..4675c34 100644
--- a/.gitignore
+++ b/.gitignore
@@ -9,6 +9,12 @@ npm-debug.*
*.mobileprovision
*.orig.*
web-build/
+*.log
+*.app
+*.tar.gz
+*.ipa
+*.apk
+*.aab
# macOS
.DS_Store
diff --git a/App.tsx b/App.tsx
index c1c37d7..0a270af 100644
--- a/App.tsx
+++ b/App.tsx
@@ -1,15 +1,36 @@
+import React from "react";
import { StatusBar } from "expo-status-bar";
import { SafeAreaProvider } from "react-native-safe-area-context";
+import { Logs } from 'expo'
+import { SafeAreaView, useSafeAreaInsets } from "react-native-safe-area-context";
-import AppView from "./AppView";
+import GameEngine from "./game/systems/GameEngine";
export default function App() {
+ Logs.enableExpoCliLogging()
+
return (
<>
-
+
>
);
}
+
+function SafeView() {
+ const { top, bottom, left, right } = useSafeAreaInsets();
+ const topInset = top.valueOf();
+ global.topInset = topInset;
+ global.bottomInset = bottom;
+ global.leftInset = left;
+ global.rightInset = right;
+
+ return (
+
+
+
+ );
+}
+
diff --git a/AppView.tsx b/AppView.tsx
deleted file mode 100644
index e278437..0000000
--- a/AppView.tsx
+++ /dev/null
@@ -1,94 +0,0 @@
-import React, { useEffect, useState } from "react";
-import { StyleSheet, Text, TouchableOpacity, View } from "react-native";
-import { GameEngine } from "react-native-game-engine";
-import { SafeAreaView, useSafeAreaInsets } from "react-native-safe-area-context";
-
-import { entities, useEntities } from "@entities";
-import { GameLoop } from "@systems";
-import { IGameEngine } from "@types";
-
-export default function AppView() {
- const [isRunning, setIsRunning] = React.useState(true);
- const [score, setScore] = useState(0);
- const [gameEngine, setGameEngine] = useState(null);
- const { entities } = useEntities();
- const { top } = useSafeAreaInsets();
- const topInset = top.valueOf();
- (global as any).topInset = topInset;
-
- const gameEntities = entities();
- const { engine, world } = gameEntities.physics;
-
- // console.log(topInset)
-
- // const gameEntities = entities();
- useEffect(() => {
- (global as any).gameEngine = gameEngine;
- }, [gameEngine]);
-
- return (
-
- {/* @ts-ignore */}
- setGameEngine(ref as IGameEngine)}
- systems={[GameLoop]}
- entities={gameEntities}
- running={isRunning}
- onEvent={({ type, ...rest }: any) => {
- switch (type) {
- case "addToScore": {
- setScore(score => score + 1);
- break;
- }
- case "subtractFromScore": {
- setScore(score => score - 1);
- break;
- }
- }
- }}
- style={{ position: "absolute", top: 0, left: 0, right: 0, bottom: 0 }}
- >
- {
- // gameEngine?.swap(entities());
- if (isRunning) {
- gameEngine?.stop();
- setIsRunning(false);
- } else {
- gameEngine?.start();
- setIsRunning(true);
- }
- }}
- style={{
- position: "absolute",
- top: 0,
- left: 0,
- height: 55,
- width: "100%",
- // borderColor: "red",
- // borderWidth: 1,
- }}
- >
-
- {isRunning ? score : "Press to Resume"}
-
-
-
-
- );
-}
-
-const styles = StyleSheet.create({
- container: {
- flex: 1,
- },
-});
diff --git a/app.json b/app.json
index bba08a9..00f0af0 100644
--- a/app.json
+++ b/app.json
@@ -18,7 +18,8 @@
"**/*"
],
"ios": {
- "supportsTablet": true
+ "supportsTablet": true,
+ "bundleIdentifier": "com.nightness.reactnativegameengineexpotypescripttemplate"
},
"android": {
"adaptiveIcon": {
@@ -28,6 +29,12 @@
},
"web": {
"favicon": "./assets/favicon.png"
+ },
+ "jsEngine": "jsc",
+ "extra": {
+ "eas": {
+ "projectId": "bb283987-7da9-4a8e-b730-4aebcd816864"
+ }
}
}
}
diff --git a/assets/SVG/BalloonSVG.js b/assets/SVG/BalloonSVG.js
index 2a00279..7b03e10 100644
--- a/assets/SVG/BalloonSVG.js
+++ b/assets/SVG/BalloonSVG.js
@@ -20,6 +20,5 @@ export const BalloonSVG = (props) => {
- )
+ );
};
-
diff --git a/eas.json b/eas.json
new file mode 100644
index 0000000..1985877
--- /dev/null
+++ b/eas.json
@@ -0,0 +1,62 @@
+{
+ "cli": {
+ "version": ">= 2.7.1"
+ },
+ "build": {
+ "local": {
+ "distribution": "internal",
+ "android": {
+ "buildType": "apk",
+ "image": "latest"
+ },
+ "ios": {
+ "simulator": true
+ }
+ },
+ "development": {
+ "developmentClient": true,
+ "distribution": "internal",
+ "android": {
+ "buildType": "apk",
+ "image": "latest"
+ },
+ "ios": {
+ "simulator": true,
+ "resourceClass": "m-medium"
+ }
+ },
+ "preview": {
+ "channel": "preview",
+ "android": {
+ "buildType": "app-bundle",
+ "image": "latest"
+ },
+ "ios": {
+ "resourceClass": "m-medium"
+ }
+ },
+ "production": {
+ "channel": "production",
+ "android": {
+ "buildType": "app-bundle",
+ "image": "latest"
+ },
+ "ios": {
+ "resourceClass": "m-medium"
+ }
+ }
+ },
+ "submit": {
+ "preview": {
+ "android": {
+ "releaseStatus": "draft"
+ }
+ },
+ "production": {
+ "android": {
+ "track": "production",
+ "releaseStatus": "completed"
+ }
+ }
+ }
+}
diff --git a/game/entities/Balloon.tsx b/game/entities/Balloon.tsx
index d5b248e..fbe27e3 100644
--- a/game/entities/Balloon.tsx
+++ b/game/entities/Balloon.tsx
@@ -1,61 +1,53 @@
+import React from 'react'
import Matter from 'matter-js'
import { ColorValue, View } from 'react-native'
import { BalloonSVG } from '@svg'
-import { Position2D, Size2D } from '@types'
+import { GameEntity, Position2D, Size2D } from '@types'
-const Balloon = ({ body, color }: any) => {
- const widthBody = body.bounds.max.x - body.bounds.min.x;
- const heightBody = body.bounds.max.y - body.bounds.min.y;
-
- const xBody = body.position.x - widthBody / 2;
- const yBody = body.position.y - heightBody / 2;
-
- return (
-
-
-
- );
+const Balloon = ({ body, color }: GameEntity) => {
+ const heightBody = body.bounds.max.y - body.bounds.min.y;
+ const widthBody = body.bounds.max.x - body.bounds.min.x;
+
+ const xBody = body.position.x - widthBody / 2;
+ const yBody = body.position.y - heightBody / 2;
+
+ return (
+
+
+
+ );
+};
+
+export default (
+ label: string,
+ world: Matter.Composite,
+ color: ColorValue,
+ pos: Position2D,
+ size: Size2D
+) => {
+ const body = Matter.Bodies.rectangle(pos.x, pos.y, size.width, size.height, {
+ label,
+ isStatic: false,
+ id: 5,
+ frictionAir: 0.5,
+ });
+ Matter.Composite.add(world, body);
+
+ return {
+ body,
+ color,
+ pos,
+ renderer: Balloon,
};
-
- export default (
- label: string,
- world: Matter.Composite,
- color: ColorValue,
- pos: Position2D,
- size: Size2D
- ) => {
- const body = Matter.Bodies.circle(pos.x, pos.y, 50, {
- label,
- isStatic: false,
- id: 5,
- // restitution: 0.4,
- // friction: 1,
- frictionAir: 0.5,
- // mass: 0.1,
- // inverseMass: 0.1,
- // bounds: {
- // min: { x: size.width, y: size.height },
- // max: { x: size.width, y: size.height },
- // },
- // inertia: Infinity,
- // inverseInertia: Infinity,
- } as Matter.IChamferableBodyDefinition);
- Matter.Composite.add(world, body);
-
- return {
- body,
- color,
- pos,
- renderer: Balloon,
- };
- };
-
\ No newline at end of file
+};
diff --git a/game/entities/Wall.tsx b/game/entities/Wall.tsx
index 9adff87..7ed361d 100644
--- a/game/entities/Wall.tsx
+++ b/game/entities/Wall.tsx
@@ -2,9 +2,9 @@ import Matter from 'matter-js'
import React from 'react'
import { ColorValue, View } from 'react-native'
-import { Position2D, Size2D } from '@types'
+import { GameEntity, Position2D, Size2D } from '@types'
-const Wall = ({ body, color }: any) => {
+const Wall = ({ body, color }: GameEntity) => {
const widthBody = body.bounds.max.x - body.bounds.min.x
const heightBody = body.bounds.max.y - body.bounds.min.y
diff --git a/game/entities/entities.ts b/game/entities/entities.ts
index d04fcab..5a26417 100644
--- a/game/entities/entities.ts
+++ b/game/entities/entities.ts
@@ -1,17 +1,22 @@
-import { Dimensions } from "react-native";
import Matter from "matter-js";
import { windowHeight, windowWidth } from "@game";
import { Balloon, Wall } from ".";
+import { GameEngineEntities } from "@types";
-export const entities = (restart: boolean = false) => {
- let engine = Matter.Engine.create(undefined, {
+export function entities(): GameEngineEntities {
+ const engine = Matter.Engine.create({
enableSleeping: false,
- gravity: { x: 0, y: 0.001 },
+ gravity: { x: 0, y: 1.75 },
} as Matter.IEngineDefinition);
- let world = engine.world;
- const topInset = (global as any).topInset; // for notch handling
+ const world = engine.world;
+ const [top, bottom] = [
+ global.topInset,
+ global.bottomInset,
+ global.leftInset,
+ global.rightInset,
+ ];
const newBalloon = () =>
Balloon(
@@ -20,41 +25,41 @@ export const entities = (restart: boolean = false) => {
"red",
{
x: Math.random() * (windowWidth - 100) + 50,
- y: 150,
+ y: 200,
},
- { width: 50, height: 50 }
+ { width: 40, height: 50 }
);
- let entities = {
+ const entities = {
physics: { engine, world },
Balloon: newBalloon(),
- LeftWall: Wall(
- "LeftWall",
- world,
- "orange",
- { x: 0 - 25, y: windowHeight / 2 },
- { height: windowHeight, width: 50 }
- ),
- RightWall: Wall(
- "RightWall",
- world,
- "orange",
- { x: windowWidth + 25, y: windowHeight / 2 },
- { height: windowHeight, width: 50 }
- ),
+ // LeftWall: Wall(
+ // "LeftWall",
+ // world,
+ // "orange",
+ // { x: 0 - 25, y: windowHeight / 2 },
+ // { height: windowHeight - topInset - bottomInset + 560, width: 50 }
+ // ),
+ // RightWall: Wall(
+ // "RightWall",
+ // world,
+ // "orange",
+ // { x: windowWidth + 25, y: windowHeight / 2 },
+ // { height: windowHeight - topInset - bottomInset + 560, width: 50 }
+ // ),
Ceiling: Wall(
"Ceiling",
world,
"orange",
{ x: 0, y: 0 },
- { height: 110 + topInset, width: windowWidth * 2 }
+ { height: 110 + top, width: windowWidth * 2 }
),
Floor: Wall(
"Floor",
world,
"orange",
- { x: windowWidth / 2, y: windowHeight + 60 },
- { height: 60, width: windowWidth }
+ { x: windowWidth / 2, y: windowHeight - top },
+ { height: 60 + bottom, width: windowWidth }
),
};
@@ -72,23 +77,25 @@ export const entities = (restart: boolean = false) => {
Matter.Events.on(
engine,
"collisionStart",
- ({ pairs, name, source, timestamp }: Matter.IEventCollision) => {
- for (var i = 0, j = pairs.length; i != j; ++i) {
+ ({ pairs }: Matter.IEventCollision