Skip to content

Instantly share code, notes, and snippets.

@NovaSquirrel
Last active April 10, 2022 18:59
Show Gist options
  • Save NovaSquirrel/3d00d3da77c453067308a98890e9faf4 to your computer and use it in GitHub Desktop.
Save NovaSquirrel/3d00d3da77c453067308a98890e9faf4 to your computer and use it in GitHub Desktop.
Thumby platformer
import time
import thumby
import math
import random
thumby.display.setFPS(60)
playerSprite = thumby.Sprite(8, 8, bytearray([126,129,173,225,225,173,129,126]), 0, 0, 0)
levelGfx = bytearray([0,0,0,0,0,0,0,0,255,129,141,177,141,177,129,255,0,0,92,244,94,116,0,0,255,153,159,153,153,249,153,255,255,129,133,213,213,157,129,255,255,129,165,153,153,165,129,255,255,129,129,129,129,129,129,255,255,255,102,102,102,102,255,255,32,80,208,80,80,208,80,32,64,160,160,160,160,160,160,64,15,9,9,9,9,9,9,15,240,144,144,144,144,144,144,240,15,11,13,11,13,11,13,15,240,176,208,176,208,176,208,240])
class Tilemap:
def __init__(self, width, height):
self.data = bytearray(width*height)
self.screenBytes = bytearray(72*6)
self.width = width
self.height = height
def put(self, x, y, value):
self.data[y*self.height+x] = value
def get(self, x, y):
return self.data[y*self.width+x]
def getp(self, x, y):
if x < 0 or y < 0 or x >= self.width*8 or y >= self.height*8:
return 0
return self.data[int(y//8)*self.width+int(x//8)]
@micropython.viper
def draw(self, cameraX : int, cameraY : int):
screen = ptr8(self.screenBytes)
data = ptr8(self.data)
gfx = ptr8(levelGfx)
width = int(self.width)
topleft = cameraX//8 + (cameraY//8*width)
for tileRow in range(6):
write = 72*tileRow
read = data[topleft + tileRow*width]*8
fineX = cameraX & 7
side = 8 - fineX
for col in range(side):
screen[write] = gfx[read + 8 - side + col]
write += 1
for col in range(1,9):
read = data[topleft + tileRow*width + col]*8
screen[write+0] = gfx[read+0]
screen[write+1] = gfx[read+1]
screen[write+2] = gfx[read+2]
screen[write+3] = gfx[read+3]
screen[write+4] = gfx[read+4]
screen[write+5] = gfx[read+5]
screen[write+6] = gfx[read+6]
screen[write+7] = gfx[read+7]
write += 8
side = fineX
if side != 0:
read = data[topleft + tileRow*width + 9]*8
for col in range(side):
screen[write] = gfx[read + col]
write += 1
thumby.display.blit(screen, 0, 0-(cameraY&7), 72, 48, -1, 0, 0)
def solidOnTop(id):
return id != 0
def solidOnBottom(id):
return id != 0
def solidOnLeft(id):
return id != 0
def solidOnRight(id):
return id != 0
level = Tilemap(30, 30)
level.put(1, 0, 1)
level.put(0, 3, 1)
level.put(0, 4, 1)
level.put(1, 4, 1)
level.put(2, 4, 1)
level.put(3, 4, 1)
level.put(4, 4, 1)
level.put(4, 3, 1)
level.put(5, 3, 1)
level.put(6, 3, 1)
level.put(6, 2, 1)
level.put(3, 8, 1)
level.put(4, 8, 1)
level.put(5, 8, 1)
level.put(6, 8, 1)
level.put(7, 7, 1)
level.put(8, 6, 1)
level.put(9, 5, 1)
level.put(10, 4, 1)
level.put(11, 3, 1)
level.put(12, 2, 1)
playerPX = 4
playerPY = 0
playerPYGround = 0
playerVX = 0
playerVY = 0
jumpGracePeriod = 0
playerWantsToJump = 0
lastJumpPress = 0
jumpCanceled = 0
upHeld = 0
downHeld = 0
cameraX = 0
cameraY = 0
exit = False
while not exit:
playerVX = 0
playerOnGround = 0
if jumpGracePeriod:
jumpGracePeriod -= 1
if playerWantsToJump:
playerWantsToJump -= 1
if thumby.buttonL.pressed():
playerVX = -1
if thumby.buttonR.pressed():
playerVX = 1
playerPX += playerVX
if playerVX > 0 and (solidOnLeft(level.getp(playerPX+3, playerPY-7)) or solidOnLeft(level.getp(playerPX+3, playerPY-1))):
playerPX = (int(playerPX) & ~7) + 4
if playerVX < 0 and (solidOnLeft(level.getp(playerPX-4, playerPY-7)) or solidOnLeft(level.getp(playerPX-4, playerPY-1))):
playerPX = (int(playerPX) & ~7) + 4
if thumby.buttonU.pressed():
upHeld += 1
else:
upHeld = 0
if thumby.buttonD.pressed():
downHeld += 1
else:
downHeld = 0
jumpButton = thumby.buttonA.pressed()
if jumpButton and not lastJumpPress:
playerWantsToJump = 3
lastJumpPress = jumpButton
if playerVY < 0 and not jumpCanceled and not jumpButton:
jumpCanceled = 1
playerVY = -0.1
playerVY = min(4, playerVY + 0.1)
playerPY += playerVY
if solidOnBottom(level.getp(playerPX-4, playerPY-7)) or solidOnBottom(level.getp(playerPX+3, playerPY-7)):
playerVY = 0
playerPY = (int(playerPY) & ~7) + 8
if solidOnTop(level.getp(playerPX-4, playerPY)) or solidOnTop(level.getp(playerPX+3, playerPY)):
playerVY = 0
playerPY = int(playerPY) & ~7
playerOnGround = 1
jumpCanceled = 0
playerPYGround = playerPY
jumpGracePeriod = 4
if playerPY > playerPYGround:
playerPYGround = playerPY
if playerWantsToJump and (playerOnGround or jumpGracePeriod):
jumpGradePeriod = 0
playerWantsToJump = 0
playerVY = -2
if playerPY > level.height*8:
playerPX = 4
playerPY = 0
if thumby.buttonB.pressed():
exit = True
# ------------------------------------------
targetCameraX = int(playerPX) - 72//2
targetCameraX = min(max(targetCameraX, 0), level.width*8-72)
targetCameraY = int(playerPYGround) - 60//2
if upHeld > 20:
targetCameraY -= 20
if downHeld > 20:
targetCameraY += 20
targetCameraY = min(max(targetCameraY, 0), level.height*8-40)
cameraX += (targetCameraX-cameraX)/4
cameraY += (targetCameraY-cameraY)/8
cameraPixelX = int(round(cameraX))
cameraPixelY = int(round(cameraY))
level.draw(cameraPixelX, cameraPixelY)
playerSprite.x = round(playerPX) - 4 - cameraPixelX
playerSprite.y = round(playerPY) - 8 - cameraPixelY
thumby.display.drawSprite(playerSprite)
thumby.display.update()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment