5 Commits

Author SHA1 Message Date
William Hubbard
ce1436b1c2 Adds sub-pixel collisions 2023-02-04 22:11:39 -07:00
William Hubbard
6004a54e9f Merge branch 'master' of https://github.com/Markil3/Throot 2023-02-04 20:26:44 -07:00
Neal Finger
c668a68097 Merge pull request #4 from Markil3/game_manager
Game Manager
2023-02-04 20:25:25 -07:00
Neal Finger
7e454cd8e4 Game Manager
merge of game manager,  Gameloop and player animation. Animation is brocken.
2023-02-04 20:24:16 -07:00
William Hubbard
11667a1b92 Adds a score system 2023-02-04 18:56:46 -07:00
5 changed files with 130 additions and 53 deletions

105
Throot.py
View File

@@ -1,20 +1,79 @@
import time
import thumby
import math
import thumby
import Games.Throot.map
import Games.Throot.sprites
from Games.Throot.artrepository import OBSTACLES
from Games.Throot.player import Player
from random import randrange
import thumby
from Games.Throot.artrepository import OBSTACLES
from Games.Throot.player import Player
from Games.Throot.map import ObstacleSlice, OBSTACLE_SLICES
from Games.Throot.sprites import update_entities
from Games.Throot.sprites import Obstacle, update_entities
from Games.Throot.constants import CONST_FPS
class GameLoop:
class GameManager:
EVENT_ROOM_CHANGE = {'start': 0, 'main': 1, 'end': 2, 'next': -1}
def __init__(self, *rooms):
self.rooms = rooms
self.room_index = 0
def start(self):
# Set the FPS (without this call, the default fps is 30)
thumby.display.setFPS(CONST_FPS)
def room_goto(self, index):
if index < 0:
self.room_index = min(self.room_index + 1, len(self.rooms))
else:
self.room_index = index
self.rooms[self.room_index].start()
def restart(self):
self.room_index = 0
def update(self, tpf):
event = self.rooms[self.room_index].update(tpf)
thumby.display.update()
if event:
self.room_goto(self.EVENT_ROOM_CHANGE[event])
class Room:
def start(self):
t0 = time.ticks_ms() # Get time (ms)
thumby.display.fill(0) # Fill canvas to black
def update(self, tpf):
pass
class RoomTitle(Room):
def update(self, tpf):
super().update(tpf)
if thumby.inputPressed():
return 'main'
# draw title sprite
title_text = 'press a to start'
chr_len = 5
x = int(round(thumby.display.width / 2 - (chr_len * len(title_text)) / 2))
y = int(round(thumby.display.height / 2 - chr_len / 2))
buff = 2
w = chr_len * len(title_text) + buff
h = chr_len + buff
thumby.display.drawFilledRectangle(x - buff, y - buff, w, h, 1)
thumby.display.drawText(title_text, x, y, 0)
class GameLoop(Room):
def __init__(self):
self.current_depth = 0
self.diving_velocity = 10
@@ -23,6 +82,8 @@ class GameLoop:
self.entities = set()
self.player = Player()
self.score = 0
def get_obstacle_slice(self):
return OBSTACLE_SLICES[randrange(0, len(OBSTACLE_SLICES))]
@@ -31,11 +92,18 @@ class GameLoop:
"""
Executes one tick of the game
"""
super().update(tpf)
prev_depth = self.current_depth
self.diving_velocity += self.diving_accel * tpf
self.current_depth += self.diving_velocity * tpf
#print("%f (%f)" % (self.current_depth, self.current_depth % ObstacleSlice.height))
if self.current_depth % ObstacleSlice.height < prev_depth % ObstacleSlice.height:
#print("%f -> %f: %f -> %f" % (prev_depth, self.current_depth, prev_depth % ObstacleSlice.height, self.current_depth % ObstacleSlice.height))
if (
self.current_depth > prev_depth and self.current_depth % ObstacleSlice.height < prev_depth % ObstacleSlice.height
or self.current_depth < prev_depth and self.current_depth % ObstacleSlice.height > prev_depth % ObstacleSlice.height
):
self.current_obstacle_slice = self.get_obstacle_slice()
self.player.update_phys(self.current_depth, prev_depth)
@@ -48,27 +116,32 @@ class GameLoop:
for entity in self.entities:
if not entity.update(tpf, self.current_depth, prev_depth):
to_remove.add(entity)
elif entity.intersects_pixel(self.player.xsub, self.player.ysub):
if isinstance(entity, Obstacle):
print("Hit!")
self.entities -= to_remove
self.score = int(self.current_depth * 10)
thumby.display.fill(0)
# Draw the entities
for entity in self.entities:
entity.render(tpf, self.current_depth, prev_depth)
self.player.update_draw(self.current_depth, prev_depth)
thumby.display.drawText(str(self.score), thumby.display.width - (len(str(self.score)) + 2) * 5, 1, 1)
thumby.display.update()
def main():
# Set the FPS (without this call, the default fps is 30)
thumby.display.setFPS(60)
print("Starting game loop")
loop = GameLoop()
def main():
game = GameManager(RoomTitle(), GameLoop())
game.start()
prev_time = 0
while True:
t0 = time.ticks_ms()
tps = (t0 - prev_time) / 1000
loop.update(tps)
#loop.update(tps)
game.update(tps)
prev_time = t0
main()

View File

@@ -4,28 +4,21 @@ SpriteImage = namedtuple("SpriteImage", ["image", "collision", "width", "height"
# BITMAP: width: 8, height: 8
skull = SpriteImage(
bytearray([227,29,102,126,38,222,221,227]),
bytearray([0,28,102,126,38,30,28,0]),
None,
8,
8
)
# BITMAP: width: 8, height: 8
pizza = SpriteImage(
bytearray([127,63,95,111,87,107,125,0]),
bytearray([0,0,64,96,80,104,124,0]),
None,
8,
8
)
# BITMAP: width: 10, height: 10
boulder = SpriteImage(
bytearray([31,175,119,183,107,251,115,7,15,31,3,2,1,0,1,0,0,0,0,2]),
None,
10,
10
)
# BITMAP: width: 10, height: 10
ball = SpriteImage(
bytearray([135,43,85,170,124,254,122,229,123,135,3,3,2,0,1,0,1,2,3,3]),
bytearray([224,80,136,72,148,4,140,248,240,224,0,1,2,3,2,3,3,3,3,1]),
None,
10,
10
@@ -39,28 +32,21 @@ ball = SpriteImage(
)
# BITMAP: width: 10, height: 10
steve = SpriteImage(
bytearray([0,240,252,92,188,188,92,252,240,0,0,1,1,0,0,0,0,1,1,0]),
bytearray([255,1,225,249,185,121,121,185,249,225,1,255,15,8,11,11,8,9,9,8,11,11,8,15]),
None,
10,
10
12,
12
)
# BITMAP: width: 11, height: 8
spaceinv = SpriteImage(
bytearray([143,231,130,73,67,195,67,73,130,231,143]),
None,
11,
8
)
# BITMAP: width: 11, height: 8
spaceinv2 = SpriteImage(
bytearray([248,103,130,201,195,195,195,201,130,103,248]),
bytearray([112,24,125,182,188,60,188,182,125,24,112,7,152,125,54,60,60,60,54,125,152,7]),
None,
11,
8
)
# BITMAP: width: 11, height: 8
mathroot = SpriteImage(
bytearray([255,255,239,207,159,63,1,193,249,249,255]),
bytearray([0,0,16,48,96,192,254,62,6,6,0]),
None,
11,
8
@@ -68,56 +54,68 @@ mathroot = SpriteImage(
#/ = bytearray([255,255,239,239,72,10,192,10,72,239,239])
# BITMAP: width: 11, height: 8
robot = SpriteImage(
bytearray([255,255,239,239,72,10,192,10,72,239,239]),
bytearray([0,16,16,183,245,63,245,183,16,16,0]),
None,
11,
8
)
# BITMAP: width: 11, height: 8
dinoskull = SpriteImage(
bytearray([240,246,246,245,238,237,219,221,235,247,255]),
bytearray([15,9,9,10,17,18,36,34,20,8,0]),
None,
11,
8
)
# BITMAP: width: 11, height: 8
dinojaw = SpriteImage(
bytearray([193,190,190,62,118,242,126,249,87,239,31]),
bytearray([62,65,65,193,137,13,129,6,168,16,224]),
None,
11,
8
)
# BITMAP: width: 11, height: 8
dinospine = SpriteImage(
bytearray([199,187,215,187,199,199,187,215,187,199,255]),
bytearray([56,68,40,68,56,56,68,40,68,56,0]),
None,
11,
8
)
# BITMAP: width: 11, height: 8
bone = SpriteImage(
bytearray([215,171,187,215,215,215,215,215,187,171,215]),
bytearray([40,84,68,40,40,40,40,40,68,84,40]),
None,
11,
8
)
# BITMAP: width: 70, height: 40
bigdinohead = SpriteImage(
bytearray([255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,127,127,127,127,127,127,127,127,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,231,193,157,124,254,118,243,243,225,225,243,159,158,140,253,153,243,247,207,159,63,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,249,250,247,246,244,245,243,245,243,245,243,245,243,245,251,253,254,254,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255]),
bytearray([0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,128,128,128,128,128,128,128,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,24,62,98,131,1,137,12,12,30,30,12,96,97,115,2,102,12,8,48,96,192,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,6,5,8,9,11,10,12,10,12,10,12,10,12,10,4,2,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]),
None,
70,
40
)
# BITMAP: width: 70, height: 40
bigboneddiag = SpriteImage(
bytearray([255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,127,127,63,223,223,63,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,252,251,251,251,247,239,222,189,123,247,239,223,191,127,127,127,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,254,241,239,239,243,251,251,252,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255]),
bytearray([0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,128,128,192,32,32,192,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
3,4,4,4,8,16,33,66,132,8,16,32,64,128,128,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,1,14,16,16,12,4,4,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]),
None,
70,
40
)
# BITMAP: width: 70, height: 40
bigdoritoobstacle = SpriteImage(
bytearray([254,244,253,219,251,247,175,207,223,223,223,191,63,127,127,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,223,255,247,255,255,255,249,255,239,254,254,252,252,249,219,243,183,167,239,207,223,191,63,127,127,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,127,255,127,191,95,191,95,191,87,47,87,47,151,175,155,151,203,215,235,231,235,231,235,231,235,231,235,231,234,246,245,241,243,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,127,127,127,127,127,127,127,127,127,63,191,191,191,250,249,248,253,252,254,254,254,254,255,255,255,255,255,255,255,255,255,255,255,255,127,127,127,127,127,127,127,127,127,127,127,127,191,191,159,223,223,223,223,223,239,239,239,239,239,239,231,231,243,123,251,253,254,254,254,254,255,239,251,255,255,255,255,251,255,253,251,254,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,254,253,253,253,253,253,249,251,251,251,245,243,237,235,229,235,215,203,223,215,203,215,222,219,203,213,203,215,207,215,207,215,223,207,215,207,215,159,151,175,183,171,183,175,183,191,159,55,127]),
bytearray([1,11,2,36,4,8,80,48,32,32,32,64,192,128,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,32,0,8,0,0,0,6,0,16,1,1,3,3,6,36,12,72,88,16,48,32,64,192,128,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,128,0,128,64,160,64,160,64,168,208,168,208,104,80,100,104,52,40,20,24,20,24,20,24,20,24,20,24,21,9,10,14,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,128,128,128,128,128,128,128,128,192,64,64,64,
5,6,7,2,3,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,128,128,128,128,128,128,128,128,128,128,128,128,64,64,96,32,32,32,32,32,16,16,16,16,16,16,24,24,12,132,4,2,1,1,1,1,0,16,4,0,0,0,0,4,0,2,4,1,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,2,2,2,2,2,6,4,4,4,10,12,18,20,26,20,40,52,32,40,52,40,33,36,52,42,52,40,48,40,48,40,32,48,40,48,40,96,104,80,72,84,72,80,72,64,96,200,128]),
None,
70,
40
@@ -131,6 +129,6 @@ leaf = SpriteImage(
)
UNDERGROUND_OBSTACLES = [skull, pizza, boulder, ball, steve, mathroot, robot, dinoskull, dinojaw, dinospine, bone, bigdinohead, bigboneddiag, bigdoritoobstacle]
OVERGROUND_OBSTACLES = [spaceinv, spaceinv2, leaf]
OVERGROUND_OBSTACLES = [spaceinv, leaf]
OBSTACLES = UNDERGROUND_OBSTACLES + OVERGROUND_OBSTACLES

1
constants.py Normal file
View File

@@ -0,0 +1 @@
CONST_FPS = 60

View File

@@ -3,11 +3,12 @@ import thumby
import math
import random
from Games.Throot.constants import CONST_FPS
# didplay width 72
# display height 40
# constants
CONST_FPS = 60
CONST_PL_SCREEN_Y = int((0.5) * thumby.display.height)
CONST_INP_MOVE_LEFT = thumby.buttonL

View File

@@ -33,8 +33,8 @@ class Entity:
return False
if loc_x < self.x or loc_x >= self.x + self.width or loc_y < self.y or loc_y >= self.y + self.height:
return False
rel_x = loc_x - self.x
rel_y = loc_y - self.y
rel_x = int(loc_x - self.x)
rel_y = int(loc_y - self.y)
return bool((self.collision[rel_x] >> (self.height - rel_y)) & 1)
def can_render(self, current_depth: int) -> bool:
@@ -124,14 +124,18 @@ def update_entities(current_slice: ObstacleSlice, current_depth: int, prev_depth
# Local y relative to the top of the slice
slice_y = (current_depth) % ObstacleSlice.height
slice_prev_y = (prev_depth) % ObstacleSlice.height
if slice_prev_y > slice_y:
if prev_depth < current_depth and slice_prev_y > slice_y:
slice_prev_y -= ObstacleSlice.height
elif current_depth < prev_depth and slice_y > slice_prev_y:
slice_prev_y += ObstacleSlice.height
min_y = min(slice_prev_y, slice_y)
max_y = max(slice_prev_y, slice_y)
spawned = set()
for entity in current_slice.obstacle_map:
# The position the entity should spawn at, relative to the slice top
entity_y = entity[1]
if entity_y >= slice_prev_y and entity_y < slice_y:
if entity_y >= min_y and entity_y < max_y:
sprite_image = OBSTACLES[entity[2]]
sprite = thumby.Sprite(sprite_image.width, sprite_image.height, sprite_image.image, 0, 0, 0, entity[3], entity[4])
spawned.add(Obstacle(entity[0], entity_y + current_depth // ObstacleSlice.height * ObstacleSlice.height, sprite_image.width, sprite_image.height, sprite_image.collision, sprite))
spawned.add(Obstacle(entity[0], entity_y + current_depth // ObstacleSlice.height * ObstacleSlice.height, sprite_image.width, sprite_image.height, sprite_image.collision or sprite_image.image, sprite))
return spawned