I made a proof of concept for the M5Stick with Joystick hat. Using the joystick hat you can move a circle around the screen. Said circle has simple collision detection. Currently there is only one obstacle though. Adding more would be my next step.
Also I included the ability to pause using button B. While paused you can even adjust the display brightness with the joystick.
from m5stack import axp, btnA, btnB
from m5ui import M5Rect, M5Circle, setScreenColor
from uiflow import wait_ms
import time
import hat
# configure size of deadzone on joystick input
joyTolerance = 0.5
# configure display
intDisplayBrightness = 35
setScreenColor(0x111111)
axp.setLcdBrightness(intDisplayBrightness)
# configure cursor position and size
lstCursorCrd = [20, 5] # initial position
cursorRad = 4
circle0 = M5Circle(lstCursorCrd[0], lstCursorCrd[1], cursorRad, 0xFFFFFF, 0xFFFFFF)
# rectangular obstruction and hit box around it
obs = (29, 109, 20, 20)
rectangle0 = M5Rect(obs[0], obs[1], obs[2], obs[3], 0xFF5500, 0xFF5500)
rectLeadX = obs[0]
rectLeadY = obs[1]
rectEndX = obs[0] + obs[2]
rectEndY = obs[1] + obs[3]
# define joystick hat
joy0 = hat.get(hat.JOYSTICK)
#get center positions on joystick for calibration
joyX = joy0.InvertX
joyY = joy0.InvertY
# store booleans of invalid motion
boolXPlus = True
boolXMinus = True
boolYPlus = True
boolYMinus = True
# store timeouts to reduce collision flicker
yTimeoutDur = None
xTimeoutDur = None
yTimedout = False
xTimedout = False
#store current state for play/pause
play = True
while True:
while play is True:
# move cursor hitbox
circLeadY = round(lstCursorCrd[0]) - cursorRad - 2
circLeadX = round(lstCursorCrd[1]) - cursorRad - 2
circEndY = round(lstCursorCrd[0]) + cursorRad + 2
circEndX = round(lstCursorCrd[1]) + cursorRad + 2
if not ((circEndY > rectLeadY) and (circLeadY < rectEndY) and (circLeadX < rectEndX) and (circEndX > rectLeadX)):
# left
if lstCursorCrd[0] < 153 and (joy0.InvertY - joyY) > (0 + joyTolerance) and yTimedout is False:
lstCursorCrd[0] += abs((joy0.InvertY - joyY)/75)
# right
if lstCursorCrd[0] > 5 and (joy0.InvertY - joyY) < (0 - joyTolerance) and yTimedout is False:
lstCursorCrd[0] -= abs((joy0.InvertY - joyY)/75)
# down
if lstCursorCrd[1] > 4 and (joy0.InvertX - joyX) > (0 + joyTolerance) and xTimedout is False:
lstCursorCrd[1] -= abs((joy0.InvertX - joyX)/75)
# up
if lstCursorCrd[1] < 75 and (joy0.InvertX - joyX) < (0 - joyTolerance) and xTimedout is False:
lstCursorCrd[1] += abs((joy0.InvertX - joyX)/75)
#collision detection code
elif circEndY >= rectLeadY and circLeadY < rectLeadY:
# time out the cursor to prevent blink
yTimeoutDur = time.ticks_ms()
yTimedout = True
# move cusor back
lstCursorCrd[0] -= 1
elif circLeadY <= rectEndY and circEndY > rectEndY:
# time out the cursor to prevent blink
yTimeoutDur = time.ticks_ms()
yTimedout = True
# move cursor back
lstCursorCrd[0] += 1
elif circEndX >= rectLeadX and circLeadX < rectLeadX:
# time out the cursor to prevent blink
xTimeoutDur = time.ticks_ms()
xTimedout = True
# move cursor back
lstCursorCrd[1] -= 1
elif circLeadX <= rectEndX and circEndX > rectEndX:
# time out the cursor to prevent blink
xTimeoutDur = time.ticks_ms()
xTimedout = True
# move cursor back
lstCursorCrd[1] += 1
#render cursor in current position
circle0.setPosition(y=round(lstCursorCrd[0]), x=round(lstCursorCrd[1]))
# unpause cursor movement after set duration from collision
if time.ticks_diff(time.ticks_ms(), yTimeoutDur) > 200:
yTimedout = False
if time.ticks_diff(time.ticks_ms(), xTimeoutDur) > 200:
xTimedout = False
# pause game with button
if btnB.wasPressed():
play = False
rectangle0.show()
# adjust display brightness while paused
if (joy0.InvertX - joyX) < (0 - joyTolerance) and intDisplayBrightness < 100:
intDisplayBrightness += 5
axp.setLcdBrightness(intDisplayBrightness)
wait_ms(100)
if (joy0.InvertX - joyX) > (0 + joyTolerance) and intDisplayBrightness > 20:
intDisplayBrightness -= 5
axp.setLcdBrightness(intDisplayBrightness)
wait_ms(100)
# resume game
if btnB.wasPressed():
play = True