そこで、pygame で長方形のキャラクターに線形補間を追加することにしました。数日前に lerp を見ましたが、何かが欠けているかどうかわかりません。
問題は、たとえば右に移動するときです。目的の最大速度に到達するための速度補間 - (7) または (左の場合は -7)。キーを放すと、ベロシティは再び最大ベロシティから 0 まで非常に滑らかに補間されます。しかし、右に移動中に左ボタンを押すと、補間が速度 7 から 0 になり、キャラクターが停止します。
編集: これはゲーム全体の一部です。ジャンプやウィンドウ境界との衝突検出などの機能はスキップしました。しかし、このコードはまだ私が望んでいない動きを再現しています。
import pygame
import sys
import math
import datetime
from pygame.locals import *
class Vector(object):
''' Performs vector aritmetics
'''
def __init__(self, x, y):
self.x = x
self.y = y
def add(self, v):
x = self.x + v.x
y = self.y + v.y
return Vector(x, y)
class GroundData(object):
''' Ground data structure.
Creates a ground data structure and her component's.
'''
def __init__(self):
# Vectors
self.position = Vector(0, WINDOWHEIGHT - WINDOWHEIGHT / 3)
self.size = Vector(WINDOWWIDTH, WINDOWHEIGHT-self.position.y)
# Ground data structure
self.color = (128, 128, 128) # Gray
self.rect = pygame.Rect((self.position.x, self.position.y),
(self.size.x, self.size.y))
self.ground = {'shape': self.rect, 'color': self.color}
def draw(self):
''' Draw's the ground shape and color using pygame.draw.rect(...).
'''
pygame.draw.rect(WINDOWSURFACE, self.ground['color'],
self.ground['shape'])
class PlayerData(object):
''' Player data structure.
Creates a player data structure and handles few actions.
'''
def __init__(self):
self.ground = GroundData()
# Vectors
self.size = Vector(50, 70)
self.position = Vector(
15, self.ground.position.y - self.size.y + 1) # + 1 forced collision
self.velocity = Vector(0, 0)
self.velocity_goal = Vector(0, 0)
self.gravity = Vector(0, 3)
# Player data structure
self.color = (0, 100, 0) # Dark Green
self.rect = pygame.Rect((self.position.x, self.position.y),
(self.size.x, self.size.y))
self.player = {'shape': self.rect, 'color': self.color}
def is_colliding_ground(self):
''' Returns true if player shape is colliding with a ground.
'''
if self.position.y + self.size.y >= self.ground.position.y:
return True
return False
def approach(self, vel_goal, vel_curr, dt):
difference = vel_goal - vel_curr
if difference > dt:
return vel_curr + dt
if difference < -dt:
return vel_curr - dt
return vel_goal
def update(self, dt):
self.velocity.x = self.approach(self.velocity_goal.x,
self.velocity.x, dt * 95)
# Update position and velocity
# self.position = self.position.add(self.velocity) * dt
# If I mult (x, y) by dt I get alot slower.
self.position = self.position.add(self.velocity)
self.player['shape'].top = self.position.y
self.player['shape'].left = self.position.x
def draw(self):
''' Draw's the player shape and color using pygame.draw.rect(...).
'''
pygame.draw.rect(WINDOWSURFACE, self.player['color'],
self.player['shape'])
class EventManagement(object):
''' Handles keyboard event's.
Toggles player variables according to the event's.
'''
def __init__(self, player):
self.player = player
def is_doneloop(self, flag):
global is_doneloop
is_doneloop = flag
return is_doneloop
def listen(self):
''' Toggles player variables according to keyboard/mouse input.
'''
for event in pygame.event.get():
if event.type == QUIT:
self.is_doneloop(True)
if event.type == KEYDOWN:
if event.key == ord('a'):
self.player.velocity_goal.x = -7
if event.key == ord('d'):
self.player.velocity_goal.x = 7
if event.type == KEYUP:
if event.key == K_ESCAPE:
self.is_doneloop(True)
if event.key == ord('a'):
self.player.velocity_goal.x = 0
if event.key == ord('d'):
self.player.velocity_goal.x = 0
#-------------------------------------------------------------------------
WINDOWWIDTH = 900
WINDOWHEIGHT = 500
WINDOWSURFACE = pygame.display.set_mode((WINDOWWIDTH, WINDOWHEIGHT), 0, 32)
is_doneloop = False
Clock = pygame.time.Clock()
FPS = 40
def mainloop():
pygame.init()
Ground = GroundData()
Player = PlayerData()
EventHandle = EventManagement(Player)
prev_time = 0
curr_time = datetime.datetime.now()
while not is_doneloop:
# Get deltaT
dt = Clock.tick(FPS)
dt = dt / 1000.0 # Convert milliseconds to seconds
pygame.display.set_caption('FPS: %.2f' % Clock.get_fps())
# Handle events
EventHandle.listen()
# Update game state
Player.update(dt)
# Draw
WINDOWSURFACE.fill((0, 0, 0)) # Black
Ground.draw()
Player.draw()
pygame.display.update()
pygame.quit()
sys.exit()
if __name__ == '__main__':
mainloop()
私の Event クラスの UPDATE 2
class EventManager(object):
''' Event management.
Listens and handles keyboard and mouse events.
'''
def __init__(self, player):
self.player = player
# Player movement flags, according to keyboard/mouse state
self.is_move_left, self.is_move_right = False, False
self.is_jump = False
def exit_game(self):
''' Closes pygame and sys modules.
A break statement follows this method to break the mainloop.
'''
pygame.quit()
sys.exit()
def listener(self):
''' Toggles Player movement flags, according to keyboard/mouse state.
'''
for event in pygame.event.get():
if event.type == QUIT:
self.exit_game()
break
if event.type == KEYDOWN:
if event.key == K_a:
self.is_move_left = True
elif event.key == K_d:
self.is_move_right = True
if event.type == KEYUP:
if event.key == K_ESCAPE:
self.exit_game()
break
if event.key == K_a:
self.is_move_left = False
elif event.key == K_d:
self.is_move_right = False
def handler(self):
''' Set Player velocity_goal according to movement flags.
'''
if self.is_move_left and not self.is_move_right:
self.player.velocity_goal.x = -self.player.MAX_VELOCITY
elif self.is_move_right and not self.is_move_left:
self.player.velocity_goal.x = self.player.MAX_VELOCITY
elif not self.is_move_left and not self.is_move_right:
self.player.velocity_goal.x = 0