Skip to content

Instantly share code, notes, and snippets.

@samneggs
Last active October 29, 2025 08:59
Show Gist options
  • Save samneggs/1e5ae813fa86de75f0c380c3c5f40444 to your computer and use it in GitHub Desktop.
Save samneggs/1e5ae813fa86de75f0c380c3c5f40444 to your computer and use it in GitHub Desktop.
Space Invaders game on Pi Pico in MicroPython
from time import sleep, ticks_us, ticks_diff, ticks_ms, sleep_ms
import gc
import _thread, array
from machine import Timer, Pin, PWM
from sys import exit
class Game_Sound:
def __init__(self):
# index,start,dur,pause,number, volume
self.SPIDER_TUNE = array.array('I',(5,0, 31,71,10,12,500,550,800,10000,500,550,800,10000,800,500,550)) # 24,60
self.EXPLODE2_TUNE= array.array('I',(5,0,100, 0, 5,7,100,90,80,70,60,60))
self.EXPLODE_TUNE = array.array('I',(5,0,41, 0, 5, 10,1400,1300,1400,1300,1400,1450))
self.BACK_TUNE = array.array('I',(5,0,120,800, 3,10,147,131,117,110)) # 5,0, 21, 21,8,10
self.FIRE_TUNE = array.array('I',(5,0,11,21, 4,10,1000,2300,1000,2300,1000))
self.SOUND = 0
self.OFF = 0
self.pwm = PWM(Pin(17))
Pin(16,Pin.OUT).high()
self.pwm.duty_u16(1<<12)
def reset_fire(self):
self.BACK_TUNE[0] = 6
@micropython.viper
def callback1(self):
if self.OFF: return
sound = int(self.SOUND)
if sound & 1<<1:
tune = ptr32(self.EXPLODE2_TUNE)
elif sound & 1<<3:
tune = ptr32(self.FIRE_TUNE)
elif sound & 1<<2:
tune = ptr32(self.EXPLODE_TUNE)
elif sound & 1<<0:
tune = ptr32(self.BACK_TUNE)
else:
self.pwm.duty_u16(0)
return
index = tune[0]
start_ms = tune[1]
dur = tune[2]
pause = tune[3]
number = tune[4]
volume = tune[5]
now_ms = int(ticks_ms())
if now_ms - start_ms < dur: # or start_ms == 0:
self.pwm.duty_u16(1<<volume)
if tune[index] >=50: # not too low freq
self.pwm.freq(tune[index])
else:
self.pwm.duty_u16(0)
elif now_ms - start_ms < pause:
self.pwm.duty_u16(0)
else:
tune[0] += 1
if tune[0] > number+6:
tune[0] = 5
if not(sound & 1<<0) or 1:
self.SOUND = 1<<0
else:
tune[1] = int(ticks_ms()) # reset time
def deinit(self):
self.pwm.duty_u16(0)
self.SOUND = 0
#self.timer1.deinit()
@micropython.viper
def core1():
global EXIT, GAME_SOUND
GAME_SOUND = Game_Sound()
GAME_SOUND.OFF = 0
while not EXIT:
GAME_SOUND.callback1()
sleep_ms(10)
print('Core1 Stop')
if __name__=='__main__':
EXIT = False
_thread.start_new_thread(core1, ())
sleep_ms(500)
GAME_SOUND.SOUND = 0
for loop in range(3):
GAME_SOUND.SOUND = 1<<1
sleep_ms(1000)
#sleep(2)
GAME_SOUND.deinit()
exit()
# Convert Program
# Generated bytearray from: Space Invaders.bin
# Total size: 3588 bytes
binary_data = bytearray([
0x04, 0x40, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00,
0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00,
0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00,
0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff,
0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00,
0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff,
0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00
])
with open ('Space Invaders.bin', "w") as file:
file.write(binary_data)
file.close()
b = bytearray([
0x00, 0xff, 0x00,
0xff, 0x00, 0x00,
0x00, 0xff, 0x00,
0x00, 0x00, 0xff,
0x00, 0xff, 0x00,
0xff, 0x00, 0x00,
0x00, 0xff, 0x00,
0xff, 0x00, 0x00,
0x00, 0xff, 0x00,
0x00, 0x00, 0xff,
0x00, 0xff, 0x00,
0xff, 0x00, 0x00,
0x00, 0xff, 0x00,
0x00, 0x00, 0xff,
0x00, 0xff, 0x00,
0x00, 0x00, 0xff,
0x00, 0xff, 0x00,
0xff, 0x00, 0x00,
0x00, 0xff, 0x00,
0x00, 0x00, 0xff,
0x00, 0xff, 0x00,
0x00, 0x00, 0xff,
0x00, 0xff, 0x00,
0xff, 0x00, 0x00,
0x00, 0xff, 0x00,
0x00, 0x00, 0xff,
0x00, 0xff, 0x00,
0xff, 0x00, 0x00,
0x00, 0xff, 0x00,
0x00, 0xff, 0x00,
0x00, 0xff, 0x00,
0x00, 0xff, 0x00,
0x00, 0xff, 0x00,
0x00, 0xff, 0x00,
0xff, 0xff, 0xff,
0x00, 0xff, 0x00,
0x00, 0xff, 0x00,
0x00, 0xff, 0x00,
0x00, 0xff, 0x00,
0xff, 0xff, 0xff,
0x00, 0xff, 0x00,
0x00, 0xff, 0x00,
0x00, 0xff, 0x00,
0x00, 0xff, 0x00,
0xff, 0xff, 0xff,
0x00, 0xff, 0x00,
0x00, 0xff, 0x00,
0x00, 0xff, 0x00,
0x00, 0xff, 0x00,
0xff, 0xff, 0xff,
0x00, 0xff, 0x00,
0x00, 0xff, 0x00,
0x00, 0xff, 0x00,
0x00, 0xff, 0x00,
0x00, 0xff, 0x00,
0x00, 0xff, 0x00,
0x00, 0xff, 0x00,
0x00, 0xff, 0x00,
0x00, 0xff, 0x00,
0x00, 0xff, 0x00,
0x00, 0xff, 0x00,
0x00, 0xff, 0x00,
0x00, 0xff, 0x00,
0x00, 0xff, 0x00,
0x00, 0xff, 0x00,
0xff, 0xff, 0x00,
0x00, 0xff, 0xff,
0x00, 0xff, 0x00,
0xff, 0xff, 0x00,
0x00, 0xff, 0xff,
0x00, 0xff, 0x00,
0x00, 0xff, 0x00,
0x00, 0xff, 0x00,
0x00, 0xff, 0x00,
0x00, 0xff, 0x00,
0x00, 0xff, 0x00,
0x00, 0xff, 0x00,
0x00, 0xff, 0xff,
0xff, 0xff, 0x00,
0x00, 0xff, 0x00,
0x00, 0xff, 0xff,
0xff, 0xff, 0x00,
0x00, 0xff, 0x00,
0x00, 0xff, 0x00])
with open ('s_inv_miss.bin', "w") as file:
file.write(b)
file.close()
# Space Invaders
from lcd_1_8 import LCD_1inch8
import machine
from machine import Pin, PWM
from uctypes import addressof
from time import sleep, ticks_us, ticks_diff, ticks_ms, sleep_ms
import gc, _thread, array
from sys import exit
from micropython import const
from random import randint
from math import sin,cos,tan,radians,sqrt
#from rp2 import bootsel_button as RESET_PB
from invaders_sound import Game_Sound
with open ('Space Invaders.bin', "rb") as file:
SPRITES = file.read()
file.close()
with open ('s_inv_miss.bin', "rb") as file:
MISS_SPR = file.read()
file.close()
MAXSCREEN_X = const(160)
MAXSCREEN_Y = const(128)
SCALE = const(13)
COLUMNS = const(10)
S_WIDTH = const(16)
S_HEIGHT = const(8)
NUM_BUNKERS = const(4)
NUM_MISSILES = const(3)
BUNKER_Y = const(100)
PLAYER_Y = const(119)
START_SPEED = const(200)
SPEEDUP =const(4)
BUNKER_HEIGHT = const(16)
PLAYER_PARAMS = const(10)
# X,Y
FIRE = const(2)
HIT = const(3)
INVADER_PARAMS = const(10)
X = const(0)
Y = const(1)
DIR = const(2)
LEFT = const(3)
RIGHT = const(4)
BOTTOM = const(5)
COUNT = const(6)
MISSILE_PARAMS = const(10)
#X,Y,DIR
M_SPRITE = const(3)
M_SPRITE2 = const(4)
GAME_PARAMS = const(10)
FPS = const(0)
LIVES = const(1)
SPEED = const(2)
TOGGLE = const(3)
TIME = const(4)
BUNKERS= const(5)
SCORE = const(6)
SCORE_MAP = bytearray([30,20,20,10,10])
EXP_MAP=array.array('b',(
0,0,1,0,0,0,
1,0,0,0,1,0,
0,0,1,1,0,1,
0,1,1,1,1,0,
1,0,1,1,1,0,
0,1,1,1,1,1,
1,0,1,1,1,0,
0,1,0,1,0,1))
char_map=array.array('b',(
0x3E, 0x63, 0x73, 0x7B, 0x6F, 0x67, 0x3E, 0x00, # U+0030 (0)
0x0C, 0x0E, 0x0C, 0x0C, 0x0C, 0x0C, 0x3F, 0x00, # U+0031 (1)
0x1E, 0x33, 0x30, 0x1C, 0x06, 0x33, 0x3F, 0x00, # U+0032 (2)
0x1E, 0x33, 0x30, 0x1C, 0x30, 0x33, 0x1E, 0x00, # U+0033 (3)
0x38, 0x3C, 0x36, 0x33, 0x7F, 0x30, 0x78, 0x00, # U+0034 (4)
0x3F, 0x03, 0x1F, 0x30, 0x30, 0x33, 0x1E, 0x00, # U+0035 (5)
0x1C, 0x06, 0x03, 0x1F, 0x33, 0x33, 0x1E, 0x00, # U+0036 (6)
0x3F, 0x33, 0x30, 0x18, 0x0C, 0x0C, 0x0C, 0x00, # U+0037 (7)
0x1E, 0x33, 0x33, 0x1E, 0x33, 0x33, 0x1E, 0x00, # U+0038 (8)
0x1E, 0x33, 0x33, 0x3E, 0x30, 0x18, 0x0E, 0x00)) # U+0039 (9)
@micropython.viper
def show_num_viper(num:int,x_offset:int,y_offset:int,color:int):
char_ptr = ptr8(char_map)
screen_ptr = ptr16(LCD.buffer)
size = 1 # 1,2,3
char = 0
offset = MAXSCREEN_X*y_offset+x_offset
while num > 0:
total = num//10
digit = num - (total * 10)
num = total
for y in range(8):
row_data = char_ptr[digit*8+y]
for x in range(8):
if row_data & (1<<x) > 0:
addr = size*y*MAXSCREEN_X+x-(char*8)+offset
screen_ptr[addr] = color
if size>1:
screen_ptr[MAXSCREEN_X+addr] = color
if size>2:
screen_ptr[2*MAXSCREEN_X+addr] = color
char += 1
def init_pot():
global POT_X,POT_Y,POT_X_ZERO,POT_Y_ZERO
POT_X = machine.ADC(27)
POT_Y = machine.ADC(26)
POT_X_ZERO = 0
POT_Y_ZERO = 0
for i in range(1000):
POT_X_ZERO += POT_X.read_u16()
POT_Y_ZERO += POT_Y.read_u16()
POT_X_ZERO = POT_X_ZERO//1000
POT_Y_ZERO = POT_Y_ZERO//1000
pot_scale = 12
@micropython.viper
def read_pot():
player = ptr32(PLAYER)
missile = ptr32(MISSILE)
pot_scale = 12
x_inc = int(POT_X.read_u16() - POT_X_ZERO)>>pot_scale
y_inc = int(POT_Y.read_u16() - POT_Y_ZERO)>>pot_scale
x_inc += 2
if x_inc < 2 and x_inc > -2:
x_inc=0
if not FIRE_BUTTON.value():
player[FIRE] = 1
if missile[Y] == 0:
if int(GAME_SOUND.SOUND) & 1<<3 == 0:
GAME_SOUND.SOUND = int(GAME_SOUND.SOUND) | 1<<3
missile[Y] = PLAYER_Y-1
missile[X] = player[X] + 8
x = player[X] - x_inc//4
if x > 0 and x < 145:
player[X] = x
def init_invaders():
global INVADERS, ALIVE, FIRE_INV
INVADERS = array.array('i',0 for _ in range(INVADER_PARAMS))
ALIVE = bytearray(5 * COLUMNS) # 3 = alive, 2 and 1 = exploding
FIRE_INV = bytearray(11) # bottom invaders that can fire
def init_player():
global PLAYER, MISSILE
PLAYER = array.array('i',0 for _ in range(PLAYER_PARAMS))
MISSILE = array.array('i',0 for _ in range(MISSILE_PARAMS*3))
MISSILE[DIR] = -2 # player missile direction and speed
MISSILE[DIR+MISSILE_PARAMS] = 1 # invader missile #1 dir and speed
MISSILE[DIR+MISSILE_PARAMS*2] = 1 # invader missile #2
PLAYER[HIT] = 0 # 0=alive, 2,1 = exploding
def init_game():
global GAME, FPS_ARRY
GAME = array.array('i',0 for _ in range(GAME_PARAMS))
FPS_ARRY = bytearray(35)
GAME[FPS] = 0
GAME[LIVES] = 3
def init_bunker():
global BUNKER
BUNKER = bytearray(160*20) # 16
def reset_bunker():
for b in range(NUM_BUNKERS):
for y in range(0,5):
for x in range(5-y,17+y):
BUNKER[y*MAXSCREEN_X+x+b*40+10] = 1
for y in range(5,16):
for x in range(22):
BUNKER[y*MAXSCREEN_X+x+b*40+10] = 1
for y in range(11,16):
for x in range(19-y,3+y):
BUNKER[y*MAXSCREEN_X+x+b*40+10] = 0
def reset_invaders():
for i in range(5 * COLUMNS):
ALIVE[i] = 3
INVADERS[X] = 2
INVADERS[Y] = 0
INVADERS[DIR] = 1
INVADERS[COUNT] = 5 * COLUMNS
GAME[TIME] = START_SPEED
GAME[BUNKERS] = 1
@micropython.viper
def move():
player = ptr32(PLAYER)
game = ptr32(GAME)
invaders = ptr32(INVADERS)
alive = ptr8(ALIVE)
if player[HIT] == 0:
game[TOGGLE] ^= 1
invaders[X] += invaders[DIR]
right_most = (COLUMNS * 14) - (invaders[RIGHT] * 14)
left_most = invaders[LEFT] * 14
bottom_most = (3+invaders[BOTTOM]) * 10 + invaders[Y]//MAXSCREEN_X
if invaders[X] > right_most or invaders[X]+left_most < 1 : # edge of screen, move down
invaders[DIR] *= -1
invaders[Y] += 4*MAXSCREEN_X
if bottom_most > BUNKER_Y+8:
game[BUNKERS] = 0
if bottom_most > 130:
game[LIVES] -= 1
reset_invaders()
for i in range(5 * COLUMNS): # invader explosions
if alive[i] < 3 and alive[i] > 0:
alive[i] -= 1
if player[HIT] > 0: # player explosion
player[HIT] -= 1
if player[HIT] == 0:
game[LIVES] -= 1
if game[LIVES] == 0:
game_over()
@micropython.viper
def move_missiles():
missile = ptr32(MISSILE)
player = ptr32(PLAYER)
for index in range(NUM_MISSILES):
i = index * MISSILE_PARAMS
if missile[Y + i] > 0 and missile[Y + i] < MAXSCREEN_Y-7:
missile[Y + i] += missile[DIR + i] # move missile up or down
miss_collision()
missile[M_SPRITE + i] += 1
if missile[M_SPRITE + i] > 3*4:
missile[M_SPRITE + i] = 0
elif i==0:
player[FIRE] = 1
else:
missile[Y + i] = 0 # clear missile from bottom
@micropython.viper
def miss_collision():
player = ptr32(PLAYER)
missile = ptr32(MISSILE)
invaders = ptr32(INVADERS)
alive = ptr8(ALIVE)
game = ptr32(GAME)
bunker = ptr8(BUNKER)
m_x = missile[X]
m_y = missile[Y]
inv_x = invaders[X]
inv_y = invaders[Y] // MAXSCREEN_X
for i in range(5 * COLUMNS): # check missile vs invaders
if alive[i] == 3:
i_x = (i % COLUMNS)*14 + inv_x
i_y = (i // COLUMNS)*10 + inv_y + 10
if m_x > i_x and m_x < i_x + 14 and m_y > i_y and m_y < i_y + 14:
GAME_SOUND.SOUND = int(GAME_SOUND.SOUND) | 1<<2
game[SCORE] += int(SCORE_MAP[i // COLUMNS])
player[FIRE] = 0
missile[Y] = 0
alive[i] -= 1
get_edges()
game[TIME] -= SPEEDUP
GAME_SOUND.BACK_TUNE[3] = 200 + game[TIME]*3 # 800 max
invaders[COUNT] -= 1
if invaders[COUNT] == 0:
reset_invaders()
reset_bunker()
p_x = player[X]
p_y = PLAYER_Y
pm_x = missile[X] # player missile
pm_y = missile[Y]
for index in range(1,NUM_MISSILES-1):
i = index * MISSILE_PARAMS
m_x = missile[X + i]
m_y = missile[Y + i]
if m_y > 0 and m_x > p_x and m_x < p_x + 16 and m_y > p_y and m_y < p_y + 8: # invader missile vs player
missile[Y + i] = 0
player[HIT] = 10 #2
GAME_SOUND.SOUND = 1<<1
break
if game[BUNKERS] == 1 and m_y >= BUNKER_Y and m_y < BUNKER_Y + 22: # invader missile vs bunker
b_y = m_y-BUNKER_Y
if bunker[b_y * MAXSCREEN_X + m_x] == 1:
missile[Y + i] = 0
bunker_exp(m_x,b_y+2)
if m_y > 0 and pm_y > 0 and m_x > pm_x and m_x < pm_x + 3 and m_y > pm_y and m_y < pm_y + 7: # invader missile vs player missile
missile[Y + i] = 0
missile[Y] = 0
if game[BUNKERS] == 1 and pm_y >= BUNKER_Y and pm_y < BUNKER_Y + 22 and pm_x > 9: # player missile vs bunker
b_y = pm_y-BUNKER_Y
if bunker[b_y * MAXSCREEN_X + pm_x] == 1 or bunker[(b_y+1) * MAXSCREEN_X + pm_x] == 1 :
missile[Y] = 0
bunker_exp(pm_x,b_y+2)
@micropython.viper
def bunker_exp(e_x:int,e_y:int):
bunker = ptr8(BUNKER)
exp_map= ptr8(EXP_MAP)
for y in range(-4,4):
for x in range(-3,3):
bunk_addr = (e_y + y) * MAXSCREEN_X + e_x + x
exp = exp_map[(y+4)*8 + x + 3]
if exp == 1 and bunk_addr > 0 and bunk_addr < MAXSCREEN_X * 16:
bunker[bunk_addr] = 0
@micropython.viper
def get_edges():
game = ptr32(GAME)
invaders = ptr32(INVADERS)
alive = ptr8(ALIVE)
fire_inv = ptr8(FIRE_INV)
invaders[RIGHT] = 0
invaders[LEFT] = 10
invaders[BOTTOM] = 0
for i in range(5 * COLUMNS):
if alive[i] == 3:
x = i % COLUMNS
y = i // COLUMNS
if x > invaders[RIGHT]: invaders[RIGHT] = x
if x < invaders[LEFT]: invaders[LEFT] = x
if y > invaders[BOTTOM]: invaders[BOTTOM] = y
for x in range(COLUMNS): # find the bottom invaders that can fire
fire_inv[x] = 0
for y in range(5):
if alive[y * COLUMNS + x] == 3:
fire_inv[x] = y + 1
@micropython.viper
def invaders_fire():
invaders = ptr32(INVADERS)
missile = ptr32(MISSILE)
fire_inv = ptr8(FIRE_INV)
for index in range(1,NUM_MISSILES):
i = index * MISSILE_PARAMS
if missile[Y + i] > 0 and missile[Y + i] < MAXSCREEN_Y: continue
firing_invader = int(randint(0,COLUMNS))
while fire_inv[firing_invader] == 0: # find random bottom invader
firing_invader += 1
if firing_invader > COLUMNS: firing_invader = 0 # loop around
missile[Y + i] = invaders[Y]//MAXSCREEN_X + fire_inv[firing_invader] * 8 + 10
missile[X + i] = invaders[X] + firing_invader * 14 + 7
missile[M_SPRITE2 + i] = int(randint(0,2))*4 # start sprite 0,4,8
missile[M_SPRITE + i] = 0
return
@micropython.viper
def draw_invaders():
sprites = ptr16(SPRITES)
screen = ptr16(LCD.buffer)
invaders = ptr32(INVADERS)
game = ptr32(GAME)
alive = ptr8(ALIVE)
sprite_offset = 2 + game[TOGGLE]*S_HEIGHT*S_WIDTH
screen_offset = invaders[Y]+10*MAXSCREEN_X + invaders[X]
for x1 in range(COLUMNS):
test_alive = alive[x1]
if test_alive > 0:
if test_alive < 3:
sprite_offset = 2 + S_WIDTH*S_HEIGHT*5 + (test_alive)*8*S_WIDTH
else:
sprite_offset = 2 + game[TOGGLE]*S_HEIGHT*S_WIDTH
for y in range(S_HEIGHT):
for x in range(S_WIDTH):
color = sprites[sprite_offset + y*S_WIDTH + x]
screen[y*MAXSCREEN_X + x+x1*14+screen_offset] = color
sprite_offset = 2 + S_WIDTH*S_HEIGHT*2 + game[TOGGLE]*S_HEIGHT*S_WIDTH
screen_offset = invaders[Y]+20*MAXSCREEN_X + invaders[X]
for y1 in range(2):
for x1 in range(COLUMNS):
test_alive = alive[(y1+1)*COLUMNS + x1]
if test_alive > 0:
if test_alive < 3:
sprite_offset = 2 + S_WIDTH*S_HEIGHT*5 + (test_alive)*8*S_WIDTH
else:
sprite_offset = 2 + S_WIDTH*S_HEIGHT*2 + game[TOGGLE]*S_HEIGHT*S_WIDTH
for y in range(S_HEIGHT):
for x in range(S_WIDTH):
color = sprites[sprite_offset + y*S_WIDTH + x]
screen[y1*10*MAXSCREEN_X+y*MAXSCREEN_X + x+x1*14+screen_offset] = color
sprite_offset = 2 + S_WIDTH*S_HEIGHT*4 + game[TOGGLE]*8*S_WIDTH
screen_offset = invaders[Y]+40*MAXSCREEN_X + invaders[X]
for y1 in range(2):
for x1 in range(COLUMNS):
test_alive = alive[(y1+3)*COLUMNS + x1]
if test_alive > 0:
if test_alive < 3:
sprite_offset = 2 + S_WIDTH*S_HEIGHT*5 + (test_alive)*8*S_WIDTH
else:
sprite_offset = 2 + S_WIDTH*S_HEIGHT*4 + game[TOGGLE]*8*S_WIDTH
for y in range(S_HEIGHT):
for x in range(S_WIDTH):
color = sprites[sprite_offset + y*S_WIDTH + x]
screen[y1*10*MAXSCREEN_X+y*MAXSCREEN_X + x+x1*14+screen_offset] = color
@micropython.viper
def draw_player():
sprites = ptr16(SPRITES)
screen = ptr16(LCD.buffer)
invaders = ptr32(INVADERS)
player = ptr32(PLAYER)
game = ptr32(GAME)
if player[HIT] > 0:
sprite_offset = 2 + S_WIDTH*S_HEIGHT*(11+(player[HIT]%2))
else:
sprite_offset = 2 + S_WIDTH*S_HEIGHT*11
screen_offset = MAXSCREEN_X * PLAYER_Y + player[X]
for y in range(S_HEIGHT):
for x in range(S_WIDTH):
color = sprites[sprite_offset + y*S_WIDTH + x]
screen[y*MAXSCREEN_X + x+screen_offset] = color
@micropython.viper
def draw_bunker():
game = ptr32(GAME)
bunker = ptr8(BUNKER)
screen = ptr16(LCD.buffer)
if not game[BUNKERS]: return
screen_offset = MAXSCREEN_X*BUNKER_Y
for y in range(BUNKER_HEIGHT):
for x in range(MAXSCREEN_X):
color = bunker[y*MAXSCREEN_X+x]
if color > 0:
screen[screen_offset + y * MAXSCREEN_X + x] = 0xe007
@micropython.viper
def draw_missile():
missile = ptr32(MISSILE)
screen = ptr16(LCD.buffer)
miss_spr = ptr8(MISS_SPR)
for index in range(1,NUM_MISSILES): # invader missiles
i = index * MISSILE_PARAMS
if missile[Y + i] > 0 and missile[Y + i] < MAXSCREEN_Y:
x = missile[X + i]
y = missile[Y + i]
offset = missile[M_SPRITE2 + i] + (missile[M_SPRITE + i] // 4)
for y1 in range(7):
for x1 in range(3):
miss_addr = y1 * 3 + x1 + (offset * 3 * 7)
if miss_spr[miss_addr] == 0xff:
screen[(y+y1) * 160 + x + x1] = 0xffff
if missile[Y] > 0: # player missile
x = missile[X]
y = missile[Y]
LCD.line(x,y,x,y+7,0xffff)
def game_over():
GAME_SOUND.SOUND = 0
LCD.text('GAME OVER',40,50,0xff)
LCD.show()
exit()
@micropython.viper
def draw():
draw_invaders()
draw_player()
draw_bunker()
draw_missile()
game = ptr32(GAME)
if game[SCORE] == 0:
LCD.text('FPS',0,80,0xff)
show_num_viper(game[FPS],40,80,0xff)
if game[SCORE] == 10 :
LCD.text('FREE MEM',0,90,0xff)
show_num_viper(gc.mem_free(),120,90,0xff)
LCD.text('SCORE',0,0,0xff)
show_num_viper(game[SCORE],70,0,0xff)
LCD.text('LIVES',100,0,0xff)
show_num_viper(game[LIVES],145,0,0xff)
LCD.show()
LCD.rect(0,0,MAXSCREEN_X,MAXSCREEN_Y,0,1)
@micropython.asm_thumb
def avg_fps_asm(r0,r1): # r0 = fps[] , r1 = current_fps
ldrb(r2,[r0,0]) # r2 = fps[0]
add(r2,r2,1) # fps[0] += 1
cmp(r2,33)
blt(LT_32) # if fps[0] > 32:
mov(r2,1)
label(LT_32)
strb(r2,[r0,0]) # fps[0] = new index
add(r2,r2,r0)
strb(r1,[r2,0]) # fps[fps[0]] = current_fps
mov(r2,1) # r2 = i
mov(r3,0) # r3 = tot
label(LOOP)
add(r0,r0,1)
ldrb(r4,[r0,0]) # r4 = fps[i]
add(r3,r3,r4) # tot += fps[i]
add(r2,r2,1)
cmp(r2,33) #33
blt(LOOP)
asr(r0,r3,5)
@micropython.viper
def core1():
global EXIT, GAME_SOUND
GAME_SOUND = Game_Sound()
GAME_SOUND.OFF = 0
while not EXIT:
GAME_SOUND.callback1()
sleep_ms(10)
@micropython.viper
def main():
init_pot()
init_game()
init_player()
init_invaders()
init_bunker()
reset_bunker()
reset_invaders()
get_edges()
game = ptr32(GAME)
pot_ticks = 0
move_ticks = 0
inv_fire_ticks = 0
GAME_SOUND.SOUND = 1<<0
while not EXIT: # and not RESET_PB():
gticks = int(ticks_ms())
sleep(0.001)
if gticks > pot_ticks + 10:
pot_ticks = gticks
read_pot()
if gticks > move_ticks + game[TIME] and 1:
move_ticks = gticks
move()
if gticks > inv_fire_ticks + game[TIME]*10:
inv_fire_ticks = gticks
invaders_fire()
move_missiles()
draw()
game[FPS] = int(avg_fps_asm(FPS_ARRY,1_000//int(ticks_diff(ticks_ms(),gticks))))
def shutdown():
global EXIT
EXIT = True
Pin(16,Pin.OUT).low() # buzzer off
pwm.deinit()
Pin(13,Pin.OUT).low() # screen off
gc.collect()
print(gc.mem_free())
print('Core0 Stop')
exit()
if __name__=='__main__':
FIRE_BUTTON = Pin(22, Pin.IN, Pin.PULL_UP)
#machine.freq(200_000_000)
#machine.mem32[0x40008048] = 1<<11 # enable peri_ctrl clock
machine.freq(220_000_000) #220
machine.mem32[0x40010048] = 1<<11 # enable peri_ctrl clock
pwm = PWM(Pin(13))
pwm.freq(1000)
pwm.duty_u16(0x8fff)#max 0xffff
LCD = LCD_1inch8()
LCD.fill(0)
LCD.show()
EXIT = False
_thread.start_new_thread(core1, ())
#main()
try:
main()
shutdown()
except KeyboardInterrupt :
shutdown()
# Space Invaders
from lcd_1_8 import LCD_1inch8
import machine
from machine import Pin, PWM
from uctypes import addressof
from time import sleep, ticks_us, ticks_diff, ticks_ms, sleep_ms
import gc, _thread, array
from sys import exit
from micropython import const
from random import randint
from math import sin,cos,tan,radians,sqrt
from rp2 import bootsel_button as RESET_PB
from invaders_sound import Game_Sound
with open ('Space Invaders.bin', "rb") as file:
SPRITES = file.read()
file.close()
with open ('s_inv_miss.bin', "rb") as file:
MISS_SPR = file.read()
file.close()
MAXSCREEN_X = const(160)
MAXSCREEN_Y = const(128)
SCALE = const(13)
COLUMNS = const(10)
S_WIDTH = const(16)
S_HEIGHT = const(8)
NUM_BUNKERS = const(4)
NUM_MISSILES = const(3)
BUNKER_Y = const(100)
PLAYER_Y = const(119)
START_SPEED = const(200)
SPEEDUP =const(4)
BUNKER_HEIGHT = const(16)
PLAYER_PARAMS = const(10)
# X,Y
FIRE = const(2)
HIT = const(3)
INVADER_PARAMS = const(10)
X = const(0)
Y = const(1)
DIR = const(2)
LEFT = const(3)
RIGHT = const(4)
BOTTOM = const(5)
COUNT = const(6)
MISSILE_PARAMS = const(10)
#X,Y,DIR
M_SPRITE = const(3)
M_SPRITE2 = const(4)
GAME_PARAMS = const(10)
FPS = const(0)
LIVES = const(1)
SPEED = const(2)
TOGGLE = const(3)
TIME = const(4)
BUNKERS= const(5)
SCORE = const(6)
SCORE_MAP = bytearray([30,20,20,10,10])
EXP_MAP=array.array('b',(
0,0,1,0,0,0,
1,0,0,0,1,0,
0,0,1,1,0,1,
0,1,1,1,1,0,
1,0,1,1,1,0,
0,1,1,1,1,1,
1,0,1,1,1,0,
0,1,0,1,0,1))
char_map=array.array('b',(
0x3E, 0x63, 0x73, 0x7B, 0x6F, 0x67, 0x3E, 0x00, # U+0030 (0)
0x0C, 0x0E, 0x0C, 0x0C, 0x0C, 0x0C, 0x3F, 0x00, # U+0031 (1)
0x1E, 0x33, 0x30, 0x1C, 0x06, 0x33, 0x3F, 0x00, # U+0032 (2)
0x1E, 0x33, 0x30, 0x1C, 0x30, 0x33, 0x1E, 0x00, # U+0033 (3)
0x38, 0x3C, 0x36, 0x33, 0x7F, 0x30, 0x78, 0x00, # U+0034 (4)
0x3F, 0x03, 0x1F, 0x30, 0x30, 0x33, 0x1E, 0x00, # U+0035 (5)
0x1C, 0x06, 0x03, 0x1F, 0x33, 0x33, 0x1E, 0x00, # U+0036 (6)
0x3F, 0x33, 0x30, 0x18, 0x0C, 0x0C, 0x0C, 0x00, # U+0037 (7)
0x1E, 0x33, 0x33, 0x1E, 0x33, 0x33, 0x1E, 0x00, # U+0038 (8)
0x1E, 0x33, 0x33, 0x3E, 0x30, 0x18, 0x0E, 0x00)) # U+0039 (9)
@micropython.viper
def show_num_viper(num:int,x_offset:int,y_offset:int,color:int):
char_ptr = ptr8(char_map)
screen_ptr = ptr16(LCD.buffer)
size = 1 # 1,2,3
char = 0
offset = MAXSCREEN_X*y_offset+x_offset
while num > 0:
total = num//10
digit = num - (total * 10)
num = total
for y in range(8):
row_data = char_ptr[digit*8+y]
for x in range(8):
if row_data & (1<<x) > 0:
addr = size*y*MAXSCREEN_X+x-(char*8)+offset
screen_ptr[addr] = color
if size>1:
screen_ptr[MAXSCREEN_X+addr] = color
if size>2:
screen_ptr[2*MAXSCREEN_X+addr] = color
char += 1
def init_pot():
global POT_X,POT_Y,POT_X_ZERO,POT_Y_ZERO
POT_X = machine.ADC(27)
POT_Y = machine.ADC(26)
POT_X_ZERO = 0
POT_Y_ZERO = 0
for i in range(1000):
POT_X_ZERO += POT_X.read_u16()
POT_Y_ZERO += POT_Y.read_u16()
POT_X_ZERO = POT_X_ZERO//1000
POT_Y_ZERO = POT_Y_ZERO//1000
pot_scale = 12
@micropython.viper
def read_pot():
player = ptr32(PLAYER)
missile = ptr32(MISSILE)
pot_scale = 12
x_inc = int(POT_X.read_u16() - POT_X_ZERO)>>pot_scale
y_inc = int(POT_Y.read_u16() - POT_Y_ZERO)>>pot_scale
x_inc += 2
if x_inc < 2 and x_inc > -2:
x_inc=0
if not FIRE_BUTTON.value():
player[FIRE] = 1
if missile[Y] == 0:
if int(GAME_SOUND.SOUND) & 1<<3 == 0:
GAME_SOUND.SOUND = int(GAME_SOUND.SOUND) | 1<<3
missile[Y] = PLAYER_Y-1
missile[X] = player[X] + 8
x = player[X] - x_inc//4
if x > 0 and x < 145:
player[X] = x
def init_invaders():
global INVADERS, ALIVE, FIRE_INV
INVADERS = array.array('i',0 for _ in range(INVADER_PARAMS))
ALIVE = bytearray(5 * COLUMNS) # 3 = alive, 2 and 1 = exploding
FIRE_INV = bytearray(11) # bottom invaders that can fire
def init_player():
global PLAYER, MISSILE
PLAYER = array.array('i',0 for _ in range(PLAYER_PARAMS))
MISSILE = array.array('i',0 for _ in range(MISSILE_PARAMS*3))
MISSILE[DIR] = -2 # player missile direction and speed
MISSILE[DIR+MISSILE_PARAMS] = 1 # invader missile #1 dir and speed
MISSILE[DIR+MISSILE_PARAMS*2] = 1 # invader missile #2
PLAYER[HIT] = 0 # 0=alive, 2,1 = exploding
def init_game():
global GAME, FPS_ARRY
GAME = array.array('i',0 for _ in range(GAME_PARAMS))
FPS_ARRY = bytearray(35)
GAME[FPS] = 0
GAME[LIVES] = 3
def init_bunker():
global BUNKER
BUNKER = bytearray(160*20) # 16
def reset_bunker():
for b in range(NUM_BUNKERS):
for y in range(0,5):
for x in range(5-y,17+y):
BUNKER[y*MAXSCREEN_X+x+b*40+10] = 1
for y in range(5,16):
for x in range(22):
BUNKER[y*MAXSCREEN_X+x+b*40+10] = 1
for y in range(11,16):
for x in range(19-y,3+y):
BUNKER[y*MAXSCREEN_X+x+b*40+10] = 0
def reset_invaders():
for i in range(5 * COLUMNS):
ALIVE[i] = 3
INVADERS[X] = 2
INVADERS[Y] = 0
INVADERS[DIR] = 1
INVADERS[COUNT] = 5 * COLUMNS
GAME[TIME] = START_SPEED
GAME[BUNKERS] = 1
@micropython.viper
def move():
player = ptr32(PLAYER)
game = ptr32(GAME)
invaders = ptr32(INVADERS)
alive = ptr8(ALIVE)
if player[HIT] == 0:
game[TOGGLE] ^= 1
invaders[X] += invaders[DIR]
right_most = (COLUMNS * 14) - (invaders[RIGHT] * 14)
left_most = invaders[LEFT] * 14
bottom_most = (3+invaders[BOTTOM]) * 10 + invaders[Y]//MAXSCREEN_X
if invaders[X] > right_most or invaders[X]+left_most < 1 : # edge of screen, move down
invaders[DIR] *= -1
invaders[Y] += 4*MAXSCREEN_X
if bottom_most > BUNKER_Y+8:
game[BUNKERS] = 0
if bottom_most > 130:
game[LIVES] -= 1
reset_invaders()
for i in range(5 * COLUMNS): # invader explosions
if alive[i] < 3 and alive[i] > 0:
alive[i] -= 1
if player[HIT] > 0: # player explosion
player[HIT] -= 1
if player[HIT] == 0:
game[LIVES] -= 1
if game[LIVES] == 0:
game_over()
@micropython.viper
def move_missiles():
missile = ptr32(MISSILE)
player = ptr32(PLAYER)
for index in range(NUM_MISSILES):
i = index * MISSILE_PARAMS
if missile[Y + i] > 0 and missile[Y + i] < MAXSCREEN_Y-7:
missile[Y + i] += missile[DIR + i] # move missile up or down
miss_collision()
missile[M_SPRITE + i] += 1
if missile[M_SPRITE + i] > 3*4:
missile[M_SPRITE + i] = 0
elif i==0:
player[FIRE] = 1
else:
missile[Y + i] = 0 # clear missile from bottom
@micropython.viper
def miss_collision():
player = ptr32(PLAYER)
missile = ptr32(MISSILE)
invaders = ptr32(INVADERS)
alive = ptr8(ALIVE)
game = ptr32(GAME)
bunker = ptr8(BUNKER)
m_x = missile[X]
m_y = missile[Y]
inv_x = invaders[X]
inv_y = invaders[Y] // MAXSCREEN_X
for i in range(5 * COLUMNS): # check missile vs invaders
if alive[i] == 3:
i_x = (i % COLUMNS)*14 + inv_x
i_y = (i // COLUMNS)*10 + inv_y + 10
if m_x > i_x and m_x < i_x + 14 and m_y > i_y and m_y < i_y + 14:
GAME_SOUND.SOUND = int(GAME_SOUND.SOUND) | 1<<2
game[SCORE] += int(SCORE_MAP[i // COLUMNS])
player[FIRE] = 0
missile[Y] = 0
alive[i] -= 1
get_edges()
game[TIME] -= SPEEDUP
GAME_SOUND.BACK_TUNE[3] = 200 + game[TIME]*3 # 800 max
invaders[COUNT] -= 1
if invaders[COUNT] == 0:
reset_invaders()
reset_bunker()
p_x = player[X]
p_y = PLAYER_Y
pm_x = missile[X] # player missile
pm_y = missile[Y]
for index in range(1,NUM_MISSILES-1):
i = index * MISSILE_PARAMS
m_x = missile[X + i]
m_y = missile[Y + i]
if m_y > 0 and m_x > p_x and m_x < p_x + 16 and m_y > p_y and m_y < p_y + 8: # invader missile vs player
missile[Y + i] = 0
player[HIT] = 10 #2
GAME_SOUND.SOUND = 1<<1
break
if game[BUNKERS] == 1 and m_y >= BUNKER_Y and m_y < BUNKER_Y + 22: # invader missile vs bunker
b_y = m_y-BUNKER_Y
if bunker[b_y * MAXSCREEN_X + m_x] == 1:
missile[Y + i] = 0
bunker_exp(m_x,b_y+2)
if m_y > 0 and pm_y > 0 and m_x > pm_x and m_x < pm_x + 3 and m_y > pm_y and m_y < pm_y + 7: # invader missile vs player missile
missile[Y + i] = 0
missile[Y] = 0
if game[BUNKERS] == 1 and pm_y >= BUNKER_Y and pm_y < BUNKER_Y + 22 and pm_x > 9: # player missile vs bunker
b_y = pm_y-BUNKER_Y
if bunker[b_y * MAXSCREEN_X + pm_x] == 1 or bunker[(b_y+1) * MAXSCREEN_X + pm_x] == 1 :
missile[Y] = 0
bunker_exp(pm_x,b_y+2)
@micropython.viper
def bunker_exp(e_x:int,e_y:int):
bunker = ptr8(BUNKER)
exp_map= ptr8(EXP_MAP)
for y in range(-4,4):
for x in range(-3,3):
bunk_addr = (e_y + y) * MAXSCREEN_X + e_x + x
exp = exp_map[(y+4)*8 + x + 3]
if exp == 1 and bunk_addr > 0 and bunk_addr < MAXSCREEN_X * 16:
bunker[bunk_addr] = 0
@micropython.viper
def get_edges():
game = ptr32(GAME)
invaders = ptr32(INVADERS)
alive = ptr8(ALIVE)
fire_inv = ptr8(FIRE_INV)
invaders[RIGHT] = 0
invaders[LEFT] = 10
invaders[BOTTOM] = 0
for i in range(5 * COLUMNS):
if alive[i] == 3:
x = i % COLUMNS
y = i // COLUMNS
if x > invaders[RIGHT]: invaders[RIGHT] = x
if x < invaders[LEFT]: invaders[LEFT] = x
if y > invaders[BOTTOM]: invaders[BOTTOM] = y
for x in range(COLUMNS): # find the bottom invaders that can fire
fire_inv[x] = 0
for y in range(5):
if alive[y * COLUMNS + x] == 3:
fire_inv[x] = y + 1
@micropython.viper
def invaders_fire():
invaders = ptr32(INVADERS)
missile = ptr32(MISSILE)
fire_inv = ptr8(FIRE_INV)
for index in range(1,NUM_MISSILES):
i = index * MISSILE_PARAMS
if missile[Y + i] > 0 and missile[Y + i] < MAXSCREEN_Y: continue
firing_invader = int(randint(0,COLUMNS))
while fire_inv[firing_invader] == 0: # find random bottom invader
firing_invader += 1
if firing_invader > COLUMNS: firing_invader = 0 # loop around
missile[Y + i] = invaders[Y]//MAXSCREEN_X + fire_inv[firing_invader] * 8 + 10
missile[X + i] = invaders[X] + firing_invader * 14 + 7
missile[M_SPRITE2 + i] = int(randint(0,2))*4 # start sprite 0,4,8
missile[M_SPRITE + i] = 0
return
@micropython.viper
def draw_invaders():
sprites = ptr16(SPRITES)
screen = ptr16(LCD.buffer)
invaders = ptr32(INVADERS)
game = ptr32(GAME)
alive = ptr8(ALIVE)
sprite_offset = 2 + game[TOGGLE]*S_HEIGHT*S_WIDTH
screen_offset = invaders[Y]+10*MAXSCREEN_X + invaders[X]
for x1 in range(COLUMNS):
test_alive = alive[x1]
if test_alive > 0:
if test_alive < 3:
sprite_offset = 2 + S_WIDTH*S_HEIGHT*5 + (test_alive)*8*S_WIDTH
else:
sprite_offset = 2 + game[TOGGLE]*S_HEIGHT*S_WIDTH
for y in range(S_HEIGHT):
for x in range(S_WIDTH):
color = sprites[sprite_offset + y*S_WIDTH + x]
screen[y*MAXSCREEN_X + x+x1*14+screen_offset] = color
sprite_offset = 2 + S_WIDTH*S_HEIGHT*2 + game[TOGGLE]*S_HEIGHT*S_WIDTH
screen_offset = invaders[Y]+20*MAXSCREEN_X + invaders[X]
for y1 in range(2):
for x1 in range(COLUMNS):
test_alive = alive[(y1+1)*COLUMNS + x1]
if test_alive > 0:
if test_alive < 3:
sprite_offset = 2 + S_WIDTH*S_HEIGHT*5 + (test_alive)*8*S_WIDTH
else:
sprite_offset = 2 + S_WIDTH*S_HEIGHT*2 + game[TOGGLE]*S_HEIGHT*S_WIDTH
for y in range(S_HEIGHT):
for x in range(S_WIDTH):
color = sprites[sprite_offset + y*S_WIDTH + x]
screen[y1*10*MAXSCREEN_X+y*MAXSCREEN_X + x+x1*14+screen_offset] = color
sprite_offset = 2 + S_WIDTH*S_HEIGHT*4 + game[TOGGLE]*8*S_WIDTH
screen_offset = invaders[Y]+40*MAXSCREEN_X + invaders[X]
for y1 in range(2):
for x1 in range(COLUMNS):
test_alive = alive[(y1+3)*COLUMNS + x1]
if test_alive > 0:
if test_alive < 3:
sprite_offset = 2 + S_WIDTH*S_HEIGHT*5 + (test_alive)*8*S_WIDTH
else:
sprite_offset = 2 + S_WIDTH*S_HEIGHT*4 + game[TOGGLE]*8*S_WIDTH
for y in range(S_HEIGHT):
for x in range(S_WIDTH):
color = sprites[sprite_offset + y*S_WIDTH + x]
screen[y1*10*MAXSCREEN_X+y*MAXSCREEN_X + x+x1*14+screen_offset] = color
@micropython.viper
def draw_player():
sprites = ptr16(SPRITES)
screen = ptr16(LCD.buffer)
invaders = ptr32(INVADERS)
player = ptr32(PLAYER)
game = ptr32(GAME)
if player[HIT] > 0:
sprite_offset = 2 + S_WIDTH*S_HEIGHT*(11+(player[HIT]%2))
else:
sprite_offset = 2 + S_WIDTH*S_HEIGHT*11
screen_offset = MAXSCREEN_X * PLAYER_Y + player[X]
for y in range(S_HEIGHT):
for x in range(S_WIDTH):
color = sprites[sprite_offset + y*S_WIDTH + x]
screen[y*MAXSCREEN_X + x+screen_offset] = color
@micropython.viper
def draw_bunker():
game = ptr32(GAME)
bunker = ptr8(BUNKER)
screen = ptr16(LCD.buffer)
if not game[BUNKERS]: return
screen_offset = MAXSCREEN_X*BUNKER_Y
for y in range(BUNKER_HEIGHT):
for x in range(MAXSCREEN_X):
color = bunker[y*MAXSCREEN_X+x]
if color > 0:
screen[screen_offset + y * MAXSCREEN_X + x] = 0xe007
@micropython.viper
def draw_missile():
missile = ptr32(MISSILE)
screen = ptr16(LCD.buffer)
miss_spr = ptr8(MISS_SPR)
for index in range(1,NUM_MISSILES): # invader missiles
i = index * MISSILE_PARAMS
if missile[Y + i] > 0 and missile[Y + i] < MAXSCREEN_Y:
x = missile[X + i]
y = missile[Y + i]
offset = missile[M_SPRITE2 + i] + (missile[M_SPRITE + i] // 4)
for y1 in range(7):
for x1 in range(3):
miss_addr = y1 * 3 + x1 + (offset * 3 * 7)
if miss_spr[miss_addr] == 0xff:
screen[(y+y1) * 160 + x + x1] = 0xffff
if missile[Y] > 0: # player missile
x = missile[X]
y = missile[Y]
LCD.line(x,y,x,y+7,0xffff)
def game_over():
GAME_SOUND.SOUND = 0
LCD.text('GAME OVER',40,50,0xff)
LCD.show()
exit()
@micropython.viper
def draw():
draw_invaders()
draw_player()
draw_bunker()
draw_missile()
game = ptr32(GAME)
if game[SCORE] == 0:
LCD.text('FPS',0,80,0xff)
show_num_viper(game[FPS],40,80,0xff)
if game[SCORE] == 10 :
LCD.text('FREE MEM',0,90,0xff)
show_num_viper(gc.mem_free(),120,90,0xff)
LCD.text('SCORE',0,0,0xff)
show_num_viper(game[SCORE],70,0,0xff)
LCD.text('LIVES',100,0,0xff)
show_num_viper(game[LIVES],145,0,0xff)
LCD.show()
LCD.rect(0,0,MAXSCREEN_X,MAXSCREEN_Y,0,1)
@micropython.asm_thumb
def avg_fps_asm(r0,r1): # r0 = fps[] , r1 = current_fps
ldrb(r2,[r0,0]) # r2 = fps[0]
add(r2,r2,1) # fps[0] += 1
cmp(r2,33)
blt(LT_32) # if fps[0] > 32:
mov(r2,1)
label(LT_32)
strb(r2,[r0,0]) # fps[0] = new index
add(r2,r2,r0)
strb(r1,[r2,0]) # fps[fps[0]] = current_fps
mov(r2,1) # r2 = i
mov(r3,0) # r3 = tot
label(LOOP)
add(r0,r0,1)
ldrb(r4,[r0,0]) # r4 = fps[i]
add(r3,r3,r4) # tot += fps[i]
add(r2,r2,1)
cmp(r2,33) #33
blt(LOOP)
asr(r0,r3,5)
@micropython.viper
def core1():
global EXIT, GAME_SOUND
GAME_SOUND = Game_Sound()
GAME_SOUND.OFF = 0
while not EXIT:
GAME_SOUND.callback1()
sleep_ms(10)
@micropython.viper
def main():
init_pot()
init_game()
init_player()
init_invaders()
init_bunker()
reset_bunker()
reset_invaders()
get_edges()
game = ptr32(GAME)
pot_ticks = 0
move_ticks = 0
inv_fire_ticks = 0
GAME_SOUND.SOUND = 1<<0
while not EXIT and not RESET_PB():
gticks = int(ticks_ms())
sleep(0.001)
if gticks > pot_ticks + 10:
pot_ticks = gticks
read_pot()
if gticks > move_ticks + game[TIME] and 1:
move_ticks = gticks
move()
if gticks > inv_fire_ticks + game[TIME]*10:
inv_fire_ticks = gticks
invaders_fire()
move_missiles()
draw()
game[FPS] = int(avg_fps_asm(FPS_ARRY,1_000//int(ticks_diff(ticks_ms(),gticks))))
def shutdown():
global EXIT
EXIT = True
Pin(16,Pin.OUT).low() # buzzer off
pwm.deinit()
Pin(13,Pin.OUT).low() # screen off
gc.collect()
print(gc.mem_free())
print('Core0 Stop')
exit()
if __name__=='__main__':
FIRE_BUTTON = Pin(22, Pin.IN, Pin.PULL_UP)
machine.freq(200_000_000)
machine.mem32[0x40008048] = 1<<11 # enable peri_ctrl clock
pwm = PWM(Pin(13))
pwm.freq(1000)
pwm.duty_u16(0x8fff)#max 0xffff
LCD = LCD_1inch8()
LCD.fill(0)
LCD.show()
EXIT = False
_thread.start_new_thread(core1, ())
try:
main()
shutdown()
except KeyboardInterrupt :
shutdown()
@Zorglupy
Copy link

Hello, I'm trying to test this code but I noticed that some important elements are missing, such as the sprite files. Would it be possible for you to publish them? Thank you.

@samneggs
Copy link
Author

@Zorglupy
On the Pico run make_sprites.py and s_inv_miss-py to create the binaries needed.
I also added a modified version for the Pico2 that removes the problematic RESET_PB() and changes the overclocking address.

@Zorglupy
Copy link

@samneggs , Thanks for adding the missing elements 😉 I’m now able to run the program successfully. While exploring your repository filled with these great programs and strong educational value (especially the low-level optimizations using Viper, ASM, and PIO), I noticed that many of the programs have the same issue as this one — they’re missing key components (e.g., Centipede, Tetris, Hill Climb, Race Bots → sprite, texture, sound library, gfx library) that would allow them to run properly. It would be fantastic if you could also add the missing elements for those programs. A brief reference to the hardware and libraries used (e.g., GT911, GC9A01, etc.) would also be very helpful. Thanks again for sharing such interesting work!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment