Reputation: 99
I currently have a game where I want the user to control an orb by dragging their mouse from the orb to an arbitrary position, which the program will respond by moving the orb in the opposite direction. The direction is fine, however, I noticed when using the program the orb moves less in the up-left direction than the down-right direction. I believe this might be due to the gravity slow I've implemented to the orb, however, I can't find exactly where it is causing the problem.
Main.py:
import pygame, sys, orb ...
def run_game():
#Screen settings
-snip-
main_orb = Orb(screen)
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
elif event.type == pygame.MOUSEBUTTONDOWN:
main_orb.reset()
elif event.type == pygame.MOUSEBUTTONUP:
main_orb.release = True
main_orb.calc_vector(mouse_pos)
main_orb.update()
main_orb.release_func(mouse_pos)
main_orb.blitme()
pygame.display.flip()
run_game()
orb.py
import pygame, math ...
class Orb():
def __init__(self,screen):
self.screen = screen
# Get self image&rect and center position
-snip-
# Physics properties
self.velocity = 0
self.acceleration = 0
self.vector = pygame.Vector2(0,-1)
self.g = -30
self.release = False
# Update flag
self.dont_update = False
def reset(self):
self.acceleration = 0
self.velocity = 0
def update(self):
if self.velocity < 0 or self.dont_update == True:
self.acceleration = 0
self.velocity = 0
self.dont_update = True
else:
self.acceleration = self.acceleration + self.g/60/60
self.velocity = self.velocity + self.acceleration
self.rect.x = self.rect.x + self.vector[0] * self.velocity
self.rect.y = self.rect.y + self.vector[1] * self.velocity
def calc_vector(self, mouse_pos):
self.vector = pygame.Vector2(mouse_pos[0] - self.rect.centerx,
mouse_pos[1] - self.rect.centery)
self.vector.rotate_ip(180)
self.vector.normalize_ip()
def release_func(self,mouse_pos):
if self.release == True:
self.acceleration = 2/1000 * math.hypot((self.rect.x-mouse_pos[0]),(self.rect.y-mouse_pos[1]))
self.dont_update = False
self.release = False
def blitme(self):
self.screen.blit(self.image,self.rect)
(P.S.) I know I use a lot of flags, so if there any suggestions of how to refactor the code it will be much appreciated.
Upvotes: 1
Views: 107
Reputation: 210889
The issue is caused, because pygame.Rect
stores integral coordinates:
The coordinates for Rect objects are all integers. [...]
The fraction component of self.vector[0] * self.velocity
and self.vector[1] * self.velocity
is lost when you do:
self.rect.x = self.rect.x + self.vector[0] * self.velocity
self.rect.y = self.rect.y + self.vector[1] * self.velocity
See also Pygame doesn't let me use float for rect.move, but I need it.
You have to do the calculations with floating point accuracy. Add an attribute self.pos
of type pygame.Vector2
to the class:
class Orb():
def __init__(self,screen):
# [...]
self.rect.center = self.screen_rect.center
self.pos = pygame.Vector2(self.rect.center)
Increment the attribute in update
and synchronize the rect
attribute:
class Orb():
# [...]
def update(self):
if self.velocity < 0 or self.dont_update == True:
# [...]
else:
# [...]
self.pos = self.pos + self.vector * self.velocity
self.rect.center = round(self.pos.x), round(self.pos.y)
Complete class Orb
:
class Orb():
def __init__(self,screen):
self.screen = screen
# Get self image&rect and center position
self.image = pygame.image.load('orb.bmp')
self.rect = self.image.get_rect()
self.screen_rect = screen.get_rect()
self.rect.center = self.screen_rect.center
self.pos = pygame.Vector2(self.rect.center)
# physics properties
self.velocity = 0
self.acceleration = 0
self.vector = pygame.Vector2(0,-1)
self.collided = False
self.g = -20
self.release = False
# Update flag
self.dont_update = False
def reset(self):
self.acceleration = 0
self.velocity = 0
def update(self):
if self.velocity < 0 or self.dont_update == True:
self.acceleration = 0
self.velocity = 0
self.dont_update = True
else:
self.acceleration = self.acceleration + self.g/60/60
self.velocity = self.velocity + self.acceleration
print(self.vector)
print(self.velocity)
self.pos = self.pos + self.vector * self.velocity
self.rect.center = round(self.pos.x), round(self.pos.y)
def calc_vector(self, mouse_pos):
self.vector = pygame.Vector2(mouse_pos[0] - self.pos.x, mouse_pos[1] - self.pos.y)
self.vector.rotate_ip(180)
self.vector.normalize_ip()
def blitme(self):
self.screen.blit(self.image,self.rect)
def release_func(self,mouse_pos):
if self.release == True:
self.acceleration = 2/1000 * math.hypot((self.pos.x-mouse_pos[0]),(self.pos.y-mouse_pos[1]))
self.dont_update = False
self.release = False
def collisioncheck(self):
if self.rect.bottom >= self.screen_rect.bottom:
self.collided = True
elif self.rect.top <= self.screen_rect.top:
self.collided = False
elif self.rect.left <= self.screen_rect.left:
self.collided = True
elif self.rect.right >= self.screen_rect.right:
self.collided = True
else:
self.collided = False
Upvotes: 1