I am once again asking the community. I spend hours on this already. I did endless google searches and videos. Please moderators, don't close this question, because the posts with similar questions are not helping.
import pygame
import math
pygame.init()
win_height=400
win_width=800
win=pygame.display.set_mode((0,0),pygame.FULLSCREEN)
pygame.display.set_caption("game")
white=(255,255,255)
black=(0,0,0)
blue=(0,0,255)
green=(255,169,69)
red=(255,0,0)
base_pos=(20,680)
clock=pygame.time.Clock()
arrows=pygame.sprite.Group()
class Arrow(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.image=pygame.Surface((5,5))
self.image.fill(white)
self.rect=self.image.get_rect()
self.rect.center=base_pos
self.speed=2
self.angle=math.atan2(mouse_pos[1]-base_pos[1],mouse_pos[0]-base_pos[0])
#I did learn the formula for finding the angle between two points in radians here, but I can't
move it properly
self.xv=math.cos(self.angle)*self.speed
self.yv=math.sin(self.angle)*self.speed
def update(self):
self.rect.x+=self.xv
self.rect.y+=self.yv
timer=0
while True:
timer+=0.017
pygame.event.get()
mouse_pos=pygame.mouse.get_pos()
mouse_down=pygame.mouse.get_pressed()
keys=pygame.key.get_pressed()
clock.tick(60)
if keys[pygame.K_ESCAPE]:
pygame.quit()
win.fill(blue)
pygame.draw.rect(win,green,(0,700,2000,2000))
pygame.draw.rect(win,red,(20,680,20,20))
if timer>0.5:
arrow=Arrow()
arrows.add(arrow)
arrows.update()
arrows.draw(win)
pygame.display.update()
I suspect the culprit is the part where I calculate xv and yv. I did this before, and it somehow worked, but it was really weird. I'm getting so many different answers right now with the google searches and my own projects, so I really need someone to explain what the actually correct way is.
pygame.Rect
can just store integral coordinates:
The coordinates for Rect objects are all integers.
In the following code
self.rect.x += self.xv self.rect.y += self.yv
the fractional component of self.xv
and self.yv
is lost because self.rect.x
and self.rect.y
can only store integral values.
You have to do the calculations with floating point accuracy. Add an x
and y
attribute to the class. Increment the attributes in update and synchronize the rect
attribute:
class Arrow(pygame.sprite.Sprite):
def __init__(self):
# [...]
self.xv = math.cos(self.angle)*self.speed
self.yv = math.sin(self.angle)*self.speed
self.x = base_pos[0]
self.y = base_pos[1]
def update(self):
self.x += self.xv
self.y += self.yv
self.rect.center = round(self.x), round(self.y)