Created
April 16, 2023 02:30
-
-
Save samneggs/b712092662938ccf55e3ef2966b0a27e to your computer and use it in GitHub Desktop.
StarCastle game on Pi Pico in MicroPython
This file contains hidden or 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
| # Star Castle | |
| 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,atan2 | |
| MAXSCREEN_X = const(160) | |
| MAXSCREEN_Y = const(128) | |
| SCALE = const(13) | |
| NUM_STARS = const(100) | |
| NUM_MISSILES= const(20) | |
| SKYBLUE = const(0b11111111_00111011) | |
| YELLOW = const(255) | |
| ORANGE = const(0xe0fb) | |
| RED = const(248) | |
| PLAYER_PARAMS = const(10) | |
| X = const(0) | |
| Y = const(1) | |
| DEG = const(2) | |
| VX = const(3) | |
| VY = const(4) | |
| AX = const(5) | |
| AY = const(6) | |
| M = const(7) | |
| GAME_PARAMS = const(10) | |
| FPS = const(0) | |
| LIVES = const(1) | |
| HIT_CANNON = const(2) | |
| DEG_CANNON = const(3) | |
| FIRE_CANNON = const(4) | |
| SCORE = const(5) | |
| SHIELD_PARAMS = const(10) | |
| SHIELD_LIFE = const(3) | |
| SHIELD_DIR = const(4) | |
| SHIELD_RAD = const(5) | |
| MISSILE_PARAMS = const(10) | |
| MISS_LIFE = const(2) | |
| STARS_PARAMS = const(10) | |
| STAR_COLOR = const(2) | |
| STAR_DIR = const(3) | |
| EXPLODE_PARAMS = const(10) | |
| EXP_LIFE = const(2) | |
| EXP_COLOR = const(5) | |
| MINE_SHIELD = const(5) | |
| SHIP_POINTS = const(16) | |
| SHIP_DEG = array.array('H',(0, 306, 180, 54, 0, 333, 349, 333, 189, 333, 0, 27, 11, 27, 171, 27) ) | |
| SHIP_RADIUS = array.array('H',(0, 17, 8, 17, 0, 4, 10, 9, 12, 4, 0, 4, 10, 9, 12, 4) ) | |
| 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_imath(): #integer math | |
| global ISIN,ICOS | |
| ISIN = array.array('i',()) | |
| ICOS = array.array('i',()) | |
| for i in range(0,360): | |
| ISIN.append(int(sin(radians(i))*(1<<SCALE))) | |
| ICOS.append(int(cos(radians(i))*(1<<SCALE))) | |
| 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 | |
| isin = ptr32(ISIN) | |
| icos = ptr32(ICOS) | |
| player = ptr32(PLAYER) | |
| 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 or y_inc > 0 : | |
| y_inc=0 | |
| if not FIRE_BUTTON.value(): EXIT = True | |
| player[DEG] -= x_inc | |
| if player[DEG] >= 360: player[DEG] -= 360 | |
| if player[DEG] < 0 : player[DEG] += 360 | |
| deg = int(player[DEG]) | |
| x = (100*y_inc * int(icos[deg]))>>SCALE | |
| y = (100*y_inc * int(isin[deg]))>>SCALE | |
| player[VX] += x | |
| player[VY] += y | |
| def init_player(): | |
| global PLAYER , SHIP_COORDS, MISSILES, CANNON_COORDS | |
| PLAYER = array.array('i',0 for _ in range(PLAYER_PARAMS)) | |
| SHIP_COORDS = array.array('i',0 for _ in range(50*2)) | |
| CANNON_COORDS = array.array('i',0 for _ in range(50*2)) | |
| MISSILES = array.array('i',0 for _ in range(MISSILE_PARAMS*NUM_MISSILES)) | |
| PLAYER[X] = 10<<SCALE | |
| PLAYER[Y] = 10<<SCALE | |
| PLAYER[DEG]= 220 | |
| PLAYER[VX] = 0<<SCALE | |
| PLAYER[VY] = 0<<SCALE | |
| PLAYER[AX] = 0 | |
| PLAYER[AY] = 0 | |
| PLAYER[M] = 0 | |
| @micropython.viper | |
| def player_reset(): | |
| miss = ptr32(MISSILES) | |
| player = ptr32(PLAYER) | |
| player[X] = 10<<SCALE | |
| player[Y] = 10<<SCALE | |
| player[DEG]= 220 | |
| for index in range(NUM_MISSILES): | |
| i = index * MISSILE_PARAMS | |
| miss[i + MISS_LIFE] = 0 | |
| def init_game(): | |
| global GAME, SHIELD, STARS, COLORS, EXPLODE, FPS_ARRY, CANNON_MISL, MINES | |
| GAME = array.array('i',0 for _ in range(GAME_PARAMS)) | |
| SHIELD = array.array('i',0 for _ in range(SHIELD_PARAMS*12*3)) | |
| STARS = array.array('i',0 for _ in range(STARS_PARAMS*NUM_STARS)) | |
| COLORS = array.array('H',(YELLOW,ORANGE,RED)) | |
| EXPLODE = array.array('i',0 for _ in range(EXPLODE_PARAMS*20)) | |
| CANNON_MISL = array.array('i',0 for _ in range(MISSILE_PARAMS)) | |
| MINES = array.array('i',0 for _ in range(MISSILE_PARAMS*3)) | |
| FPS_ARRY = bytearray(100) | |
| GAME[FPS] = 0 | |
| GAME[LIVES] = 3 | |
| for index in range(NUM_STARS): | |
| i = index * STARS_PARAMS | |
| STARS[i + X] = randint(0,159) | |
| STARS[i + Y] = randint(0,127) | |
| STARS[i + STAR_COLOR] = randint(0,15) | |
| if STARS[i + STAR_COLOR] > 7: | |
| STARS[i + STAR_DIR] = -1 | |
| else: | |
| STARS[i + STAR_DIR] = 1 | |
| def init_shields(): | |
| global SHIELD | |
| for index in range(12*3): | |
| i = index * SHIELD_PARAMS | |
| deg = (index % 12) * 30 | |
| radius = 10 + (5 * (index//12)) | |
| SHIELD[i + X] = int(cos(radians(deg))*radius + MAXSCREEN_X//2) | |
| SHIELD[i + Y] = int(sin(radians(deg))*radius + MAXSCREEN_Y//2) | |
| SHIELD[i + DEG] = deg | |
| SHIELD[i + SHIELD_LIFE] = 2 | |
| SHIELD[i + SHIELD_DIR] = 5 | |
| if index>11 and index<24: | |
| SHIELD[i + SHIELD_DIR] = -5 | |
| SHIELD[i + SHIELD_RAD] = radius | |
| @micropython.viper | |
| def init_missile(): | |
| miss = ptr32(MISSILES) | |
| player = ptr32(PLAYER) | |
| isin = ptr32(ISIN) | |
| icos = ptr32(ICOS) | |
| game = ptr32(GAME) | |
| 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]*10 + x | |
| miss[i + Y] = isin[deg]*10 + 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: | |
| miss[i + VX] = (icos[deg])>>1 | |
| miss[i + VY] = (isin[deg])>>1 | |
| else: | |
| miss[i + VX] = (vx + icos[deg])>>1 | |
| miss[i + VY] = (vy + isin[deg])>>1 | |
| return | |
| @micropython.viper | |
| def init_cannon(): | |
| miss = ptr32(CANNON_MISL) | |
| game = ptr32(GAME) | |
| isin = ptr32(ISIN) | |
| icos = ptr32(ICOS) | |
| if game[LIVES] == 0: return | |
| x = 80 << SCALE | |
| y = 64 << SCALE | |
| deg = game[DEG_CANNON] + 180 | |
| if deg >= 360: deg -= 360 | |
| if miss[MISS_LIFE] == 0: | |
| miss[MISS_LIFE] = 200 | |
| miss[X] = icos[deg]*10 + x | |
| miss[Y] = isin[deg]*10 + y | |
| miss[VX] = (icos[deg])>>1 | |
| miss[VY] = (isin[deg])>>1 | |
| @micropython.viper | |
| def init_mine(): | |
| mine = ptr32(MINES) | |
| mine[(0*MISSILE_PARAMS) + MINE_SHIELD] = 1 | |
| mine[(1*MISSILE_PARAMS) + MINE_SHIELD] = 4 | |
| mine[(2*MISSILE_PARAMS) + MINE_SHIELD] = 8 | |
| @micropython.viper | |
| def move_mine(): | |
| shield = ptr32(SHIELD) | |
| mine = ptr32(MINES) | |
| isin = ptr32(ISIN) | |
| icos = ptr32(ICOS) | |
| player = ptr32(PLAYER) | |
| game = ptr32(GAME) | |
| for index in range(3): | |
| i = index * MISSILE_PARAMS | |
| shield_pos = mine[i + MINE_SHIELD] | |
| shield_index = shield_pos * SHIELD_PARAMS | |
| if shield_pos < 24 and shield[shield_index + DEG] == shield[(12*SHIELD_PARAMS+shield_index) + DEG] and int(randint(1,3))==3: | |
| shield_pos += 12 | |
| mine[i + MINE_SHIELD] = shield_pos | |
| if shield[(12*SHIELD_PARAMS+shield_index) + SHIELD_LIFE] == 0: | |
| mine[i + MINE_SHIELD] == 36 | |
| if shield_pos < 36: | |
| shield_index = shield_pos * MISSILE_PARAMS | |
| mine[i + X] = shield[shield_index + X] << SCALE | |
| mine[i + Y] = shield[shield_index + Y] << SCALE | |
| if shield_pos > 23 and shield_pos < 36 and int(randint(1,20))==20: | |
| mine[i + MINE_SHIELD] = 36 | |
| deg = shield[shield_index + DEG] | |
| mine[i + VX] = (icos[deg])>>1 | |
| mine[i + VY] = (isin[deg])>>1 | |
| mine[i + MISS_LIFE] = 20000 | |
| if mine[i + MINE_SHIELD] == 36 and mine[i + MISS_LIFE] > 0 : | |
| mine[i + MISS_LIFE] -= 1 | |
| mine[i + X] += mine[i + VX] | |
| mine[i + Y] += mine[i + VY] | |
| if mine[i + X] < player[X] : mine[i + VX] += 200 | |
| if mine[i + X] > player[X] : mine[i + VX] -= 200 | |
| if mine[i + Y] < player[Y] : mine[i + VY] += 200 | |
| if mine[i + Y] > player[Y] : mine[i + VY] -= 200 | |
| if mine[i + X] < 0 or mine[i + X] > MAXSCREEN_X<<SCALE or mine[i + Y] < 0 or mine[i + Y] > MAXSCREEN_Y<<SCALE: | |
| mine[i + MINE_SHIELD] = 1 | |
| if mine[i + X] > player[X] - 20000 and mine[i + X] < player[X] + 20000 and mine[i + Y] > player[Y]-20000 and mine[i + Y] < player[Y]+20000: | |
| init_explode(player[X],player[Y],30,10000) | |
| game[LIVES] -= 1 | |
| player_reset() | |
| init_mine() | |
| @micropython.viper | |
| def move_missile(): | |
| miss = ptr32(MISSILES) | |
| isin = ptr32(ISIN) | |
| icos = ptr32(ICOS) | |
| shield = ptr32(SHIELD) | |
| game = ptr32(GAME) | |
| mine = ptr32(MINES) | |
| 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] | |
| if x < 0 or y < 0 or x > MAXSCREEN_X<<SCALE or y > MAXSCREEN_Y<<SCALE: | |
| miss[i + MISS_LIFE] = 0 | |
| continue | |
| miss[i + X] = x | |
| miss[i + Y] = y | |
| x >>= SCALE | |
| y >>= SCALE | |
| if x > 77 and x < 83 and y > 62 and y < 68: # hit cannon | |
| miss[i + MISS_LIFE] = 0 | |
| init_explode(miss[i + X],miss[i + Y],100,10000) | |
| game[HIT_CANNON] = 80 | |
| player_reset() | |
| game[SCORE] += 1440 | |
| game[LIVES] += 1 | |
| break | |
| for index2 in range(12*3): # missile to shield collision | |
| i2 = index2 * SHIELD_PARAMS | |
| if shield[i2 + SHIELD_LIFE] > 0: | |
| s_x1 = shield[i2 + X] | |
| s_y1 = shield[i2 + Y] | |
| if index2 == 11 or index2 == 23 or index2 == 35: | |
| s_x2 = shield[(index2-11) * SHIELD_PARAMS + X ] | |
| s_y2 = shield[(index2-11) * SHIELD_PARAMS + Y ] | |
| else: | |
| s_x2 = shield[i2 + X + SHIELD_PARAMS] | |
| s_y2 = shield[i2 + Y + SHIELD_PARAMS] | |
| if s_x1 > s_x2: s_x1,s_x2 = s_x2,s_x1 | |
| if s_y1 > s_y2: s_y1,s_y2 = s_y2,s_y1 | |
| if x > s_x1-1 and x < s_x2+1 and y > s_y1-1 and y < s_y2+1: # hit shield | |
| shield[i2 + SHIELD_LIFE] -= 1 | |
| miss[i + MISS_LIFE] = 0 | |
| if shield[i2 + SHIELD_LIFE] == 0: | |
| init_explode(miss[i + X],miss[i + Y],20,5000) # 10, 10000 | |
| score(index2) | |
| break | |
| for index3 in range(3): | |
| i = index3 * MISSILE_PARAMS | |
| mine_x = mine[i + X] >> SCALE | |
| mine_y = mine[i + Y] >> SCALE | |
| if x > mine_x-3 and x < mine_x+3 and y > mine_y-3 and y < mine_y+3: # hit mine | |
| mine[i + MINE_SHIELD] = 1 | |
| init_explode(mine[i + X],mine[i + Y],20,5000) | |
| @micropython.viper | |
| def score(shield:int): | |
| game = ptr32(GAME) | |
| if shield > 23: | |
| game[SCORE] += 10 | |
| elif shield < 12: | |
| game[SCORE] += 30 | |
| else: | |
| game[SCORE] += 20 | |
| @micropython.viper | |
| def move_cannon_misl(): | |
| miss = ptr32(CANNON_MISL) | |
| game = ptr32(GAME) | |
| player = ptr32(PLAYER) | |
| player_x = player[X]>>SCALE | |
| player_y = player[Y]>>SCALE | |
| if miss[MISS_LIFE] > 0: | |
| miss[MISS_LIFE] -= 1 | |
| x = miss[X] | |
| y = miss[Y] | |
| x += miss[VX] | |
| y += miss[VY] | |
| if x < 0 or y < 0 or x > MAXSCREEN_X<<SCALE or y > MAXSCREEN_Y<<SCALE: | |
| miss[MISS_LIFE] = 0 | |
| return | |
| miss[X] = x | |
| miss[Y] = y | |
| x >>= SCALE | |
| y >>= SCALE | |
| if x > player_x-4 and x < player_x+4 and y > player_y-4 and y < player_y+4: # hit player | |
| miss[MISS_LIFE] = 0 | |
| init_explode(miss[X],miss[Y],30,10000) | |
| game[LIVES] -= 1 | |
| player_reset() | |
| @micropython.viper | |
| def move_cannon(): | |
| game = ptr32(GAME) | |
| player = ptr32(PLAYER) | |
| x = (player[X]>>SCALE) - 80 | |
| y = (player[Y]>>SCALE) - 64 | |
| start = int(my_atan2(x,y)) | |
| end = game[DEG_CANNON] | |
| raw_diff = int(abs(start - end)) | |
| mod_diff = raw_diff % 360 | |
| if mod_diff > 180: | |
| dist = 360 - mod_diff | |
| if start < end: | |
| dist = dist * -1 | |
| else: | |
| dist = mod_diff | |
| if start > end: | |
| dist = dist * -1 | |
| if dist>0: | |
| game[DEG_CANNON] -= 1 | |
| else: | |
| game[DEG_CANNON] += 1 | |
| if game[DEG_CANNON] > 359: game[DEG_CANNON] -= 360 | |
| if game[DEG_CANNON] < 0 : game[DEG_CANNON] += 360 | |
| def my_atan2(x,y): | |
| return int(atan2(y,x) * 180 / 3.1415926) + 180 | |
| @micropython.viper | |
| def move(): | |
| player = ptr32(PLAYER) | |
| deg = ptr16(SHIP_DEG) | |
| radius = ptr16(SHIP_RADIUS) | |
| coords = ptr32(SHIP_COORDS) | |
| cannon = ptr32(CANNON_COORDS) | |
| isin = ptr32(ISIN) | |
| icos = ptr32(ICOS) | |
| shield = ptr32(SHIELD) | |
| stars = ptr32(STARS) | |
| game = ptr32(GAME) | |
| size = 1 | |
| player[X] += player[VX] | |
| player[Y] += player[VY] | |
| player[VX] -= player[VX]>>5 # auto slow to stop | |
| player[VY] -= player[VY]>>5 | |
| if player[X] < 0: player[X] = MAXSCREEN_X<<SCALE | |
| if player[Y] < 0: player[Y] = MAXSCREEN_Y<<SCALE | |
| if player[X] > MAXSCREEN_X<<SCALE : player[X] = 0 | |
| if player[Y] > MAXSCREEN_Y<<SCALE : player[Y] = 0 | |
| x = player[X] | |
| y = player[Y] | |
| for index in range(SHIP_POINTS): # 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[i] = ((radius[index] * size * icos[pt_deg])>>14) | |
| coords[i+1] = ((radius[index] * size * isin[pt_deg])>>14) | |
| for index in range(SHIP_POINTS): # calc cannon points | |
| i = index * 2 | |
| pt_deg = deg[index] + game[DEG_CANNON] | |
| if pt_deg >= 360: pt_deg -= 360 | |
| if pt_deg < 0 : pt_deg += 360 | |
| cannon[i] = ((radius[index] * size * icos[pt_deg])>>14) | |
| cannon[i+1] = ((radius[index] * size * isin[pt_deg])>>14) | |
| for index in range(12*3): # calc shield points | |
| i = index * SHIELD_PARAMS | |
| shield_rad = shield[i + SHIELD_RAD] | |
| shield_deg = shield[i + DEG] + shield[i + SHIELD_DIR] | |
| if shield_deg < 0: shield_deg += 360 | |
| if shield_deg >= 360: shield_deg -= 360 | |
| shield[i + DEG] = shield_deg | |
| shield[i + X] = ((icos[shield_deg]*shield_rad)>>SCALE) + MAXSCREEN_X//2 | |
| shield[i + Y] = ((isin[shield_deg]*shield_rad)>>SCALE) + MAXSCREEN_Y//2 | |
| x >>= SCALE | |
| y >>= SCALE | |
| for index in range(12*3): # ship/shield collision | |
| i = index * SHIELD_PARAMS | |
| if shield[i + SHIELD_LIFE] > 0: | |
| s_x1 = shield[i + X] | |
| s_y1 = shield[i + Y] | |
| if index == 11 or index == 23 or index == 35: | |
| s_x2 = shield[(index-11) * SHIELD_PARAMS + X ] | |
| s_y2 = shield[(index-11) * SHIELD_PARAMS + Y ] | |
| else: | |
| s_x2 = shield[i + X + SHIELD_PARAMS] | |
| s_y2 = shield[i + Y + SHIELD_PARAMS] | |
| if s_x1 > s_x2: s_x1,s_x2 = s_x2,s_x1 | |
| if s_y1 > s_y2: s_y1,s_y2 = s_y2,s_y1 | |
| if x > s_x1 and x < s_x2 and y > s_y1 and y < s_y2: # hit | |
| player_deg = player[DEG] + 180 | |
| if player_deg >= 360: player_deg -= 360 | |
| if player_deg < 0 : player_deg += 360 | |
| player[DEG] = player_deg | |
| player[VX] *= -1 | |
| player[VY] *= -1 | |
| player[X] += player[VX]<<3 | |
| player[Y] += player[VY]<<3 | |
| @micropython.viper | |
| def check_cannon(): | |
| shield = ptr32(SHIELD) | |
| game = ptr32(GAME) | |
| cannon_deg = game[DEG_CANNON] | |
| first = 0 | |
| second = 0 | |
| third = 0 | |
| for index in range(0,36): # 0-12, 13-24, 25-36 | |
| i = index * SHIELD_PARAMS | |
| deg = (index % 12) * 30 | |
| shield_deg = shield[i + DEG] + 180 | |
| if shield_deg > 359: shield_deg -= 360 | |
| shield_life = shield[i + SHIELD_LIFE] | |
| if shield_life > 0 or shield_deg > cannon_deg + 15 or shield_deg < cannon_deg - 15: continue | |
| if index < 12: | |
| first = 1 | |
| elif index > 24: | |
| third = 1 | |
| else: | |
| second = 1 | |
| if first+second+third == 3: | |
| game[FIRE_CANNON] = 1 | |
| init_cannon() | |
| @micropython.viper | |
| def twinkle_stars(): | |
| stars = ptr32(STARS) | |
| for index in range(NUM_STARS): | |
| i = index * STARS_PARAMS | |
| dim = int(stars[i + STAR_COLOR]) | |
| dim += stars[i + STAR_DIR] | |
| if dim > 14 or dim < 1: | |
| stars[i + STAR_DIR] *= -1 | |
| else: | |
| stars[i + STAR_COLOR] = dim | |
| @micropython.viper | |
| def init_explode(x:int,y:int,life:int,speed:int): | |
| exp = ptr32(EXPLODE) | |
| exp[X] = x | |
| exp[Y] = y | |
| for index in range(1,20): | |
| i = index * EXPLODE_PARAMS | |
| exp[i + X] = x | |
| exp[i + Y] = y | |
| exp[i + VX] = int(randint(-1*speed,speed)) | |
| exp[i + VY] = int(randint(-1*speed,speed)) | |
| exp[i + EXP_LIFE] = life | |
| exp[i + EXP_COLOR] = 0 | |
| @micropython.viper | |
| def explode(): | |
| exp = ptr32(EXPLODE) | |
| game = ptr32(GAME) | |
| if game[HIT_CANNON] > 0: | |
| game[HIT_CANNON] -= 1 | |
| if game[HIT_CANNON] == 0: | |
| init_shields() | |
| init_mine() | |
| for index in range(1,20): | |
| i = index * EXPLODE_PARAMS | |
| if exp[i + EXP_LIFE] > 0: | |
| exp[i + X] += exp[i + VX] | |
| exp[i + Y] += exp[i + VY] | |
| exp[i + EXP_LIFE] -= 1 | |
| @micropython.viper | |
| def draw(): | |
| game = ptr32(GAME) | |
| player = ptr32(PLAYER) | |
| coords = ptr32(SHIP_COORDS) | |
| can_miss = ptr32(CANNON_MISL) | |
| stars = ptr32(STARS) | |
| shield = ptr32(SHIELD) | |
| colors = ptr16(COLORS) | |
| miss = ptr32(MISSILES) | |
| exp = ptr32(EXPLODE) | |
| mine = ptr32(MINES) | |
| for index in range(NUM_STARS): # draw stars | |
| i = index * STARS_PARAMS | |
| LCD.pixel(stars[i+X],stars[i+Y],stars[i + STAR_COLOR]<<8) | |
| if game[HIT_CANNON] == 0: | |
| for index in range(12*3): # draw shield | |
| i = index * SHIELD_PARAMS | |
| if shield[i + SHIELD_LIFE] > 0: | |
| x1 = shield[i + X] | |
| y1 = shield[i + Y] | |
| if index == 11 or index == 23 or index == 35: | |
| x2 = shield[(index-11) * SHIELD_PARAMS + X ] | |
| y2 = shield[(index-11) * SHIELD_PARAMS + Y ] | |
| else: | |
| x2 = shield[i + X + SHIELD_PARAMS] | |
| y2 = shield[i + Y + SHIELD_PARAMS] | |
| LCD.line(x1,y1,x2,y2,colors[index//12]) | |
| for index in range(NUM_MISSILES): # draw missiles | |
| i = index * MISSILE_PARAMS | |
| if miss[i + MISS_LIFE] > 0: | |
| LCD.pixel(miss[i + X]>>SCALE, miss[i + Y]>>SCALE, 0xffff) | |
| if can_miss[MISS_LIFE] > 0: | |
| cannon_misl_x = can_miss[X]>>SCALE | |
| cannon_misl_y = can_miss[Y]>>SCALE | |
| LCD.pixel(cannon_misl_x,cannon_misl_y, 0xffff) # draw cannon missile | |
| color = colors[int(randint(0,2))] | |
| for i in range(10): | |
| x = int(randint(-8,8)) | |
| y = int(randint(-8,8)) | |
| LCD.line(cannon_misl_x,cannon_misl_y, cannon_misl_x+x,cannon_misl_y+y,color) | |
| e_x = exp[X] | |
| e_y = exp[Y] | |
| for index in range(1,20): # draw explosion | |
| i = index * EXPLODE_PARAMS | |
| if exp[i + EXP_LIFE] > 0: | |
| LCD.line(e_x>>SCALE,e_y>>SCALE,exp[i + X]>>SCALE,exp[i + Y]>>SCALE,colors[(exp[i + EXP_LIFE]//12) % 3]) | |
| for index in range(3): | |
| i = index * MISSILE_PARAMS # draw mines | |
| mine_x = mine[i + X] >> SCALE | |
| mine_y = mine[i + Y] >> SCALE | |
| for i in range(10): | |
| x = int(randint(-3,3)) | |
| y = int(randint(-3,3)) | |
| LCD.line(mine_x,mine_y, mine_x+x,mine_y+y,0xffff) | |
| LCD.text('FPS',0,0,0xff) | |
| show_num_viper(game[FPS],10,10,0xff) | |
| LCD.text('SCORE',60,0,0xff) | |
| show_num_viper(game[SCORE],90,10,0xff) | |
| LCD.text('LIVES',115,0,0xff) | |
| show_num_viper(game[LIVES],125,10,0xff) | |
| if game[FIRE_CANNON] == 1 and 0: | |
| LCD.text('OPEN',60,10,0xff) | |
| if game[LIVES] == 0: | |
| LCD.text('GAME OVER',42,30,0xff) | |
| x = player[X] >> SCALE | |
| y = player[Y] >> SCALE | |
| if game[LIVES] > 0: | |
| LCD.poly(x,y,SHIP_COORDS,SKYBLUE) # draw ship | |
| if game[HIT_CANNON] == 0: | |
| LCD.poly(80,64,CANNON_COORDS,0xffff) # draw cannon | |
| LCD.show() | |
| LCD.rect(0,0,MAXSCREEN_X,MAXSCREEN_Y,0,1) # clear screen | |
| @micropython.viper | |
| def main(): | |
| init_imath() | |
| init_pot() | |
| init_game() | |
| init_shields() | |
| init_player() | |
| init_mine() | |
| game = ptr32(GAME) | |
| gticks = int(ticks_ms()) | |
| pot_ticks = gticks | |
| move_ticks = gticks | |
| init_miss_ticks = gticks | |
| move_miss_ticks = gticks | |
| twinkle_ticks = gticks | |
| explode_ticks = gticks | |
| while not EXIT: | |
| gticks = int(ticks_ms()) | |
| if gticks-pot_ticks>30: | |
| pot_ticks = int(ticks_ms()) | |
| read_pot() | |
| if gticks-move_ticks>40: | |
| move_ticks = int(ticks_ms()) | |
| move() | |
| move_mine() | |
| check_cannon() | |
| if gticks-init_miss_ticks>300: | |
| init_miss_ticks = int(ticks_ms()) | |
| init_missile() | |
| if gticks-twinkle_ticks>100: | |
| twinkle_ticks = int(ticks_ms()) | |
| twinkle_stars() | |
| if gticks-explode_ticks>10: | |
| explode_ticks = int(ticks_ms()) | |
| explode() | |
| move_cannon() | |
| move_missile() | |
| move_cannon_misl() | |
| draw() | |
| avg_fps(1_000//int(ticks_diff(ticks_ms(),gticks))) | |
| @micropython.viper | |
| def avg_fps(current_fps:int): | |
| game = ptr32(GAME) | |
| fps = ptr8(FPS_ARRY) | |
| fps[0] += 1 | |
| fps[fps[0]] = current_fps | |
| if fps[0] > 32: | |
| fps[0] = 0 | |
| tot = 0 | |
| for i in range(2,34): | |
| tot += fps[i] | |
| game[FPS] = tot >> 5 # 16 samples | |
| 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