How to fix flickering drawings in PyGame? Only updating screen once - python

import pygame as pg
from pygame.constants import MOUSEBUTTONDOWN, MOUSEBUTTONUP
import random
pg.init()
WIDTH = 700
HEIGHT = 700
screen = pg.display.set_mode((WIDTH, HEIGHT))
screen.fill("white")
boxIMG = pg.image.load('asteroid.png')
rndCorner = [(0, 0), (0, 700), (700, 0), (700, 700)]
def draw_screen():
obstacle = pg.draw.line(screen, (0, 0, 0), (random.choice(rndCorner)), (200, 200), 2)
def box(x, y):
screen.blit(boxIMG, (x, y))
def game_loop():
running = True
left_clicking = False
boxX = 0
boxY = 0
clock = pg.time.Clock()
while running:
screen.fill("white")
for event in pg.event.get():
if event.type == pg.QUIT:
running = False
pg.quit()
if event.type == MOUSEBUTTONDOWN:
if event.button == 1:
left_clicking = True
if event.type == MOUSEBUTTONUP:
if event.button == 1:
left_clicking = False
if left_clicking:
boxX, boxY = pg.mouse.get_pos()
boxX -= 32.5
boxY -= 32.5
if boxX < 0:
boxX = 0
elif boxX > 635:
boxX = 635
elif boxY < 0:
boxY = 0
elif boxY > 635:
boxY = 635
# Update Screen
draw_screen()
box(boxX, boxY)
pg.display.update()
clock.tick(60)
game_loop()
So I am running into an issue where the lines I drew when calling 'draw_Screen()` are flickering. I tried using doublebuf but that didn't fix the issue for me. If you are wondering what I am trying to achieve, I am trying to move the box (main player) while holding the left click button, hence the 'if left_clicking'

You choose a new random corner coordinate in every frame. This causes the flickering. Pick a random corner once and use the same coordinate in every frame:
random_corner = random.choice(rndCorner)
def draw_screen():
obstacle = pg.draw.line(screen, (0, 0, 0), random_corner, (200, 200), 2)

Related

Pygame slider is not moving on the place I pressed [duplicate]

I want to be able to drag the blue object along the x-axis (black line) using mouse so that it does not move in y-direction. When I try to drag it, nothing happens. Where is the problem?
import pygame
def initialize():
pygame.init()
global height, width
height = 600
width = 900
screen = pygame.display.set_mode((width, height))
screen.fill((255, 255, 255))
pygame.draw.line(screen, (0, 0 ,0), (0, height / 2), (width, height / 2), 3)
return screen
def object():
dragging = False
object_1 = pygame.rect.Rect(width / 4, height / 2 - 75, 50, 150)
if event.type == pygame.MOUSEBUTTONDOWN:
if event.button == 1:
if object_1.collidepoint(event.pos):
dragging = True
mouse_x, mouse_y = event.pos
offset_x = object_1.x - mouse_x
elif event.type == pygame.MOUSEBUTTONUP:
if event.button == 1:
dragging = False
elif event.type == pygame.MOUSEMOTION:
if dragging:
mouse_x, mouse_y = event.pos
object_1.x = mouse_x + offset_x
return object_1
if __name__ == "__main__":
running = True
screen = initialize()
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
object_1 = object()
pygame.draw.rect(screen, (0, 0, 250), object_1)
pygame.display.update()
You have to create the object once before the main application loop and you have to handle the events in the application loop.
Furthermore you have to redraw the entire scene in the application loop. The main application loop has to:
handle the events by either pygame.event.pump() or pygame.event.get().
update the game states and positions of objects dependent on the input events and time (respectively frames)
clear the entire display or draw the background
draw the entire scene (blit all the objects)
update the display by either pygame.display.update() or pygame.display.flip()
Add a function which creates an object:
def create_object():
object_1 = pygame.rect.Rect(width / 4, height / 2 - 75, 50, 150)
return object_1
Create an object before the application loop:
if __name__ == "__main__":
# [...]
object_1 = create_object()
while running:
# [...]
Add a function which can drag an object:
dragging = False
def drag_object(events, object_1):
global dragging, offset_x
for event in events:
if event.type == pygame.MOUSEBUTTONDOWN:
if event.button == 1:
if object_1.collidepoint(event.pos):
dragging = True
mouse_x, mouse_y = event.pos
offset_x = object_1.x - mouse_x
elif event.type == pygame.MOUSEBUTTONUP:
if event.button == 1:
dragging = False
elif event.type == pygame.MOUSEMOTION:
if dragging:
mouse_x, mouse_y = event.pos
object_1.x = mouse_x + offset_x
Get the list of events once in the application loop and pass the events to the function drag_object:
while running:
# [...]
drag_object(events, object_1)
Clear the display, draw the scene and update the display in the application loop:
while running:
# [...]
screen.fill((255, 255, 255))
pygame.draw.line(screen, (0, 0 ,0), (0, height / 2), (width, height / 2), 3)
pygame.draw.rect(screen, (0, 0, 250), object_1)
pygame.display.update()
See the example:
import pygame
def initialize():
pygame.init()
global height, width
height = 600
width = 900
screen = pygame.display.set_mode((width, height))
return screen
def create_object():
object_1 = pygame.rect.Rect(width / 4, height / 2 - 75, 50, 150)
return object_1
dragging = False
def drag_object(events, object_1):
global dragging, offset_x
for event in events:
if event.type == pygame.MOUSEBUTTONDOWN:
if event.button == 1:
if object_1.collidepoint(event.pos):
dragging = True
mouse_x, mouse_y = event.pos
offset_x = object_1.x - mouse_x
elif event.type == pygame.MOUSEBUTTONUP:
if event.button == 1:
dragging = False
elif event.type == pygame.MOUSEMOTION:
if dragging:
mouse_x, mouse_y = event.pos
object_1.x = mouse_x + offset_x
if __name__ == "__main__":
running = True
screen = initialize()
object_1 = create_object()
while running:
events = pygame.event.get()
for event in events:
if event.type == pygame.QUIT:
running = False
drag_object(events, object_1)
screen.fill((255, 255, 255))
pygame.draw.line(screen, (0, 0 ,0), (0, height / 2), (width, height / 2), 3)
pygame.draw.rect(screen, (0, 0, 250), object_1)
pygame.display.update()
Alternatively you can create a class for the object:
import pygame
def initialize():
pygame.init()
global height, width
height = 600
width = 900
screen = pygame.display.set_mode((width, height))
return screen
class MyObject:
def __init__(self):
self.rect = pygame.rect.Rect(width / 4, height / 2 - 75, 50, 150)
self.dragging = False
self.offset_x = 0
def drag(self, events):
for event in events:
if event.type == pygame.MOUSEBUTTONDOWN:
if event.button == 1:
if self.rect.collidepoint(event.pos):
self.dragging = True
self.offset_x = self.rect.x - event.pos[0]
elif event.type == pygame.MOUSEBUTTONUP:
if event.button == 1:
self.dragging = False
elif event.type == pygame.MOUSEMOTION:
if self.dragging:
self.rect.x = event.pos[0] + self.offset_x
def draw(self, surf):
pygame.draw.rect(surf, (0, 0, 250), object_1)
if __name__ == "__main__":
running = True
screen = initialize()
object_1 = MyObject()
while running:
events = pygame.event.get()
for event in events:
if event.type == pygame.QUIT:
running = False
object_1.drag(events)
screen.fill((255, 255, 255))
pygame.draw.line(screen, (0, 0 ,0), (0, height / 2), (width, height / 2), 3)
object_1.draw(screen)
pygame.display.update()

I'm trying to detect the collision between two moving Rects in pygame

So I keep trying to detect two different moving rects in pygame colliding but its just constantly registering a collision. As in the console constantly print lose, but the enemy isn't even touching the ball. The effect I want is just a simple game where the ball has to avoid the tack so that the ball doesn't pop.
import pygame
import sys
import math
import random
pygame.init()
size = width, height = 800, 600
white = 255, 255, 255
red = 255, 0, 0
clock = pygame.time.Clock()
screen = pygame.display.set_mode(size)
character = pygame.image.load("intro_ball.gif")
charrect = character.get_rect()
x = 340
y = 480
enemy = pygame.image.load("ho.png")
enrect = enemy.get_rect()
ex = random.randint(0, 690)
ey = 0
lose = False
while 1:
clock.tick(60)
for event in pygame.event.get():
if event.type == pygame.QUIT: sys.exit()
if ey >= 600 and lose != True:
ey = 0
ex = random.randint(0, 690)
collide = pygame.Rect.colliderect(charrect, enrect)
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_RIGHT and x < 690:
x += 4
if event.key == pygame.K_LEFT and x > 0:
x -= 4
if collide:
lose = True
else: lose = False
if lose == True: print("lose")
ey += 2
screen.fill(white)
screen.blit(enemy, (ex, ey))
screen.blit(character, (x, y))
pygame.display.update()
pygame.Surface.get_rect.get_rect() returns a rectangle with the size of the Surface object, that always starts at (0, 0) since a Surface object has no position. A Surface is blit at a position on the screen. The position of the rectangle can be specified by a keyword argument. For example, the top lelft of the rectangle can be specified with the keyword argument topleft. These keyword argument are applied to the attributes of the pygame.Rect before it is returned (see pygame.Rect for a full list of the keyword arguments):
while 1:
# [...]
charrect = character.get_rect(topleft = (x, y))
enrect = enemy.get_rect(topleft = (ex, ey))
collide = pygame.Rect.colliderect(charrect, enrect)
# [...]
On the other hand you do not need the variables x, y, ex, ey at all. Use the features of the pygame.Rect objects.
Additionally read How can I make a sprite move when key is held down
Minimal example:
import pygame, sys, math, random
pygame.init()
size = width, height = 800, 600
white = 255, 255, 255
red = 255, 0, 0
clock = pygame.time.Clock()
screen = pygame.display.set_mode(size)
#character = pygame.image.load("intro_ball.gif")
character = pygame.Surface((20, 20))
character.fill((0, 255, 0))
charrect = character.get_rect(topleft = (340, 480))
#enemy = pygame.image.load("ho.png")
enemy = pygame.Surface((20, 20))
enemy.fill((255, 0, 0))
enrect = enemy.get_rect(topleft = (random.randint(0, 690), 0))
lose = False
run = True
while run:
clock.tick(60)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
keys = pygame.key.get_pressed()
charrect.x += (keys[pygame.K_RIGHT] - keys[pygame.K_LEFT]) * 4
charrect.clamp_ip(screen.get_rect())
enrect.y += 2
if enrect.y >= 600 and lose != True:
enrect.y = 0
enrect.x = random.randint(0, 690)
collide = pygame.Rect.colliderect(charrect, enrect)
if collide:
lose = True
else:
lose = False
if lose == True:
print("lose")
screen.fill(white)
screen.blit(enemy, enrect)
screen.blit(character, charrect)
pygame.display.update()
pygame.quit()
exit()

Moving scalable rectangle with mouse in pygame

I'm trying to move a rectangle inside of pygame, and making it scalable.
The scalable rectangle code is something like this then I tried to add an event like this:
from pygame imports *
init()
rect1 = (rect1x, rect1y, 300,300)
rect1x = 0
rect1y = 0
while running:
x,y = mouse.get_pos()
if rect1Pressed == True:
rect1x = x
rect1y = y
for evnt in event.get():
if evnt.type == QUIT:
running = False
if evnt.type == MOUSEBUTTONDOWN:
if evnt.button == 1:
if rect1.collidepoint(mouse.get_pos()):
rect1Pressed == True
How would i incorporate the scalable rectangle and being able to make it move with the mouse? So that the window will follow the mouse motion. So it kinda is like a on your laptop where your able to scale the window and also move it around.
You could check which mouse button is pressed in the elif event.type == pg.MOUSEMOTION: block, e.g. if event.buttons[0]:, and then either move or scale the rect depending on the button. To move the rect, just add the event.rel to the rect.x and rect.y attributes.
import pygame as pg
pg.init()
screen = pg.display.set_mode((640, 480))
clock = pg.time.Clock()
rect1 = pg.Rect(100, 100, 161, 100)
rect2 = pg.Rect(300, 200, 161, 100)
selected_rect = None
done = False
while not done:
for event in pg.event.get():
if event.type == pg.QUIT:
done = True
elif event.type == pg.MOUSEBUTTONDOWN:
for rect in (rect1, rect2):
if rect.collidepoint(event.pos):
selected_rect = rect # Select the colliding rect.
elif event.type == pg.MOUSEBUTTONUP:
selected_rect = None # De-select the rect.
elif event.type == pg.MOUSEMOTION:
if selected_rect is not None: # If a rect is selected.
if event.buttons[0]: # Left mouse button is down.
# Move the rect.
selected_rect.x += event.rel[0]
selected_rect.y += event.rel[1]
else: # Right or middle mouse button.
# Scale the rect.
selected_rect.w += event.rel[0]
selected_rect.h += event.rel[1]
selected_rect.w = max(selected_rect.w, 10)
selected_rect.h = max(selected_rect.h, 10)
screen.fill((30, 30, 30))
pg.draw.rect(screen, (0, 100, 250), rect1)
pg.draw.rect(screen, (0, 200, 120), rect2)
pg.display.flip()
clock.tick(30)

How to draw objects that can be dragged and droped on the screen using pygame?

I am trying to draw 5 rectangles all of which I can drag and drop across the screen. I am using pygame. I managed to draw 1 rectangle that I can drag and drop but I can't do it with 5. This is my code:
import pygame
from pygame.locals import *
from random import randint
SCREEN_WIDTH = 1024
SCREEN_HEIGHT = 768
BLACK = ( 0, 0, 0)
WHITE = (255, 255, 255)
RED = (255, 0, 0)
pygame.init()
screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
screen_rect = screen.get_rect()
pygame.display.set_caption("Moving circles")
rectangle = pygame.rect.Rect(20,20, 17, 17)
rectangle_draging = False
clock = pygame.time.Clock()
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
elif event.type == pygame.MOUSEBUTTONDOWN:
if event.button == 1:
if rectangle.collidepoint(event.pos):
rectangle_draging = True
mouse_x, mouse_y = event.pos
offset_x = rectangle.x - mouse_x
offset_y = rectangle.y - mouse_y
elif event.type == pygame.MOUSEBUTTONUP:
if event.button == 1:
rectangle_draging = False
elif event.type == pygame.MOUSEMOTION:
if rectangle_draging:
mouse_x, mouse_y = event.pos
rectangle.x = mouse_x + offset_x
rectangle.y = mouse_y + offset_y
screen.fill(WHITE)
pygame.draw.rect(screen, RED, rectangle)
pygame.display.flip()
clock.tick(FPS)
pygame.quit()
I guess this is the most important part:
pygame.draw.rect(screen, RED, rectangle)
Every time I try drawing 5 of them I can't drag any of them. Does anyone have a solution for this?
You can create a list of rectangles and a selected_rect variable which points to the currently selected rect. In the event loop check if one of the rects collides with the event.pos, then set the selected_rect to the rect under the mouse cursor and move it.
I'm using a pygame.math.Vector2 for the offset to save a few lines in the example.
import sys
import pygame as pg
from pygame.math import Vector2
pg.init()
WHITE = (255, 255, 255)
RED = (255, 0, 0)
screen = pg.display.set_mode((1024, 768))
selected_rect = None # Currently selected rectangle.
rectangles = []
for y in range(5):
rectangles.append(pg.Rect(20, 30*y, 17, 17))
# As a list comprehension.
# rectangles = [pg.Rect(20, 30*y, 17, 17) for y in range(5)]
clock = pg.time.Clock()
running = True
while running:
for event in pg.event.get():
if event.type == pg.QUIT:
running = False
elif event.type == pg.MOUSEBUTTONDOWN:
if event.button == 1:
for rectangle in rectangles:
if rectangle.collidepoint(event.pos):
offset = Vector2(rectangle.topleft) - event.pos
selected_rect = rectangle
elif event.type == pg.MOUSEBUTTONUP:
if event.button == 1:
selected_rect = None
elif event.type == pg.MOUSEMOTION:
if selected_rect:
selected_rect.topleft = event.pos + offset
screen.fill(WHITE)
for rectangle in rectangles:
pg.draw.rect(screen, RED, rectangle)
pg.display.flip()
clock.tick(30)
pg.quit()
sys.exit()

Pygame mouse movement failing

I am working through pygame tutorials and at the moment I am trying to figure out how to select a circle which is firing a ball where a ball hits another ball which in turn knocks a box down. The knocking of the box works fine when the ball hits the box. However, when I add the mouse movement so that I can select the ball again and place it in the same position so that it can be hit again so that the box knocks again. The ball just rolls backwards without firing the second ball to knock the box.Here is the previous code that works with one ball firing another ball but without the mouse movements i.e without allowing the ball to be selected and dragged.
import pygame
from pygame.locals import *
from pygame.color import *
import pymunk as pm
from pymunk import Vec2d
import sys
from random import randint
def to_pygame(p):
"""Small hack to convert pymunk to pygame coordinates"""
return int(p[0]), int(-p[1]+600)
def draw_ball(screen, ball, colour):
r = ball.radius
rot = ball.body.rotation_vector
p = to_pygame(ball.body.position)
p2 = Vec2d(rot.x, -rot.y) * r * 0.9
pygame.draw.line(screen, THECOLORS["red"], p, p+p2)
pygame.draw.circle(screen, colour, p, int(r), 3)
def add_ball(space, x=0, y=130):
mass = 1.3
radius = 20
inertia = pm.moment_for_circle(mass, 0, radius, (0,0))
body = pm.Body(mass, inertia)
body.position = (x,y)
shape = pm.Circle(body, radius, (0,0))
shape.friction = 10.0
shape.elasticity = 1.0
space.add(body, shape)
return shape
def add_box(space, size, pos, mass=0.3):
points = [(-size, -size), (-size, size), (size,size), (size, -size)]
moment = pm.moment_for_poly(int(mass), points, (0,0))
body = pm.Body(mass, moment)
body.position = pos
shape = pm.Poly(body, points, (0,0))
shape.friction = 1
space.add(body,shape)
return shape
def draw_box(screen, box):
ps = box.get_points()
ps.append(ps[0])
newps = [to_pygame(x) for x in ps]
pygame.draw.polygon(screen, THECOLORS["blue"], newps, 3)
def main():
pygame.init()
screen = pygame.display.set_mode((600, 600))
pygame.display.set_caption("Impulsive balls")
clock = pygame.time.Clock()
balls = []
space = pm.Space()
space.gravity = (0.0, -300.0)
# ground
body = pm.Body()
shape = pm.Segment(body, (0,100), (450,100), .0)
shape.friction = 6.0
space.add(shape)
# hidden ramp
body = pm.Body()
slope = pm.Segment(body, (0,100), (180,150), .0)
space.add(slope)
balls.append(add_ball(space, 10, 130))
balls.append(add_ball(space, 100, 150))
#joint = pm.PinJoint(balls[0].body, balls[1].body)
#joint.distance = 90
mass = 1.0
size = 20
box = add_box(space, size, (400,100+size), mass)
count = 0
while 1:
space.step(1/30.0)
clock.tick(30)
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit(0)
elif event.type == KEYDOWN:
if event.key == K_ESCAPE:
pygame.quit()
sys.exit(0)
if count == 10:
pm.Body.apply_impulse(balls[0].body, (450,0))
screen.fill(THECOLORS["white"])
pygame.draw.line(screen, THECOLORS["red"], to_pygame((0,100)), to_pygame((450,100)), 3)
pygame.draw.line(screen, THECOLORS["red"], to_pygame((0,100)), to_pygame((180,150)), 3)
draw_box(screen, box)
for ball in balls:
draw_ball(screen, ball, THECOLORS["green"])
pygame.display.flip()
count += 1
if __name__ == '__main__':
main()
Here is the second version where I add the mouse movement code
import pygame
from pygame.locals import *
from pygame.color import *
import pymunk as pm
from pymunk import Vec2d
import sys
from random import randint
def to_pygame(p):
"""Small hack to convert pymunk to pygame coordinates"""
return int(p[0]), int(-p[1]+600)
def from_pygame(p):
return to_pygame(p)
def draw_ball(screen, ball, colour):
r = ball.radius
rot = ball.body.rotation_vector
p = to_pygame(ball.body.position)
p2 = Vec2d(rot.x, -rot.y) * r * 0.9
pygame.draw.line(screen, THECOLORS["blue"], p, p+p2)
pygame.draw.circle(screen, colour, p, int(r), 3)
def add_ball(space, x=0, y=130):
mass = 1.3 #1.5
radius = 20
inertia = pm.moment_for_circle(mass, 0, radius, (0,0))
body = pm.Body(mass, inertia)
body.position = (x,y)
shape = pm.Circle(body, radius, (0,0))
shape.friction = 10.0
shape.elasticity = 1.0
space.add(body, shape)
return shape
def add_box(space, size, pos, mass=0.3):
points = [(-size, -size), (-size, size), (size,size), (size, -size)]
moment = pm.moment_for_poly(int(mass), points, (0,0))
body = pm.Body(mass, moment)
body.position = pos
shape = pm.Poly(body, points, (0,0))
shape.friction = 1
space.add(body,shape)
return shape
def draw_box(screen, box):
ps = box.get_points()
ps.append(ps[0])
newps = [to_pygame(x) for x in ps]
pygame.draw.polygon(screen, THECOLORS["blue"], newps, 3)
def main():
pygame.init()
screen = pygame.display.set_mode((600, 600))
pygame.display.set_caption("Impulsive balls")
clock = pygame.time.Clock()
body = []
selected = None
balls = []
space = pm.Space()
space.gravity = (0.0, -300.0)
# ground
body = pm.Body()
shape = pm.Segment(body, (0,100), (450,100), .0)
shape.friction = 6.0
space.add(shape)
# hidden ramp
body = pm.Body()
slope = pm.Segment(body, (0,100), (180,150), .0)
space.add(slope)
balls.append(add_ball(space, 10, 130))
balls.append(add_ball(space, 100, 150))
#joint = pm.PinJoint(balls[0].body, balls[1].body)
#joint.distance = 90
mass = 1.0
size = 20
box = add_box(space, size, (400,100+size), mass)
count = 0
while 1:
space.step(1/30.0)
clock.tick(30)
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit(0)
elif event.type == KEYDOWN:
if event.key == K_ESCAPE:
pygame.quit()
sys.exit(0)
if count == 10:
pm.Body.apply_impulse(balls[0].body, (450,0))
if event.key == K_p:
balls[0].body.apply_impulse((450,0))
if event.key == K_s:
balls[0].body.apply_impulse((-450,0))
elif event.type == MOUSEBUTTONDOWN:
p = from_pygame(Vec2d(event.pos))
selected = space.point_query_first(p)
elif event.type == MOUSEBUTTONUP:
if selected != None:
selected = None
elif event.type == MOUSEMOTION:
if selected != None:
selected.body.position = from_pygame(event.pos)
screen.fill(THECOLORS["white"])
pygame.draw.line(screen, THECOLORS["red"], to_pygame((0,100)), to_pygame((450,100)), 3)
pygame.draw.line(screen, THECOLORS["red"], to_pygame((0,100)), to_pygame((180,150)), 3)
draw_box(screen, box)
for ball in balls:
draw_ball(screen, ball, THECOLORS["green"])
pygame.display.flip()
count += 1
if __name__ == '__main__':
main()
Also, how can I have the ball at the same position so that I can drag it and push the other ball to knock the box instead of making the ball roll back, so later I can select the fired ball again and place it next to the ball without rolling back
For your first issue, where the ball is not firing in the second file. The problem is that you have put that code into the event block, which only happens when an external event is fired (like pressing a key). To fix it, that chunk needs to be moved out of that for loop as shown below:
...
while 1:
space.step(1/30.0)
clock.tick(30)
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit(0)
elif event.type == KEYDOWN:
if event.key == K_ESCAPE:
pygame.quit()
sys.exit(0)
if event.key == K_p:
balls[0].body.apply_impulse((450,0))
if event.key == K_s:
balls[0].body.apply_impulse((-450,0))
elif event.type == MOUSEBUTTONDOWN:
p = from_pygame(Vec2d(event.pos))
selected = space.point_query_first(p)
elif event.type == MOUSEBUTTONUP:
if selected != None:
selected = None
elif event.type == MOUSEMOTION:
if selected != None:
selected.body.position = from_pygame(event.pos)
if count == 10:
pm.Body.apply_impulse(balls[0].body, (450,0))
...
To keep the ball from moving, what I would recommend is to place them on flat ground. I've made the following changes to main to show what I mean. Please note that I disabled the ball firing so that you can see that the balls stay in position. I'd also recommend that you put some invisible walls off the screen on to keep all of the objects stuck inside the frame.
...
def main():
pygame.init()
screen = pygame.display.set_mode((600, 600))
pygame.display.set_caption("Impulsive balls")
clock = pygame.time.Clock()
body = []
selected = None
balls = []
space = pm.Space()
space.gravity = (0.0, -300.0)
# ground
body = pm.Body()
shape = pm.Segment(body, (0,100), (450,100), .0)
shape.friction = 6.0
space.add(shape)
# hidden ramp
body = pm.Body()
slope = pm.Segment(body, (20,100), (180,150), .0)
space.add(slope)
body = pm.Body()
slopetop = pm.Segment(body, (180,150), (190,150), .0)
space.add(slopetop)
balls.append(add_ball(space, 10, 130))
balls.append(add_ball(space, 185, 170))
#joint = pm.PinJoint(balls[0].body, balls[1].body)
#joint.distance = 90
mass = 1.0
size = 20
box = add_box(space, size, (400,100+size), mass)
count = 0
while 1:
space.step(1/30.0)
clock.tick(30)
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit(0)
elif event.type == KEYDOWN:
if event.key == K_ESCAPE:
pygame.quit()
sys.exit(0)
if event.key == K_p:
balls[0].body.apply_impulse((450,0))
if event.key == K_s:
balls[0].body.apply_impulse((-450,0))
elif event.type == MOUSEBUTTONDOWN:
p = from_pygame(Vec2d(event.pos))
selected = space.point_query_first(p)
elif event.type == MOUSEBUTTONUP:
if selected != None:
selected = None
elif event.type == MOUSEMOTION:
if selected != None:
selected.body.position = from_pygame(event.pos)
if count == 10 and 0:
pm.Body.apply_impulse(balls[0].body, (450,0))
screen.fill(THECOLORS["white"])
pygame.draw.line(screen, THECOLORS["red"], to_pygame((0,100)), to_pygame((450,100)), 3)
pygame.draw.line(screen, THECOLORS["red"], to_pygame((20,100)), to_pygame((180,150)), 3)
pygame.draw.line(screen, THECOLORS["red"], to_pygame((180,150)), to_pygame((190,150)), 3)
draw_box(screen, box)
for ball in balls:
draw_ball(screen, ball, THECOLORS["green"])
pygame.display.flip()
count += 1
...

Categories

Resources