Skip to content

Commit

Permalink
Merge pull request #3 from GreenWizard2015/dev
Browse files Browse the repository at this point in the history
Dev
  • Loading branch information
GreenWizard2015 authored Jun 28, 2024
2 parents 7971060 + bcb125f commit 45a2de0
Show file tree
Hide file tree
Showing 47 changed files with 2,889 additions and 1,531 deletions.
2 changes: 2 additions & 0 deletions .github/FUNDING.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
patreon: GreenWizard
buy_me_a_coffee: greenwizard89
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@ __pycache__
/.project
/Data/
/.vscode
/debug.log
131 changes: 28 additions & 103 deletions App/AppModes.py
Original file line number Diff line number Diff line change
@@ -1,33 +1,11 @@
import numpy as np
import pygame
import pygame.locals as G
from App.Utils import Colors, normalized
from App.CSpinningTarget import CSpinningTarget
import time
import scipy.interpolate as sInterp

class CAppMode:
def __init__(self, app):
self._app = app
self._paused = True
return

def on_event(self, event):
if event.type == G.KEYDOWN:
if event.key in [G.K_p, G.K_RETURN]:
self._paused = not self._paused
return

def on_render(self, window):
if self._paused:
self._app.drawText('Paused', (55, 55), Colors.RED)
return

def accept(self, tracked):
if self._paused: return
self._app._dataset.store(tracked, np.array(self._pos))
return
pass
from App.CGameMode import CGameMode
from App.CAppMode import CAppMode

class CMoveToGoal(CAppMode):
def __init__(self, app):
Expand Down Expand Up @@ -94,16 +72,22 @@ def on_event(self, event):
return

if G.K_RIGHT == event.key:
self._reset(clockwise=False)
self._active = True
return

if G.K_LEFT == event.key:
self._reset(clockwise=True)
self._active = True
return
return

def accept(self, tracked):
def on_sample(self, tracked):
if self._active:
super().accept(tracked)
super().on_sample(tracked)
return

def _reset(self):
def _reset(self, clockwise=False):
path = np.array([
[-1, 1],
[ 1, 1],
Expand All @@ -112,7 +96,9 @@ def _reset(self):
[-1, 1],
], np.float32)
lvl = (self._maxLevel - self._level) / ((2.0 * self._maxLevel) + 0)
self._pos, self._goal, *self._path = 0.5 + lvl * path
path = 0.5 + lvl * path
if clockwise: path = path[::-1]
self._pos, self._goal, *self._path = path
self._active = False
self._transitionStart = None
return
Expand Down Expand Up @@ -150,9 +136,9 @@ def on_tick(self, deltaT):
self._startT = time.time()
return

def accept(self, tracked):
def on_sample(self, tracked):
if self._active:
super().accept(tracked)
super().on_sample(tracked)
return

def on_render(self, window):
Expand All @@ -173,13 +159,23 @@ def __init__(self, app):
self._pos = np.zeros((2, )) + 0.5
self._target = CSpinningTarget(app)
self._points = None
self._scale = 1.0
self._newSpline(extend=False)
return

def _updateScale(self):
newScale = np.random.uniform(0.1, 0.2) + self._scale
self._scale = newScale
if 1.0 < self._scale: self._scale = 0.0
return newScale

def _newSpline(self, extend=True):
self._T = 0.0
N = 3
points = np.random.normal(size=(4, 2), loc=0.5, scale=0.5)
scale = self._updateScale()
points = np.random.uniform(size=(N + 1, 2)) - 0.5
points /= np.linalg.norm(points, axis=-1, keepdims=True) + 1e-6
points = 0.5 + (points * scale)
if extend:
points = np.concatenate([self._points[-N:], points], axis=0)

Expand All @@ -189,7 +185,7 @@ def _newSpline(self, extend=True):

speed = np.random.uniform(0.15, 1.0, size=1)[0]
T = distance[-1] / speed
self._maxT = np.clip(T, 20, 40)
self._maxT = np.clip(T, N * 3, N * 10)
distance /= distance[-1]

shift = distance[N - 1] if extend else 0.0
Expand Down Expand Up @@ -260,78 +256,7 @@ def on_event(self, event):
return
pass
#####################
# TODO: find a way to collect data during the game mode and then use it to train the model
# Maybe store the last 2 seconds before the hit
class CGameMode:
def __init__(self, app):
self._app = app
self._pos = np.zeros((2, )) + 0.5
self._T = 0.0
self._currentRadius = 0.0
self._radiusPerSecond = 0.01
self._hits = 0
self._maxHits = 3

self._totalTime = 0
self._totalHits = 0
self._totalDistance = 0
return

def on_tick(self, deltaT):
self._T += deltaT
T = self._T
self._currentRadius = T * self._radiusPerSecond
return

def on_render(self, window):
wh = np.array(window.get_size())
pos = tuple(np.multiply(wh, self._pos).astype(np.int32))
self._app.drawObject(pos, color=Colors.RED, R=3)
# second circle
R = np.multiply(wh, self._currentRadius).min().astype(np.int32)
pygame.draw.circle(window, Colors.RED, pos, int(R), width=1)

# score at the top center
if 0 < self._totalHits:
self._app.drawText(
'Hits: %d, mean accuracy: %.4f, time: %.1f' % (
self._totalHits, self._totalDistance / self._totalHits, self._totalTime / self._totalHits
),
pos=(wh[0] // 2, 80),
color=Colors.BLACK,
)
return

def on_event(self, event):
return

def play(self, pos, tracked):
pos = np.array(pos).reshape((2, ))
# check if the click is inside the circle
D = np.square(np.subtract(pos, self._pos)).sum()
D = np.sqrt(D)
if D < self._currentRadius:
self._hit(D)
return

def _hit(self, D):
self._totalHits += 1
self._totalDistance += D
self._totalTime += self._T

self._T = 0.0
self._currentRadius = 0.0

self._hits += 1
if self._maxHits <= self._hits:
self._pos = np.random.uniform(size=(2, ))
self._hits = 0
return
pass

#####################
APP_MODES = [
CGameMode,
CLookAtMode,
CCornerMode,
CSplineMode,
Expand Down
32 changes: 32 additions & 0 deletions App/CAppMode.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import pygame as G
import numpy as np

class CAppMode:
def __init__(self, app):
self._app = app
self._paused = True
return

def on_event(self, event):
if event.type == G.KEYDOWN:
if event.key in [G.K_p, G.K_RETURN]:
self._paused = not self._paused

if event.key == G.K_SPACE:
self._paused = True
return

def on_render(self, window):
return

def on_sample(self, tracked):
if self._paused: return
self._app._dataset.store(tracked, np.array(self._pos))
return

def on_prediction(self, pos, data):
return

@property
def paused(self): return self._paused
pass
40 changes: 40 additions & 0 deletions App/CBackground.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import pygame
import pygame.locals as G
import numpy as np
import time
from App.Utils import Colors

class CBackground:
def __init__(self):
self._backgroundDynamic = False
return

def on_tick(self, deltaT):
return

def _brightness(self):
T = time.time()
amplitude = 1.0 / 2.0
duration = 30.0
# smooth brightness change over N seconds
sin = np.sin(2.0 * np.pi * T / duration)
res = 1.0 + amplitude * sin
return res

def on_render(self, window):
bg = Colors.SILVER
if self._backgroundDynamic:
# take color from Colors.asList based on current time, change every 5 seconds
bg = Colors.asList[int(time.time() / 5) % len(Colors.asList)]
# apply brightness
bg = np.multiply(bg, self._brightness()).clip(0, 255).astype(np.uint8)
window.fill(bg)
return

def on_event(self, event):
if not(event.type == G.KEYDOWN): return
# toggle background dynamic (B)
if G.K_b == event.key:
self._backgroundDynamic = not self._backgroundDynamic
return
pass
Loading

0 comments on commit 45a2de0

Please sign in to comment.