Last active
August 14, 2021 23:49
-
-
Save todbot/92373f93db9da0fca5ca4adee8d7d75b to your computer and use it in GitHub Desktop.
fake Almost Asteroids, using CircuitPython and displayio.TileGrid()
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
# staroids_tilegrid_code.py -- fakey Almost Asteroids | |
# 4 Aug 2021 - @todbot | |
import board, time, math, random | |
import displayio, terminalio, bitmaptools | |
import adafruit_imageload | |
import digitalio | |
num_roids = 4 # how many asteroids do you want | |
button_L = digitalio.DigitalInOut(board.BUTTON_UP) # turn left | |
button_L.switch_to_input(pull=digitalio.Pull.DOWN) | |
button_R = digitalio.DigitalInOut(board.BUTTON_DOWN) # turn right | |
button_R.switch_to_input(pull=digitalio.Pull.DOWN) | |
button_F = digitalio.DigitalInOut(board.BUTTON_SELECT) # thrust! | |
button_F.switch_to_input(pull=digitalio.Pull.DOWN) | |
display = board.DISPLAY | |
display.auto_refresh=False | |
screen = displayio.Group() # group that holds everything | |
display.show(screen) # add main group to display | |
# helper object for physics things | |
class Thing: | |
def __init__(self, x,y, vx,vy, angle, va=0, tilegrid=None, num_tiles=1): | |
self.x, self.y = x,y | |
self.vx,self.vy = vx,vy | |
self.angle = angle | |
self.va = va # default angular velocity | |
self.vmax = 2 # maximum velocity | |
self.tg = tilegrid | |
self.num_tiles = num_tiles | |
def accelerate(self,angle, amount): | |
self.vx = min(self.vmax, self.vx + (math.sin(angle) * amount) ) | |
self.vy = min(self.vmax, self.vy - (math.cos(angle) * amount) ) | |
def update_pos(self, alt_sprite_index=0): | |
self.x, self.y = self.x + self.vx, self.y + self.vy | |
self.tg.x = int(self.x) % display.width | |
self.tg.y = int(self.y) % display.height # hmmm not self-contained | |
self.angle += self.va | |
# get a tilegrid index based on angle and number of tiles total | |
i = int(math.degrees(self.angle) / (360 / self.num_tiles)) % self.num_tiles | |
self.tg[0] = i + (alt_sprite_index * self.num_tiles) | |
# get ship sprites | |
num_ship_tiles = 36 | |
ship_sprites,ship_sprites_pal = adafruit_imageload.load('ship-all.bmp') | |
ship_sprites_pal.make_transparent(0) | |
shiptg = displayio.TileGrid(ship_sprites, pixel_shader=ship_sprites_pal, | |
width=1, height=1, tile_width=30, tile_height=30) | |
# get asteroid sprites | |
num_roid_tiles = 120 # tiles per image | |
roid_spr_pal = [] | |
for f in ['roid0-all.bmp','roid1-all.bmp']: | |
spr,pal = adafruit_imageload.load(f) | |
pal.make_transparent(0) | |
roid_spr_pal.append( (spr,pal) ) | |
##get background image, hubble star field | |
bgimg, bgpal = adafruit_imageload.load("bg_starfield.bmp") | |
screen.append(displayio.TileGrid(bgimg, pixel_shader=bgpal)) | |
# create ship object | |
ship = Thing( display.width/2, display.height/2, 0.5, 0.2, 0, va=0, | |
tilegrid=shiptg, num_tiles=num_ship_tiles) | |
# create all the asteroids, add them to the screen | |
roids = [] | |
for i in range(num_roids): | |
vx,vy = random.uniform(-1,1), random.uniform(-1,1) | |
spr,pal = roid_spr_pal[ i % len(roid_spr_pal) ] | |
roidtg = displayio.TileGrid(spr, pixel_shader=pal, | |
width=1, height=1, tile_width=30, tile_height=30) | |
va = random.choice((-0.01,0.01)) # either rotate a little one way or other | |
roid = Thing(display.width/2, display.height/2, vx,vy, 0, va=va, | |
tilegrid=roidtg, num_tiles=num_roid_tiles) | |
roids.append(roid) | |
screen.append(roid.tg) | |
# finally add our ship to the screen | |
screen.append(ship.tg) | |
last_debug_time = 0 | |
while True: | |
# check on the user | |
if button_L.value: # rotate left | |
ship.angle = ship.angle - 0.1 | |
if button_R.value: # rotate right | |
ship.angle = ship.angle + 0.1 | |
if button_F.value: # thrust! | |
ship.accelerate( ship.angle, 0.1) | |
# update ship position | |
ship.update_pos( button_F.value ) | |
# update asteroids | |
for roid in roids: | |
roid.update_pos() | |
display.refresh(target_frames_per_second=60) | |
# time.sleep(0.0015) # sets framerate | |
# debug | |
if time.monotonic() - last_debug_time > 0.2: | |
roid = roids[0] | |
print("roid0:",roid.x,roid.y, roid.vx,roid.vy, roid.angle, roid.tg[0]) | |
last_debug_time = time.monotonic() | |
To create a rotation sprite-sheet, I made a single square image, made several rotated versions, then create a single image from those, and converted it to 2-color BMP for CircuitPython. The entire set of ImageMagick command-line commands look like:
for i in $(seq -w 0 3 359) ; do
echo $i
convert roid0.png -distort SRT $i roid0-r$i.png
done
montage -mode concatenate -tile x1 roid0-r*png roid0-all.png
convert roid0-all.png -colors 2 -type palette BMP3:roid0-all.bmp
To avoid people losing time on the gist version, I suggest to have a look at the github repo: https://github.com/todbot/circuitpython_staroids
Thanks @dglaude!
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Needs the following files, converted to 2-color BMP3:


