Skip to content

Instantly share code, notes, and snippets.

@todbot
Last active August 14, 2021 23:49
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save todbot/92373f93db9da0fca5ca4adee8d7d75b to your computer and use it in GitHub Desktop.
Save todbot/92373f93db9da0fca5ca4adee8d7d75b to your computer and use it in GitHub Desktop.
fake Almost Asteroids, using CircuitPython and displayio.TileGrid()
# 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()
@todbot
Copy link
Author

todbot commented Aug 5, 2021

Needs the following files, converted to 2-color BMP3:
ship-all
roid0-all
roid1-all

@todbot
Copy link
Author

todbot commented Aug 5, 2021

With 120 rotations of the asteroids, they look about as smooth as using rotozoom
roid0-all
roid1-all

@todbot
Copy link
Author

todbot commented Aug 5, 2021

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

@dglaude
Copy link

dglaude commented Aug 14, 2021

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

@todbot
Copy link
Author

todbot commented Aug 14, 2021

Thanks @dglaude!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment