Created
November 18, 2023 21:42
-
-
Save samneggs/1e5ae813fa86de75f0c380c3c5f40444 to your computer and use it in GitHub Desktop.
Space Invaders game on Pi Pico in MicroPython
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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() | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# 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() | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment