Habib Ismail
Habib Ismail

Reputation: 47

Pygame Curve Movement Problem How To Fix?

VIDEO < I'm trying to make the white rectangle curve slowly and smoothly towards the red rectangle and then stop but for some reason the white rectangle isn't curving right and its moving way to fast I want it to move smoothly and curve smoothly that the eyes can see and also alawys curve to the red rectangle is there a way i could change up my code and get it to work like that? in my curvemove rect class I have a
self.yspeed = 0.05 self.xspeed = -0.5 self.gravity = -0.01 the x and y speed the rect will move in and the gravity effecting it then on my redraw on the curvemove class this is how my rect is moving if the key V is pressed then it should mave the self.move true after that it should run the code which curves the object

        if keys[pygame.K_v]:
            curve_move1.move = True
        if self.move:
            curve_move1.x += curve_move1.xspeed
            curve_move1.y += curve_move1.yspeed
            curve_move1.yspeed += curve_move1.gravity
            # curve it towards the red rectangle

        else:
            curve_move1.move2 = True
class curvemove:
    def __init__(self,x,y,height,width,color):
        self.x = x
        self.y = y
        self.height = height
        self.width = width
        self.color = color
        self.rect = pygame.Rect(x,y,height,width)
        self.yspeed = 0.05
        self.xspeed = -0.5
        self.gravity = -0.01
        self.move = False
    def draw(self):
        self.rect.topleft = (self.x,self.y)
        pygame.draw.rect(window,self.color,self.rect)
        # -------------- curve_move1 is our curving rectangle
        if keys[pygame.K_v]:
            curve_move1.move = True
        if self.move:
            curve_move1.x += curve_move1.xspeed
            curve_move1.y += curve_move1.yspeed
            curve_move1.yspeed += curve_move1.gravity
            # curve it towards the red rectangle

        else:
            curve_move1.move2 = True

full code its all rectangles so you can test it out

import pygame
pygame.init()


# our window
window = pygame.display.set_mode((500,500))
pygame.display.set_caption("test map")


# our class
class curvemove:
    def __init__(self,x,y,height,width,color):
        self.x = x
        self.y = y
        self.height = height
        self.width = width
        self.color = color
        self.rect = pygame.Rect(x,y,height,width)
        self.yspeed = 0.05
        self.xspeed = -0.5
        self.gravity = -0.01
        self.move = False
    def draw(self):
        self.rect.topleft = (self.x,self.y)
        pygame.draw.rect(window,self.color,self.rect)
        # -------------- curve_move1 is our curving rectangle
        if keys[pygame.K_v]:
            curve_move1.move = True
        if self.move:
            curve_move1.x += curve_move1.xspeed
            curve_move1.y += curve_move1.yspeed
            curve_move1.yspeed += curve_move1.gravity
            # curve it towards the red rectangle

        else:
            curve_move1.move2 = True


white = 255,255,255
red = 205,0,10
curve_move1 = curvemove(250,400,50,50,white)

touched = curvemove(250,200,50,50,red)

# our game fps
fps = 60
clock = pygame.time.Clock()

# d redraw()
def redraw():
    window.fill((0,0,0))
    curve_move1.draw()
    touched.draw()

# our main loop
run = True
while run:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            run = False
    keys = pygame.key.get_pressed()

    if curve_move1.rect.colliderect(touched.rect):
        curve_move1.move = False
        

    redraw()
    pygame.display.update()
pygame.quit()



I want a way to make this rect smooth curve towards the red rectangle not fast but normal this is my best try

Upvotes: 1

Views: 181

Answers (1)

Rabbid76
Rabbid76

Reputation: 210909

The gravitational force must act in the direction of the target.

I recommend to use pygame.math.Vector2 for the calculations. Calculate the direction vector from the object to the target and scale it to the size of the gravitational force. Change the motion vector depending on gravity in each frame:

dir_vec = pygame.math.Vector2(target_pos) - self.rect.center
v_len_sq = dir_vec.length_squared()
if v_len_sq > 0:
    dir_vec.scale_to_length(self.gravity)
    self.speed = (self.speed + dir_vec) * self.friction
    self.pos += self.speed

Minimal example:

import pygame
pygame.init()

class curvemove:
    def __init__(self, x, y, height, width, color):
        self.pos = pygame.math.Vector2(x, y)
        self.color = color
        self.rect = pygame.Rect(x, y, height, width)
        self.speed = pygame.math.Vector2(-5.0, 0)
        self.gravity = 0.5
        self.friction = 0.99
    
    def draw(self):
        self.rect.center = (self.pos.x, self.pos.y)
        pygame.draw.circle(window, self.color, (self.pos.x, self.pos.y), self.rect.width//2)
    
    def update(self, target_pos):
        dir_vec = pygame.math.Vector2(target_pos) - self.rect.center
        v_len_sq = dir_vec.length_squared()
        if v_len_sq > 0:
            dir_vec.scale_to_length(self.gravity)
            self.speed = (self.speed + dir_vec) * self.friction
            self.pos += self.speed

window = pygame.display.set_mode((500,500))
pygame.display.set_caption("test map")
clock = pygame.time.Clock()
white = 255, 255, 255
red = 205, 0, 10
curve_move1 = curvemove(250, 400, 20, 20, white)
touched = curvemove(250, 200, 20, 20, red)
fps = 60
move = False

def redraw():
    window.fill((0,0,0))
    curve_move1.draw()
    touched.draw()

run = True
while run:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            run = False
        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_v:
                move = True
            if event.key == pygame.K_r:
                move = False
                curve_move1 = curvemove(250, 400, 20, 20, white)

    if (curve_move1.pos - touched.pos).length() < 10:
        move = False
    if move:
        curve_move1.update(touched.rect.center)
    redraw()
    pygame.display.update()
    clock.tick(fps)

pygame.quit()
exit()

Play around with the values of speed, gravity and friction to get different effects.

e.g.:

self.speed = pygame.math.Vector2(-10.0, 0)
self.gravity = 1
self.friction = 0.95

e.g.:

self.speed = pygame.math.Vector2(-10.0, 0)
self.gravity = 1
self.friction = 0.91

Upvotes: 1

Related Questions