Skip to content

Instantly share code, notes, and snippets.

@benekastah
Last active February 21, 2023 17:57
Show Gist options
  • Save benekastah/ec703f11b696e158bd11dffbb0cfc33d to your computer and use it in GitHub Desktop.
Save benekastah/ec703f11b696e158bd11dffbb0cfc33d to your computer and use it in GitHub Desktop.
import random
import subprocess, sys, time
FRAME_RATE = 30
def wrap_pos(pos: int, canvas_size: int):
while True:
pos %= canvas_size
yield pos
pos += 1
class GameObject:
image = None
devlogs = []
def __init__(self, position, velocity=None):
self.position = position
self.start_position = position
self.velocity = velocity or (0, 0)
def tick(self, dt, canvas_size):
self.devlogs = []
self.position = (self.start_position[0] + self.velocity[0] * dt, self.start_position[1] + self.velocity[1] * dt)
def wrap_position(self, pos, canvas_size, image_size):
return pos % canvas_size
def positions(self, pos: int, canvas_size: int, image_size: int):
while True:
pos = self.wrap_position(pos, canvas_size, image_size)
yield pos
pos += 1
def draw(self, canvas):
for y_pos, line in zip(self.positions(round(self.position[1]), len(canvas), self.height), self.full_image):
try:
for x_pos, ch in zip(self.positions(round(self.position[0]), len(canvas[y_pos]), self.width), line):
canvas[y_pos][x_pos] = ch
except IndexError:
pass
@property
def full_image(self):
return self.image + self.devlogs
@property
def width(self):
return max(len(l) for l in self.full_image)
@property
def height(self):
return len(self.full_image)
def log(self, msg):
self.devlogs.append(str(msg))
class BounceyBall(GameObject):
dt_offset = 0
def __init__(self, position, velocity=None):
super().__init__(position, velocity)
def wrap_position(self, pos, canvas_size, image_size):
moving_left = int(pos / canvas_size) % 2 == 0
if moving_left:
pos = abs(pos) % canvas_size
else:
pos = canvas_size - (pos % canvas_size)
return pos
def positions(self, pos: int, canvas_size: int, image_size: int):
# width_edge = canvas_size - image_size
# wrapped_pos = self.wrap_position(pos, canvas_size, image_size)
# moving_left = int(pos / canvas_size) % 2 == 0
while True:
pos = self.wrap_position(pos, canvas_size, image_size)
yield pos
pos += 1
class SquattyP(BounceyBall):
image = [
' .:------::. ',
' :--:.. ..:--:. ',
' --: .:::::. :--. ',
' .-: :--:....::--: :=: ',
' :=. :--. ... .--. :=: ',
' .=: :=: .--:::--. :=. -= ',
' := =- :=: :=. -- .=:',
' -= .=: -=. .=: -= .=:',
' -= .=: -=-. :-- .=- :=.',
' -= .=: -=::---:. .-- -- ',
' -= .=: -=. .--: .-- ',
' -= --. -=-------:. :=: ',
' -=--: :=: .--: ',
' -= .-=--::::::---:. ',
' -=::-=-: ...... ',
]
class Cloud(GameObject):
image = [
' _ _',
' ( ` )_',
' ( ) `)',
'(_ (_ . _) _)',
]
def __init__(self, canvas_size, min_velocity=5, max_velocity=10):
position = tuple(
random.uniform(0, d)
for d in canvas_size
)
velocity = [
random.uniform(min_velocity, max_velocity)
for _ in range(2)
]
# let horizontal velocity be bigger than vertical
velocity[1] /= 4
super().__init__(position, velocity)
class Star(GameObject):
stages = ['*', '·', ' ']
last_twinkle = 0
def __init__(self, canvas_size, min_twinkle_rate=.2, max_twinkle_rate=.8):
self.stage = random.choice(range(len(self.stages)))
position = tuple(
random.uniform(0, d)
for d in canvas_size
)
self.twinkle_rate = random.uniform(min_twinkle_rate, max_twinkle_rate)
super().__init__(position)
@property
def image(self):
return [self.stages[self.stage]]
def tick(self, dt, canvas_size):
if (dt - self.last_twinkle) > self.twinkle_rate:
self.last_twinkle = dt
self.stage = (self.stage + 1) % len(self.stages)
def main(height=40, width=100):
canvas_size = (width, height)
objects = [
*(Star(canvas_size) for _ in range(80)),
*(Cloud(canvas_size) for _ in range(3)),
SquattyP((10, 8), (20, 20)),
*(Cloud(canvas_size) for _ in range(2)),
]
start_t = time.time()
while True:
td = time.time() - start_t
canvas = [[' ' for _ in range(width)] for _ in range(height)]
for obj in objects:
obj.draw(canvas)
obj.tick(td, canvas_size)
subprocess.run('clear')
print('\n'.join(''.join(line) for line in canvas))
sys.stdout.flush()
time.sleep(1 / FRAME_RATE)
if __name__ == '__main__':
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment