|
import math |
|
import collider |
|
|
|
FLYING_ACCEL = (0, 0, 0) |
|
GRAVITY_ACCEL = (0, -32, 0) |
|
|
|
|
|
|
|
FRICTION = ( 20, 20, 20) |
|
|
|
DRAG_FLY = ( 5, 5, 5) |
|
DRAG_JUMP = (1.8, 0, 1.8) |
|
DRAG_FALL = (1.8, 0.4, 1.8) |
|
|
|
class Entity: |
|
def __init__(self, world): |
|
self.world = world |
|
|
|
|
|
|
|
self.jump_height = 1.25 |
|
self.flying = False |
|
|
|
self.position = [0, 80, 0] |
|
self.rotation = [-math.tau / 4, 0] |
|
|
|
self.velocity = [0, 0, 0] |
|
self.accel = [0, 0, 0] |
|
|
|
|
|
|
|
self.width = 0.6 |
|
self.height = 1.8 |
|
|
|
self.collider = collider.Collider() |
|
self.grounded = False |
|
|
|
def update_collider(self): |
|
x, y, z = self.position |
|
|
|
self.collider.x1 = x - self.width / 2 |
|
self.collider.x2 = x + self.width / 2 |
|
|
|
self.collider.y1 = y |
|
self.collider.y2 = y + self.height |
|
|
|
self.collider.z1 = z - self.width / 2 |
|
self.collider.z2 = z + self.width / 2 |
|
|
|
def teleport(self, pos): |
|
self.position = list(pos) |
|
self.velocity = [0, 0, 0] |
|
|
|
def jump(self, height = None): |
|
|
|
|
|
if not self.grounded: |
|
return |
|
|
|
if height is None: |
|
height = self.jump_height |
|
|
|
self.velocity[1] = math.sqrt(-2 * GRAVITY_ACCEL[1] * height) |
|
|
|
@property |
|
def friction(self): |
|
if self.flying: |
|
return DRAG_FLY |
|
|
|
elif self.grounded: |
|
return FRICTION |
|
|
|
elif self.velocity[1] > 0: |
|
return DRAG_JUMP |
|
|
|
return DRAG_FALL |
|
|
|
def update(self, delta_time): |
|
|
|
|
|
self.velocity = [v + a * f * delta_time for v, a, f in zip(self.velocity, self.accel, self.friction)] |
|
self.accel = [0, 0, 0] |
|
|
|
|
|
|
|
self.update_collider() |
|
self.grounded = False |
|
|
|
for _ in range(3): |
|
adjusted_velocity = [v * delta_time for v in self.velocity] |
|
vx, vy, vz = adjusted_velocity |
|
|
|
|
|
|
|
|
|
step_x = 1 if vx > 0 else -1 |
|
step_y = 1 if vy > 0 else -1 |
|
step_z = 1 if vz > 0 else -1 |
|
|
|
steps_xz = int(self.width / 2) |
|
steps_y = int(self.height) |
|
|
|
x, y, z = map(int, self.position) |
|
cx, cy, cz = [int(x + v) for x, v in zip(self.position, adjusted_velocity)] |
|
|
|
potential_collisions = [] |
|
|
|
for i in range(x - step_x * (steps_xz + 1), cx + step_x * (steps_xz + 2), step_x): |
|
for j in range(y - step_y * (steps_y + 2), cy + step_y * (steps_y + 3), step_y): |
|
for k in range(z - step_z * (steps_xz + 1), cz + step_z * (steps_xz + 2), step_z): |
|
pos = (i, j, k) |
|
num = self.world.get_block_number(pos) |
|
|
|
if not num: |
|
continue |
|
|
|
for _collider in self.world.block_types[num].colliders: |
|
entry_time, normal = self.collider.collide(_collider + pos, adjusted_velocity) |
|
|
|
if normal is None: |
|
continue |
|
|
|
potential_collisions.append((entry_time, normal)) |
|
|
|
|
|
|
|
if not potential_collisions: |
|
break |
|
|
|
entry_time, normal = min(potential_collisions, key = lambda x: x[0]) |
|
entry_time -= 0.001 |
|
|
|
if normal[0]: |
|
self.velocity[0] = 0 |
|
self.position[0] += vx * entry_time |
|
|
|
if normal[1]: |
|
self.velocity[1] = 0 |
|
self.position[1] += vy * entry_time |
|
|
|
if normal[2]: |
|
self.velocity[2] = 0 |
|
self.position[2] += vz * entry_time |
|
|
|
if normal[1] == 1: |
|
self.grounded = True |
|
|
|
self.position = [x + v * delta_time for x, v in zip(self.position, self.velocity)] |
|
|
|
|
|
|
|
gravity = FLYING_ACCEL if self.flying else GRAVITY_ACCEL |
|
self.velocity = [v + a * delta_time for v, a in zip(self.velocity, gravity)] |
|
|
|
|
|
|
|
self.velocity = [v - min(v * f * delta_time, v, key = abs) for v, f in zip(self.velocity, self.friction)] |
|
|
|
|
|
|
|
self.update_collider() |