How Would I Make an Object Move by Itself?

Viewed 387

For my simulation I am trying to make I need the shapes to have a gravity effect. In other words, when I click the button to create a new shape how would I make it fall down on its own? Any help would be appreciated.

Note: I've only been trying to get the circles to work for now so the other shape's code is behind. I also need to finish collision detection so that is why there is some random stuff for that in there.

main.py:

import pygame
import time
from shapes import *
from inv import *

pygame.init()

width, height = (1000, 800)
screen = pygame.display.set_mode((width, height))
pygame.display.set_caption("Physics Game")
bgc = (223, 255, 252)
screen.fill(bgc)

# Inv Button Variables
iwidth = 100
iheight = 100

# Inventory Classes
icir = InvCir(10, 10, iwidth, iheight)
irect = InvRect(15 + iwidth, 10, iwidth, iheight)
itri = InvTri(20 + (iwidth * 2), 10, iwidth, iheight)

# Object Classes
cir = Circle(40, (97, 160, 255), 500, 300)
rect = Rect(300, 300, 80, 80)

# Shape Lists
cirList = []
rectList = []

def main():
    run = True
    FPS = 60
    clock = pygame.time.Clock()

    def updateScreen():
        icir.draw(screen, (0, 0, 0))
        irect.draw(screen, (0, 0, 0))
        itri.draw(screen, (0, 0, 0))

        pygame.display.update()

    def addList(list, shape):
        list.append(shape)
        print(list)

    while run:
        clock.tick(FPS)

        mpos = pygame.mouse.get_pos()

        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                run = False

            if event.type == pygame.MOUSEBUTTONDOWN:
                if icir.checkClick(mpos):
                    cir.itemDraw(screen)
                    addList(cirList, cir)


            if event.type == pygame.MOUSEBUTTONDOWN:
                if irect.checkClick(mpos):
                    rect.itemDraw(screen)
                    addList(rectList, rect)

        if pygame.mouse.get_pressed()[0]:
                pass

        

        updateScreen()

main()

shapes.py:

import pygame
import os
from inv import *

pygame.init()

bgc = (223, 255, 252)
width, height = (1000, 800)
screen = pygame.display.set_mode((width, height))

# Images
CIRCLE = pygame.image.load(os.path.join("assets", "circle.png"))

def collide(obj1, obj2):
    offsetX = obj2.x - obj1.x
    offsetY = obj2.y - obj1.y
    return obj1.mask.overlap(obj2.mask, (offsetX, offsetY)) != None

class Circle:
    def __init__(self, radius, color, x, y):
        self.radius = radius
        self.color = color
        self.x = x
        self.y = y
        self.img = CIRCLE
        self.mask = pygame.mask.from_surface(self.img)

    def itemDraw(self, window):
        window.blit(self.img, (self.x, self.y))

    def move(self, vel):
        self.y += vel

    def wallCol(self, height, width):
        pass

    def objCol(self, obj):
        return collide(self, obj)

class Rect:
    def __init__(self, x, y, width, height):
        self.x = x
        self.y = y
        self.width = width
        self.height = height
        self.color = (255, 163, 76)

    def itemDraw(self, window):
        pygame.draw.rect(window, self.color, (self.x, self.y, self.width, self.height))

inv.py:

import pygame
import os

pygame.init()

CIRCLE = pygame.image.load(os.path.join("assets", "circ_button.png"))
SQUARE = pygame.image.load(os.path.join("assets", "square_button.png"))
TRIANGLE = pygame.image.load(os.path.join("assets", "tri_button.png"))

class Inv:
    def __init__(self, x, y, width, height):
        self.x = x
        self.y = y
        self.width = width
        self.height = height

class InvCir(Inv):
    def __init__(self, x, y, width, height):
        super().__init__(x, y, width, height)

    def draw(self, window, outline = None):
        if outline:
            pygame.draw.rect(window, outline, (self.x - 2, self.y - 2, self.width + 4, self.height + 4), 0)

        window.blit(CIRCLE, (self.x, self.y))

    def checkClick(self, pos):
        if pos[0] > self.x and pos[0] < self.x + self.width:
            if pos[1] > self.y and pos[1] < self.y + self.height:
                return True

        return False

class InvRect(Inv):
    def __init__(self, x, y, width, height):
        super().__init__(x, y, width, height)

    def draw(self, window, outline = None):
        if outline:
            pygame.draw.rect(window, outline, (self.x - 2, self.y - 2, self.width + 4, self.height + 4), 0)

        window.blit(SQUARE, (self.x, self.y))
    
    def checkClick(self, pos):
        if pos[0] > self.x and pos[0] < self.x + self.width:
            if pos[1] > self.y and pos[1] < self.y + self.height:
                return True

        return False

class InvTri(Inv):
    def __init__(self, x, y, width, height):
        super().__init__(x, y, width, height)

    def draw(self, window, outline = None):
        if outline:
            pygame.draw.rect(window, outline, (self.x - 2, self.y - 2, self.width + 4, self.height + 4), 0)

        window.blit(TRIANGLE, (self.x, self.y))

    def checkClick(self):
        pass
1 Answers

The trick for a bouncing ball is to add gravity. Gravity always accelerates the Y (vertical) speed toward the floor.

  • As the ball falls, speed increases
  • As the ball rises, speed decreases

When the ball hits the ground, the speed is reversed and the ball 'bounces'. When the ball speed reaches zero at the top, gravity will reverse the speed and pull the ball toward the ground.

Here's a simple example of a bouncing ball:

import pygame as pg
from time import sleep, time

pg.init()

Height = Width = 500  # window dimensions

pg.display.set_caption("Bounce") # window title
win = pg.display.set_mode((Height, Width)) # create window

ball = {'x':Width/2, 'y':100, 'xs':3, 'ys':3 } # ball start position and speed
radius = 20  # ball radius

while True:   # main loop
   for event in pg.event.get(): # required for OS events
      if event.type == pg.QUIT:
         pg.quit()
         
   pg.time.Clock().tick(30)  # 30 FPS
   win.fill((255, 255, 255))  # clear screen
   pg.draw.circle(win, (200, 0, 0), (int(ball['x']), int(ball['y'])), 20) # draw ball

   ball['x'] += ball['xs'] # move ball left \ right
   ball['y'] += ball['ys'] # move ball up \ down
   if ball['y'] >= Height - radius: ball['ys'] = -ball['ys']  # bounce on floor
   else: ball['ys'] += .2   # accelerate toward floor, increase speed down, decrease up
   if ball['x'] <= radius or ball['x'] > Width - radius: ball['xs'] = -ball['xs']  # bounce on wall

   pg.display.update()
Related