Created
August 29, 2023 23:41
-
-
Save samneggs/741a1835ea3c50b91547da89fa2b7ef5 to your computer and use it in GitHub Desktop.
Astro Miner 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
# AstroMiner | |
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 cavetiles import map_texture as MAP | |
from pot import Pot | |
from astro_sound import Astro_Sound | |
# Tile set https://rottingpixels.itch.io/cave-platformer-tileset-16x16free | |
with open ('cavetextures.bin', "rb") as file: | |
TILES = file.read() | |
file.close() | |
MAXSCREEN_X = const(160) | |
MAXSCREEN_Y = const(128) | |
SCALE = const(13) | |
NUM_STARS = const(100) | |
NUM_MISSILES= const(10) | |
NUM_ENEMY = const(7) | |
NUM_EXPLODE = const(11) | |
NUM_STRUCT = const(10) | |
WHITE = const(0xffff) | |
MAP_WIDTH = const(6) | |
MAP_HEIGHT = const(6) | |
BORDER = const(90) | |
SHADOW_MASK = const(0b0111_1111) | |
SHIP_SIZE = const(2) | |
PLAYER_PARAMS = const(20) | |
X = const(0) | |
Y = const(1) | |
DEG = const(2) | |
VX = const(3) | |
VY = const(4) | |
AX = const(5) | |
AY = const(6) | |
M = const(7) | |
MAP_X = const(8) | |
MAP_Y = const(9) | |
SHIELD= const(10) | |
OLD_X = const(11) | |
OLD_Y = const(12) | |
MISL = const(13) | |
S_EXP = const(14) | |
SEGS = const(15) | |
TYPE = const(16) | |
BUTTON= const(17) | |
EXPLODE_PARAMS = const(20) | |
X1 = const(0) | |
X2 = const(1) | |
Y1 = const(2) | |
Y2 = const(3) | |
DX = const(4) | |
DY = const(5) | |
E_STR = const(6) | |
#S_EXP = const(14) | |
#SEGS = const(15) | |
#TYPE = const(16) | |
MISSILE_PARAMS = const(15) | |
#X,Y | |
MISS_LIFE = const(2) | |
#VX,VY | |
GAME_PARAMS = const(10) | |
FPS = const(0) | |
LIVES = const(1) | |
DEBUG = const(2) | |
M_MAP = const(3) | |
G_OVER= const(4) | |
STRUCT_PARAMS = const(7) # exact | |
#X,Y, DEG | |
S_TYPE = const(3) | |
S_HITS = const(4) | |
ST_EXP = const(5) | |
E_START = const(6) # start of exp index | |
SHIP_POINTS = const(16) | |
SHIP_SEGMENTS = const(30) | |
DEG_LIST = [] | |
RADIUS_LIST = [] | |
DEG_LIST.extend([0, 306, 180, 54, 0, 333, 349, 333, 189, 333, 0, 27, 11, 27, 171, 27 ]+[0]*14) # starcastle ship | |
RADIUS_LIST.extend([0, 17, 8, 17, 0, 4, 10, 9, 12, 4, 0, 4, 10, 9, 12, 4]+[0]*14) | |
DEG_LIST.extend( [172, 188, 207, 219, 233, 236, 225, 270, 270, 256, 330, 270, 270, 351, 9, 90, 90, 30, 104, 90, 90, 135, 124, 127, 141, 153, 172]+[0]*3 ) | |
RADIUS_LIST.extend( [14, 14, 13, 13, 10, 7, 3, 2, 8, 8, 16, 8, 2, 12, 12, 2, 8, 16, 8, 8, 2, 3, 7, 10, 13, 13, 14]+[0]*3 ) # enterprise | |
DEG_LIST.extend([90, 56, 67, 45, 45, 0, 323, 292, 248, 217, 180, 135, 135, 113, 124, 90]+[0]*14 ) # enterprise2 | |
RADIUS_LIST.extend([2, 7, 15, 8, 3, 8, 10, 11, 11, 10, 8, 3, 8, 15, 7, 2]+[0]*14 ) | |
DEG_LIST.extend( [180, 320, 323, 37, 40, 180]+[0]*24 ) #asteroids ship | |
RADIUS_LIST.extend( [14, 16, 10, 10, 16, 14]+[0]*24 ) | |
DEG_LIST.extend([98, 82, 278, 262, 98, 79, 108, 45, 225, 288, 259, 278, 262, 281, 252, 315, 135, 72, 101, 82]+[0]*10 ) | |
RADIUS_LIST.extend([14, 14, 14, 14, 14, 10, 6, 3, 3, 6, 10, 14, 14, 10, 6, 3, 3, 6, 10, 14] +[0]*10) # dense scaffold tower | |
DEG_LIST.extend([248, 292, 315, 338, 0, 27, 56, 124, 153, 180, 202, 225, 248]+[0]*17) # oval tank | |
RADIUS_LIST.extend([11, 11, 11, 11, 10, 9, 7, 7, 9, 10, 11, 11, 11]+[0]*17 ) | |
DEG_LIST.extend( [37, 270, 143, 37, 22, 270, 22, 50, 60, 37, 120, 143, 60, 120]+[0]*16) #pyramid | |
RADIUS_LIST.extend( [10, 8, 10, 10, 11, 8, 11, 16, 16, 10, 16, 10, 16, 16]+[0]*16) | |
SHIP_SEG_NUMS = bytearray([15,26,15,5,19,12,14,0,0,0]) | |
SHIP_DEG = array.array('H',DEG_LIST) | |
SHIP_RADIUS = array.array('H',RADIUS_LIST) | |
del DEG_LIST, RADIUS_LIST | |
STRUCT_LOC = array.array('i',(400,115,90,0,3,0,0, # X,Y,DEG,TYPE,HITS,EXP,INDEX | |
430,115,90,1,3,0,0, | |
460,115,00,2,3,0,0, | |
490,115,90,3,3,0,0, | |
530, 42,00,4,3,0,0, | |
530, 70,00,4,3,0,0, | |
530, 88,00,4,3,0,0, | |
530,115,00,4,3,0,0, | |
560,125,00,5,3,0,0, | |
590,115,00,6,3,0,0, | |
630,115,00,5,3,0,0, | |
000,000,00,0,0,0,0)) | |
dark_grey = const(0x4711) #pico_display.create_pen(20, 40, 60) | |
black = const(0) #pico_display.create_pen(0, 0, 0) | |
dark_green = const(0x0024) #pico_display.create_pen(32, 128, 0) | |
lt_blue = const(0x3e44) #pico_display.create_pen(66, 133, 244) | |
lt_yellow = const(0x33ff) #pico_display.create_pen(255, 229, 153) | |
lt_green = const(0xe007) #pico_display.create_pen(0, 255, 0) | |
brown = const(0xe079) #pico_display.create_pen(120, 63, 4) | |
white = const(0xffff) #pico_display.create_pen(255, 255, 255) | |
sky_blue = const(0x1f66) #pico_display.create_pen(96, 192, 255) | |
blue = const(0x1f00) | |
red = const(0xf8) # rrrrr_gggggg_bbbbb | |
lt_brown = const(0x52de) # ggg_bbbbb_rrrrr_ggg | |
MOD_TILES = bytearray(16) | |
SHADOW = array.array('i',(0,0,0,0,0,0)) | |
colors3 = array.array('H',(0x0,0xffff,0x0,0x4eeb,0xadbb,0x8a8a,0x772,0x5b1,0x8759,0xa570,0xe320,0x93f6,0xa8fe,0x3fd,0x2ca4, | |
0x41fb,0xa8bb,0x685a,0xc641,0xc89e,0x715d,0x515,0x2c34,0xc71b,0x2923,0x8722,0xb826,0x411,0xfb24, | |
0xf82a,0xac11,0xd079,0x53ba,0x2641,0xa438,0x8210,0x0)) | |
INTERP0_ACCUM0 = const(0x080) | |
INTERP0_ACCUM1 = const(0x084) | |
INTERP0_BASE0 = const(0x088) | |
INTERP0_BASE1 = const(0x08c) | |
INTERP0_BASE2 = const(0x090) | |
INTERP0_POP_FULL = const(0x09c) | |
INTERP0_CTRL_LANE0 = const(0x0ac) | |
INTERP0_CTRL_LANE1 = const(0x0b0) | |
INTERP1_ACCUM0 = const(0x0c0) | |
INTERP1_ACCUM1 = const(0x0c4) | |
INTERP1_BASE0 = const(0x0c8) | |
INTERP1_BASE1 = const(0x0cc) | |
INTERP1_BASE2 = const(0x0d0) | |
INTERP1_POP_FULL = const(0x0dc) | |
INTERP1_CTRL_LANE0 = const(0x0ec) | |
INTERP1_CTRL_LANE1 = const(0x0f0) | |
@micropython.viper | |
def interp_setup(map_width_bits:int, map_height_bits:int, uv_fractional_bits:int, tile_width_bits:int, tile_height_bits:int): | |
# texture width | |
sio=ptr32(0xd000_0000) # shift raw mask MSB LSB | |
sio[INTERP0_CTRL_LANE0//4] = 16 | 1<<18 | (map_width_bits-1)<<10 | 0<<5 | |
sio[INTERP0_CTRL_LANE1//4] = 16-map_width_bits | 1<<18 | (map_width_bits+map_height_bits-1)<<10 | map_width_bits<<5 | |
sio[INTERP1_CTRL_LANE0//4] = 16-4 | 1<<18 | 3<<10 | 0<<5 #tile | |
sio[INTERP1_CTRL_LANE1//4] = 16-8 | 1<<18 | 7<<10 | 4<<5 | |
du = 65536 // 16 | |
dv = 0 | |
sio[INTERP0_BASE0//4] = du | |
sio[INTERP0_BASE1//4] = dv | |
sio[INTERP1_BASE0//4] = du | |
sio[INTERP1_BASE1//4] = dv | |
SCREEN_CTL = const(0) | |
COLORS_CTL = const(4) | |
TILES_CTL = const(8) | |
MAP_CTL = const(12) | |
PLAYER_CTL = const(16) | |
SIO_CTL = const(20) | |
@micropython.asm_thumb | |
def draw_tiles_asm(r0): | |
ldr(r1,[r0,PLAYER_CTL]) | |
ldr(r1,[r1,MAP_X*4]) # r1 : u = player_ptr[MAP_X] | |
mov(r2,0) # r2 : y | |
label(LOOP_Y) | |
ldr(r3,[r0,PLAYER_CTL]) | |
ldr(r3,[r3,MAP_Y*4]) # player_ptr[MAP_Y] | |
asr(r3,r3,SCALE) # player_ptr[MAP_Y]>>SCALE | |
add(r3,r3,r2) # player_ptr[MAP_Y]>>SCALE)+y | |
lsl(r3,r3,12) # r3 : v = ((player_ptr[MAP_Y]>>SCALE)+y)<<12 | |
ldr(r4,[r0,SIO_CTL]) # 0xd000_0080 | |
str(r1,[r4,0]) # sio[INTERP0_ACCUM0//4] = u | |
str(r1,[r4,0x40]) # sio[INTERP1_ACCUM0//4] = u | |
str(r3,[r4,0x4]) # sio[INTERP0_ACCUM1//4] = v | |
str(r3,[r4,0x44]) # sio[INTERP1_ACCUM1//4] = v | |
mov(r5,MAXSCREEN_X) | |
mul(r5,r2) # r5 : y_offset = y * MAXSCREEN_X | |
mov(r6,0) # r6 : x | |
label(LOOP_X) | |
ldr(r4,[r0,SIO_CTL]) # 0xd000_0080 | |
ldr(r7,[r4,0x1c]) # t = sio[INTERP0_POP_FULL//4] # map | |
ldr(r3,[r0,MAP_CTL]) # map_ptr | |
add(r7,r3,r7) # [t] | |
ldrb(r3,[r7,0]) # map_ptr[t] tile number | |
data(2,0b010001_10__1__0_111_000) #MOV(r8,r7) # tile address | |
data(2,0b010001_10__1__0_011_001) #MOV(r9,r3) # tile number, with mask | |
mov(r7,SHADOW_MASK) | |
and_(r3,r7) # mask high bit | |
data(2,0b010001_10__1__0_011_010) #MOV(r10,r3) # tile number, unmasked | |
lsl(r3,r3,8) # map_ptr[t]<<8 | |
ldr(r7,[r4,0x5c]) # c = sio[INTERP1_POP_FULL//4] # tile | |
add(r3,r3,r7) # c+(map_ptr[t]<<8) | |
ldr(r7,[r0,TILES_CTL]) # tiles_ptr | |
add(r3,r3,r7) | |
ldrb(r7,[r3,0]) # tiles_ptr[c+(map_ptr[t]<<8)] | |
add(r7,r7,r7) # double for ldrh | |
ldr(r3,[r0,COLORS_CTL]) # colors_ptr | |
add(r3,r3,r7) # | |
ldrh(r3,[r3,0]) # r3 : pixel = colors_ptr[tiles_ptr[c+(map_ptr[t]<<8)]] | |
ldr(r7,[r0,SCREEN_CTL]) # | |
add(r4,r5,r6) # y_offset+x | |
add(r4,r4,r4) # double for strh | |
add(r7,r7,r4) # output[y_offset+x] | |
ldrh(r4,[r7,0]) # t4 = shadow pixel | |
data(2,0b010001_01__1__1_010_001) #CMP(r9,r10) | |
beq(SHOW) | |
cmp(r4,0) # check for shadow mask | |
beq(NO_SHOW) | |
label(SHOW) | |
eor(r3,r4)##### | |
strh(r3,[r7,0]) # output[y_offset+x] = pixel | |
data(2,0b010001_10__0__1_000_111) #MOV(r7,r8) # tile address | |
data(2,0b010001_10__0__1_010_011) #MOV(r3,r10) # tile number, unmasked | |
strb(r3,[r7,0]) # remove shadow | |
label(NO_SHOW) | |
add(r6,r6,1) | |
cmp(r6,MAXSCREEN_X) | |
blt(LOOP_X) | |
add(r2,r2,1) | |
cmp(r2,MAXSCREEN_Y) | |
blt(LOOP_Y) | |
label(EXIT) | |
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 | |
@micropython.viper | |
def read_pot(): | |
global EXIT | |
player = ptr32(PLAYER) | |
isin = ptr32(ISIN) | |
icos = ptr32(ICOS) | |
game = ptr32(GAME) | |
pot_ary = ptr32(pot.ary) | |
x_inc = pot_ary[0] | |
y_inc = pot_ary[1] | |
player[BUTTON] = pot_ary[2] | |
if y_inc>0: | |
y_inc=0 | |
game[M_MAP] += 1 | |
else: | |
game[M_MAP] = 0 | |
player[DEG] += x_inc | |
if player[DEG] >= 360: player[DEG] -= 360 | |
if player[DEG] < 0 : player[DEG] += 360 | |
deg = player[DEG] | |
x = (200*y_inc * int(icos[deg]))>>SCALE | |
y = (200*y_inc * int(isin[deg]))>>SCALE | |
player[VX] += x | |
player[VY] += y | |
def init_player(): | |
global PLAYER , SHIP_COORDS, MISSILES, DRAW_TILES_CTL, EXPLODE | |
PLAYER = array.array('i',0 for _ in range(PLAYER_PARAMS)) | |
EXPLODE = array.array('i',0 for _ in range(EXPLODE_PARAMS*NUM_EXPLODE*SHIP_SEGMENTS)) | |
SHIP_COORDS = array.array('i',0 for _ in range((NUM_ENEMY * SHIP_SEGMENTS + SHIP_SEGMENTS)*2)) | |
MISSILES = array.array('i',0 for _ in range(MISSILE_PARAMS*NUM_MISSILES)) | |
DRAW_TILES_CTL = array.array('I',(addressof(LCD.buffer),addressof(colors3),addressof(TILES)-(16*16), | |
addressof(MAP),addressof(PLAYER),0xd000_0080)) | |
PLAYER[X] = 80<<SCALE | |
PLAYER[Y] = 64<<SCALE | |
PLAYER[DEG]= 180 | |
PLAYER[VX] = 0 | |
PLAYER[VY] = 0 #23000 | |
PLAYER[AX] = 0 | |
PLAYER[AY] = 0 | |
PLAYER[M] = 0 | |
PLAYER[TYPE] = 0 | |
PLAYER[SEGS] = SHIP_SEG_NUMS[PLAYER[TYPE]] | |
PLAYER[MAP_X] = 0<<SCALE | |
PLAYER[MAP_Y] = 30<<SCALE | |
def init_imath(): #integer math | |
global ISIN,ICOS | |
ISIN = array.array('i', int(sin(radians(i)) * (1 << SCALE)) for i in range(360)) | |
ICOS = array.array('i', int(cos(radians(i)) * (1 << SCALE)) for i in range(360)) | |
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 | |
GAME[G_OVER] = 0 | |
@micropython.viper | |
def init_struct(): | |
segments = ptr8(SHIP_SEG_NUMS) | |
struct = ptr32(STRUCT_LOC) | |
isin = ptr32(ISIN) | |
icos = ptr32(ICOS) | |
deg = ptr16(SHIP_DEG) | |
radius = ptr16(SHIP_RADIUS) | |
coords = ptr32(SHIP_COORDS) | |
for index2 in range(0,NUM_STRUCT): | |
i2 = index2 * STRUCT_PARAMS | |
ship_type = struct[i2 + S_TYPE] | |
index_coords = index2 * SHIP_SEGMENTS * 2 + 60 | |
segs = segments[ship_type] + 2 | |
for index in range(ship_type*SHIP_SEGMENTS,ship_type*SHIP_SEGMENTS+segs): # calc ship points | |
i = index * 2 | |
pt_deg = deg[index] + struct[i2 + DEG] | |
if pt_deg >= 360: pt_deg -= 360 | |
if pt_deg < 0 : pt_deg += 360 | |
coords[index_coords] = ((radius[index] * SHIP_SIZE * icos[pt_deg])>>14) | |
coords[index_coords+1] = ((radius[index] * SHIP_SIZE * isin[pt_deg])>>14) | |
index_coords += 2 | |
@micropython.viper | |
def init_tiles(): | |
back_map = ptr8(MAP) | |
tiles = ptr8(TILES) | |
#rand_percent = int(randint(0,100)) | |
for i in range(4): # 5 | |
rand_location = int(randint(0,16*16)) | |
rand_color = int(randint(0,2)) | |
tiles[16*16*45+rand_location] = 4 + rand_color | |
for i in range(64*64): # MAP size | |
continue | |
back_map[i] = back_map[i] | 0b1000_0000 # make invis | |
@micropython.viper | |
def init_missile(): | |
miss = ptr32(MISSILES) | |
player = ptr32(PLAYER) | |
isin = ptr32(ISIN) | |
icos = ptr32(ICOS) | |
game = ptr32(GAME) | |
player[MISL] = 0 | |
if game[LIVES] < 1: return | |
x = player[X] | |
y = player[Y] | |
vx = player[VX] | |
vy = player[VY] | |
deg = player[DEG] + 180 | |
if deg >= 360: deg -= 360 | |
for index in range(NUM_MISSILES): | |
i = index * MISSILE_PARAMS | |
if miss[i + MISS_LIFE] == 0: | |
miss[i + MISS_LIFE] = 200 | |
miss[i + X] = icos[deg]*0 + x | |
miss[i + Y] = isin[deg]*0 + y | |
abs_vx = (vx + icos[deg])>>1 | |
abs_vy = (vy + isin[deg])>>1 | |
abs_vx = abs_vx if abs_vx > 0 else abs_vx*-1 | |
abs_vy = abs_vy if abs_vy > 0 else abs_vy*-1 | |
if abs_vx < 5000 and abs_vy < 5000 or 1: | |
miss[i + VX] = (icos[deg])<<1 | |
miss[i + VY] = (isin[deg])<<1 | |
else: | |
miss[i + VX] = (vx + icos[deg])<<1 # buggy | |
miss[i + VY] = (vy + isin[deg])<<1 | |
ASTRO_SOUND.reset_fire() | |
ASTRO_SOUND.SOUND = int(ASTRO_SOUND.SOUND) | 1<<0 | |
return | |
def reset_player(): | |
PLAYER[MAP_X] = 5<<SCALE | |
PLAYER[MAP_Y] = 5<<SCALE | |
PLAYER[DEG] = 180 | |
PLAYER[VX] = 0 | |
PLAYER[VY] = 0 | |
@micropython.viper | |
def init_explode(ship_type:int,degrees:int,struct_num:int): | |
player = ptr32(PLAYER) | |
deg = ptr16(SHIP_DEG) | |
radius = ptr16(SHIP_RADIUS) | |
coords = ptr32(SHIP_COORDS) | |
isin = ptr32(ISIN) | |
icos = ptr32(ICOS) | |
game = ptr32(GAME) | |
segs = ptr8(SHIP_SEG_NUMS) | |
explode = ptr32(EXPLODE) | |
struct = ptr32(STRUCT_LOC) | |
num_segs = segs[ship_type] | |
for slot in range(NUM_EXPLODE): # find free explosion slot | |
i = slot * EXPLODE_PARAMS * SHIP_SEGMENTS | |
if slot == NUM_EXPLODE-1 : return # no more slots | |
elif explode[i + S_EXP] == 0: break # found slot | |
explode[i + TYPE] = ship_type | |
explode[i + S_EXP] = 19 | |
explode[i + E_STR] = struct_num | |
struct_index = struct_num * STRUCT_PARAMS | |
struct[struct_index + E_START] = i # pass exp index to structure | |
explode_index = i | |
index_start = i | |
explode_index = 0 | |
for index in range(ship_type*SHIP_SEGMENTS,ship_type*SHIP_SEGMENTS+(num_segs)): # calc ship points | |
e_i = index_start + explode_index * EXPLODE_PARAMS | |
#print(slot,i,explode_index,e_i) | |
pt_deg1 = deg[index] + degrees | |
if index == ship_type*SHIP_SEGMENTS+num_segs - 1: #SHIP_POINTS-1: | |
pt_deg2 = deg[0] + degrees | |
else: | |
pt_deg2 = deg[index+1] + degrees | |
if pt_deg1 >= 360: pt_deg1 -= 360 | |
if pt_deg1 < 0 : pt_deg1 += 360 | |
if pt_deg2 >= 360: pt_deg2 -= 360 | |
if pt_deg2 < 0 : pt_deg2 += 360 | |
explode[e_i+X1] = ((radius[index] * SHIP_SIZE * icos[pt_deg1])) | |
explode[e_i+Y1] = ((radius[index] * SHIP_SIZE * isin[pt_deg1])) | |
explode[e_i+DX] = icos[pt_deg1] | |
explode[e_i+DY] = isin[pt_deg1] | |
if index == ship_type*SHIP_SEGMENTS+num_segs - 1:# SHIP_POINTS-1: | |
explode[e_i+X2] = ((radius[0] * SHIP_SIZE * icos[pt_deg2])) | |
explode[e_i+Y2] = ((radius[0] * SHIP_SIZE * isin[pt_deg2])) | |
else: | |
explode[e_i+X2] = ((radius[index+1] * SHIP_SIZE * icos[pt_deg2])) | |
explode[e_i+Y2] = ((radius[index+1] * SHIP_SIZE * isin[pt_deg2])) | |
explode_index += 1 | |
ASTRO_SOUND.SOUND = int(ASTRO_SOUND.SOUND) | 1<<2 | |
@micropython.viper | |
def ship_explode(): | |
return | |
player = ptr32(PLAYER) | |
game = ptr32(GAME) | |
explode = ptr32(EXPLODE) | |
player[S_EXP] -= 1 | |
if player[S_EXP] == 0: | |
game[LIVES] -= 1 | |
if game[LIVES] == 0: | |
game[G_OVER] = 1 | |
reset_player() | |
return | |
ship_type = player[TYPE] | |
ship_segs = player[SEGS] | |
for index in range(ship_segs): # calc ship points | |
i = index * EXPLODE_PARAMS | |
if int(randint(0,15)) == 0: | |
explode[i + S_EXP] = 0 | |
explode[i+X1] = 0 | |
explode[i+Y1] = 0 | |
explode[i+X2] = 0 | |
explode[i+Y2] = 0 | |
explode[i+DX] = 0 | |
explode[i+DY] = 0 | |
explode[i+DX] = 0 | |
explode[i+DY] = 0 | |
else: | |
explode[i+X1] += explode[i+DX] | |
explode[i+Y1] += explode[i+DY] | |
explode[i+X2] += explode[i+DX] | |
explode[i+Y2] += explode[i+DY] | |
@micropython.viper | |
def struct_explode(): | |
global MAX_I | |
player = ptr32(PLAYER) | |
game = ptr32(GAME) | |
explode = ptr32(EXPLODE) | |
segs = ptr8(SHIP_SEG_NUMS) | |
struct = ptr32(STRUCT_LOC) | |
deg = struct[2+7*4] + 10 # mod struct deg | |
if deg >= 360: deg -= 360 | |
struct[2+7*4] = deg | |
struct[2+7*5] = deg | |
struct[2+7*6] = deg | |
struct[2+7*7] = deg | |
init_struct() | |
if player[S_EXP] > 0: # player explode | |
player[S_EXP] -= 1 | |
if player[S_EXP] == 0: | |
game[LIVES] -= 1 | |
if game[LIVES] == 0: | |
game[G_OVER] = 1 | |
reset_player() | |
return | |
for slot in range(NUM_EXPLODE): # find active explosion | |
i = slot * EXPLODE_PARAMS * SHIP_SEGMENTS | |
if explode[i + S_EXP] > 0: | |
explode[i + S_EXP] -= 1 | |
ship_type = explode[i + TYPE] | |
ship_segs = segs[ship_type] | |
struct_num = explode[i + E_STR] | |
struct_exp = struct[struct_num * STRUCT_PARAMS + ST_EXP] | |
struct[struct_num * STRUCT_PARAMS + ST_EXP] = explode[i + S_EXP] | |
for index2 in range(ship_segs): # calc struct points | |
i2 = (index2 * EXPLODE_PARAMS) + i | |
if int(randint(0,15)) == 0 or explode[i + S_EXP] == 0: | |
explode[i2+X1] = 0 | |
explode[i2+Y1] = 0 | |
explode[i2+X2] = 0 | |
explode[i2+Y2] = 0 | |
explode[i2+DX] = 0 | |
explode[i2+DY] = 0 | |
explode[i2+DX] = 0 | |
explode[i2+DY] = 0 | |
else: | |
explode[i2+X1] += explode[i2+DX] | |
explode[i2+Y1] += explode[i2+DY] | |
explode[i2+X2] += explode[i2+DX] | |
explode[i2+Y2] += explode[i2+DY] | |
@micropython.viper | |
def move(): | |
player = ptr32(PLAYER) | |
deg = ptr16(SHIP_DEG) | |
radius = ptr16(SHIP_RADIUS) | |
coords = ptr32(SHIP_COORDS) | |
isin = ptr32(ISIN) | |
icos = ptr32(ICOS) | |
game = ptr32(GAME) | |
back_map = ptr8(MAP) | |
struct = ptr32(STRUCT_LOC) | |
cx = ((player[MAP_X])>>16)+5 # & 63 | |
cy = ((player[MAP_Y])>>17)+4 # & 63 | |
color = back_map[64*cy+cx] & SHADOW_MASK | |
game[DEBUG] = color | |
#back_map[64*cy+cx] = 0 | |
d = player[DEG] | |
for index in range(NUM_STRUCT): | |
i = index * STRUCT_PARAMS | |
if struct[i + S_HITS] == 0: continue | |
s_x = struct[i + X] - (player[MAP_X]>>(SCALE-1)) - 60 | |
s_y = struct[i + Y] - (player[MAP_Y]>>SCALE) - 50 | |
if s_x > 0 and s_x < 40 and s_y > 0 and s_y < 40: | |
player[S_EXP] = 19 | |
player[SHIELD] = 0 | |
init_explode(player[TYPE],player[DEG],0) | |
struct[i + S_HITS] = 0 | |
struct[i + ST_EXP] = 20 | |
init_explode(struct[i + S_TYPE], struct[i + DEG],index) # type, deg, number | |
return | |
if color == 72 or color == 80 or color == 87 or color == 88: # hit spike | |
player[S_EXP] = 19 | |
player[SHIELD] = 0 | |
init_explode(player[TYPE],player[DEG],0) | |
return | |
if 80 < color < 85: # hit diamond | |
back_map[64*cy+cx] = 46 | |
game[LIVES] += 1 | |
color = 46 | |
ASTRO_SOUND.SOUND = int(ASTRO_SOUND.SOUND) | 1<<3 | |
if color != 46 and player[SHIELD] == 0: # hit wall, shield | |
d += 180 | |
if d >= 360: | |
d -= 360 | |
player[SHIELD] = 5 | |
player[VX] = -1 * (player[VX]>>1) | |
player[VY] = -1 * (player[VY]>>1) | |
ASTRO_SOUND.SOUND = int(ASTRO_SOUND.SOUND) | 1<<1 | |
else: | |
player[SHIELD] -= 1 | |
if player[SHIELD] < 0 : player[SHIELD] = 0 | |
player[VX] -= player[VX]>>5 # auto slow to stop | |
player[VY] -= player[VY]>>5 | |
player[MAP_X] += player[VX] | |
player[MAP_Y] += player[VY] | |
ship_type = player[TYPE] | |
index_coords = 0 | |
for index in range(ship_type*SHIP_SEGMENTS,ship_type*SHIP_SEGMENTS+SHIP_SEGMENTS): # calc ship points | |
i = index * 2 | |
pt_deg = deg[index] + player[DEG] | |
if pt_deg >= 360: pt_deg -= 360 | |
if pt_deg < 0 : pt_deg += 360 | |
coords[index_coords] = ((radius[index] * SHIP_SIZE * icos[pt_deg])>>14) | |
coords[index_coords+1] = ((radius[index] * SHIP_SIZE * isin[pt_deg])>>14) | |
index_coords += 2 | |
@micropython.viper | |
def move_missile(): | |
miss = ptr32(MISSILES) | |
isin = ptr32(ISIN) | |
icos = ptr32(ICOS) | |
game = ptr32(GAME) | |
player = ptr32(PLAYER) | |
back_map = ptr8(MAP) | |
struct = ptr32(STRUCT_LOC) | |
for index in range(NUM_MISSILES): # calc missile positions | |
i = index * MISSILE_PARAMS | |
if miss[i + MISS_LIFE] > 0: | |
miss[i + MISS_LIFE] -= 1 | |
x = miss[i + X] | |
y = miss[i + Y] | |
x += miss[i + VX] | |
y += miss[i + VY] | |
cx = (((x>>1) + player[MAP_X])>>16) # & 63 | |
cy = ((y + player[MAP_Y])>>17) # & 63 | |
color = back_map[64*cy+cx] | |
#back_map[64*cy+cx] = 0 | |
#print(x>>SCALE, y>>SCALE,cx,cy) | |
#color = 46 | |
if 1 and color != 46 or x < 0 or y < 0 or x > MAXSCREEN_X<<SCALE or y > MAXSCREEN_Y<<SCALE: # miss hit map | |
miss[i + MISS_LIFE] = 0 | |
ASTRO_SOUND.reset_fire() | |
ASTRO_SOUND.SOUND = int(ASTRO_SOUND.SOUND) & 0b1101 | |
continue | |
miss[i + X] = x | |
miss[i + Y] = y | |
#miss[i + VY] += 1000 | |
m_x = x >> SCALE | |
m_y = y >> SCALE | |
for index2 in range(0,NUM_STRUCT): | |
i2 = index2 * STRUCT_PARAMS | |
if struct[i2 + S_HITS] == 0: continue | |
s_x = struct[i2 + X] - (player[MAP_X]>>(SCALE-1)) - 10 | |
s_y = struct[i2 + Y] - (player[MAP_Y]>>SCALE) - 10 | |
if m_x > s_x-10 and m_x < s_x+20 and m_y > s_y-10 and m_y < s_y+20 and struct[i2 + S_HITS] > 0: # miss hit struct | |
struct[i2 + S_HITS] -= 1 | |
miss[i + MISS_LIFE] = 0 | |
if struct[i2 + S_HITS] == 0: | |
struct[i2 + ST_EXP] = 20 | |
init_explode(struct[i2 + S_TYPE], struct[i2 + DEG],index2) # type, deg, number | |
break | |
@micropython.viper | |
def mod_tiles(): | |
tiles = ptr8(TILES) | |
player = ptr32(PLAYER) | |
buffer = ptr8(MOD_TILES) | |
rand0 = int(randint(0,16)) | |
rand1 = int(randint(0,16*16)) | |
rand2 = int(randint(0,16*16)) | |
rand3 = int(randint(0,100)) | |
offset_p = 1000 | |
offset_m = -1000 | |
if player[VY] < offset_m: | |
for x in range(16): | |
buffer[x] = tiles[16*16*45+240+x] # save last row | |
for y in range(15,0,-1): | |
for x in range(16): | |
tiles[16*16*45+y*16+x] = tiles[16*16*45+(y-1)*16+x] | |
for x in range(16): | |
tiles[16*16*45+x] = buffer[x] # store in first row | |
if player[VY] > offset_p: | |
for x in range(16): | |
buffer[x] = tiles[16*16*45+x] # save first row | |
for y in range(0,15): | |
for x in range(16): | |
tiles[16*16*45+y*16+x] = tiles[16*16*45+(y+1)*16+x] | |
for x in range(16): | |
tiles[16*16*45+240+x] = buffer[x] # store in last row | |
if player[VX] < offset_m: | |
for y in range(16): | |
buffer[y] = tiles[16*16*45+(16*y)+15] # save last column | |
for x in range(15,0,-1): | |
for y in range(16): | |
tiles[16*16*45+y*16+x] = tiles[16*16*45+y*16+(x-1)] | |
for y in range(16): | |
tiles[16*16*45+(16*y)] = buffer[y] # store in first column | |
if player[VX] > offset_p: | |
for y in range(16): | |
buffer[y] = tiles[16*16*45+(16*y)] # save first column | |
for x in range(0,15): | |
for y in range(16): | |
tiles[16*16*45+y*16+x] = tiles[16*16*45+y*16+(x+1)] | |
for y in range(16): | |
tiles[16*16*45+(16*y)+15] = buffer[y] # store in last column | |
def draw_colors(): # 37 colors utility | |
index = 0 | |
for y in range(6): | |
for x in range(6): | |
LCD.rect(x*26,y*21,26,21,colors3[index],1) | |
LCD.text(str(index),x*26,y*21,0xffff) | |
index += 1 | |
@micropython.viper | |
def draw_dark(): # scan cone | |
player = ptr32(PLAYER) | |
shadow = ptr32(SHADOW) | |
miss = ptr32(MISSILES) | |
if player[S_EXP] > 0: return | |
x = player[X]>>SCALE | |
y = player[Y]>>SCALE | |
isin = ptr32(ISIN) | |
icos = ptr32(ICOS) | |
#LCD.ellipse(x,y,20,20,0xffff,1) | |
d = player[DEG] + 180 | |
d1 = d - 10 | |
d2 = d + 10 | |
if d1 < 0: d1 += 360 | |
if d1 >= 360: d1 -= 360 | |
if d2 >= 360: d2 -= 360 | |
x1 = ((3 * icos[d1])>>8) | |
y1 = ((3 * isin[d1])>>8) | |
x2 = ((3 * icos[d2])>>8) | |
y2 = ((3 * isin[d2])>>8) | |
shadow[0] = 0 | |
shadow[1] = 0 | |
shadow[2] = x1 | |
shadow[3] = y1 | |
shadow[4] = x2 | |
shadow[5] = y2 | |
LCD.poly(x,y,SHADOW,0b111000,1) # 0xffff | |
for index in range(NUM_MISSILES): # draw missiles | |
i = index * MISSILE_PARAMS | |
if miss[i + MISS_LIFE] > 0: | |
r1 = int(randint(1,3)) | |
r2 = int(randint(1,3)) | |
if randint(0,1): | |
color = red | |
else: | |
color = 0x33ff | |
LCD.ellipse(miss[i + X]>>SCALE, miss[i + Y]>>SCALE,r1,r2, color,1) # 33ff | |
@micropython.viper | |
def draw_struct(): | |
player = ptr32(PLAYER) | |
struct = ptr32(STRUCT_LOC) | |
segs = ptr8(SHIP_SEG_NUMS) | |
coords = ptr32(SHIP_COORDS) | |
explode = ptr32(EXPLODE) | |
x = player[MAP_X]>>(SCALE-1) | |
y = player[MAP_Y]>>SCALE | |
for index in range(0,NUM_STRUCT): | |
i = index * STRUCT_PARAMS | |
s_type = struct[i + S_TYPE] | |
s_seg = segs[s_type] | |
s_x = struct[i + X] | |
s_y = struct[i + Y] | |
x1 = s_x - x | |
y1 = s_y - y | |
if x1 > MAXSCREEN_X or x1 < 0 or y1 > MAXSCREEN_Y or y1 < 0: continue | |
if struct[i + S_HITS] > 0: | |
for index2 in range(index*SHIP_SEGMENTS,index*SHIP_SEGMENTS+s_seg): | |
i2 = index2 * 2 + 60 | |
x2 = x1+(coords[i2+0]) | |
y2 = y1+(coords[i2+1]) | |
x3 = x1+(coords[i2+2]) | |
y3 = y1+(coords[i2+3]) | |
LCD.line(x2,y2,x3,y3,WHITE) # whole struct | |
elif struct[i + ST_EXP] > 0: | |
for index2 in range(s_seg-1): | |
i2 = (index2 * EXPLODE_PARAMS) + struct[i + E_START] | |
x2 = x1+(explode[i2+X1]>>14) | |
y2 = y1+(explode[i2+Y1]>>14) | |
x3 = x1+(explode[i2+X2]>>14) | |
y3 = y1+(explode[i2+Y2]>>14) | |
LCD.line(x2,y2,x3,y3,WHITE) # exploding struct | |
LCD.pixel(x,y,0) | |
@micropython.viper | |
def draw(): | |
game = ptr32(GAME) | |
player = ptr32(PLAYER) | |
miss = ptr32(MISSILES) | |
coords = ptr32(SHIP_COORDS) | |
explode = ptr32(EXPLODE) | |
x = player[X]>>SCALE | |
y = player[Y]>>SCALE | |
if game[LIVES] > 0: | |
ship_type = player[TYPE] | |
ship_segs = player[SEGS] | |
if player[S_EXP] > 0: | |
for index in range(ship_segs): | |
i = index * EXPLODE_PARAMS | |
x1 = x+(explode[i+X1]>>14) | |
y1 = y+(explode[i+Y1]>>14) | |
x2 = x+(explode[i+X2]>>14) | |
y2 = y+(explode[i+Y2]>>14) | |
LCD.line(x1,y1,x2,y2,WHITE) # exploding ship | |
LCD.pixel(x,y,0) | |
else: | |
for index in range(ship_segs): | |
i = index * 2 | |
x1 = x+(coords[i+0]) | |
y1 = y+(coords[i+1]) | |
x2 = x+(coords[i+2]) | |
y2 = y+(coords[i+3]) | |
LCD.line(x1,y1,x2,y2,WHITE) # draw ship | |
map_x = (player[MAP_X])<<1 | |
map_y = (player[MAP_Y]) | |
draw_struct() | |
LCD.text('FPS',0,0,0xff) | |
if player[SHIELD]: | |
LCD.ellipse(x,y,9*SHIP_SIZE,9*SHIP_SIZE,0xffff) # draw shield | |
show_num_viper(game[FPS],20,7,0xff) | |
#show_num_viper(gc.mem_free(),40,17,0xff) | |
LCD.text('LIVES',115,0,0xff) | |
show_num_viper(game[LIVES],125,10,0xff) | |
#show_num_viper(game[DEBUG],60,0,0xff) | |
if game[M_MAP] > 20: | |
if game[G_OVER]: | |
reset_game() | |
return | |
mini_map() # draw mini map | |
if game[G_OVER]: | |
LCD.text('GAME OVER',50,50,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 mini_map()-> int: | |
screen = ptr16(LCD.buffer) | |
back_map = ptr8(MAP) | |
player = ptr32(PLAYER) | |
cx = ((0 + player[MAP_X])>>16) # & 63 | |
cy = ((0 + player[MAP_Y])>>17) # & 63 | |
offset = 0 | |
for y in range(64): | |
for x in range(64): | |
c = back_map[y*64+x] | |
c = black if c == 46 else brown #red | |
screen[y*MAXSCREEN_X+x+offset] = c | |
if cx + cy & 1 or 1: | |
dot = (5+cy)*MAXSCREEN_X+cx+5 | |
screen[dot] = 0xffff | |
screen[dot+1] = 0xffff | |
screen[dot-1] = 0xffff | |
screen[dot+MAXSCREEN_X+1] = 0xffff | |
screen[dot-MAXSCREEN_X+1] = 0xffff | |
def reset_game(): | |
GAME[LIVES] = 3 | |
GAME[G_OVER] = 0 | |
PLAYER[X] = 80<<SCALE | |
PLAYER[Y] = 64<<SCALE | |
PLAYER[DEG]= 180 | |
PLAYER[TYPE] = 0 | |
PLAYER[SEGS] = SHIP_SEG_NUMS[PLAYER[TYPE]] | |
PLAYER[MAP_X] = 0<<SCALE | |
PLAYER[MAP_Y] = 30<<SCALE | |
@micropython.viper | |
def main(): | |
global pot | |
init_tiles() | |
interp_setup(MAP_WIDTH, MAP_HEIGHT, 16, 4, 4) | |
init_imath() | |
pot = Pot() | |
_thread.start_new_thread(core1, ()) | |
init_game() | |
init_player() | |
#init_enemy() | |
init_struct() | |
player = ptr32(PLAYER) | |
game = ptr32(GAME) | |
twinkle_ticks = 0 | |
pot_ticks = 0 | |
move_ticks = 0 | |
missile_ticks = 0 | |
ship_exp_ticks = 0 | |
background_ticks = 0 | |
struct_explode_ticks = 0 | |
gc.collect() | |
print(gc.mem_free()) | |
while not EXIT and not RESET_PB(): | |
gticks = int(ticks_ms()) | |
sleep(0.001) # catch ctrl-C exit | |
if game[G_OVER]: | |
read_pot() | |
draw() | |
continue | |
if gticks-pot_ticks>20: | |
pot_ticks = int(ticks_ms()) | |
read_pot() | |
if player[S_EXP]>0: | |
if gticks-ship_exp_ticks>80: #20 | |
ship_exp_ticks = int(ticks_ms()) | |
ship_explode() | |
else: | |
if gticks-move_ticks>40: | |
move_ticks = int(ticks_ms()) | |
move() | |
if gticks-missile_ticks>200 and not player[BUTTON]: #200 | |
missile_ticks = int(ticks_ms()) | |
init_missile() | |
if gticks-struct_explode_ticks>80: | |
struct_explode_ticks = int(ticks_ms()) | |
struct_explode() | |
if gticks-background_ticks>80: #500 | |
background_ticks = int(ticks_ms()) | |
mod_tiles() | |
move_missile() | |
draw_dark() | |
draw_tiles_asm(DRAW_TILES_CTL) | |
draw() | |
game[FPS] = int(avg_fps_asm(FPS_ARRY,1_000//int(ticks_diff(ticks_ms(),gticks)))) | |
shutdown() | |
def shutdown(): | |
global EXIT | |
EXIT = True | |
Pin(16,Pin.OUT).low() # buzzer off | |
pwm.deinit() | |
ASTRO_SOUND.deinit() | |
Pin(13,Pin.OUT).low() # screen off | |
#gc.collect() | |
print(gc.mem_free()) | |
machine.freq(125_000_000) | |
for i in range(10000): pass | |
print('Core0 Stop') | |
print(PLAYER[MAP_X]>>SCALE,PLAYER[MAP_Y]>>SCALE) | |
exit() | |
def core1(): | |
global pot, EXIT, ASTRO_SOUND | |
ASTRO_SOUND = Astro_Sound() | |
ASTRO_SOUND.OFF = 0 | |
while not EXIT: | |
pot.read_xyb(0) | |
ASTRO_SOUND.callback1() | |
#for delay in range(1000): pass | |
sleep_ms(10) | |
print('Core1 Stop') | |
if __name__=='__main__': | |
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) | |
draw_colors() | |
LCD.show() | |
#exit() | |
EXIT = False | |
try: | |
main() | |
shutdown() | |
except KeyboardInterrupt : | |
shutdown() | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment