Last active
February 27, 2023 07:08
-
-
Save samneggs/7ad05d05927a655e66bc6714da1dab78 to your computer and use it in GitHub Desktop.
Missile Command game in MicroPython on Pi Pico
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
# Missile Command game | |
from machine import Pin,SPI,PWM,ADC, Timer, reset, soft_reset | |
import framebuf, gc | |
import time, array, _thread | |
from time import sleep, ticks_us, ticks_diff, ticks_ms | |
from lcd_1_8 import LCD_1inch8 | |
from random import randint | |
from sys import exit | |
MAXSCREEN_X = const(160) | |
MAXSCREEN_Y = const(128) | |
NUM_ENEMY = const(10) | |
NUM_ASSET = const(50) | |
EXIT = False | |
LIVE_ASSETS = 0 | |
PLAYER_BLINK = const(30) | |
ENEMY_BLINK = const(200) | |
ASSET_BLINK = const(30) | |
BOTTOM_SCREEN = const(160*119) | |
LAUNCH_LEFT = const(160*120) | |
LAUNCH_CENTER = const(160*120+75) | |
LAUNCH_RIGHT = const(160*120+150) | |
X_POS = const(0) | |
Y_POS = const(1) | |
SPRITE = const(2) | |
BUTTON = const(3) | |
LIFE = const(3) | |
TARGET = const(4) | |
TARGETED = const(5) | |
CROSS_X = const(6) | |
CROSS_Y = const(7) | |
PARAMS = const(6) | |
X_INC = const(2) | |
Y_INC = const(3) | |
DURATION = const(4) | |
EXP_DIR = const(5) | |
EXP_PARAMS = const(6) | |
ENEMY_PARAMS = const(6) | |
ASSET_PARAMS = const(8) | |
EXP_SIZE = const(15) | |
cursor = array.array('B',( | |
1,0,0,1, | |
0,0,0,0, | |
0,0,0,0, | |
1,0,0,1)) | |
enemy_sprite = array.array('B',( | |
1,1,1,1, | |
1,0,0,1, | |
1,0,0,1, | |
1,1,1,1)) | |
asset_sprite = array.array('B',( | |
0,0,0,0, | |
0,1,1,0, | |
0,1,1,0, | |
0,0,0,0, | |
1,0,0,1, | |
0,1,1,0, | |
0,1,1,0, | |
1,0,0,1)) | |
fire_rgb = array.array('H',(8192 ,8216 ,24616 ,24640 ,41040 ,57440 ,57456 ,8329 ,24729 ,57513 ,8378 ,8386 ,24794 , | |
41178 ,41178 ,57554 ,57554 ,8659 ,25035 ,41419 ,57803 ,8908 ,8900 ,25284 ,41924 ,58300 , | |
58300 ,9405 ,9405 ,26045 ,26037 ,42421 ,42677 ,28110 ,62430 ,30959 ,65535)) | |
city_sprite = array.array('H',(0,0,0,0,0,0,0,0,0,0,0,7936,0,0,0,0,0,0,7936,0,0,0,0,0,0,0,0,7936,0,0,0,0,0,0,7936,7936,0,0,0,0,0,7936,0, | |
7936,0,0,0,0,0,0,7936,7936,0,7936,0,0,65287,7936,7936,7936,7936,0,7936,0,0,7936,7936,7936,7936,7936,7936, | |
0,65287,65287,7936,7936,7936,7936,7936,0,0,7936,65287,7936,7936,65287,7936,65287,65287,65287,7936,7936, | |
65287,7936,7936,0,7936,7936,65287,65287,7936,65287,65287,65287,7936,65287,65287,7936,65287,65287,7936, | |
7936,57599,65287,65287,65287,65287,65287,7936,7936,7936,7936,65287,65287,65287,65287,65287,57599,0,0,0, | |
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, | |
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, | |
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0)) | |
def init_player(): | |
global player | |
player = array.array('i',(X_POS,Y_POS,SPRITE,BUTTON)) | |
player[X_POS] = MAXSCREEN_X>>1 | |
player[Y_POS] = MAXSCREEN_Y>>1 | |
def init_enemy(): | |
global enemy | |
enemy = array.array('i',()) | |
j=0 | |
for i in range(NUM_ENEMY): | |
enemy.append(randint(5,MAXSCREEN_X-5)) # XPOS | |
enemy.append(0) # YPOS | |
enemy.append(enemy[X_POS+j*ENEMY_PARAMS]) # SPRITE | |
enemy.append(100) # LIFE | |
enemy.append(TARGET) | |
enemy.append(99) # TARGETED | |
j+=1 | |
def init_asset(): | |
global asset, trail | |
asset = array.array('i', 0 for _ in range(NUM_ASSET*ASSET_PARAMS)) | |
trail = array.array('B', 0 for _ in range(NUM_ASSET*210*2)) | |
def init_joystick(): | |
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 | |
def init_field(): | |
global SOUND | |
LCD.fill(0) | |
LCD.show() | |
SOUND = 1 | |
def init_explode(): | |
global explosion | |
explosion = array.array('i',()) | |
for i in range(0,1000,EXP_PARAMS): | |
explosion.append(X_POS) # X_POS | |
explosion.append(Y_POS) # Y_POS | |
explosion.append(randint(0-(1<<16),1<<16)) # x inc | |
explosion.append(randint(0-(1<<16),1<<16)) # y inc | |
explosion.append(EXP_SIZE+1) # DURATION | |
explosion.append(-1) # EXP_DIR | |
@micropython.viper | |
def start_explode(x:int,y:int): | |
exp = ptr32(explosion) | |
for j in range(1): # num particles, 1 for circle | |
for i in range(0,EXP_PARAMS*20,EXP_PARAMS): | |
if exp[i+DURATION] < EXP_SIZE+1: continue | |
explosion[i+X_POS] = x<<16 | |
explosion[i+Y_POS] = y<<16 | |
explosion[i+DURATION] = EXP_SIZE | |
explosion[i+EXP_DIR] = -1 | |
break | |
@micropython.viper | |
def draw_explode(explode_inc:int): # circle explosion | |
global ENEMY_REMAIN | |
screen_ptr = ptr16(LCD.buffer) | |
exp = ptr32(explosion) | |
enemy_ptr = ptr32(enemy) | |
fire_ptr = ptr16(fire_rgb) | |
max_addr = MAXSCREEN_X * MAXSCREEN_Y | |
finish_exp = 1 | |
for i in range(0,1000,EXP_PARAMS): | |
if exp[i+DURATION] > EXP_SIZE: continue | |
if exp[i+DURATION] == 0 and exp[i+EXP_DIR] == -1: | |
exp[i+EXP_DIR] = 1 | |
exp[i+DURATION] = 1 | |
x0 = exp[i+X_POS]>>16 | |
y0 = exp[i+Y_POS]>>16 | |
radius = 1+EXP_SIZE - (exp[i+DURATION]) | |
if explode_inc == 1 : | |
exp[i+DURATION] += exp[i+EXP_DIR] | |
fill_circle(x0,y0, radius, fire_ptr[37-(radius<<1)]) | |
finish_exp = 0 | |
for j in range(NUM_ENEMY): | |
index = ENEMY_PARAMS*j | |
if enemy_ptr[index+LIFE] == 0 : continue | |
enemy_x = enemy_ptr[index+X_POS] | |
enemy_y = enemy_ptr[index+Y_POS] | |
dx = enemy_x - x0 | |
dy = enemy_y - y0 | |
dist_squared = dx*dx + dy*dy | |
radius_squared = radius*radius | |
if dist_squared < radius_squared: | |
ENEMY_REMAIN = int(ENEMY_REMAIN)-1 | |
enemy_ptr[index+LIFE] = 0 | |
start_explode(enemy_x,enemy_y) | |
if int(ENEMY_REMAIN) == 0 and finish_exp == 1: | |
init_enemy() | |
@micropython.viper | |
def draw_explode2(game_counter:int): # particle explosion | |
screen_ptr = ptr16(LCD.buffer) | |
exp = ptr32(explosion) | |
fire_ptr = ptr16(fire_rgb) | |
max_addr = MAXSCREEN_X * MAXSCREEN_Y | |
for i in range(0,1000,EXP_PARAMS): | |
if exp[i+DURATION] > EXP_SIZE or exp[i+DURATION] == 0 : | |
exp[i+DURATION] = EXP_SIZE + 1 | |
continue | |
if not (game_counter % 10): | |
exp[i+DURATION] -= 1 | |
exp[i+X_POS] += exp[i+X_INC] | |
exp[i+Y_POS] += exp[i+Y_INC] | |
addr = (exp[i+Y_POS]>>16)*MAXSCREEN_X + (exp[i+X_POS]>>16) | |
if addr>=0 and addr < max_addr: | |
screen_ptr[addr] = fire_ptr[7+(exp[i+DURATION]<<1)] | |
@micropython.viper | |
def fill_circle(x0:int, y0:int, radius:int, color:int): | |
screen_ptr = ptr16(LCD.buffer) | |
max_addr = MAXSCREEN_X * MAXSCREEN_Y | |
# From Adafruit GFX Arduino library | |
y_start = y0 - radius | |
for y2 in range(y_start, y_start+2*radius + 1): | |
addr = y2 * MAXSCREEN_X + x0 | |
if addr > 0 and addr < max_addr: | |
screen_ptr[addr] = color | |
f = 1 - radius | |
ddF_x = 1 | |
ddF_y = -2 * radius | |
x = 0 | |
y = radius | |
while x < y: | |
if f >= 0: | |
y -= 1 | |
ddF_y += 2 | |
f += ddF_y | |
x += 1 | |
ddF_x += 2 | |
f += ddF_x | |
x2 = x0 + x | |
y_start = y0 - y | |
for y2 in range(y_start, y_start+2*y + 1): | |
addr = y2 * MAXSCREEN_X + x2 | |
if addr > 0 and addr < max_addr: | |
screen_ptr[addr] = color | |
x2 = x0 + y | |
y_start = y0 - x | |
for y2 in range(y_start,y_start+ 2*x + 1): | |
addr = y2 * MAXSCREEN_X + x2 | |
if addr > 0 and addr < max_addr: | |
screen_ptr[addr] = color | |
x2 = x0 - x | |
y_start = y0 - y | |
for y2 in range(y_start, y_start+2*y + 1): | |
addr = y2 * MAXSCREEN_X + x2 | |
if addr > 0 and addr < max_addr: | |
screen_ptr[addr] = color | |
x2 = x0 - y | |
y_start = y0 - x | |
for y2 in range(y_start, y_start+2*x + 1): | |
addr = y2 * MAXSCREEN_X + x2 | |
if addr > 0 and addr < max_addr: | |
screen_ptr[addr] = color | |
@micropython.viper | |
def draw(fps:int): | |
screen_ptr = ptr16(LCD.buffer) | |
player_ptr = ptr32(player) | |
enemy_ptr = ptr32(enemy) | |
asset_ptr = ptr32(asset) | |
cursor_ptr = ptr8(cursor) | |
e_sprite_ptr = ptr8(enemy_sprite) | |
a_sprite_ptr = ptr8(asset_sprite) | |
trail_ptr = ptr8(trail) | |
size = 4 | |
offset = 0 | |
# ggg_bbbbbrrrrr_ggg | |
red = 0b111_0011111111_001 | |
player_ptr[SPRITE]+=1 | |
if player_ptr[SPRITE] > PLAYER_BLINK: | |
player_ptr[SPRITE] = 0 | |
for y in range(size): | |
for x in range(size): | |
color = cursor_ptr[y*4+x] | |
if (color == 1 and player_ptr[SPRITE]<PLAYER_BLINK>>1) or (color == 0 and player_ptr[SPRITE]>=PLAYER_BLINK>>1): | |
screen_ptr[(y+player_ptr[Y_POS])*MAXSCREEN_X + player_ptr[X_POS]+x] = 0xffff | |
for i in range(NUM_ENEMY): #NUM_ENEMY | |
if enemy_ptr[i*ENEMY_PARAMS+LIFE] == 0: continue | |
sprite_index = SPRITE+ENEMY_PARAMS*i | |
enemy_ptr[sprite_index]+=1 | |
if enemy_ptr[sprite_index] > ENEMY_BLINK: | |
enemy_ptr[sprite_index] = 0 | |
for y in range(size): | |
for x in range(size): | |
x1 = X_POS + ENEMY_PARAMS * i | |
y1 = Y_POS + ENEMY_PARAMS * i | |
color = e_sprite_ptr[y*4+x] | |
if (color == 1 and enemy_ptr[sprite_index]<ENEMY_BLINK>>1) or (color == 0 and enemy_ptr[sprite_index]>=ENEMY_BLINK>>1): | |
screen_ptr[(y+enemy_ptr[y1])*MAXSCREEN_X + enemy_ptr[x1]+x] = red | |
for i in range(NUM_ASSET): | |
index = ASSET_PARAMS*i | |
index2 = 200*(i)*2 | |
pos = asset_ptr[index+LIFE] # 400 -> 0 | |
if pos == 0: continue | |
#print(pos) | |
for j in range(400,pos,-2): | |
x = trail_ptr[index2+j] | |
y = trail_ptr[index2+j+1] | |
addr = y * MAXSCREEN_X + x | |
screen_ptr[addr] = 0xffff | |
LCD.text(str(fps),0,0,0xff) | |
LCD.text(str(ENEMY_REMAIN),0,10,0xff) | |
LCD.show() | |
LCD.fill(0) | |
@micropython.viper | |
def draw_citys(): | |
screen_ptr = ptr16(LCD.buffer) | |
bitmap_ptr = ptr16(city_sprite) | |
for n in range(3): | |
for y in range(9): | |
for x in range(16): | |
addr = y * 160 + x + 15 + BOTTOM_SCREEN | |
screen_ptr[addr+n*20] = bitmap_ptr[y*16+x] | |
screen_ptr[addr+n*20+72] = bitmap_ptr[y*16+x] | |
for y in range(6): | |
for x in range(14): | |
screen_ptr[y*160+n*72+x+(160*2)+BOTTOM_SCREEN] = 0xff | |
def read_joystick(): | |
global player | |
pot_scale = 13 | |
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 x_inc==0 and y_inc==0: return | |
player[X_POS] -= x_inc | |
player[Y_POS] += y_inc | |
if player[X_POS] < 0: | |
player[X_POS] = 0 | |
if player[X_POS] > MAXSCREEN_X-1: | |
player[X_POS] = MAXSCREEN_X-1 | |
if player[Y_POS] < 0: | |
player[Y_POS] = 0 | |
if player[Y_POS] > MAXSCREEN_Y-1: | |
player[Y_POS] = MAXSCREEN_Y-1 | |
@micropython.viper | |
def button(): | |
global LIVE_ASSETS, SOUND | |
player_ptr = ptr32(player) | |
enemy_ptr = ptr32(enemy) | |
pushed = not FIRE.value() | |
asset_ptr = ptr32(asset) | |
if not pushed: return | |
x = player_ptr[X_POS] | |
y = player_ptr[Y_POS] | |
for i in range(NUM_ASSET): # search through assets to find unused | |
index = ASSET_PARAMS*i | |
if asset_ptr[index+LIFE] == 0: | |
asset_ptr[index+X_POS] = (LAUNCH_CENTER % 160)<<16 | |
asset_ptr[index+Y_POS] = (LAUNCH_CENTER // 160)<<16 | |
asset_ptr[index+CROSS_X] = x<<16 | |
asset_ptr[index+CROSS_Y] = y<<16 | |
# min_distance = MAXSCREEN_X + MAXSCREEN_Y | |
# for j in range(NUM_ENEMY): # search through enemies to target | |
# enemy_index = ASSET_PARAMS*j | |
# if enemy_ptr[enemy_index+LIFE] == 0 or enemy_ptr[enemy_index+TARGETED]<99: | |
# continue | |
# #distance = int(abs(x-enemy_ptr[enemy_index+X_POS])+abs(y-enemy_ptr[enemy_index+Y_POS])) | |
# distance = int(distance_asm(x,y,enemy_ptr[enemy_index+X_POS],enemy_ptr[enemy_index+Y_POS])) | |
# if distance<min_distance: | |
# min_distance = distance | |
# closest_enemy = j | |
# if closest_enemy>NUM_ENEMY: return # no enemies left | |
asset_ptr[index+LIFE] = 200*2 | |
init_trail((LAUNCH_CENTER % 160)<<16,(LAUNCH_CENTER // 160)<<16,x<<16,y<<16,i) | |
SOUND = 2 | |
return | |
@micropython.viper | |
def move_asset(t): | |
player_ptr = ptr32(player) | |
enemy_ptr = ptr32(enemy) | |
asset_ptr = ptr32(asset) | |
trail_ptr = ptr8(trail) | |
for i in range(NUM_ASSET): | |
index = ASSET_PARAMS*i | |
if asset_ptr[index+LIFE] == 0 : continue | |
asset_ptr[index+LIFE] -= 2 | |
pos = asset_ptr[index+LIFE] | |
trail_x = trail_ptr[i*200+pos] | |
trail_y = trail_ptr[i*200+pos+1] | |
cross_x = asset_ptr[index+CROSS_X]>>16 | |
cross_y = asset_ptr[index+CROSS_Y]>>16 | |
print(pos,cross_x,trail_x,cross_y,trail_y) | |
if cross_x == trail_x and (cross_y == trail_y or cross_y == trail_y-1): # trail hits cross | |
asset_ptr[index+LIFE] = 0 | |
start_explode(trail_x,trail_y) | |
@micropython.viper | |
def move_enemy(): | |
global ENEMY_REMAIN | |
player_ptr = ptr32(player) | |
enemy_ptr = ptr32(enemy) | |
ENEMY_REMAIN = 0 | |
for i in range(NUM_ENEMY): | |
index = ENEMY_PARAMS*i | |
if enemy_ptr[index+LIFE] == 0 : continue | |
ENEMY_REMAIN = int(ENEMY_REMAIN)+1 | |
enemy_x = enemy_ptr[index+X_POS] | |
enemy_y = enemy_ptr[index+Y_POS] | |
#target = ENEMY_PARAMS*enemy_ptr[index+TARGET] | |
target_x = player_ptr[X_POS] | |
target_y = player_ptr[Y_POS] | |
dx = enemy_x - target_x | |
dy = enemy_y - target_y | |
if dx<0 : enemy_ptr[index+X_POS] += 1 | |
elif dx>0: enemy_ptr[index+X_POS] -= 1 | |
if dy>0 : enemy_ptr[index+Y_POS] -= 1 | |
elif dy<0: enemy_ptr[index+Y_POS] += 1 | |
if dy == 0 and dx==0: | |
enemy_ptr[index+LIFE] = 0 | |
enemy_ptr[index+TARGETED] = 99 | |
if enemy_ptr[index+LIFE]<=0: | |
enemy_ptr[index+LIFE] = 0 | |
start_explode(enemy_x,enemy_y) | |
@micropython.viper | |
def init_trail(x1:int,y1:int,x2:int,y2:int,index:int): | |
trail_ptr = ptr8(trail) | |
x = x1 | |
y = y1 | |
dx = (x2-x1) | |
dy = (y2-y1) | |
dx_a = int(abs(dx)) | |
dy_a = int(abs(dy)) | |
#if (dx>>16)*(dy>>16)==0: return x,y | |
index = index * 200 * 2+400 | |
if dy_a >= dx_a: | |
if y2 > y1: | |
y_inc = 1<<16 | |
x_inc = dx//(dy>>16) * -1 | |
for y in range(y1,y1-dy_a,1<<16): | |
x -= x_inc | |
index -= 2 | |
trail_ptr[index ] = x>>16 | |
trail_ptr[index+1] = y>>16 | |
#x -= x_inc | |
#index -= 2 | |
else: | |
y_inc = -1<<16 | |
x_inc = dx//(dy>>16) | |
for y in range(y1,y1-dy_a,-1<<16): | |
x -= x_inc | |
index -= 2 | |
trail_ptr[index ] = x>>16 | |
trail_ptr[index+1] = y>>16 | |
#x -= x_inc | |
#index -= 2 | |
else: | |
y_inc = dy//(dx>>16) | |
if x2 > x1: | |
x_inc = 1<<16 | |
for x in range(x1,x2,1<<16): | |
index -= 2 | |
y += y_inc | |
trail_ptr[index ] = x>>16 | |
trail_ptr[index+1] = y>>16 | |
#index -= 2 | |
#y += y_inc | |
else: | |
x_inc = -1<<16 | |
y_inc = y_inc * -1 | |
for x in range(x1,x2,-1<<16): | |
index -= 2 | |
y += y_inc | |
trail_ptr[index ] = x>>16 | |
trail_ptr[index+1] = y>>16 | |
#index -= 2 | |
#y += y_inc | |
def core1(): | |
global SOUND,WATCHDOG | |
sleep(1) | |
while(1): | |
WATCHDOG += 1 | |
if WATCHDOG == 100_000: | |
print('core 0 crash') | |
reset() | |
if SOUND==1: | |
sound_alarm() | |
if SOUND==1: | |
SOUND = 0 | |
if SOUND==2: | |
sound_missile() | |
if SOUND==2: | |
SOUND = 0 | |
@micropython.asm_thumb | |
def distance_asm(r0,r1,r2,r3): # x1,y1,x2,y2 | |
sub(r4,r2,r0) # x2-x1 | |
sub(r5,r3,r1) # y2-y1 | |
mul(r4,r4) # (x2-x1)^2 | |
mul(r5,r5) # (y2-y1)^2 | |
add(r0,r4,r5) # (x2-x1)^2 + (y2-y1)^2 | |
mov(r2,0) # r2 = res | |
cmp(r0,0) # r0 = num | |
bpl(MAIN) | |
mov(r0,0) | |
b(EXIT) | |
label(MAIN) | |
mov(r1,1) # r1 = bit | |
lsl(r1,r1,30) | |
label(FOUR_POWER) | |
cmp(r1,r0) # bit <= num | |
ble(LOOP) | |
asr(r1,r1,2) # bit = bit >> 2 | |
b(FOUR_POWER) | |
label(LOOP) | |
cmp(r1,0) | |
beq(EXIT) # bit == 0 | |
add(r3,r1,r2) # res + bit | |
cmp(r0,r3) # if num >= res + bit | |
blt(ELSE) | |
sub(r0,r0,r3) # num = num - (res + bit) | |
asr(r4,r2,1) # res >> 1 | |
add(r2,r4,r1) # res = (res >> 1) + bit | |
b(IF_DONE) | |
label(ELSE) | |
asr(r2,r2,1) # res = res>>1 | |
label(IF_DONE) | |
asr(r1,r1,2) # bit = bit >> 2 | |
b(LOOP) | |
label(EXIT) | |
cmp(r0,r2) # if num <= res: | |
ble(NO_ROUND) | |
add(r2,r2,1) # res += 1 | |
label(NO_ROUND) | |
mov(r0,r2) | |
def is_collision(x, y, x0, y0, r): | |
dx = x - x0 | |
dy = y - y0 | |
dist_squared = dx**2 + dy**2 | |
radius_squared = r**2 | |
return dist_squared <= radius_squared | |
def sound_alarm(): | |
volume = 1000 | |
POWER.on() | |
BUZZ.duty_u16(volume) | |
start =1250 | |
end = 1050 | |
for repeats in range(6): | |
for i in range(start,end,-10): | |
BUZZ.duty_u16(volume) | |
BUZZ.freq(i) | |
sleep(.014) | |
POWER.off() | |
def sound_missile(): | |
global SOUND | |
SOUND = 0 | |
volume = 2000 | |
POWER.on() | |
BUZZ.duty_u16(volume) | |
start =1500 | |
end = 500 | |
for i in range(start,end,-1): | |
BUZZ.duty_u16(volume) | |
volume -= 2 | |
BUZZ.freq(i) | |
if SOUND == 2 : | |
POWER.off() | |
return | |
for delay in range(150): | |
pass | |
POWER.off() | |
if __name__=='__main__': | |
FIRE = Pin(22, Pin.IN, Pin.PULL_UP) | |
POWER = Pin(16, machine.Pin.OUT) | |
BUZZ = machine.PWM(Pin(17, machine.Pin.OUT)) | |
pwm = PWM(Pin(13)) | |
pwm.freq(1000) | |
pwm.duty_u16(0x7fff)#max 65535 | |
#machine.freq(200_000_000) | |
LCD = LCD_1inch8() | |
#machine.mem32[0x40008048] = 1<<11 # enable peri_ctrl clock | |
WATCHDOG = 0 | |
SOUND = 0 | |
_thread.start_new_thread(core1, ()) | |
init_player() | |
init_enemy() | |
init_asset() | |
init_joystick() | |
init_field() | |
init_explode() | |
gc.collect() | |
print(gc.mem_free()) | |
fps = 0 | |
game_counter = 0 | |
ENEMY_REMAIN = 0 | |
move_enemy_ticks = ticks_ms() | |
explode_ticks = ticks_ms() | |
explode_inc = 0 | |
move_asset_ticks = ticks_ms() | |
button_ticks = ticks_ms() | |
joystick_ticks = ticks_ms() | |
while not EXIT: | |
gticks = ticks_us() | |
WATCHDOG = 0 | |
game_counter +=1 | |
if game_counter > 50: game_counter = 0 | |
if ticks_diff(ticks_ms(),move_enemy_ticks) > 1000: | |
move_enemy() | |
move_enemy_ticks = ticks_ms() | |
if ticks_diff(ticks_ms(),move_asset_ticks) > 50: | |
move_asset(0) | |
move_asset_ticks = ticks_ms() | |
if ticks_diff(ticks_ms(),joystick_ticks) > 50: | |
read_joystick() | |
joystick_ticks = ticks_ms() | |
if ticks_diff(ticks_ms(),button_ticks) > 200: | |
button() | |
button_ticks = ticks_ms() | |
if ticks_diff(ticks_ms(),explode_ticks) > 100: | |
explode_ticks = ticks_ms() | |
explode_inc = 1 | |
else: | |
explode_inc = 0 | |
draw_explode(explode_inc) | |
draw_citys() | |
draw(fps) | |
fps = 1_000_000//int(ticks_diff(ticks_us(),gticks)) |
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
# Missile Command game | |
from machine import Pin,SPI,PWM,ADC, Timer, reset, soft_reset | |
import framebuf, gc | |
import time, array, _thread | |
from time import sleep, ticks_us, ticks_diff, ticks_ms | |
from lcd_1_8 import LCD_1inch8 | |
from random import randint | |
from sys import exit | |
MAXSCREEN_X = const(160) | |
MAXSCREEN_Y = const(128) | |
NUM_ENEMY = const(10) # 10 | |
NUM_ASSET = const(10) | |
EXIT = False | |
LIVE_ASSETS = 0 | |
PLAYER_BLINK = const(30) | |
ENEMY_BLINK = const(200) | |
ASSET_BLINK = const(30) | |
BOTTOM_SCREEN = const(160*119) | |
LAUNCH_LEFT = const(160*120) | |
LAUNCH_CENTER = const(160*120+75) | |
LAUNCH_RIGHT = const(160*120+150) | |
X_POS = const(0) | |
Y_POS = const(1) | |
SPRITE = const(2) | |
BUTTON = const(3) | |
LIFE = const(3) | |
TARGET_X = const(4) | |
TARGET_Y = const(5) | |
CROSS_X = const(6) | |
CROSS_Y = const(7) | |
PARAMS = const(6) | |
X_INC = const(2) | |
Y_INC = const(3) | |
DURATION = const(4) | |
EXP_DIR = const(5) | |
EXP_PARAMS = const(6) | |
ENEMY_PARAMS = const(6) | |
ASSET_PARAMS = const(8) | |
EXP_SIZE = const(15) | |
cursor = array.array('B',( | |
1,0,0,1, | |
0,0,0,0, | |
0,0,0,0, | |
1,0,0,1)) | |
enemy_sprite = array.array('B',( | |
1,1,1,1, | |
1,0,0,1, | |
1,0,0,1, | |
1,1,1,1)) | |
asset_sprite = array.array('B',( | |
0,0,0,0, | |
0,1,1,0, | |
0,1,1,0, | |
0,0,0,0, | |
1,0,0,1, | |
0,1,1,0, | |
0,1,1,0, | |
1,0,0,1)) | |
fire_rgb = array.array('H',(8192 ,8216 ,24616 ,24640 ,41040 ,57440 ,57456 ,8329 ,24729 ,57513 ,8378 ,8386 ,24794 , | |
41178 ,41178 ,57554 ,57554 ,8659 ,25035 ,41419 ,57803 ,8908 ,8900 ,25284 ,41924 ,58300 , | |
58300 ,9405 ,9405 ,26045 ,26037 ,42421 ,42677 ,28110 ,62430 ,30959 ,65535)) | |
city_sprite = array.array('H',(0,0,0,0,0,0,0,0,0,0,0,7936,0,0,0,0,0,0,7936,0,0,0,0,0,0,0,0,7936,0,0,0,0,0,0,7936,7936,0,0,0,0,0,7936,0, | |
7936,0,0,0,0,0,0,7936,7936,0,7936,0,0,65287,7936,7936,7936,7936,0,7936,0,0,7936,7936,7936,7936,7936,7936, | |
0,65287,65287,7936,7936,7936,7936,7936,0,0,7936,65287,7936,7936,65287,7936,65287,65287,65287,7936,7936, | |
65287,7936,7936,0,7936,7936,65287,65287,7936,65287,65287,65287,7936,65287,65287,7936,65287,65287,7936, | |
7936,57599,65287,65287,65287,65287,65287,7936,7936,7936,7936,65287,65287,65287,65287,65287,57599,0,0,0, | |
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, | |
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, | |
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0)) | |
def init_player(): | |
global player | |
player = array.array('i',(X_POS,Y_POS,SPRITE,BUTTON)) | |
player[X_POS] = MAXSCREEN_X>>1 | |
player[Y_POS] = MAXSCREEN_Y>>1 | |
def init_enemy(): | |
global enemy, trail2, ENEMY_REMAIN | |
enemy = array.array('i',()) | |
for i in range(NUM_ENEMY): | |
x1 = randint(5,MAXSCREEN_X-5) | |
y1 = randint(0,10) | |
enemy.append(x1) # XPOS | |
enemy.append(y1) # YPOS | |
enemy.append(enemy[X_POS+i*ENEMY_PARAMS]) # SPRITE | |
enemy.append(400) # LIFE | |
x2 = (randint(1,9)*16) | |
y2 = 120 | |
enemy.append(x2) # TARGET_X | |
enemy.append(y2) # TARGET_Y | |
init_trail(trail2,x1<<16,y1<<16,x2<<16,y2<<16,i) | |
ENEMY_REMAIN += 1 | |
def init_asset(): | |
global asset, trail, trail2 | |
asset = array.array('i', 0 for _ in range(NUM_ASSET*ASSET_PARAMS)) | |
trail = array.array('B', 0 for _ in range(NUM_ASSET*402)) | |
trail2 = array.array('B', 0 for _ in range(NUM_ENEMY*402)) | |
def init_joystick(): | |
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 | |
def init_field(): | |
global SOUND | |
LCD.fill(0) | |
LCD.show() | |
SOUND = 1 | |
def init_explode(): | |
global explosion | |
explosion = array.array('i',()) | |
for i in range(0,1000,EXP_PARAMS): | |
explosion.append(X_POS) # X_POS | |
explosion.append(Y_POS) # Y_POS | |
explosion.append(randint(0-(1<<16),1<<16)) # x inc | |
explosion.append(randint(0-(1<<16),1<<16)) # y inc | |
explosion.append(EXP_SIZE+1) # DURATION | |
explosion.append(-1) # EXP_DIR | |
@micropython.viper | |
def start_explode(x:int,y:int): | |
exp = ptr32(explosion) | |
for j in range(1): # num particles, 1 for circle | |
for i in range(0,EXP_PARAMS*20,EXP_PARAMS): | |
if exp[i+DURATION] < EXP_SIZE+1: continue | |
explosion[i+X_POS] = x<<16 | |
explosion[i+Y_POS] = y<<16 | |
explosion[i+DURATION] = EXP_SIZE | |
explosion[i+EXP_DIR] = -1 | |
break | |
@micropython.viper | |
def draw_explode(explode_inc:int): # circle explosion | |
global ENEMY_REMAIN | |
screen_ptr = ptr16(LCD.buffer) | |
exp = ptr32(explosion) | |
enemy_ptr = ptr32(enemy) | |
trail_ptr = ptr8(trail2) | |
fire_ptr = ptr16(fire_rgb) | |
max_addr = MAXSCREEN_X * MAXSCREEN_Y | |
finish_exp = 1 | |
for i in range(0,1000,EXP_PARAMS): | |
if exp[i+DURATION] > EXP_SIZE: continue | |
if exp[i+DURATION] == 0 and exp[i+EXP_DIR] == -1: | |
exp[i+EXP_DIR] = 1 | |
exp[i+DURATION] = 1 | |
x0 = exp[i+X_POS]>>16 | |
y0 = exp[i+Y_POS]>>16 | |
radius = 1+EXP_SIZE - (exp[i+DURATION]) | |
if explode_inc == 1 : | |
exp[i+DURATION] += exp[i+EXP_DIR] | |
fill_circle(x0,y0, radius, fire_ptr[37-(radius<<1)]) | |
finish_exp = 0 | |
for j in range(NUM_ENEMY): | |
index = ENEMY_PARAMS*j | |
if enemy_ptr[index+LIFE] == 0 : continue | |
pos = enemy_ptr[index+LIFE] | |
trail_x = trail_ptr[j*400+pos] | |
trail_y = trail_ptr[j*400+pos+1] | |
dx = trail_x - x0 | |
dy = trail_y - y0 | |
dist_squared = dx*dx + dy*dy | |
radius_squared = radius*radius | |
if dist_squared < radius_squared: | |
ENEMY_REMAIN = int(ENEMY_REMAIN)-1 | |
enemy_ptr[index+LIFE] = 0 | |
start_explode(trail_x,trail_y) | |
if int(ENEMY_REMAIN) == 0 and finish_exp == 1: | |
init_enemy() | |
@micropython.viper | |
def fill_circle(x0:int, y0:int, radius:int, color:int): | |
screen_ptr = ptr16(LCD.buffer) | |
max_addr = MAXSCREEN_X * MAXSCREEN_Y | |
# From Adafruit GFX Arduino library | |
y_start = y0 - radius | |
for y2 in range(y_start, y_start+2*radius + 1): | |
addr = y2 * MAXSCREEN_X + x0 | |
if addr > 0 and addr < max_addr: | |
screen_ptr[addr] = color | |
f = 1 - radius | |
ddF_x = 1 | |
ddF_y = -2 * radius | |
x = 0 | |
y = radius | |
while x < y: | |
if f >= 0: | |
y -= 1 | |
ddF_y += 2 | |
f += ddF_y | |
x += 1 | |
ddF_x += 2 | |
f += ddF_x | |
x2 = x0 + x | |
y_start = y0 - y | |
for y2 in range(y_start, y_start+2*y + 1): | |
addr = y2 * MAXSCREEN_X + x2 | |
if addr > 0 and addr < max_addr: | |
screen_ptr[addr] = color | |
x2 = x0 + y | |
y_start = y0 - x | |
for y2 in range(y_start,y_start+ 2*x + 1): | |
addr = y2 * MAXSCREEN_X + x2 | |
if addr > 0 and addr < max_addr: | |
screen_ptr[addr] = color | |
x2 = x0 - x | |
y_start = y0 - y | |
for y2 in range(y_start, y_start+2*y + 1): | |
addr = y2 * MAXSCREEN_X + x2 | |
if addr > 0 and addr < max_addr: | |
screen_ptr[addr] = color | |
x2 = x0 - y | |
y_start = y0 - x | |
for y2 in range(y_start, y_start+2*x + 1): | |
addr = y2 * MAXSCREEN_X + x2 | |
if addr > 0 and addr < max_addr: | |
screen_ptr[addr] = color | |
@micropython.viper | |
def draw(fps:int): | |
screen_ptr = ptr16(LCD.buffer) | |
player_ptr = ptr32(player) | |
enemy_ptr = ptr32(enemy) | |
asset_ptr = ptr32(asset) | |
cursor_ptr = ptr8(cursor) | |
e_sprite_ptr = ptr8(enemy_sprite) | |
a_sprite_ptr = ptr8(asset_sprite) | |
trail_ptr = ptr8(trail) | |
trail2_ptr = ptr8(trail2) | |
size = 4 | |
offset = 0 | |
# ggg_bbbbbrrrrr_ggg | |
red = 0b111_0011111111_001 | |
blue= 0b000_1111100000_000 | |
player_ptr[SPRITE]+=1 | |
if player_ptr[SPRITE] > PLAYER_BLINK: | |
player_ptr[SPRITE] = 0 | |
for y in range(size): | |
for x in range(size): | |
color = cursor_ptr[y*4+x] | |
if (color == 1 and player_ptr[SPRITE]<PLAYER_BLINK>>1) or (color == 0 and player_ptr[SPRITE]>=PLAYER_BLINK>>1): | |
screen_ptr[(y+player_ptr[Y_POS])*MAXSCREEN_X + player_ptr[X_POS]+x] = 0xffff | |
# for i in range(NUM_ENEMY): #NUM_ENEMY | |
# if enemy_ptr[i*ENEMY_PARAMS+LIFE] == 0: continue | |
# sprite_index = SPRITE+ENEMY_PARAMS*i | |
# enemy_ptr[sprite_index]+=1 | |
# if enemy_ptr[sprite_index] > ENEMY_BLINK: | |
# enemy_ptr[sprite_index] = 0 | |
# for y in range(size): | |
# for x in range(size): | |
# x1 = X_POS + ENEMY_PARAMS * i | |
# y1 = Y_POS + ENEMY_PARAMS * i | |
# color = e_sprite_ptr[y*4+x] | |
# if (color == 1 and enemy_ptr[sprite_index]<ENEMY_BLINK>>1) or (color == 0 and enemy_ptr[sprite_index]>=ENEMY_BLINK>>1): | |
# screen_ptr[(y+enemy_ptr[y1])*MAXSCREEN_X + enemy_ptr[x1]+x] = red | |
for i in range(NUM_ASSET): # draw player missiles | |
index = ASSET_PARAMS*i | |
index2 = 200*(i)*2 | |
pos = asset_ptr[index+LIFE] # 400 -> 0 | |
if pos == 0: continue | |
for j in range(400,pos-2,-2): | |
x = trail_ptr[index2+j] | |
y = trail_ptr[index2+j+1] | |
addr = y * MAXSCREEN_X + x | |
screen_ptr[addr] = blue | |
screen_ptr[addr] = 0xffff | |
for i in range(NUM_ENEMY): # draw enemy missiles | |
index = ENEMY_PARAMS*i | |
index2 = 200*(i)*2 | |
pos = enemy_ptr[index+LIFE] # 400 -> 0 | |
if pos == 0: continue | |
for j in range(400,pos-2,-2): | |
x = trail2_ptr[index2+j] | |
y = trail2_ptr[index2+j+1] | |
addr = y * MAXSCREEN_X + x | |
screen_ptr[addr] = red | |
screen_ptr[addr] = 0xffff | |
LCD.text(str(fps),0,0,0xff) | |
LCD.text(str(ENEMY_REMAIN),0,10,0xff) | |
LCD.show() | |
LCD.fill(0) | |
@micropython.viper | |
def draw_citys(): | |
screen_ptr = ptr16(LCD.buffer) | |
bitmap_ptr = ptr16(city_sprite) | |
for n in range(3): | |
for y in range(9): | |
for x in range(16): | |
addr = y * 160 + x + 15 + BOTTOM_SCREEN | |
screen_ptr[addr+n*20] = bitmap_ptr[y*16+x] | |
screen_ptr[addr+n*20+72] = bitmap_ptr[y*16+x] | |
for y in range(6): | |
for x in range(14): | |
screen_ptr[y*160+n*72+x+(160*2)+BOTTOM_SCREEN] = 0xff | |
def read_joystick(): | |
global player | |
pot_scale = 13 | |
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 x_inc==0 and y_inc==0: return | |
player[X_POS] -= x_inc | |
player[Y_POS] += y_inc | |
if player[X_POS] < 15: | |
player[X_POS] = 15 | |
if player[X_POS] > MAXSCREEN_X-15: | |
player[X_POS] = MAXSCREEN_X-15 | |
if player[Y_POS] < 15: | |
player[Y_POS] = 15 | |
if player[Y_POS] > MAXSCREEN_Y-15: | |
player[Y_POS] = MAXSCREEN_Y-15 | |
@micropython.viper | |
def button(): | |
global LIVE_ASSETS, SOUND | |
player_ptr = ptr32(player) | |
enemy_ptr = ptr32(enemy) | |
pushed = not FIRE.value() | |
asset_ptr = ptr32(asset) | |
if not pushed: return | |
x = player_ptr[X_POS] | |
y = player_ptr[Y_POS] | |
for i in range(NUM_ASSET): # search through assets to find unused | |
index = ASSET_PARAMS*i | |
if asset_ptr[index+LIFE] == 0: | |
asset_ptr[index+X_POS] = (LAUNCH_CENTER % 160)<<16 | |
asset_ptr[index+Y_POS] = (LAUNCH_CENTER // 160)<<16 | |
asset_ptr[index+CROSS_X] = x<<16 | |
asset_ptr[index+CROSS_Y] = y<<16 | |
# min_distance = MAXSCREEN_X + MAXSCREEN_Y | |
# for j in range(NUM_ENEMY): # search through enemies to | |
# enemy_index = ASSET_PARAMS*j | |
# if enemy_ptr[enemy_index+LIFE] == 0 or enemy_ptr[enemy_index+TARGETED]<99: | |
# continue | |
# #distance = int(abs(x-enemy_ptr[enemy_index+X_POS])+abs(y-enemy_ptr[enemy_index+Y_POS])) | |
# distance = int(distance_asm(x,y,enemy_ptr[enemy_index+X_POS],enemy_ptr[enemy_index+Y_POS])) | |
# if distance<min_distance: | |
# min_distance = distance | |
# closest_enemy = j | |
# if closest_enemy>NUM_ENEMY: return # no enemies left | |
asset_ptr[index+LIFE] = 200*2 | |
init_trail(trail,(LAUNCH_CENTER % 160)<<16,(LAUNCH_CENTER // 160)<<16,x<<16,y<<16,i) | |
SOUND = 2 | |
return | |
@micropython.viper | |
def move_asset(): | |
player_ptr = ptr32(player) | |
enemy_ptr = ptr32(enemy) | |
asset_ptr = ptr32(asset) | |
trail_ptr = ptr8(trail) | |
for i in range(NUM_ASSET): | |
index = ASSET_PARAMS*i | |
if asset_ptr[index+LIFE] == 0 : continue | |
asset_ptr[index+LIFE] -= 2 | |
pos = asset_ptr[index+LIFE] | |
trail_x = trail_ptr[i*400+pos] | |
trail_y = trail_ptr[i*400+pos+1] | |
cross_x = asset_ptr[index+CROSS_X]>>16 | |
cross_y = asset_ptr[index+CROSS_Y]>>16 | |
#print(i,pos,cross_x,trail_x,cross_y,trail_y) | |
if (cross_x == trail_x or cross_x == trail_x-1 or cross_x == trail_x+1) and (cross_y == trail_y or cross_y == trail_y-1 or cross_y == trail_y+1): # trail hits cross | |
asset_ptr[index+LIFE] = 0 | |
start_explode(trail_x,trail_y) | |
@micropython.viper | |
def move_enemy(): | |
global ENEMY_REMAIN | |
enemy_ptr = ptr32(enemy) | |
trail_ptr = ptr8(trail2) | |
for i in range(NUM_ENEMY): | |
index = ENEMY_PARAMS*i | |
if enemy_ptr[index+LIFE] == 0 : continue | |
enemy_ptr[index+LIFE] -= 2 | |
pos = enemy_ptr[index+LIFE] | |
trail_x = trail_ptr[i*400+pos] | |
trail_y = trail_ptr[i*400+pos+1] | |
target_x = enemy_ptr[index+TARGET_X] | |
target_y = enemy_ptr[index+TARGET_Y] | |
if (target_x == trail_x or target_x == trail_x-1 or target_x == trail_x+1) and (target_y == trail_y or target_y == trail_y+1): # trail hits target | |
enemy_ptr[index+LIFE] = 0 | |
start_explode(trail_x,trail_y) | |
ENEMY_REMAIN = int(ENEMY_REMAIN)-1 | |
#print(i,pos,target_x,trail_x,target_y,trail_y) | |
@micropython.viper | |
def init_trail(t,x1:int,y1:int,x2:int,y2:int,index:int): | |
trail_ptr = ptr8(t) | |
x = x1 | |
y = y1 | |
dx = (x2-x1) | |
dy = (y2-y1) | |
dx_a = int(abs(dx)) | |
dy_a = int(abs(dy)) | |
#if (dx>>16)*(dy>>16)==0: return x,y | |
index = (index * 400)+400 | |
if dy_a >= dx_a: | |
if y2 > y1: | |
y_inc = 1<<16 | |
x_inc = dx//(dy>>16) * -1 | |
for y in range(y1,y1+dy_a+(1<<16),1<<16): | |
x -= x_inc | |
index -= 2 | |
trail_ptr[index ] = x>>16 | |
trail_ptr[index+1] = y>>16 | |
else: | |
y_inc = -1<<16 | |
x_inc = dx//(dy>>16) | |
for y in range(y1,y1-dy_a-(0<<16),-1<<16): | |
x -= x_inc | |
index -= 2 | |
trail_ptr[index ] = x>>16 | |
trail_ptr[index+1] = y>>16 | |
else: | |
y_inc = dy//(dx>>16) | |
if x2 > x1: | |
x_inc = 1<<16 | |
for x in range(x1,x2+(0<<16),1<<16): | |
index -= 2 | |
y += y_inc | |
trail_ptr[index ] = x>>16 | |
trail_ptr[index+1] = y>>16 | |
else: | |
x_inc = -1<<16 | |
y_inc = y_inc * -1 | |
for x in range(x1,x2-(0<<16),-1<<16): | |
index -= 2 | |
y += y_inc | |
trail_ptr[index ] = x>>16 | |
trail_ptr[index+1] = y>>16 | |
def core1(): | |
global SOUND,WATCHDOG | |
sleep(.2) | |
while(1): | |
WATCHDOG += 1 | |
if WATCHDOG == 100_000: | |
print('core 0 crash') | |
reset() | |
if SOUND==1: | |
sound_alarm() | |
if SOUND==1: | |
SOUND = 0 | |
if SOUND==2: | |
sound_missile() | |
if SOUND==2: | |
SOUND = 0 | |
@micropython.asm_thumb | |
def distance_asm(r0,r1,r2,r3): # x1,y1,x2,y2 | |
sub(r4,r2,r0) # x2-x1 | |
sub(r5,r3,r1) # y2-y1 | |
mul(r4,r4) # (x2-x1)^2 | |
mul(r5,r5) # (y2-y1)^2 | |
add(r0,r4,r5) # (x2-x1)^2 + (y2-y1)^2 | |
mov(r2,0) # r2 = res | |
cmp(r0,0) # r0 = num | |
bpl(MAIN) | |
mov(r0,0) | |
b(EXIT) | |
label(MAIN) | |
mov(r1,1) # r1 = bit | |
lsl(r1,r1,30) | |
label(FOUR_POWER) | |
cmp(r1,r0) # bit <= num | |
ble(LOOP) | |
asr(r1,r1,2) # bit = bit >> 2 | |
b(FOUR_POWER) | |
label(LOOP) | |
cmp(r1,0) | |
beq(EXIT) # bit == 0 | |
add(r3,r1,r2) # res + bit | |
cmp(r0,r3) # if num >= res + bit | |
blt(ELSE) | |
sub(r0,r0,r3) # num = num - (res + bit) | |
asr(r4,r2,1) # res >> 1 | |
add(r2,r4,r1) # res = (res >> 1) + bit | |
b(IF_DONE) | |
label(ELSE) | |
asr(r2,r2,1) # res = res>>1 | |
label(IF_DONE) | |
asr(r1,r1,2) # bit = bit >> 2 | |
b(LOOP) | |
label(EXIT) | |
cmp(r0,r2) # if num <= res: | |
ble(NO_ROUND) | |
add(r2,r2,1) # res += 1 | |
label(NO_ROUND) | |
mov(r0,r2) | |
def sound_alarm(): | |
volume = 1000 | |
POWER.on() | |
BUZZ.duty_u16(volume) | |
start =1250 | |
end = 1050 | |
for repeats in range(6): | |
for i in range(start,end,-10): | |
BUZZ.duty_u16(volume) | |
BUZZ.freq(i) | |
sleep(.014) | |
POWER.off() | |
def sound_missile(): | |
global SOUND | |
SOUND = 0 | |
volume = 2000 | |
POWER.on() | |
BUZZ.duty_u16(volume) | |
start =1500 | |
end = 500 | |
for i in range(start,end,-1): | |
BUZZ.duty_u16(volume) | |
volume -= 2 | |
BUZZ.freq(i) | |
if SOUND == 2 : | |
POWER.off() | |
return | |
for delay in range(150): | |
pass | |
POWER.off() | |
if __name__=='__main__': | |
FIRE = Pin(22, Pin.IN, Pin.PULL_UP) | |
POWER = Pin(16, machine.Pin.OUT) | |
BUZZ = machine.PWM(Pin(17, machine.Pin.OUT)) | |
pwm = PWM(Pin(13)) | |
pwm.freq(1000) | |
pwm.duty_u16(0x7fff)#max 65535 | |
machine.freq(200_000_000) | |
LCD = LCD_1inch8() | |
machine.mem32[0x40008048] = 1<<11 # enable peri_ctrl clock | |
WATCHDOG = 0 | |
SOUND = 0 | |
ENEMY_REMAIN = 0 | |
_thread.start_new_thread(core1, ()) | |
init_player() | |
init_asset() | |
init_enemy() | |
init_joystick() | |
init_field() | |
init_explode() | |
gc.collect() | |
print(gc.mem_free()) | |
fps = 0 | |
game_counter = 0 | |
move_enemy_ticks = ticks_ms() | |
explode_ticks = ticks_ms() | |
explode_inc = 0 | |
move_asset_ticks = ticks_ms() | |
button_ticks = ticks_ms() | |
joystick_ticks = ticks_ms() | |
while not EXIT: | |
gticks = ticks_us() | |
WATCHDOG = 0 | |
game_counter +=1 | |
if game_counter > 50: game_counter = 0 | |
if ticks_diff(ticks_ms(),move_enemy_ticks) > 100: #100 | |
move_enemy_ticks = ticks_ms() | |
move_enemy() | |
if ticks_diff(ticks_ms(),move_asset_ticks) > 10: | |
move_asset_ticks = ticks_ms() | |
move_asset() | |
if ticks_diff(ticks_ms(),joystick_ticks) > 30: | |
joystick_ticks = ticks_ms() | |
read_joystick() | |
if ticks_diff(ticks_ms(),button_ticks) > 200: | |
button_ticks = ticks_ms() | |
button() | |
if ticks_diff(ticks_ms(),explode_ticks) > 100: | |
explode_ticks = ticks_ms() | |
explode_inc = 1 | |
else: | |
explode_inc = 0 | |
draw_explode(explode_inc) | |
draw_citys() | |
draw(fps) | |
fps = 1_000_000//int(ticks_diff(ticks_us(),gticks)) |
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
# Missile Command game | |
from machine import Pin,SPI,PWM,ADC, Timer, reset, soft_reset | |
import framebuf, gc | |
import time, array, _thread | |
from time import sleep, ticks_us, ticks_diff, ticks_ms | |
from lcd_1_8 import LCD_1inch8 | |
from random import randint | |
from sys import exit | |
MAXSCREEN_X = const(160) | |
MAXSCREEN_Y = const(128) | |
NUM_ENEMY = const(10) # 10 | |
NUM_ASSET = const(10) | |
EXIT = False | |
LIVE_ASSETS = 0 | |
PLAYER_BLINK = const(30) | |
ENEMY_BLINK = const(200) | |
ASSET_BLINK = const(30) | |
BOTTOM_SCREEN = const(160*119) | |
LAUNCH_LEFT = const(160*120+8) | |
LAUNCH_CENTER = const(160*120+80) | |
LAUNCH_RIGHT = const(160*120+150) | |
X_POS = const(0) | |
Y_POS = const(1) | |
SPRITE = const(2) | |
BUTTON = const(3) | |
LIFE = const(3) | |
TARGET_X = const(4) | |
TARGET_Y = const(5) | |
CROSS_X = const(6) | |
CROSS_Y = const(7) | |
TARGET = const(6) | |
X_INC = const(2) | |
Y_INC = const(3) | |
DURATION = const(4) | |
EXP_DIR = const(5) | |
EXP_PARAMS = const(6) | |
ENEMY_PARAMS = const(7) | |
ASSET_PARAMS = const(8) | |
EXP_SIZE = const(15) | |
cursor = array.array('B',( | |
1,0,0,1, | |
0,0,0,0, | |
0,0,0,0, | |
1,0,0,1)) | |
enemy_sprite = array.array('B',( | |
1,1,1,1, | |
1,0,0,1, | |
1,0,0,1, | |
1,1,1,1)) | |
asset_sprite = array.array('B',( | |
0,0,0,0, | |
0,1,1,0, | |
0,1,1,0, | |
0,0,0,0, | |
1,0,0,1, | |
0,1,1,0, | |
0,1,1,0, | |
1,0,0,1)) | |
fire_rgb = array.array('H',(8192 ,8216 ,24616 ,24640 ,41040 ,57440 ,57456 ,8329 ,24729 ,57513 ,8378 ,8386 ,24794 , | |
41178 ,41178 ,57554 ,57554 ,8659 ,25035 ,41419 ,57803 ,8908 ,8900 ,25284 ,41924 ,58300 , | |
58300 ,9405 ,9405 ,26045 ,26037 ,42421 ,42677 ,28110 ,62430 ,30959 ,65535)) | |
city_sprite = array.array('H',(0,0,0,0,0,0,0,0,0,0,0,7936,0,0,0,0,0,0,7936,0,0,0,0,0,0,0,0,7936,0,0,0,0,0,0,7936,7936,0,0,0,0,0,7936,0, | |
7936,0,0,0,0,0,0,7936,7936,0,7936,0,0,65287,7936,7936,7936,7936,0,7936,0,0,7936,7936,7936,7936,7936,7936, | |
0,65287,65287,7936,7936,7936,7936,7936,0,0,7936,65287,7936,7936,65287,7936,65287,65287,65287,7936,7936, | |
65287,7936,7936,0,7936,7936,65287,65287,7936,65287,65287,65287,7936,65287,65287,7936,65287,65287,7936, | |
7936,57599,65287,65287,65287,65287,65287,7936,7936,7936,7936,65287,65287,65287,65287,65287,57599,0,0,0, | |
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, | |
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, | |
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0)) | |
def init_player(): | |
global player, city | |
player = array.array('i',(X_POS,Y_POS,SPRITE,BUTTON)) | |
city = array.array('B',(0,1,1,1,0,1,1,1,0)) | |
player[X_POS] = MAXSCREEN_X>>1 | |
player[Y_POS] = MAXSCREEN_Y>>1 | |
def init_enemy(): | |
global enemy, trail2, ENEMY_REMAIN | |
enemy = array.array('i',()) | |
ENEMY_REMAIN = 0 | |
for i in range(NUM_ENEMY): | |
x1 = randint(5,MAXSCREEN_X-5) | |
y1 = randint(0,10) | |
enemy.append(x1) # XPOS | |
enemy.append(y1) # YPOS | |
enemy.append(enemy[X_POS+i*ENEMY_PARAMS]) # SPRITE | |
enemy.append(400) # LIFE | |
target = randint(0,8) # target city | |
#target = 5 | |
x2 = (target*16)+8 | |
if target > 4: | |
x2 += 12 | |
y2 = 120 | |
enemy.append(x2) # TARGET_X | |
enemy.append(y2) # TARGET_Y | |
enemy.append(target) # TARGET | |
init_trail(trail2,x1<<16,y1<<16,x2<<16,y2<<16,i) | |
ENEMY_REMAIN += 1 | |
def init_asset(): | |
global asset, trail, trail2 | |
asset = array.array('i', 0 for _ in range(NUM_ASSET*ASSET_PARAMS)) | |
trail = array.array('B', 0 for _ in range(NUM_ASSET*402)) | |
trail2 = array.array('B', 0 for _ in range(NUM_ENEMY*402)) | |
def init_joystick(): | |
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 | |
def init_field(): | |
global SOUND | |
LCD.fill(0) | |
LCD.show() | |
SOUND = 1 | |
def init_explode(): | |
global explosion | |
explosion = array.array('i',()) | |
for i in range(0,1000,EXP_PARAMS): | |
explosion.append(X_POS) # X_POS | |
explosion.append(Y_POS) # Y_POS | |
explosion.append(randint(0-(1<<16),1<<16)) # x inc | |
explosion.append(randint(0-(1<<16),1<<16)) # y inc | |
explosion.append(EXP_SIZE+1) # DURATION | |
explosion.append(-1) # EXP_DIR | |
@micropython.viper | |
def start_explode(x:int,y:int): | |
global SOUND | |
exp = ptr32(explosion) | |
for i in range(0,EXP_PARAMS*20,EXP_PARAMS): | |
if exp[i+DURATION] < EXP_SIZE+1: continue | |
explosion[i+X_POS] = x<<16 | |
explosion[i+Y_POS] = y<<16 | |
explosion[i+DURATION] = EXP_SIZE | |
explosion[i+EXP_DIR] = -1 | |
SOUND = 3 | |
return | |
@micropython.viper | |
def draw_explode(explode_inc:int): # circle explosion | |
global ENEMY_REMAIN, SOUND, EXIT | |
screen_ptr = ptr16(LCD.buffer) | |
exp = ptr32(explosion) | |
enemy_ptr = ptr32(enemy) | |
trail_ptr = ptr8(trail2) | |
fire_ptr = ptr16(fire_rgb) | |
max_addr = MAXSCREEN_X * MAXSCREEN_Y | |
finish_exp = 1 | |
for i in range(0,1000,EXP_PARAMS): | |
if exp[i+DURATION] > EXP_SIZE: continue | |
if exp[i+DURATION] == 0 and exp[i+EXP_DIR] == -1: | |
exp[i+EXP_DIR] = 1 | |
exp[i+DURATION] = 1 | |
x0 = exp[i+X_POS]>>16 | |
y0 = exp[i+Y_POS]>>16 | |
radius = 1+EXP_SIZE - (exp[i+DURATION]) | |
if explode_inc == 1 : | |
exp[i+DURATION] += exp[i+EXP_DIR] | |
fill_circle(x0,y0, radius, fire_ptr[37-(radius<<1)]) | |
finish_exp = 0 | |
for j in range(NUM_ENEMY): | |
index = ENEMY_PARAMS*j | |
if enemy_ptr[index+LIFE] == 0 : continue | |
pos = enemy_ptr[index+LIFE] | |
trail_x = trail_ptr[j*400+pos] | |
trail_y = trail_ptr[j*400+pos+1] | |
dx = trail_x - x0 | |
dy = trail_y - y0 | |
dist_squared = dx*dx + dy*dy | |
radius_squared = radius*radius | |
if dist_squared < radius_squared: | |
ENEMY_REMAIN = int(ENEMY_REMAIN)-1 | |
enemy_ptr[index+LIFE] = 0 | |
start_explode(trail_x,trail_y) | |
if int(ENEMY_REMAIN) == 0 and finish_exp == 1: | |
if int(OVER) == 1: | |
EXIT = 1 | |
sleep(1) | |
exit() | |
SOUND = 1 | |
init_enemy() | |
@micropython.viper | |
def fill_circle(x0:int, y0:int, radius:int, color:int): | |
screen_ptr = ptr16(LCD.buffer) | |
max_addr = MAXSCREEN_X * MAXSCREEN_Y | |
# From Adafruit GFX Arduino library | |
y_start = y0 - radius | |
for y2 in range(y_start, y_start+2*radius + 1): | |
addr = y2 * MAXSCREEN_X + x0 | |
if addr > 0 and addr < max_addr: | |
screen_ptr[addr] = color | |
f = 1 - radius | |
ddF_x = 1 | |
ddF_y = -2 * radius | |
x = 0 | |
y = radius | |
while x < y: | |
if f >= 0: | |
y -= 1 | |
ddF_y += 2 | |
f += ddF_y | |
x += 1 | |
ddF_x += 2 | |
f += ddF_x | |
x2 = x0 + x | |
y_start = y0 - y | |
for y2 in range(y_start, y_start+2*y + 1): | |
addr = y2 * MAXSCREEN_X + x2 | |
if addr > 0 and addr < max_addr: | |
screen_ptr[addr] = color | |
x2 = x0 + y | |
y_start = y0 - x | |
for y2 in range(y_start,y_start+ 2*x + 1): | |
addr = y2 * MAXSCREEN_X + x2 | |
if addr > 0 and addr < max_addr: | |
screen_ptr[addr] = color | |
x2 = x0 - x | |
y_start = y0 - y | |
for y2 in range(y_start, y_start+2*y + 1): | |
addr = y2 * MAXSCREEN_X + x2 | |
if addr > 0 and addr < max_addr: | |
screen_ptr[addr] = color | |
x2 = x0 - y | |
y_start = y0 - x | |
for y2 in range(y_start, y_start+2*x + 1): | |
addr = y2 * MAXSCREEN_X + x2 | |
if addr > 0 and addr < max_addr: | |
screen_ptr[addr] = color | |
@micropython.viper | |
def draw(fps:int): | |
screen_ptr = ptr16(LCD.buffer) | |
player_ptr = ptr32(player) | |
enemy_ptr = ptr32(enemy) | |
asset_ptr = ptr32(asset) | |
cursor_ptr = ptr8(cursor) | |
e_sprite_ptr = ptr8(enemy_sprite) | |
a_sprite_ptr = ptr8(asset_sprite) | |
trail_ptr = ptr8(trail) | |
trail2_ptr = ptr8(trail2) | |
size = 4 | |
offset = 0 | |
# ggg_bbbbbrrrrr_ggg | |
red = 0b111_0011111111_001 | |
blue= 0b000_1111100000_000 | |
player_ptr[SPRITE]+=1 | |
if player_ptr[SPRITE] > PLAYER_BLINK: | |
player_ptr[SPRITE] = 0 | |
for y in range(size): | |
for x in range(size): | |
color = cursor_ptr[y*4+x] | |
if (color == 1 and player_ptr[SPRITE]<PLAYER_BLINK>>1) or (color == 0 and player_ptr[SPRITE]>=PLAYER_BLINK>>1): | |
screen_ptr[(y+player_ptr[Y_POS])*MAXSCREEN_X + player_ptr[X_POS]+x] = 0xffff | |
for i in range(NUM_ASSET): # draw player missiles | |
index = ASSET_PARAMS*i | |
index2 = 200*(i)*2 | |
pos = asset_ptr[index+LIFE] # 400 -> 0 | |
if pos == 0: continue | |
for y in range(size): # draw cross | |
for x in range(size): | |
x1 = CROSS_X + ASSET_PARAMS * i | |
y1 = CROSS_Y + ASSET_PARAMS * i | |
color = a_sprite_ptr[y*4+x+16] | |
if color: | |
screen_ptr[(y+(asset_ptr[y1]>>16))*MAXSCREEN_X + (asset_ptr[x1]>>16)+x] = 0xffff | |
for j in range(400,pos-2,-2): | |
x = trail_ptr[index2+j] | |
y = trail_ptr[index2+j+1] | |
addr = y * MAXSCREEN_X + x | |
screen_ptr[addr] = blue | |
screen_ptr[addr] = 0xffff | |
for i in range(NUM_ENEMY): # draw enemy missiles | |
index = ENEMY_PARAMS*i | |
index2 = 200*(i)*2 | |
pos = enemy_ptr[index+LIFE] # 400 -> 0 | |
if pos == 0: continue | |
for j in range(400,pos-2,-2): | |
x = trail2_ptr[index2+j] | |
y = trail2_ptr[index2+j+1] | |
addr = y * MAXSCREEN_X + x | |
screen_ptr[addr] = red | |
screen_ptr[addr] = 0xffff | |
LCD.text(str(fps),0,0,0xff) | |
LCD.text(str(CITYS_REMAIN),0,10,0xff) | |
LCD.show() | |
LCD.fill(0) | |
@micropython.viper | |
def draw_citys(): | |
screen_ptr = ptr16(LCD.buffer) | |
bitmap_ptr = ptr16(city_sprite) | |
city_ptr = ptr8(city) | |
for n in range(3): | |
if city_ptr[n+1] == 0 : continue | |
for y in range(9): | |
for x in range(16): | |
addr = y * 160 + x + 15 + BOTTOM_SCREEN | |
screen_ptr[addr+n*20] = bitmap_ptr[y*16+x] | |
#screen_ptr[addr+n*20+72] = bitmap_ptr[y*16+x] | |
for n in range(3): | |
if city_ptr[n+5] == 0 : continue | |
for y in range(9): | |
for x in range(16): | |
addr = y * 160 + x + 15 + BOTTOM_SCREEN | |
#screen_ptr[addr+n*20] = bitmap_ptr[y*16+x] | |
screen_ptr[addr+n*20+72] = bitmap_ptr[y*16+x] | |
for n in range(3): | |
for y in range(6): | |
for x in range(14): | |
screen_ptr[y*160+n*72+x+(160*2)+BOTTOM_SCREEN] = 0xff | |
def read_joystick(): | |
global player | |
pot_scale = 13 | |
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 x_inc==0 and y_inc==0: return | |
player[X_POS] -= x_inc | |
player[Y_POS] += y_inc | |
if player[X_POS] < 15: | |
player[X_POS] = 15 | |
if player[X_POS] > MAXSCREEN_X-15: | |
player[X_POS] = MAXSCREEN_X-15 | |
if player[Y_POS] < 15: | |
player[Y_POS] = 15 | |
if player[Y_POS] > MAXSCREEN_Y-15: | |
player[Y_POS] = MAXSCREEN_Y-15 | |
@micropython.viper | |
def button(): | |
global LIVE_ASSETS, SOUND | |
player_ptr = ptr32(player) | |
enemy_ptr = ptr32(enemy) | |
pushed = not FIRE.value() | |
asset_ptr = ptr32(asset) | |
if not pushed: return | |
x = player_ptr[X_POS] | |
y = player_ptr[Y_POS] | |
for i in range(NUM_ASSET): # search through assets to find unused | |
index = ASSET_PARAMS*i | |
if asset_ptr[index+LIFE] == 0: | |
dist_left = int(distance_asm(x,y,(LAUNCH_LEFT % 160),(LAUNCH_LEFT // 160))) | |
dist_center = int(distance_asm(x,y,(LAUNCH_CENTER % 160),(LAUNCH_CENTER // 160))) | |
dist_right = int(distance_asm(x,y,(LAUNCH_RIGHT % 160),(LAUNCH_RIGHT // 160))) | |
if dist_left < dist_center and dist_left < dist_right: | |
launch_x = (LAUNCH_LEFT % 160)<<16 | |
launch_y = (LAUNCH_LEFT // 160)<<16 | |
if dist_center <= dist_left and dist_center <= dist_right: | |
launch_x = (LAUNCH_CENTER % 160)<<16 | |
launch_y = (LAUNCH_CENTER // 160)<<16 | |
if dist_right < dist_center and dist_right < dist_left: | |
launch_x = (LAUNCH_RIGHT % 160)<<16 | |
launch_y = (LAUNCH_RIGHT // 160)<<16 | |
asset_ptr[index+X_POS] = launch_x | |
asset_ptr[index+Y_POS] = launch_y | |
asset_ptr[index+CROSS_X] = x<<16 | |
asset_ptr[index+CROSS_Y] = y<<16 | |
asset_ptr[index+LIFE] = 200*2 | |
init_trail(trail,launch_x,launch_y,x<<16,y<<16,i) | |
SOUND = 2 | |
return | |
@micropython.viper | |
def move_asset(): | |
player_ptr = ptr32(player) | |
enemy_ptr = ptr32(enemy) | |
asset_ptr = ptr32(asset) | |
trail_ptr = ptr8(trail) | |
for i in range(NUM_ASSET): | |
index = ASSET_PARAMS*i | |
if asset_ptr[index+LIFE] == 0 : continue | |
asset_ptr[index+LIFE] -= 2 | |
pos = asset_ptr[index+LIFE] | |
trail_x = trail_ptr[i*400+pos] | |
trail_y = trail_ptr[i*400+pos+1] | |
cross_x = asset_ptr[index+CROSS_X]>>16 | |
cross_y = asset_ptr[index+CROSS_Y]>>16 | |
if (cross_x == trail_x or cross_x == trail_x-1 or cross_x == trail_x+1) and (cross_y == trail_y or cross_y == trail_y-1 or cross_y == trail_y+1): # trail hits cross | |
asset_ptr[index+LIFE] = 0 | |
start_explode(trail_x,trail_y) | |
@micropython.viper | |
def move_enemy(): | |
global ENEMY_REMAIN, CITYS_REMAIN, OVER | |
enemy_ptr = ptr32(enemy) | |
trail_ptr = ptr8(trail2) | |
city_ptr = ptr8(city) | |
for i in range(NUM_ENEMY): | |
index = ENEMY_PARAMS*i | |
if enemy_ptr[index+LIFE] == 0 : continue | |
enemy_ptr[index+LIFE] -= 2 | |
pos = enemy_ptr[index+LIFE] | |
trail_x = trail_ptr[i*400+pos] | |
trail_y = trail_ptr[i*400+pos+1] | |
target_x = enemy_ptr[index+TARGET_X] | |
target_y = enemy_ptr[index+TARGET_Y] | |
if (target_x == trail_x or target_x == trail_x-1 or target_x == trail_x+1) and (target_y == trail_y or target_y == trail_y+1): # trail hits target | |
enemy_ptr[index+LIFE] = 0 | |
target_hit = enemy_ptr[index+TARGET] | |
if city_ptr[target_hit] == 1 and ((target_hit > 0 and target_hit < 4) or (target_hit > 4 and target_hit < 8)): | |
CITYS_REMAIN = int(CITYS_REMAIN)-1 | |
city_ptr[target_hit] = 0 | |
start_explode(trail_x,trail_y) | |
ENEMY_REMAIN = int(ENEMY_REMAIN)-1 | |
if int(CITYS_REMAIN) == 0: | |
print('GAME OVER') | |
OVER = 1 | |
@micropython.viper | |
def init_trail(t,x1:int,y1:int,x2:int,y2:int,index:int): | |
trail_ptr = ptr8(t) | |
x = x1 | |
y = y1 | |
dx = (x2-x1) | |
dy = (y2-y1) | |
dx_a = int(abs(dx)) | |
dy_a = int(abs(dy)) | |
#if (dx>>16)*(dy>>16)==0: return x,y | |
index = (index * 400)+400 | |
if dy_a >= dx_a: | |
if y2 > y1: | |
y_inc = 1<<16 | |
x_inc = dx//(dy>>16) * -1 | |
for y in range(y1,y1+dy_a+(1<<16),1<<16): | |
x -= x_inc | |
index -= 2 | |
trail_ptr[index ] = x>>16 | |
trail_ptr[index+1] = y>>16 | |
else: | |
y_inc = -1<<16 | |
x_inc = dx//(dy>>16) | |
for y in range(y1,y1-dy_a-(0<<16),-1<<16): | |
x -= x_inc | |
index -= 2 | |
trail_ptr[index ] = x>>16 | |
trail_ptr[index+1] = y>>16 | |
else: | |
y_inc = dy//(dx>>16) | |
if x2 > x1: | |
x_inc = 1<<16 | |
for x in range(x1,x2+(0<<16),1<<16): | |
index -= 2 | |
y += y_inc | |
trail_ptr[index ] = x>>16 | |
trail_ptr[index+1] = y>>16 | |
else: | |
x_inc = -1<<16 | |
y_inc = y_inc * -1 | |
for x in range(x1,x2-(0<<16),-1<<16): | |
index -= 2 | |
y += y_inc | |
trail_ptr[index ] = x>>16 | |
trail_ptr[index+1] = y>>16 | |
def core1(): | |
global SOUND,WATCHDOG, EXIT | |
sleep(.2) | |
while not EXIT: | |
WATCHDOG += 1 | |
if WATCHDOG == 100_000: | |
print('core 0 crash') | |
reset() | |
if SOUND==1: | |
sound_alarm() | |
if SOUND==1: | |
SOUND = 0 | |
if SOUND==2: | |
sound_missile() | |
if SOUND==2: | |
SOUND = 0 | |
if SOUND==3: | |
sound_explode() | |
if SOUND==3: | |
SOUND = 0 | |
@micropython.asm_thumb | |
def distance_asm(r0,r1,r2,r3): # x1,y1,x2,y2 | |
sub(r4,r2,r0) # x2-x1 | |
sub(r5,r3,r1) # y2-y1 | |
mul(r4,r4) # (x2-x1)^2 | |
mul(r5,r5) # (y2-y1)^2 | |
add(r0,r4,r5) # (x2-x1)^2 + (y2-y1)^2 | |
mov(r2,0) # r2 = res | |
cmp(r0,0) # r0 = num | |
bpl(MAIN) | |
mov(r0,0) | |
b(EXIT) | |
label(MAIN) | |
mov(r1,1) # r1 = bit | |
lsl(r1,r1,30) | |
label(FOUR_POWER) | |
cmp(r1,r0) # bit <= num | |
ble(LOOP) | |
asr(r1,r1,2) # bit = bit >> 2 | |
b(FOUR_POWER) | |
label(LOOP) | |
cmp(r1,0) | |
beq(EXIT) # bit == 0 | |
add(r3,r1,r2) # res + bit | |
cmp(r0,r3) # if num >= res + bit | |
blt(ELSE) | |
sub(r0,r0,r3) # num = num - (res + bit) | |
asr(r4,r2,1) # res >> 1 | |
add(r2,r4,r1) # res = (res >> 1) + bit | |
b(IF_DONE) | |
label(ELSE) | |
asr(r2,r2,1) # res = res>>1 | |
label(IF_DONE) | |
asr(r1,r1,2) # bit = bit >> 2 | |
b(LOOP) | |
label(EXIT) | |
cmp(r0,r2) # if num <= res: | |
ble(NO_ROUND) | |
add(r2,r2,1) # res += 1 | |
label(NO_ROUND) | |
mov(r0,r2) | |
def sound_alarm(): | |
volume = 1000 | |
POWER.on() | |
BUZZ.duty_u16(volume) | |
start =1250 | |
end = 1050 | |
for repeats in range(6): | |
for i in range(start,end,-10): | |
BUZZ.duty_u16(volume) | |
BUZZ.freq(i) | |
sleep(.014) | |
POWER.off() | |
def sound_missile(): | |
global SOUND | |
SOUND = 0 | |
volume = 2000 | |
POWER.on() | |
BUZZ.duty_u16(volume) | |
start =1500 | |
end = 500 | |
for i in range(start,end,-1): | |
BUZZ.duty_u16(volume) | |
volume -= 2 | |
BUZZ.freq(i) | |
if SOUND == 2 : | |
POWER.off() | |
return | |
for delay in range(150): | |
pass | |
POWER.off() | |
def sound_explode(): | |
POWER.on() | |
start =1000 | |
end = 0 | |
BUZZ.freq(50) | |
for i in range(start,end,-10): | |
BUZZ.duty_u16(i) | |
sleep(.001) | |
POWER.off() | |
if __name__=='__main__': | |
FIRE = Pin(22, Pin.IN, Pin.PULL_UP) | |
POWER = Pin(16, machine.Pin.OUT) | |
BUZZ = machine.PWM(Pin(17, machine.Pin.OUT)) | |
pwm = PWM(Pin(13)) | |
pwm.freq(1000) | |
pwm.duty_u16(0x7fff)#max 65535 | |
machine.freq(200_000_000) | |
LCD = LCD_1inch8() | |
machine.mem32[0x40008048] = 1<<11 # enable peri_ctrl clock | |
WATCHDOG = 0 | |
SOUND = 0 | |
ENEMY_REMAIN = 0 | |
CITYS_REMAIN = 6 | |
EXIT = 0 | |
OVER = 0 | |
_thread.start_new_thread(core1, ()) | |
init_player() | |
init_asset() | |
init_enemy() | |
init_joystick() | |
init_field() | |
init_explode() | |
gc.collect() | |
print(gc.mem_free()) | |
fps = 0 | |
move_enemy_ticks = ticks_ms() | |
explode_ticks = ticks_ms() | |
explode_inc = 0 | |
move_asset_ticks = ticks_ms() | |
button_ticks = ticks_ms() | |
joystick_ticks = ticks_ms() | |
while not EXIT: | |
gticks = ticks_us() | |
WATCHDOG = 0 | |
if ticks_diff(ticks_ms(),move_enemy_ticks) > 100: | |
move_enemy_ticks = ticks_ms() | |
move_enemy() | |
if ticks_diff(ticks_ms(),move_asset_ticks) > 5: | |
move_asset_ticks = ticks_ms() | |
move_asset() | |
if ticks_diff(ticks_ms(),joystick_ticks) > 30: | |
joystick_ticks = ticks_ms() | |
read_joystick() | |
if ticks_diff(ticks_ms(),button_ticks) > 200: | |
button_ticks = ticks_ms() | |
button() | |
if ticks_diff(ticks_ms(),explode_ticks) > 100: | |
explode_ticks = ticks_ms() | |
explode_inc = 1 | |
else: | |
explode_inc = 0 | |
draw_citys() | |
draw_explode(explode_inc) | |
draw(fps) | |
fps = 1_000_000//int(ticks_diff(ticks_us(),gticks)) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment