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