from time import sleep
from machine import Pin, I2C, lightsleep, ADC, deepsleep
from ssd1306 import SSD1306_I2C
import framebuf, sys, machine, random
from random import getrandbits, randint, choice
randbool = lambda: not getrandbits(1)
# needed for console to work
sleep(.1)
class Rect:
x = 0
y = 0
w = 0
h = 0
def __init__(self, x, y, w, h):
self.x = x
self.y = y
self.w = w
self.h = h
def contains(self, rect):
return self.x <= rect.x \
and self.y <= rect.y \
and self.x + self.w >= rect.x + rect.w \
and self.y + self.h >= rect.y + rect.h
def overlaps(self, rect):
return self.x + self.w > rect.x \
and self.y + self.h > rect.y \
and rect.x + rect.w > self.x \
and rect.y + rect.h > self.y
def draw(self, oled):
oled.rect(self.x, self.y, self.w, self.h, 1);
SCREEN = Rect(0, 0, 128, 64)
class PhysicsRect(Rect):
dx = 0
dy = 0
def __init__(self, x, y, w, h, dx, dy):
super().__init__(x, y, w, h)
self.dx = dx
self.dy = dy
def draw(self, oled):
self.x += self.dx
self.y += self.dy
super().draw(oled)
class Player(Rect):
draw_call = 0
def draw(self, oled):
oled.pixel(self.x + (1 - self.draw_call), self.y, 1)
oled.pixel(self.x + self.draw_call, self.y + 1, 1)
self.draw_call = 1 - self.draw_call;
class Scene:
update_speed = 500
class StartScene(Scene):
START_BTN = 0
SETTINGS_BTN = 1
EXIT_BTN = 2
current_selected = 0
is_scrolling = False
scroll_delay_until_repeat = 4
current_scroll_delay_until_repeat = 0
class GameScene(Scene):
update_speed = 100
player = Player(63, 31, 2, 2)
obstacles = {}
spawn_cd = 3
max_obstacle_size = 8
current_spawn_cd = 0
score = 0
pass
class SettingsScene(Scene):
def __init__(self, current_game=None):
super().__init__()
if current_game:
self.returining_to_game = True
self.current_game = current_game
returining_to_game = False
current_game = None
pass
class FailScene(Scene):
final_score = 0
pass
def main():
current_scene = StartScene()
# joystick
joystick_horz_adc = ADC(26)
joystick_vert_adc = ADC(27);
get_joystick_pos = lambda: (
map_int(65535 - joystick_horz_adc.read_u16(), 0, 65535, -100, 100),
map_int(joystick_vert_adc.read_u16(), 0, 65535, -100, 100)
)
joystick_press_pin = Pin(22, Pin.IN, Pin.PULL_UP);
get_joystick_pressed = lambda: bool(joystick_press_pin.value() ^ 1)
# oled
oled = SSD1306_I2C(128, 64, I2C(1, scl=Pin(11), sda=Pin(10), freq=200000))
oled.show()
# button
button_press_pin = Pin(2, Pin.IN, Pin.PULL_UP)
get_button_pressed = lambda: bool(button_press_pin.value() ^ 1)
while True:
oled.fill(0)
oled.show()
(joystick_x, joystick_y) = get_joystick_pos()
joystick_pressed = get_joystick_pressed()
button_pressed = get_button_pressed()
if isinstance(current_scene, StartScene):
oled.text("DodgeMania!", 22, 0)
oled.rect(30, 27 + 10 * current_scene.current_selected, 64, 9, 1, True)
oled.text("Start", 42, 28,
1 - int(current_scene.current_selected == StartScene.START_BTN))
oled.text("Settings", 30, 38,
1 - int(current_scene.current_selected == StartScene.SETTINGS_BTN))
oled.text("Exit", 46, 48,
1 - int(current_scene.current_selected == StartScene.EXIT_BTN))
if abs(joystick_y) < 20:
# not using joystick
current_scene.is_scrolling = False
current_scene.current_scroll_delay_until_repeat = 0
else:
if current_scene.is_scrolling:
# autoscrolling
if joystick_y >= 20:
current_scene.current_selected += 2
if joystick_y <= -20:
current_scene.current_selected += 1
current_scene.current_selected %= 3
else:
# not autoscrolling
if current_scene.current_scroll_delay_until_repeat == 0:
#
current_scene.current_scroll_delay_until_repeat = current_scene.scroll_delay_until_repeat
if joystick_y >= 20:
current_scene.current_selected += 2
if joystick_y <= -20:
current_scene.current_selected += 1
current_scene.current_selected %= 3
else:
# wait until scroll delay finishes to repeat
current_scene.current_scroll_delay_until_repeat -= 1
if current_scene.current_scroll_delay_until_repeat == 0:
current_scene.is_scrolling = True
if joystick_pressed:
if current_scene.current_selected == StartScene.START_BTN:
current_scene = GameScene()
elif current_scene.current_selected == StartScene.SETTINGS_BTN:
current_scene = SettingsScene()
elif current_scene.current_selected == StartScene.EXIT_BTN:
oled.fill(0)
deepsleep(2)
machine.reset()
elif isinstance(current_scene, GameScene):
if button_pressed:
current_scene = SettingsScene(current_scene)
continue
if joystick_x >= 20:
current_scene.player.x += 1
if current_scene.player.x > 127:
current_scene.player.x = 127
if joystick_x <= -20:
current_scene.player.x -= 1
if current_scene.player.x < 0:
current_scene.player.x = 0
if joystick_y <= 20:
current_scene.player.y += 1
if current_scene.player.y > 63:
current_scene.player.y = 63
if joystick_y >= -20:
current_scene.player.y -= 1
if current_scene.player.y < 0:
current_scene.player.y = 0
current_scene.player.draw(oled)
if current_scene.current_spawn_cd == 0:
current_scene.current_spawn_cd = current_scene.spawn_cd
obstacle_w = randint(1, current_scene.max_obstacle_size)
obstacle_h = randint(1, current_scene.max_obstacle_size)
obstacle_x = None
obstacle_y = None
obstacle_dx = None
obstacle_dy = None
if randbool():
if randbool():
# spawns from west
obstacle_x = -obstacle_w + 1
obstacle_y = randint(3, 60)
obstacle_dx = randint(1, 3)
obstacle_dy = choice([-1, 0, 0, 0, 1])
else:
# spawns from east
obstacle_x = 124
obstacle_y = randint(3, 60)
obstacle_dx = randint(-3, -1)
obstacle_dy = choice([-1, 0, 0, 0, 1])
else:
if randbool():
# spawns from north
obstacle_y = -obstacle_h + 1
obstacle_x = randint(3, 124)
obstacle_dy = randint(1, 4)
obstacle_dx = choice([-1, 0, 0, 0, 0, 1])
else:
# spawns from south
obstacle_y = 63
obstacle_x = randint(3, 124)
obstacle_dy = randint(-4, -1)
obstacle_dx = choice([-1, 0, 0, 0, 0, 1])
current_scene.obstacles[random.uniform(-999, 999)] = PhysicsRect(
obstacle_x,
obstacle_y,
obstacle_w,
obstacle_h,
obstacle_dx,
obstacle_dy
)
else:
current_scene.current_spawn_cd -= 1
for obstacle_id in list(current_scene.obstacles.keys()):
obstacle = current_scene.obstacles[obstacle_id]
if not SCREEN.overlaps(obstacle):
"""
print(
"FORSAKEN x:{} y:{} w:{} h:{}"
.format(obstacle.x, obstacle.y, obstacle.w, obstacle.h)
)
"""
del current_scene.obstacles[obstacle_id]
obstacle.draw(oled)
if obstacle.overlaps(current_scene.player):
final_score = current_scene.score
current_scene = FailScene()
current_scene.final_score = final_score
break
if not isinstance(current_scene, GameScene):
continue
current_scene.score += 10
# print("DREW", len(current_scene.obstacles))
elif isinstance(current_scene, SettingsScene):
oled.text("Settings", 0, 0)
oled.text("Press To Exit", 20, 26)
if joystick_pressed:
if current_scene.returining_to_game:
current_scene = current_scene.current_game
else:
current_scene = StartScene()
pass
elif isinstance(current_scene, FailScene):
oled.text("Fail", 0, 0)
oled.text("Score: {}".format(current_scene.final_score), 0, 20)
oled.show()
sleep(3)
current_scene = StartScene()
pass
oled.show()
lightsleep(current_scene.update_speed)
# https://www.30secondsofcode.org/python/s/num-to-range/
def map_int(num, inMin, inMax, outMin, outMax):
return outMin + ((num - inMin) / (inMax - inMin) * (outMax - outMin))
if __name__ == "__main__":
main()