Created
June 28, 2023 14:31
-
-
Save samneggs/4232ebc172edcbbca7632d1830b70c1d to your computer and use it in GitHub Desktop.
Centipede 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
# Centipede | |
import centi_splash | |
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 | |
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 centi_sound import Centi_Sound | |
MAXSCREEN_X = const(160) | |
MAXSCREEN_Y = const(128) | |
SCALE = const(13) | |
TEXTURE_WIDTH = const(16) | |
TEXTURE_HEIGHT = const(16) | |
NUM_TEXTURES = const(68) | |
FIELD_WIDTH = const(MAXSCREEN_X//8) | |
FIELD_HEIGHT = const(MAXSCREEN_Y//8) | |
RED = const(0b11111_000) | |
PLAYER_PARAMS = const(10) | |
X = const(0) | |
Y = const(1) | |
FIRED = const(2) | |
SPRITE_IND = const(3) | |
MISS_X = const(4) | |
MISS_Y = const(5) | |
PLAYER_DEAD = const(6) | |
GAME_PARAMS = const(10) | |
FPS = const(0) | |
LIVES = const(1) | |
SIZE = const(2) | |
NUM_MUSH = const(3) | |
C_SEGMENTS = const(4) | |
CENTI_DEAD = const(5) | |
EXPLODE_DONE= const(6) | |
SCORE = const(7) | |
CENTI_PARAMS = const(10) | |
#X,Y | |
DIRECTION = const(2) | |
#SPRITE_IND | |
SPRITE_START = const(4) | |
UP_DOWN = const(5) | |
REACH_BOT = const(6) | |
FLEA_PARAMS = const(10) | |
#X,Y | |
FLEA_SCORE = const(2) | |
FLEA_SCORE_Y = const(3) | |
SPID_PARAMS = const(10) | |
#X,Y | |
SPID_SCORE = const(2) | |
SPID_SCORE_X = const(3) | |
SPID_POINTS = const(4) | |
SPID_XDIR = const(5) | |
SPID_XINC = const(6) | |
SPID_YINC = const(7) | |
SPID_YDIST = const(8) | |
EXPLODE_PARAMS = const(10) | |
# X,Y | |
EXP_SPRITE = const(2) | |
EXP_COUNT = const(3) | |
# directions | |
#0=dead,1=right/down, 2=left/down, 3=down/right, 4 down/left, | |
# 5=right/up, 6=left/up, 7=up/right, 8=up/left | |
DEAD = const(0) | |
RIGHT_DOWN = const(1) | |
LEFT_DOWN = const(2) | |
DOWN_RIGHT = const(3) | |
DOWN_LEFT = const(4) | |
RIGHT_UP = const(5) | |
LEFT_UP = const(6) | |
UP_RIGHT = const(7) | |
UP_LEFT = const(8) | |
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 | |
# blit_image_file from Stewart Watkiss | |
# http://www.penguintutor.com/programming/picodisplayanimations | |
def blit_image_file(buf,filename,width,height,cw,ch): # file width, file height, char width, char height | |
with open (filename, "rb") as file: | |
file_position = 0 | |
char_position = 0 | |
ecount = 0 | |
current_byte = file.read(4) # header | |
while file_position < (width * height * 2): | |
current_byte = file.read(1) | |
if len(current_byte) == 0: | |
break | |
buf[char_position] = ord(current_byte) | |
char_position += 1 | |
file_position += 1 | |
file.close() | |
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(): | |
global EXIT | |
game = ptr32(GAME) | |
player = ptr32(PLAYER) | |
field = ptr8(FIELD) | |
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 | |
if int(abs(x_inc))<2: | |
x_inc=0 | |
if int(abs(y_inc))<2: | |
y_inc=0 | |
if not FIRE_BUTTON.value() and not player[FIRED]: | |
CENTI_SOUND.SOUND = int(CENTI_SOUND.SOUND) | 1<<1 | |
player[FIRED] = 1 | |
player[MISS_X] = (player[X]>>SCALE) + 8 | |
player[MISS_Y] = (player[Y]>>SCALE) + 8 | |
test_x = player[X] - (x_inc<<12) #12 | |
test_y = player[Y] + (y_inc<<11) | |
if test_x < 0: test_x = 0 | |
if test_y < 0: test_y = 0 | |
if test_x > (MAXSCREEN_X-12)<<SCALE: test_x = (MAXSCREEN_X-12)<<SCALE | |
if test_y > (MAXSCREEN_Y-12)<<SCALE: test_y = (MAXSCREEN_Y-12)<<SCALE | |
x = ((8<<SCALE)+test_x)>>16 | |
y = ((8<<SCALE)+test_y)>>16 | |
sprite = field[y*20+x] | |
if sprite == 99: | |
player[X] = test_x | |
player[Y] = test_y | |
def init_player(): | |
global PLAYER, CENTI, DIR_INC, START_IND | |
DIR_INC = array.array('i',(0,0,1,0,-1,0,0,1,0,1,1,0,-1,0,0,-1,0,-1)) | |
START_IND = bytearray([0]) | |
segments = GAME[C_SEGMENTS] | |
PLAYER = array.array('i',0 for _ in range(PLAYER_PARAMS)) | |
CENTI = array.array('i',0 for _ in range(1+segments * CENTI_PARAMS)) | |
PLAYER[X] = 80<<SCALE | |
PLAYER[Y] = 100<<SCALE | |
@micropython.viper | |
def init_centi(): | |
field = ptr8(FIELD) | |
centi = ptr32(CENTI) | |
game = ptr32(GAME) | |
for i in range(20): | |
field[i] = 99 | |
for index in range(game[C_SEGMENTS]): | |
i = index * CENTI_PARAMS | |
centi[i+X] = 100 - (8 * index) | |
centi[i+Y] = 0 | |
centi[i+DIRECTION] = 1 | |
centi[i+SPRITE_IND] = index % 4 | |
centi[i+SPRITE_START] = 4 | |
centi[i+REACH_BOT] = 0 | |
centi[0+SPRITE_START] = 0 # head | |
def init_game(): | |
global GAME, FPS_ARRY, TEXTURES, FIELD, FLEA, SPIDER, EXPLODE | |
GAME = array.array('i',0 for _ in range(GAME_PARAMS)) | |
TEXTURES=bytearray(TEXTURE_WIDTH*TEXTURE_HEIGHT*2*NUM_TEXTURES) | |
FIELD = bytearray([99 for _ in range(FIELD_WIDTH*FIELD_HEIGHT*8)]) | |
FPS_ARRY = bytearray(35) | |
FLEA = array.array('i',0 for _ in range(FLEA_PARAMS)) | |
SPIDER = array.array('i',0 for _ in range(SPID_PARAMS)) | |
EXPLODE = array.array('i',0 for _ in range(10 * EXPLODE_PARAMS)) | |
SPIDER[SPID_XDIR] = 1 | |
GAME[FPS] = 0 | |
GAME[LIVES] = 3 | |
GAME[SIZE] = 16 | |
GAME[NUM_MUSH] = 20 # 20 mushrooms count | |
GAME[C_SEGMENTS] = 10 | |
blit_image_file(TEXTURES,"Centipede_2.bin",16,16*NUM_TEXTURES,16,16) | |
@micropython.viper | |
def init_field(): | |
field = ptr8(FIELD) | |
game = ptr32(GAME) | |
mush_count = 0 | |
while mush_count < game[NUM_MUSH]: | |
pos = int(randint(FIELD_WIDTH,FIELD_WIDTH*(FIELD_HEIGHT-4))) # clear bottom 10 rows | |
if field[pos] == 99: | |
field[pos] = 49 # shroom sprite | |
mush_count += 1 | |
@micropython.viper | |
def reset_field(): | |
field = ptr8(FIELD) | |
game = ptr32(GAME) | |
if game[LIVES] == 0: | |
CENTI_SOUND.SOUND = 0 | |
return | |
for x in range(20): | |
for y in range(16): | |
if 49 < field[y*20+x] < 53: | |
field[y*20+x] = 49 | |
CENTI_SOUND.SOUND = int(CENTI_SOUND.SOUND) | 1<<1 | |
draw_field() | |
LCD.show() | |
sleep(0.1) | |
CENTI_SOUND.SOUND = 0 | |
sleep(0.1) | |
@micropython.viper | |
def init_explode(x:int,y:int,sprite:int): | |
explode = ptr32(EXPLODE) | |
game = ptr32(GAME) | |
for index in range(10): | |
i = index * EXPLODE_PARAMS | |
if explode[i + EXP_COUNT] == 0: | |
explode[i + X] = x | |
explode[i + Y] = y | |
explode[i + EXP_SPRITE] = sprite | |
explode[i + EXP_COUNT] = 100 | |
game[EXPLODE_DONE] = 0 | |
return | |
@micropython.viper | |
def move_miss(): | |
player = ptr32(PLAYER) | |
field = ptr8(FIELD) | |
centi = ptr32(CENTI) | |
game = ptr32(GAME) | |
flea = ptr32(FLEA) | |
explode = ptr32(EXPLODE) | |
spider = ptr32(SPIDER) | |
if not player[FIRED]: | |
CENTI_SOUND.reset_fire() | |
CENTI_SOUND.SOUND = int(CENTI_SOUND.SOUND) & 0b1101 | |
if player[FIRED]: | |
player[MISS_Y] -= 5 | |
if player[MISS_Y] < 0: | |
player[FIRED] = 0 | |
return | |
miss_x = (player[MISS_X]-1)>>3 | |
miss_y = player[MISS_Y]>>3 | |
sprite = field[miss_y*20+miss_x] | |
if sprite == 52: # last shroom bit | |
field[miss_y*20+miss_x] = 99 | |
player[FIRED] = 0 | |
game[SCORE] += 1 | |
init_explode(miss_x*8+16,miss_y*8,49) | |
return | |
if 48 < sprite < 52: # hit shroom | |
field[miss_y*20+miss_x] = sprite + 1 | |
player[FIRED] = 0 | |
m_x = player[MISS_X] | |
m_y = player[MISS_Y] | |
f_x = flea[X] | |
f_y = flea[Y] | |
if flea[Y] > 0 and m_x < f_x+8 and m_x > f_x and m_y < f_y+8 and m_y > f_y: # hit flea | |
flea[FLEA_SCORE_Y] = flea[Y] | |
flea[FLEA_SCORE] = 50 | |
game[SCORE] += 300 | |
init_explode(flea[X],flea[Y],30) | |
flea[Y] = 0 | |
s_x = spider[X] | |
s_y = spider[Y] | |
if 0 < s_y < 144 and m_x < s_x+16 and m_x > s_x and m_y < s_y+8 and m_y > s_y: # hit spider | |
spider[SPID_SCORE] = 30 | |
game[SCORE] += 900 | |
init_explode(s_x,s_y,24) | |
spider[SPID_SCORE_X] = spider[X] | |
spider[X] = 0 | |
segments = game[C_SEGMENTS] | |
for index in range(segments): | |
i = index * CENTI_PARAMS | |
if centi[i + DIRECTION] == DEAD: continue | |
c_x = centi[i + X] | |
c_y = centi[i + Y] | |
if m_x < c_x+8 and m_x > c_x and m_y < c_y+8 and m_y > c_y: # hit centi | |
if centi[i+SPRITE_START] == 0 or centi[i+SPRITE_START] == 8: | |
game[SCORE] += 100 | |
else: | |
game[SCORE] += 10 | |
if index < segments-1 and centi[i + DIRECTION + CENTI_PARAMS] > 0: # make new head | |
centi[i+SPRITE_START+ CENTI_PARAMS] = 0 | |
centi[i + DIRECTION] = DEAD | |
player[FIRED] = 0 | |
field[miss_y*20+miss_x] = 49 | |
init_explode(centi[i + X],centi[i + Y],centi[i + SPRITE_START]) | |
return | |
@micropython.viper | |
def move_centi(): | |
field = ptr8(FIELD) | |
centi = ptr32(CENTI) | |
game = ptr32(GAME) | |
textures = ptr16(TEXTURES) | |
dir_inc = ptr32(DIR_INC) | |
segments = game[C_SEGMENTS] | |
player = ptr32(PLAYER) | |
alive_segs = 0 | |
for index in range(segments): | |
i = index * CENTI_PARAMS | |
if centi[i + DIRECTION] == DEAD: continue | |
alive_segs += 1 | |
inc_x = dir_inc[centi[i + DIRECTION]*2] | |
inc_y = dir_inc[centi[i + DIRECTION]*2+1] | |
test_x = centi[i + X] + inc_x | |
test_y = centi[i + Y] + inc_y | |
f_x = test_x//8 | |
f_y = test_y//8 | |
direction = centi[i + DIRECTION] | |
if field[(f_y+1) * 20 + f_x] < 99: # erase trap | |
if centi[i + UP_DOWN] == 1: | |
field[(f_y+1) * 20 + f_x] = 99 | |
if (direction == DOWN_LEFT or direction == UP_LEFT) and centi[i + UP_DOWN] > 7: | |
centi[i + UP_DOWN] = 0 | |
if test_y > MAXSCREEN_Y-(8*1): | |
direction = LEFT_UP | |
centi[i + REACH_BOT] = 1 | |
if test_y < MAXSCREEN_Y-(8*5) or centi[i + REACH_BOT] == 0: | |
direction = LEFT_DOWN | |
centi[i + REACH_BOT] = 0 | |
elif (direction == DOWN_RIGHT or direction == UP_RIGHT) and centi[i + UP_DOWN] > 7: | |
centi[i + UP_DOWN] = 0 | |
if test_y > MAXSCREEN_Y-(8*1): | |
direction = RIGHT_UP | |
centi[i + REACH_BOT] = 1 | |
if test_y < MAXSCREEN_Y-(8*5) or centi[i + REACH_BOT] == 0: | |
direction = RIGHT_DOWN | |
centi[i + REACH_BOT] = 0 | |
elif (field[f_y * 20 + f_x] < 99 or test_x > MAXSCREEN_X-8 or test_x < 0) and direction != DOWN_RIGHT and direction != DOWN_LEFT and direction != UP_RIGHT and direction != UP_LEFT: | |
if direction == RIGHT_DOWN: | |
direction = DOWN_LEFT | |
elif direction == LEFT_DOWN: | |
direction = DOWN_RIGHT | |
elif direction == RIGHT_UP: | |
direction = UP_LEFT | |
elif direction == LEFT_UP: | |
direction = UP_RIGHT | |
else: | |
centi[i + X] = test_x | |
centi[i + Y] = test_y | |
centi[i + SPRITE_IND] += 1 | |
if centi[i + SPRITE_IND] == 4: centi[i + SPRITE_IND] = 0 | |
if (2 < direction < 5) or (6 < direction): | |
centi[i + UP_DOWN] += 1 | |
centi[i + SPRITE_START] ^= (((direction+1) % 2) ^ ((centi[i + SPRITE_START] >> 3) & 1)) << 3 # set sprite direction | |
m_x = (player[X]>>SCALE)+4 | |
m_y = (player[Y]>>SCALE)+12 | |
if m_x < test_x+8 and m_x > test_x and m_y < test_y+8 and m_y > test_y: # centi hit player | |
init_explode(m_x,m_y,67) | |
player_dies() | |
centi[i + DIRECTION] = direction | |
if alive_segs == 0: | |
init_centi() | |
@micropython.viper | |
def move_flea(): | |
centi = ptr32(CENTI) | |
field = ptr8(FIELD) | |
flea = ptr32(FLEA) | |
game = ptr32(GAME) | |
player = ptr32(PLAYER) | |
if flea[FLEA_SCORE] > 0: | |
flea[FLEA_SCORE] -= 1 | |
if not flea[FLEA_SCORE]: | |
init_explode(flea[X],flea[FLEA_SCORE_Y],36) | |
if flea[Y] == 0 and int(randint(0,300)) == 300 and flea[FLEA_SCORE] == 0: # new flea | |
CENTI_SOUND.SOUND = int(CENTI_SOUND.SOUND) | 1<<2 | |
flea[X] = 8 * int(randint(0,20)) | |
flea[Y] = 8 | |
if flea[Y] == 0: | |
CENTI_SOUND.reset_flea() | |
CENTI_SOUND.SOUND = int(CENTI_SOUND.SOUND) & 0b1011 | |
return | |
flea[Y] += 1 | |
if flea[Y] > 120: | |
flea[Y] = 0 | |
return | |
f_x = flea[X]//8 | |
f_y = flea[Y]//8 | |
if int(randint(0,30)) == 30: # chance of new shroom | |
for index in range(game[C_SEGMENTS]): | |
i = index * CENTI_PARAMS | |
if centi[i + DIRECTION] == DEAD: continue | |
c_x = centi[i + X]//8 | |
c_y = centi[i + Y]//8 | |
if f_x == c_x and f_y == c_y: return | |
field[(f_y) * 20 + f_x] = 49 | |
m_x = (player[X]>>SCALE)+8 | |
m_y = (player[Y]>>SCALE)+4 | |
f_x = flea[X] | |
f_y = flea[Y] | |
if flea[Y] > 0 and m_x < f_x+8 and m_x > f_x and m_y < f_y+8 and m_y > f_y: # flea hit player | |
init_explode(m_x,m_y,67) | |
player_dies() | |
@micropython.viper | |
def move_spider(): | |
global CENTI_SOUND | |
spider = ptr32(SPIDER) | |
field = ptr8(FIELD) | |
player = ptr32(PLAYER) | |
game = ptr32(GAME) | |
if spider[SPID_SCORE] > 0: | |
spider[SPID_SCORE] -= 1 | |
if not spider[SPID_SCORE]: | |
init_explode(spider[SPID_SCORE_X],spider[Y],34) | |
if (spider[X] == 0 or spider[X] > 144) and int(randint(0,200)) == 200 and spider[SPID_SCORE] == 0: # new spider | |
CENTI_SOUND.SOUND = int(CENTI_SOUND.SOUND) | 1<<3 | |
spider[X] = 144 if spider[SPID_XDIR] == -1 else 1 | |
spider[Y] = int(randint(60,112)) | |
spider[SPID_YDIST] = int(randint(10,40)) | |
spider[SPID_XINC] = spider[SPID_XDIR] if randint(0,1) else 0 | |
spider[SPID_YINC] = -1 if randint(0,1) else 1 | |
if spider[X] < 1 or spider[X] > 144: | |
CENTI_SOUND.SOUND = int(CENTI_SOUND.SOUND) & 0b0111 # turn off spider sound | |
return | |
if spider[SPID_YDIST] > 0: | |
spider[SPID_YDIST] -= 1 | |
spider[X] += spider[SPID_XINC] | |
spider[Y] += spider[SPID_YINC] | |
s_x = spider[X]//8 | |
s_y = spider[Y]//8 | |
field[(s_y) * 20 + s_x] = 99 | |
field[(s_y) * 20 + s_x+1] = 99 | |
if spider[Y] < 60 or spider[Y] > 112: spider[SPID_YINC] *= -1 | |
if spider[X] == 0 or spider[X] > 144: spider[SPID_XDIR] *= -1 | |
else: | |
spider[SPID_YDIST] = int(randint(10,40)) | |
spider[SPID_XINC] = spider[SPID_XDIR] if randint(0,1) else 0 | |
spider[SPID_YINC] = -1 if randint(0,1) else 1 | |
m_x = (player[X]>>SCALE)+4 | |
m_y = (player[Y]>>SCALE)+12 | |
s_x = spider[X] | |
s_y = spider[Y] | |
if 0 < spider[X] < 144 and m_x < s_x+14 and m_x > s_x and m_y < s_y+14 and m_y > s_y: # spider hit player | |
init_explode(m_x,m_y,67) | |
player_dies() | |
@micropython.viper | |
def player_dies(): | |
global CENTI_SOUND | |
game = ptr32(GAME) | |
player = ptr32(PLAYER) | |
spider = ptr32(SPIDER) | |
flea = ptr32(FLEA) | |
game[LIVES] -= 1 | |
player[PLAYER_DEAD] = 100 | |
player[X] = 80<<SCALE | |
player[Y] = 100<<SCALE | |
flea[Y] = 0 | |
spider[X] = 0 | |
CENTI_SOUND.SOUND = 1 | |
@micropython.viper | |
def explode(): | |
screen = ptr16(LCD.buffer) | |
textures = ptr16(TEXTURES) | |
explode = ptr32(EXPLODE) | |
game = ptr32(GAME) | |
count = 0 | |
for index in range(10): | |
i = index * EXPLODE_PARAMS | |
if explode[i + EXP_COUNT] == 0: continue | |
count += 1 | |
x1 = explode[i + X] | |
y1 = explode[i + Y] | |
sprite = explode[i + EXP_SPRITE]<<8 | |
count = (explode[i + EXP_COUNT])//10 | |
explode[i + EXP_COUNT] -= 1 | |
for y in range(16): | |
for x in range(16): | |
x_off = ((x - 8)<<5)//(count) | |
y_off = ((y - 8)<<5)//(count) | |
addr = (y1 + y + y_off) * MAXSCREEN_X + x1 + x + x_off | |
if 0 < addr < 20480: | |
screen[addr] = textures[y * 16 + x + sprite] | |
if count == 0: game[EXPLODE_DONE] = 1 | |
@micropython.viper | |
def all_sprites(): # utility only | |
g = ptr32(GAME) | |
screen=ptr16(LCD.buffer) | |
textures = ptr16(TEXTURES) | |
sprite = 0 | |
for y1 in range(8): #16 | |
for x1 in range(10): #8 | |
sprite += 1 | |
offset = (y1*16) * MAXSCREEN_X + (x1*16) | |
for y in range(16): | |
for x in range(16): | |
if sprite<79: | |
screen[y*MAXSCREEN_X + x+ offset] = textures[y*16 + x + (sprite<<8)] | |
@micropython.viper | |
def zoom(width:int): # utility only | |
game = ptr32(GAME) | |
screen=ptr16(LCD.buffer) | |
textures = ptr16(TEXTURES) | |
player = ptr32(PLAYER) | |
sprite = player[SPRITE_IND] | |
offset = 0 | |
height = width | |
for y1 in range(height): | |
for x1 in range(width): | |
x = x1*16//width | |
y = y1*16//height | |
screen[y1*MAXSCREEN_X + x1+ offset] = textures[y*16 + x + (sprite<<8)] | |
@micropython.viper | |
def draw_field(): | |
game = ptr32(GAME) | |
player = ptr32(PLAYER) | |
textures = ptr16(TEXTURES) | |
screen=ptr16(LCD.buffer) | |
field = ptr8(FIELD) | |
for f_y in range(FIELD_HEIGHT): | |
for f_x in range(FIELD_WIDTH): | |
sprite = field[f_y*FIELD_WIDTH+f_x] | |
if sprite < 99: | |
field_pos = f_y*(8*MAXSCREEN_X)+(f_x*8) | |
sprite_offset = (sprite<<8)+ (16*4) | |
for t_y in range(TEXTURE_HEIGHT//2): | |
for t_x in range(TEXTURE_WIDTH//2): | |
screen[t_y * MAXSCREEN_X + t_x + field_pos] = textures[t_y*16 + t_x + sprite_offset] | |
@micropython.viper | |
def draw_score(x:int,y:int,sprite:int,offset:int): | |
textures = ptr16(TEXTURES) | |
screen = ptr16(LCD.buffer) | |
for t_y in range(TEXTURE_HEIGHT//2): | |
for t_x in range(TEXTURE_WIDTH): | |
screen[(y+t_y)*MAXSCREEN_X + x + t_x] = textures[(4+t_y)*16 + t_x + offset + (sprite<<8)] # draw score | |
@micropython.viper | |
def draw(): | |
game = ptr32(GAME) | |
player = ptr32(PLAYER) | |
textures = ptr16(TEXTURES) | |
screen=ptr16(LCD.buffer) | |
centi = ptr32(CENTI) | |
flea = ptr32(FLEA) | |
spider = ptr32(SPIDER) | |
p_x = player[X]>>SCALE | |
p_y = player[Y]>>SCALE | |
draw_field() | |
if player[FIRED]: | |
LCD.line(player[MISS_X],player[MISS_Y],player[MISS_X],player[MISS_Y]+5,0xffff) # draw missile | |
if not player[PLAYER_DEAD]: | |
sprite = 67 | |
for t_y in range(TEXTURE_HEIGHT): | |
for t_x in range(TEXTURE_WIDTH): | |
color = textures[t_y*16 + t_x + (sprite<<8)] | |
if color: | |
screen[(p_y+t_y)*MAXSCREEN_X + p_x+t_x] = color # draw player | |
segments = game[C_SEGMENTS] | |
for index in range(segments): | |
i = index * CENTI_PARAMS | |
if centi[i + DIRECTION] == DEAD: continue | |
c_x = centi[i + X] | |
c_y = centi[i + Y] | |
sprite = centi[i + SPRITE_IND] + centi[i + SPRITE_START] | |
for t_y in range(TEXTURE_HEIGHT//2): | |
for t_x in range(TEXTURE_WIDTH//2): | |
screen[(c_y+t_y)*MAXSCREEN_X + c_x+t_x] = textures[(4+t_y)*16 + t_x + 4 + (sprite<<8)] # draw centi | |
if flea[Y] > 0: | |
f_x = flea[X] | |
f_y = flea[Y] | |
sprite = 30 + (f_y % 4) | |
for t_y in range(TEXTURE_HEIGHT//2): | |
for t_x in range(TEXTURE_WIDTH//2): | |
screen[(f_y+t_y)*MAXSCREEN_X + f_x+t_x] = textures[(4+t_y)*16 + t_x + 4 + (sprite<<8)] # draw flea | |
if flea[FLEA_SCORE] > 0: | |
draw_score(flea[X],flea[FLEA_SCORE_Y],36,2) | |
if spider[SPID_SCORE] > 0: | |
draw_score(spider[SPID_SCORE_X],spider[Y],34,2) | |
if 0 < spider[X] < 145: | |
s_x = spider[X] | |
s_y = spider[Y] | |
sprite = 24 + (s_y % 6) | |
for t_y in range(TEXTURE_HEIGHT//2): | |
for t_x in range(TEXTURE_WIDTH): | |
color = textures[(4+t_y)*16 + t_x + 0 + (sprite<<8)] | |
if color: | |
screen[(s_y+t_y)*MAXSCREEN_X + s_x+t_x] = textures[(4+t_y)*16 + t_x + 0 + (sprite<<8)] # draw spider | |
LCD.text('FPS:',0,0,0xff) | |
show_num_viper(game[FPS],40,0,0xff) | |
#show_num_viper(gc.mem_free(),40,17,0xff) | |
show_num_viper(game[SCORE],150,0,0xff) | |
LCD.text('LIVES:',55,0,0xff) | |
show_num_viper(game[LIVES],105,0,0xff) | |
if game[LIVES] == 0: | |
LCD.rect(50,45,75,15,0,True) | |
LCD.text('GAME OVER',50,50,0xffff) | |
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) | |
def game_over(): | |
CENTI_SOUND.SOUND = 0 | |
CENTI_SOUND.OFF = 1 | |
@micropython.viper | |
def main(): | |
init_pot() | |
init_game() | |
init_player() | |
init_field() | |
init_centi() | |
game = ptr32(GAME) | |
move_centi_ticks = 0 | |
read_pot_ticks = 0 | |
move_flea_ticks = 0 | |
move_spider_ticks = 0 | |
CENTI_SOUND.SOUND = 1 | |
player = ptr32(PLAYER) | |
while not EXIT: | |
sleep(0.001) # for thonny stop | |
gticks = int(ticks_ms()) | |
if RESET_PB(): shutdown() | |
if not player[PLAYER_DEAD]: | |
if gticks - read_pot_ticks > 20: | |
read_pot_ticks = gticks | |
read_pot() | |
move_miss() | |
if gticks - move_centi_ticks > 10: | |
move_centi_ticks = gticks | |
move_centi() | |
if gticks - move_flea_ticks > 10: | |
move_flea_ticks = gticks | |
move_flea() | |
if gticks - move_spider_ticks > 20: # 20 | |
move_spider_ticks = gticks | |
move_spider() | |
else: | |
player[PLAYER_DEAD] -= 1 | |
if game[LIVES] == 0 : | |
player[PLAYER_DEAD] = 1 | |
game_over() | |
if player[PLAYER_DEAD] == 0: | |
reset_field() | |
init_centi() | |
explode() | |
draw() | |
game[FPS] = int(avg_fps_asm(FPS_ARRY,1_000//int(ticks_diff(ticks_ms(),gticks)))) | |
def core1(): | |
global CENTI_SOUND | |
CENTI_SOUND = Centi_Sound() | |
CENTI_SOUND.OFF = 0 | |
def shutdown(): | |
global EXIT | |
EXIT = True | |
Pin(16,Pin.OUT).low() # buzzer off | |
CENTI_SOUND.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, ()) | |
sleep(0.5) | |
try: | |
main() | |
shutdown() | |
except KeyboardInterrupt : | |
shutdown() | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment