diff --git a/package.json b/package.json
index b603353..126b9ba 100644
--- a/package.json
+++ b/package.json
@@ -12,6 +12,7 @@
"@testing-library/jest-dom": "^4.2.4",
"@testing-library/react": "^9.3.2",
"@testing-library/user-event": "^7.1.2",
+ "@theme-ui/color": "^0.4.0-rc.5",
"@theme-ui/components": "^0.3.1",
"@types/hammerjs": "^2.0.36",
"@types/peerjs": "^1.1.0",
@@ -53,7 +54,7 @@
"peer": "^0.5.3",
"peerjs": "^1.3.1",
"pnp-webpack-plugin": "1.6.4",
- "polished": "^3.6.5",
+ "polished": "^3.6.7",
"postcss-flexbugs-fixes": "4.1.0",
"postcss-loader": "3.0.0",
"postcss-normalize": "8.0.1",
@@ -67,6 +68,7 @@
"react-dom": "^16.13.1",
"react-hammerjs": "^1.0.1",
"react-modal": "^3.11.2",
+ "react-move": "^6.4.0",
"react-popper": "^2.2.3",
"resolve": "1.15.0",
"resolve-url-loader": "3.1.1",
@@ -108,6 +110,7 @@
},
"devDependencies": {
"@testing-library/dom": "^7.23.0",
+ "@theme-ui/css": "^0.4.0-rc.5",
"@types/dat.gui": "^0.7.5",
"@types/jest": "^26.0.10",
"@types/node": "^12.0.0",
@@ -116,7 +119,7 @@
"@types/react-dom": "^16.9.0",
"@types/react-hammerjs": "^1.0.1",
"@types/react-modal": "^3.10.6",
- "@types/theme-ui": "^0.3.6",
+ "@types/theme-ui": "^0.3.7",
"@types/uuid": "^8.3.0",
"@typescript-eslint/eslint-plugin": "^3.10.1",
"@typescript-eslint/parser": "^3.10.1",
diff --git a/public/images/sun_segment.png b/public/images/sun_segment.png
new file mode 100644
index 0000000..b9986bb
Binary files /dev/null and b/public/images/sun_segment.png differ
diff --git a/public/images/sun_segment.svg b/public/images/sun_segment.svg
new file mode 100644
index 0000000..0a21963
--- /dev/null
+++ b/public/images/sun_segment.svg
@@ -0,0 +1,291 @@
+
+
diff --git a/src/3d/constants.ts b/src/3d/constants.ts
index 89b01ca..092fdc9 100644
--- a/src/3d/constants.ts
+++ b/src/3d/constants.ts
@@ -3,6 +3,7 @@ import { Vector3 } from 'three'
export const TAU = Math.PI * 2
export const MODELS_LOCATION = process.env.PUBLIC_URL + '/models'
+export const IMAGES_LOCATION = process.env.PUBLIC_URL + '/images'
export const MODELS = {
BLUE_TOP: 'blueTop',
@@ -63,16 +64,14 @@ export const COLOR_VALUES: { [k in Color]: number } = {
}
export const SHADE_Y: { [k in GrowthStage]: number } = [-18, -10.7, -5.63, 0]
-
export const SUN_ANGLE = 52.725
-
export const TREE_TOP_Y = 10
-
export const TILE_SIZE = 5
-
export const INITIAL_SUN_ORIENTATION = 1.50 * Math.PI
-
export const GROUND_SHADE_HIDDEN_ROTATION = -0.8
+export const SUN_SEGMENT_SIZE = 56
+export const SUN_SEGMENT_POSITION_Y = 2.2
+export const SUN_SEGMENT_POSITION_Z = SUN_SEGMENT_SIZE / 2
export interface TreeGrowthProp {
tree: { scale: Vector3 }
diff --git a/src/3d/extraObjects.ts b/src/3d/extraObjects.ts
index f195d88..945b09d 100644
--- a/src/3d/extraObjects.ts
+++ b/src/3d/extraObjects.ts
@@ -1,4 +1,5 @@
-import { CylinderBufferGeometry, Mesh, MeshBasicMaterial, Object3D } from 'three'
+import { CylinderBufferGeometry, Mesh, MeshBasicMaterial, Object3D, PlaneBufferGeometry, TextureLoader } from 'three'
+import { IMAGES_LOCATION, SUN_SEGMENT_SIZE } from './constants'
const cylinderGeometry = new CylinderBufferGeometry(4, 4, 1, 12)
const cylinderMaterial = new MeshBasicMaterial()
@@ -12,3 +13,11 @@ CYLINDER_OBJ.add(cylinderMesh)
export const basicGray = new MeshBasicMaterial({
color: 0xcccccc
})
+
+const sunSegmentTexture = new TextureLoader().load(
+ IMAGES_LOCATION + '/sun_segment.png', undefined, undefined, console.error
+)
+const sunSegmentMaterial = new MeshBasicMaterial({ transparent: true, map: sunSegmentTexture })
+const sunSegmentGeometry = new PlaneBufferGeometry(SUN_SEGMENT_SIZE, SUN_SEGMENT_SIZE)
+export const sunSegmentMesh = new Mesh(sunSegmentGeometry, sunSegmentMaterial)
+sunSegmentMesh.rotation.x = -Math.PI / 2
diff --git a/src/Game/GameWorld.ts b/src/Game/GameWorld.ts
index 374be0d..9af953e 100644
--- a/src/Game/GameWorld.ts
+++ b/src/Game/GameWorld.ts
@@ -26,7 +26,7 @@ import {
MODELS,
SKY_COLOR,
SUN_ANGLE,
- SUN_COLOR,
+ SUN_COLOR, SUN_SEGMENT_POSITION_Y, SUN_SEGMENT_POSITION_Z,
TAU,
TREE_GROWTH_DURATION
} from '../3d/constants'
@@ -38,7 +38,7 @@ import SunOrientationTagComponent from './components/SunOrientationTagComponent'
import SunOrientationSystem from './systems/SunOrientationSystem'
import dat from 'dat.gui'
import { Axial } from '../3d/Coordinates/Axial'
-import { CYLINDER_OBJ } from '../3d/extraObjects'
+import { CYLINDER_OBJ, sunSegmentMesh } from '../3d/extraObjects'
import Stats from 'stats.js'
import GameWorldMessages from './types/GameWorldMessages'
import { TileInfo } from './types/TileInfo'
@@ -265,6 +265,21 @@ export default class GameWorld {
.addObject3DComponent(game, this.sceneEntity)
this.generateGrid()
+
+ const sunSegmentWrapperObj = new Object3D()
+ sunSegmentWrapperObj.name = 'sunSegmentWrapper'
+ const sunSegmentObj = new Object3D()
+ sunSegmentObj.name = 'sugSegment'
+ sunSegmentObj.position.y = SUN_SEGMENT_POSITION_Y
+ sunSegmentObj.position.z = SUN_SEGMENT_POSITION_Z
+ sunSegmentObj.rotation.y = Math.PI
+ sunSegmentObj.add(sunSegmentMesh)
+ sunSegmentWrapperObj.add(sunSegmentObj)
+
+ this.world
+ .createEntity('sunSegment')
+ .addObject3DComponent(sunSegmentWrapperObj, this.gameEntity)
+ .addComponent(SunOrientationTagComponent)
}
private generateGrid (): void {
diff --git a/src/Game/getInitialState.ts b/src/Game/getInitialState.ts
index befd1a7..b5245bc 100644
--- a/src/Game/getInitialState.ts
+++ b/src/Game/getInitialState.ts
@@ -40,6 +40,7 @@ export const getInitialState = (players: number): GameState => {
dirtyTiles: [],
turn: 0,
rayDirection: 0,
+ totalRevolutions: 3,
revolutionLeft: 3,
board: getInitialBoard(),
scoreTokens: {
diff --git a/src/Game/types/GameState.ts b/src/Game/types/GameState.ts
index 8a4675e..c927f01 100644
--- a/src/Game/types/GameState.ts
+++ b/src/Game/types/GameState.ts
@@ -6,6 +6,7 @@ export interface GameState {
dirtyTiles: string[]
turn: number
rayDirection: number
+ totalRevolutions: number
revolutionLeft: number
gameOver?: string
board: TileMap
diff --git a/src/components/App.tsx b/src/components/App.tsx
index c167e56..dd8e9c3 100644
--- a/src/components/App.tsx
+++ b/src/components/App.tsx
@@ -9,6 +9,7 @@ import { GamePlayer } from './GamePlayer'
import { withAlertQueue } from './common/AlertContext'
import GameRenderer from './GameRenderer'
import { Box } from '@theme-ui/components'
+import RevolutionCounter from './RevolutionCounter'
export enum AppState {
HOME,
@@ -61,6 +62,9 @@ const App: FunctionComponent = () => {
//
}
+
+
+
diff --git a/src/components/GamePlayer.tsx b/src/components/GamePlayer.tsx
index db5a5f3..8f4c821 100644
--- a/src/components/GamePlayer.tsx
+++ b/src/components/GamePlayer.tsx
@@ -90,7 +90,7 @@ export const GamePlayer: FunctionComponent
+
{hintText}
{game.state !== undefined && interactionState.axial !== undefined && interactionState.popperCoord !== undefined &&
> = ({ state, setState }) => {
+const NavBar: FunctionComponent> = () => {
const [colorMode, setColorMode] = useColorMode()
const toggleDarkMode = (): void => setColorMode(colorMode === 'default' ? 'dark' : 'default')
return (
-
+ // eslint-disable-next-line
+ // @ts-ignore
+ // eslint-disable-next-line
+
{/* {state > 0 && } */}
diff --git a/src/components/RevolutionCounter.tsx b/src/components/RevolutionCounter.tsx
new file mode 100644
index 0000000..54a675b
--- /dev/null
+++ b/src/components/RevolutionCounter.tsx
@@ -0,0 +1,371 @@
+import React, { FunctionComponent } from 'react'
+import { Animate, NodeGroup } from 'react-move'
+import { TAU } from '../3d/constants'
+import { getColor } from '@theme-ui/color'
+import { BoxProps, useThemeUI } from 'theme-ui'
+import { Box } from '@theme-ui/components'
+import { darken, lighten } from 'polished'
+import easeOutQuart from '../Game/easing/1d/easeOutQuart'
+import { useGame } from '../Game/GameContext'
+
+const getRemainingSlices = (elapsedRounds: number, circleIndex: number): number => {
+ if (elapsedRounds / 6 < circleIndex) {
+ return 6
+ } else if (elapsedRounds / 6 >= circleIndex + 1) {
+ return 0
+ } else {
+ return 6 - elapsedRounds % 6
+ }
+}
+
+const isPieEnlarged = (elapsedRounds: number, circleIndex: number): boolean => {
+ return elapsedRounds / 6 >= circleIndex
+}
+
+const getCoordinatesOnCircle = (percentageRemaining: number): { x: number, y: number } => {
+ return {
+ x: -Math.sin(TAU * percentageRemaining),
+ y: -Math.cos(TAU * percentageRemaining)
+ }
+}
+
+const BORDER_WIDTH = 0.08
+
+const RevolutionCounter: FunctionComponent = ({
+ ...boxProps
+}) => {
+ const [game] = useGame()
+ const state = game.state
+ const preparingRounds = state?.preparingRound ?? 0
+ const isPreparation = preparingRounds > 0
+ const totalRounds = isPreparation ? 6 : (state?.totalRevolutions ?? 0) * 6
+ const elapsedRounds = isPreparation ? 6 - preparingRounds : totalRounds - (state?.revolutionLeft ?? 0) * 6 + (6 - (state?.rayDirection ?? 0)) % 6
+
+ // eslint-disable-next-line
+ const circleIndexes = React.useMemo(() => [...Array(Math.ceil(totalRounds / 6)).keys()], [elapsedRounds, totalRounds])
+ const { theme } = useThemeUI()
+ // eslint-disable-next-line
+ // @ts-ignore
+ const bg = getColor(theme, 'bgs.2') as string
+ // eslint-disable-next-line
+ // @ts-ignore
+ const accent = getColor(theme, isPreparation ? 'blue.0' : 'yellow.0') as string
+ const shadow = darken(0.1, bg)
+ const highlight = lighten(0.1, bg)
+ const { sx, ...otherBoxProps } = boxProps
+ return (
+
+
+
+ )
+}
+
+export default RevolutionCounter
diff --git a/src/theme/buttons.js b/src/theme/buttons.js
index e3d97b6..f6b41e0 100644
--- a/src/theme/buttons.js
+++ b/src/theme/buttons.js
@@ -99,6 +99,9 @@ const buttonColors = {
}
}
+/**
+ * @type {Record}
+ */
const buttons = {}
for (const styleName in buttonStyles) {
diff --git a/src/theme/index.js b/src/theme/index.ts
similarity index 88%
rename from src/theme/index.js
rename to src/theme/index.ts
index 0b85ba0..3147b6d 100644
--- a/src/theme/index.js
+++ b/src/theme/index.ts
@@ -10,8 +10,9 @@ import text from './text'
import wells from './wells'
import messages from './messages'
import badges from './badges'
+import { Theme } from '@theme-ui/css'
-export default {
+const theme: Theme = {
useColorSchemeMediaQuery: true,
colors: {
...light,
@@ -24,6 +25,8 @@ export default {
danger: colors.red[0],
warning: colors.yellow[0]
},
+ // eslint-disable-next-line
+ // @ts-ignore
text,
breakpoints: ['40em', '52em', '64em', '110em'],
space: [
@@ -65,7 +68,7 @@ export default {
},
radii: [0, 4, 8, 16, 32],
shadows: [
- null,
+ 'none',
'0 2px 4px rgba(0, 0, 0, 0.2)',
'0 4px 8px rgba(0, 0, 0, 0.3)'
],
@@ -87,5 +90,8 @@ export default {
links,
dropdown,
wells,
+ // eslint-disable-next-line
+ // @ts-ignore
styles
}
+export default theme
diff --git a/yarn.lock b/yarn.lock
index 5039e71..92d9897 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1774,6 +1774,14 @@
"@theme-ui/css" "^0.3.1"
deepmerge "^4.2.2"
+"@theme-ui/color@^0.4.0-rc.5":
+ version "0.4.0-rc.5"
+ resolved "https://registry.yarnpkg.com/@theme-ui/color/-/color-0.4.0-rc.5.tgz#d638f089d2030e17438810b2b760fc9704850cc4"
+ integrity sha512-cmKnIXKC/br+qDbzmjaHg0YDgDuGdN7slKwUc2j3aSLmvx7aKdiSFBkVUMGeFhgBy32y9SIH6jmT6g3UqhogmQ==
+ dependencies:
+ "@theme-ui/css" "^0.4.0-rc.5"
+ polished "^3.4.1"
+
"@theme-ui/components@^0.3.1":
version "0.3.1"
resolved "https://registry.yarnpkg.com/@theme-ui/components/-/components-0.3.1.tgz#fe023e156c1e1c076d5f2258466426e94adc2765"
@@ -1800,6 +1808,13 @@
resolved "https://registry.yarnpkg.com/@theme-ui/css/-/css-0.3.1.tgz#b85c7e8fae948dc0de65aa30b853368993e25cb3"
integrity sha512-QB2/fZBpo4inaLHL3OrB8NOBgNfwnj8GtHzXWHb9iQSRjmtNX8zPXBe32jLT7qQP0+y8JxPT4YChZIkm5ZyIdg==
+"@theme-ui/css@^0.4.0-rc.5":
+ version "0.4.0-rc.5"
+ resolved "https://registry.yarnpkg.com/@theme-ui/css/-/css-0.4.0-rc.5.tgz#0fa254f90eecf6d8df28b1e3b4677d7fc3338d82"
+ integrity sha512-KJly9bIbfcMFwHiDB6WZ5bTMgjJSQssBFkyqETA1GpfK/M7AwpupPeyLzc65K8tYatMFXlUQmYo9JNPtLYawwg==
+ dependencies:
+ csstype "^2.5.7"
+
"@theme-ui/mdx@^0.3.0":
version "0.3.0"
resolved "https://registry.yarnpkg.com/@theme-ui/mdx/-/mdx-0.3.0.tgz#8bb1342204acfaa69914d6b6567c5c49d9a8c1e6"
@@ -2120,7 +2135,7 @@
"@types/testing-library__dom" "*"
pretty-format "^25.1.0"
-"@types/theme-ui@*", "@types/theme-ui@^0.3.6":
+"@types/theme-ui@*":
version "0.3.6"
resolved "https://registry.yarnpkg.com/@types/theme-ui/-/theme-ui-0.3.6.tgz#e7d25ef4fdaf6d3e69ef483858210df99c35c1fa"
integrity sha512-VAw3NA1Ye0dMfWM4/nfDPGTL5dFuPC1FHpDnLleEh6jRmqp2OliaJIeZnffmDVnGmb9iIvCwdaLDYAmltrnypA==
@@ -2132,6 +2147,18 @@
"@types/theme-ui__components" "*"
csstype "^3.0.2"
+"@types/theme-ui@^0.3.7":
+ version "0.3.7"
+ resolved "https://registry.yarnpkg.com/@types/theme-ui/-/theme-ui-0.3.7.tgz#67346df27d02045c7f06f9684c88e3a5622a456d"
+ integrity sha512-4hzDlDhlFYmOdXBLZTbO4N2hWfuGo1N77AcIMaSyDGEyFbdZSpelMLTkEtNzYT8yQWIl3x0WITiBzjqkfc6dUg==
+ dependencies:
+ "@emotion/serialize" "^0.11.15"
+ "@types/react" "*"
+ "@types/styled-system" "*"
+ "@types/styled-system__css" "*"
+ "@types/theme-ui__components" "*"
+ csstype "^3.0.2"
+
"@types/theme-ui__components@*":
version "0.2.5"
resolved "https://registry.yarnpkg.com/@types/theme-ui__components/-/theme-ui__components-0.2.5.tgz#65ef4e160e2e0cf7c52ae220f6579a707d33667d"
@@ -4143,6 +4170,11 @@ cyclist@^1.0.1:
resolved "https://registry.yarnpkg.com/cyclist/-/cyclist-1.0.1.tgz#596e9698fd0c80e12038c2b82d6eb1b35b6224d9"
integrity sha1-WW6WmP0MgOEgOMK4LW6xs1tiJNk=
+d3-timer@^1.0.9:
+ version "1.0.10"
+ resolved "https://registry.yarnpkg.com/d3-timer/-/d3-timer-1.0.10.tgz#dfe76b8a91748831b13b6d9c793ffbd508dd9de5"
+ integrity sha512-B1JDm0XDaQC+uvo4DT79H0XmBskgS3l6Ve+1SBCfxgmtIb1AVrPIoqd+nPSv+loMX8szQ0sVUhGngL7D5QPiXw==
+
d@1, d@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/d/-/d-1.0.1.tgz#8698095372d58dbee346ffd0c7093f99f8f9eb5a"
@@ -7095,6 +7127,13 @@ jsx-ast-utils@^2.2.1, jsx-ast-utils@^2.4.1:
array-includes "^3.1.1"
object.assign "^4.1.0"
+kapellmeister@^3.0.1:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/kapellmeister/-/kapellmeister-3.0.1.tgz#419b715cd221acda3db79892caedf63e1c9f7d25"
+ integrity sha512-S7+gYcziMREv8RxG46138mb1O4Xf9II/bCxEJPYkhlZ7PgGWTlicgsyNad/DGc5oEAlWGLXE5ExLbTDVvJmgDA==
+ dependencies:
+ d3-timer "^1.0.9"
+
killable@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/killable/-/killable-1.0.1.tgz#4c8ce441187a061c7474fb87ca08e2a638194892"
@@ -8399,7 +8438,7 @@ pnp-webpack-plugin@1.6.4:
dependencies:
ts-pnp "^1.1.6"
-polished@^3.6.5:
+polished@^3.4.1, polished@^3.6.7:
version "3.6.7"
resolved "https://registry.yarnpkg.com/polished/-/polished-3.6.7.tgz#44cbd0047f3187d83db0c479ef0c7d5583af5fb6"
integrity sha512-b4OViUOihwV0icb9PHmWbR+vPqaSzSAEbgLskvb7ANPATVXGiYv/TQFHQo65S53WU9i5EQ1I03YDOJW7K0bmYg==
@@ -9418,6 +9457,15 @@ react-modal@^3.11.2:
react-lifecycles-compat "^3.0.0"
warning "^4.0.3"
+react-move@^6.4.0:
+ version "6.4.0"
+ resolved "https://registry.yarnpkg.com/react-move/-/react-move-6.4.0.tgz#9163a87c62fff94bf6e6980685c713739192650e"
+ integrity sha512-TNyDQESDZ0xsejnxFTQ9CKarJQN6NbgpImrvIEzOVe7+jt8y7uTjJwWxqFTfmvwskIs+RmUbCWdN7PAbGyhrdA==
+ dependencies:
+ "@babel/runtime" "^7.10.3"
+ kapellmeister "^3.0.1"
+ prop-types "^15.7.2"
+
react-popper@^2.2.3:
version "2.2.3"
resolved "https://registry.yarnpkg.com/react-popper/-/react-popper-2.2.3.tgz#33d425fa6975d4bd54d9acd64897a89d904b9d97"