diff --git a/.idea/workspace.xml b/.idea/workspace.xml index 0d977f5..89ac273 100644 --- a/.idea/workspace.xml +++ b/.idea/workspace.xml @@ -2,11 +2,9 @@ - - - + - + @@ -25,8 +23,8 @@ - - + + @@ -35,10 +33,10 @@ - + - - + + @@ -47,10 +45,10 @@ - + - - + + @@ -59,46 +57,33 @@ - - - - - - - - - + + - + - - - - - + + - + - - - - - + + - + - - + + @@ -107,10 +92,10 @@ - + - - + + @@ -119,22 +104,19 @@ - + - - - - - + + - + - - + + @@ -143,8 +125,6 @@ - changePage - button this.props polygon projectorready @@ -172,7 +152,9 @@ addNonTargetElement randomstring renderall + loadfromjson settings + hr $PROJECT_DIR$/src/components @@ -184,7 +166,6 @@ @@ -440,12 +422,12 @@ - + - @@ -495,19 +477,6 @@ - - - - - - - - - - - - - @@ -583,13 +552,6 @@ - - - - - - - @@ -624,16 +586,6 @@ - - - - - - - - - - @@ -678,26 +630,6 @@ - - - - - - - - - - - - - - - - - - - - @@ -705,16 +637,6 @@ - - - - - - - - - - @@ -814,67 +736,124 @@ - + - - + + + + + - + - - + + - + - - + + - + + + + + + + + + + + + + + + + + + + + + - - + + + + + + + + + - + - - + + - + + + + + + + - - + + + + + + + + + + + + + + + + + + + + + + + - - + + diff --git a/package-lock.json b/package-lock.json index 328e393..d571e8e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1102,6 +1102,14 @@ "@fortawesome/fontawesome-common-types": "^0.2.28" } }, + "@fortawesome/free-brands-svg-icons": { + "version": "5.13.0", + "resolved": "https://registry.npmjs.org/@fortawesome/free-brands-svg-icons/-/free-brands-svg-icons-5.13.0.tgz", + "integrity": "sha512-/6xXiJFCMEQxqxXbL0FPJpwq5Cv6MRrjsbJEmH/t5vOvB4dILDpnY0f7zZSlA8+TG7jwlt12miF/yZpZkykucA==", + "requires": { + "@fortawesome/fontawesome-common-types": "^0.2.28" + } + }, "@fortawesome/free-solid-svg-icons": { "version": "5.13.0", "resolved": "https://registry.npmjs.org/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-5.13.0.tgz", @@ -8150,6 +8158,11 @@ "strip-bom": "^3.0.0" } }, + "load-script": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/load-script/-/load-script-1.0.0.tgz", + "integrity": "sha1-BJGTngvuVkPuSUp+PaPSuscMbKQ=" + }, "loader-fs-cache": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/loader-fs-cache/-/loader-fs-cache-1.0.3.tgz", @@ -11128,6 +11141,16 @@ "prop-types": "^15.6.2" } }, + "react-youtube": { + "version": "7.11.1", + "resolved": "https://registry.npmjs.org/react-youtube/-/react-youtube-7.11.1.tgz", + "integrity": "sha512-h78ZNLEDleq31WT1AZXU9hRZOFWCunLx4zCQCHydLXfMLAfmS5rgjB3atVnBJUoWmQLuj/A1NfIJuyMEM1m5AA==", + "requires": { + "fast-deep-equal": "3.1.1", + "prop-types": "15.7.2", + "youtube-player": "5.5.2" + } + }, "read-pkg": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", @@ -11977,6 +12000,11 @@ } } }, + "sister": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/sister/-/sister-3.0.2.tgz", + "integrity": "sha512-p19rtTs+NksBRKW9qn0UhZ8/TUI9BPw9lmtHny+Y3TinWlOa9jWh9xB0AtPSdmOy49NJJJSSe0Ey4C7h0TrcYA==" + }, "sisteransi": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", @@ -15256,6 +15284,31 @@ "camelcase": "^5.0.0", "decamelize": "^1.2.0" } + }, + "youtube-player": { + "version": "5.5.2", + "resolved": "https://registry.npmjs.org/youtube-player/-/youtube-player-5.5.2.tgz", + "integrity": "sha512-ZGtsemSpXnDky2AUYWgxjaopgB+shFHgXVpiJFeNB5nWEugpW1KWYDaHKuLqh2b67r24GtP6HoSW5swvf0fFIQ==", + "requires": { + "debug": "^2.6.6", + "load-script": "^1.0.0", + "sister": "^3.0.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + } + } } } } diff --git a/package.json b/package.json index 59f6c9c..85a9ddc 100644 --- a/package.json +++ b/package.json @@ -4,6 +4,7 @@ "private": true, "dependencies": { "@fortawesome/fontawesome-svg-core": "^1.2.28", + "@fortawesome/free-brands-svg-icons": "^5.13.0", "@fortawesome/free-solid-svg-icons": "^5.13.0", "@fortawesome/react-fontawesome": "^0.1.9", "@reduxjs/toolkit": "^1.3.3", @@ -21,6 +22,7 @@ "react-redux": "^7.2.0", "react-router-dom": "^5.1.2", "react-scripts": "3.4.1", + "react-youtube": "^7.11.1", "redux": "^4.0.5" }, "scripts": { diff --git a/public/manifest.json b/public/manifest.json index 080d6c7..726c19f 100644 --- a/public/manifest.json +++ b/public/manifest.json @@ -6,20 +6,10 @@ "src": "favicon.ico", "sizes": "64x64 32x32 24x24 16x16", "type": "image/x-icon" - }, - { - "src": "logo192.png", - "type": "image/png", - "sizes": "192x192" - }, - { - "src": "logo512.png", - "type": "image/png", - "sizes": "512x512" } ], "start_url": ".", "display": "standalone", "theme_color": "#000000", - "background_color": "#ffffff" + "background_color": "#171317" } diff --git a/src/components/App.js b/src/components/App.js index 73ed241..990f846 100644 --- a/src/components/App.js +++ b/src/components/App.js @@ -71,7 +71,9 @@ class App extends React.Component {
+ +
diff --git a/src/components/mainScreen/pages/Welcome.js b/src/components/mainScreen/pages/Welcome.js index 73bc6f2..f5ca653 100644 --- a/src/components/mainScreen/pages/Welcome.js +++ b/src/components/mainScreen/pages/Welcome.js @@ -3,6 +3,9 @@ import {Row, Col, Button} from "react-bootstrap"; import Card from "../../Card"; import {withRouter} from "react-router"; import GoogleAnalyticsUtils from "../../../util/GoogleAnalyticsUtils"; +import YouTube from "react-youtube"; +import {faReddit, faGithub} from "@fortawesome/free-brands-svg-icons"; +import {FontAwesomeIcon} from "@fortawesome/react-fontawesome"; class Welcome extends React.Component { constructor(props) { @@ -13,6 +16,22 @@ class Welcome extends React.Component { GoogleAnalyticsUtils.pageview(window.location.pathname + window.location.search); } + renderButton() { + return ( + <> + + { !this.props.videoReady ? +

Waiting on webcam feed...

+ : !this.props.cvReady ? +

Still loading...

+ : + null + } + + ) + } render() { return ( @@ -29,7 +48,25 @@ class Welcome extends React.Component { - + + + {this.renderButton()} + +
+ +
+ + +

About Take Aim

+ +
+ + +

Demo Video

+ + +
+

Features

@@ -88,20 +125,33 @@ class Welcome extends React.Component {
+ + +

Find Us Online!

+ +
+ + + + + Reddit + + + + + + + Github + + + + - - { !this.props.videoReady ? -

Waiting on webcam feed...

- : !this.props.cvReady ? -

Still loading...

- : - null - } + {this.renderButton()}
+ ); } diff --git a/src/components/mainScreen/shooting/ShotFeed.js b/src/components/mainScreen/shooting/ShotFeed.js index 58802f5..d904772 100644 --- a/src/components/mainScreen/shooting/ShotFeed.js +++ b/src/components/mainScreen/shooting/ShotFeed.js @@ -1,6 +1,5 @@ import React from 'react'; import ShotDetector from "../../../util/ShotDetector" -import {Button, Form} from "react-bootstrap"; import cookie from 'react-cookies' import { connect } from "react-redux"; import { addShot, wipeShots } from "../../../app/slices/shotSlice"; @@ -87,6 +86,10 @@ class ShotFeed extends React.Component { }) } + stop() { + this.shotDetector.stop(); + } + redrawCanvas(props) { if (!this.canvas) { return; diff --git a/src/components/mainScreen/shootingModes/duelingTree/DuelingShoot.js b/src/components/mainScreen/shootingModes/duelingTree/DuelingShoot.js index 6d81091..0cabef7 100644 --- a/src/components/mainScreen/shootingModes/duelingTree/DuelingShoot.js +++ b/src/components/mainScreen/shootingModes/duelingTree/DuelingShoot.js @@ -9,25 +9,29 @@ import {addNonTargetElement, wipeNonTargetElements} from "../../../../app/slices import {connect} from "react-redux"; import NonTargetObject from "../../../../app/pojos/NonTargetObject"; import Target from "../../../../app/pojos/Target"; +import Card from "../../../Card"; +import {batch} from "react-redux"; class DuelingShoot extends React.Component { constructor(props) { super(props); this.state = { plateOrientations: ["left", "right", "left", "right", "left", "right"], - targetIds: [null, null, null, null, null, null] + targetIds: [null, null, null, null, null, null], + competitionStarted: false } this.timerRef = React.createRef(); + this.shotFeedRef = React.createRef(); } componentDidMount() { + window.createjs.Sound.registerSound("/assets/sounds/timerbeep.wav", "Beep"); this.resetTarget(); } - resetTarget() { - this.props.wipeTargets(); - this.props.wipeNonTargetElements(); + loadTargets() { + this.shotFeedRef.current.startProcessing(); const toLoad = [TargetUtils.loadTarget("tree_plate"), TargetUtils.loadNonTargetImage("tree_stand.svg")]; Promise.all(toLoad).then(results => { let plate = results[0]; @@ -59,6 +63,42 @@ class DuelingShoot extends React.Component { }); } + resetTarget() { + batch(() => { + this.props.wipeTargets(); + this.props.wipeNonTargetElements(); + this.props.wipeShots(); + }); + this.setState({ + plateOrientations: ["left", "right", "left", "right", "left", "right"], + targetIds: [null, null, null, null, null, null] + }, () => { + this.loadTargets() + }) + } + + startCompetition() { + this.shotFeedRef.current.stop(); + this.setState({ + competitionStarted: true + }, () => { + setTimeout(() => { + window.createjs.Sound.play("Beep"); + this.shotFeedRef.current.startProcessing(); + + }, 5000) + }) + } + + stopCompetition() { + this.setState({ + competitionStarted: false + }, () => { + this.shotFeedRef.current.stop(); + window.createjs.Sound.play("Beep"); + }); + } + shouldComponentUpdate(nextProps, nextState, nextContext) { for (let i in nextProps.shots) { const shot = nextProps.shots[i] @@ -68,14 +108,14 @@ class DuelingShoot extends React.Component { } } } + if (nextState.competitionStarted !== this.state.competitionStarted) { + return true; + } return false; } componentDidUpdate(prevProps, prevState, snapshot) { - //This check is being done at teh shouldComponentUpdate level - //if (prevState.plateOrientations !== this.state.plateOrientations) { - this.updateTargets(); - //} + this.updateTargets(); } updateTargets() { @@ -98,6 +138,7 @@ class DuelingShoot extends React.Component { targetIds[targetIds.indexOf(targetsToRemove[i])] = null } + let toAdd = [] for (let i = 0; i < this.state.plateOrientations.length; i++) { if (targetIds[i] === null) { let plateX = this.standObj.x + (this.standObj.width * .4215) - this.plateWidth @@ -114,12 +155,22 @@ class DuelingShoot extends React.Component { }) targetIds[i] = plateObj.id; - this.props.addTarget(plateObj); + toAdd.push(plateObj); + //this.props.addTarget(plateObj); } } + batch(() => { + for (let i in toAdd){ + this.props.addTarget(toAdd[i]) + } + }); this.setState({ targetIds: targetIds, plateOrientations: plateOrientations + }, () => { + if (this.state.plateOrientations.indexOf("left") < 0 || this.state.plateOrientations.indexOf("right") < 0) { + this.stopCompetition() + } }) } @@ -132,8 +183,33 @@ class DuelingShoot extends React.Component {
- - + + +

Competition

+ + + + + + + + + + + + + +
Player 1Player 2
{this.state.plateOrientations.filter(a => a === "left").length}{this.state.plateOrientations.filter(a => a === "right").length}
+ {!this.state.competitionStarted && +
+ +

Competition will start on beep after 5 secnod delay

+
+ } +
+ + +
diff --git a/src/util/ShotDetector.js b/src/util/ShotDetector.js index 3292900..3d14a9b 100644 --- a/src/util/ShotDetector.js +++ b/src/util/ShotDetector.js @@ -117,16 +117,21 @@ class ShotDetector { stop() { clearInterval(this.interval) - this.readFrame.delete(); - this.warpedFrame.delete(); - this.minThreshold.delete(); - this.maxThreshold.delete(); - this.hsvImage.delete(); - this.thresholdImage.delete(); - this.contours.delete(); - this.hierarchy.delete(); - //this.videoCapture.release(); - this.hMatrix.delete(); + try { + this.readFrame.delete(); + this.warpedFrame.delete(); + this.minThreshold.delete(); + this.maxThreshold.delete(); + this.hsvImage.delete(); + this.thresholdImage.delete(); + this.contours.delete(); + this.hierarchy.delete(); + //this.videoCapture.release(); + this.hMatrix.delete(); + } catch (e) { + console.log("ERROR") + console.error(e) + } } processVideo() {