Files
Throot/player.py
Neal Finger 00f03652eb player movement
-input class rough draft
-use of time per frame for x movement
-y speed needed to be halved for some reason
-animation line drawing starts from player then moves outward to prepare for storing more points than can fit on the screen (scrolling up after complete stage)
2023-02-12 12:24:06 -07:00

209 lines
6.1 KiB
Python

import time
import thumby
import math
import random
from collections import namedtuple
from Games.Throot.constants import CONST_FPS
# didplay width 72
# display height 40
class Input:
def move_right(self):
return (
thumby.buttonA.pressed() or
thumby.buttonR.pressed()
)
def move_left(self):
return thumby.buttonL.pressed()
inp = Input()
### classes
class Player:
def __init__(self):
self.prev_x = 0
self.prev_y = 0
self.xsub = float(thumby.display.width / 2)
self.ysub = float(0)
self.x = int(self.xsub)
self.y = int(self.ysub)
self.isdecend = 1
self.input_x = float(0)
self.speed_x_start = 32
self.speed_x_max = 200
self.acc_x_start = 64
self.jerk_x = 128
self.speed_x = self.speed_x_start
self.acc_x = self.acc_x_start
# y speed is constant
self.speed_y = 16
self.anim = PlayerAnimation(self)
self.debugvisible = False
def update_phys(self, tpf, camera: Camera):
# debug visible
if thumby.buttonB.justPressed():
self.debugvisible = not self.debugvisible
# prevoius sub pixel position
self.prev_x = self.xsub
self.prev_y = self.ysub
### x movement
# x input
if inp.move_left() and (not inp.move_right()):
self.input_x = -1
if inp.move_right() and (not inp.move_left()):
self.input_x = 1
if (not inp.move_left()) and (not inp.move_right()):
self.input_x = 0
# acceleration and jerk
self.speed_x += self.acc_x * tpf
self.acc_x += self.jerk_x * tpf
# limit speed
self.speed_x = min(self.speed_x_max, self.speed_x)
# reset speed and acceleration if no input
if (self.input_x == 0) and (self.speed_x != self.speed_x_start):
self.speed_x = self.speed_x_start
self.acc_x = self.acc_x_start
# set x sub pixel position
self.xsub += self.speed_x * tpf * self.input_x
### y movement
# set y sub pixel position
self.ysub += self.speed_y * tpf
### stay in world bounds
self.xsub = max(min(self.xsub, thumby.display.width - 1), 0)
### pixel positions
self.x = int(self.xsub)
self.y = int(self.ysub)
### animation physics
self.anim.update_phys(camera)
def update_draw(self, camera):
# debug render
if self.debugvisible:
pix_x, pix_y = camera.relative_to_camera(self.x, self.y)
thumby.display.setPixel(int(pix_x), int(pix_y), self.isdecend)
return
### animation render
self.anim.update_draw(camera, self.isdecend)
class Camera:
def __init__(self, target):
self.x = int(0)
self.y = int(0)
self.width = thumby.display.width
self.height = thumby.display.height
self.offset = -self.height / 2
self.target = target
def entity_in_camera(self, ent_x, ent_y, ent_width = 0, ent_height = 0) -> bool:
return ent_x + ent_width >= self.x and ent_y + ent_height >= self.y and ent_x < self.x + self.width and ent_y < self.y + self.height
def relative_to_camera(self, global_x, global_y):
return (global_x - self.x, global_y - self.y)
def update_phys(self):
# position player
self.y = self.target.y + self.offset
class PlayerAnimation:
MAX_ROOT_OFFSET = int(2)
MAX_GROW_DISTANCE = int(5)#int(3)
MIN_GROW_DISTANCE = int(1)
Point = namedtuple("Point", ["x", "y"])
def __init__(self, player):
self.player = player
self.root_offset = self.MAX_ROOT_OFFSET
self.grow_distance = self.MAX_GROW_DISTANCE
self.points = []
self.add_point()
def add_point(self):
self.points.append(self.Point(self.player.x, self.player.y))
def update_phys(self, camera):
# exit if distance from player to last root point is less than gorw distance
dist_sqr = (
(self.player.x - self.points[-1].x) ** 2 +
(self.player.y - self.points[-1].y) ** 2
)
if dist_sqr < self.grow_distance ** 2:
return
# set new grow distance
self.grow_distance = random.randint(self.MIN_GROW_DISTANCE, self.MAX_GROW_DISTANCE)
# offset last root point to look random
self.points[-1] = self.Point(
self.points[-1].x + random.randrange(-self.root_offset, self.root_offset),
self.points[-1].y + random.randrange(-self.root_offset, self.root_offset)
)
# new root point created exactly on player
self.add_point()
# remove points in list that would make lines off the camera
for point in self.points[1:]:
if camera.entity_in_camera(point.x, point.y):
break
self.points.pop(0)
def update_draw(self, camera, isdecend=1):
# draw line from first position to next
point_prev = self.points[-1]
for point in self.points[-2::-1]:
x1, y1 = camera.relative_to_camera(point_prev.x, point_prev.y)
x2, y2 = camera.relative_to_camera(point.x, point.y)
point_prev = point
thumby.display.drawLine(
int(x1),
int(y1),
int(x2),
int(y2),
isdecend
)
# for i in range(len(self.points) - 1):
# x1, y1 = camera.relative_to_camera(self.points[i].x, self.points[i].y)
# x2, y2 = camera.relative_to_camera(self.points[i + 1].x, self.points[i + 1].y)
# thumby.display.drawLine(
# int(x1),
# int(y1),
# int(x2),
# int(y2),
# isdecend
# )