Python Pygame and Pymunk game library Non-colliding Shapes - python

In my game I would like to create non-colliding balls. This is the code which creates blue and red balls with right and left click with mouse.. However as you can see balls collide even though I categorized them and mask them as I commented.
import sys
import pygame as pg
from pygame.color import THECOLORS
import pymunk as pm
def to_pygame(p):
"""Small hack to convert pymunk to pygame coordinates"""
return int(p[0]), int(-p[1]+600)
pg.init()
screen = pg.display.set_mode((600, 600))
clock = pg.time.Clock()
space = pm.Space()
space.gravity = (0.0, -900.0)
# Walls
static_body = space.static_body
static_lines = [
pm.Segment(static_body, (111.0, 280.0), (407.0, 246.0), 0.0),
pm.Segment(static_body, (407.0, 246.0), (407.0, 343.0), 0.0),
pm.Segment(static_body, (111.0, 420.0), (407.0, 386.0), 0.0),
pm.Segment(static_body, (407.0, 386.0), (407.0, 493.0), 0.0),
]
for idx, line in enumerate(static_lines):
line.elasticity = 0.95
if idx < 2: # Lower lines.
# The lower lines are in category 2, in binary 0b10.
line.filter = pm.ShapeFilter(categories=2)
else: # Upper lines.
# The upper lines are in category 1, in binary 0b1.
line.filter = pm.ShapeFilter(categories=1)
space.add(static_lines)
balls = []
running = True
while running:
for event in pg.event.get():
if event.type == pg.QUIT:
running = False
elif event.type == pg.KEYDOWN and event.key == pg.K_ESCAPE:
running = False
if event.type == pg.MOUSEBUTTONDOWN:
radius = 15 if event.button == 1 else 30
mass = 10
inertia = pm.moment_for_circle(mass, 0, radius, (0,0))
body = pm.Body(mass, inertia)
body.position = to_pygame(event.pos)
shape = pm.Circle(body, radius, (0,0))
shape.elasticity = 0.95
if shape.radius > 25:
# bin(pm.ShapeFilter.ALL_MASKS ^ 1) is '0b11111111111111111111111111111110'
# That means all categories are checked for collisions except
# bit 1 (the upper lines) which are ignored.
#### HOW EVER BALSS COLLIDE
shape.filter = pm.ShapeFilter(categories=0x1)
shape.filter = pm.ShapeFilter(mask=pm.ShapeFilter.ALL_MASKS ^ 1)
else:
# Ignores category bin(2), '0b11111111111111111111111111111101'
# All categories are checked for collisions except bit 2 (the lower lines).
#### HOW EVER BALSS COLLIDE
shape.filter = pm.ShapeFilter(categories=0x2)
shape.filter = pm.ShapeFilter(mask=pm.ShapeFilter.ALL_MASKS ^ 2)
space.add(body, shape)
balls.append(shape)
screen.fill(THECOLORS["white"])
balls_to_remove = []
for ball in balls:
if ball.body.position.y < 100:
balls_to_remove.append(ball)
p = to_pygame(ball.body.position)
if ball.radius > 25:
color = THECOLORS["red"]
else:
color = THECOLORS["blue"]
pg.draw.circle(screen, color, p, int(ball.radius), 2)
for ball in balls_to_remove:
space.remove(ball, ball.body)
balls.remove(ball)
for line in static_lines:
body = line.body
pv1 = body.position + line.a.rotated(body.angle)
pv2 = body.position + line.b.rotated(body.angle)
p1 = to_pygame(pv1)
p2 = to_pygame(pv2)
pg.draw.lines(screen, THECOLORS["gray29"], False, [p1, p2])
# Update physics.
dt = 1.0/60.0
for x in range(1):
space.step(dt)
pg.display.flip()
clock.tick(50)
pg.quit()
sys.exit()
Balls DONT Collide with walls but themselves. I want non-colliding balls only!
P.S: Example Library shape filter class:
http://www.pymunk.org/en/latest/pymunk.html#pymunk.ShapeFilter

You need to put the balls into their own category and then adjust the masks, so that they don't collide with this category. For example to turn off the collision for the big red balls, you can put them into category 0b100:
shape.filter = pm.ShapeFilter(categories=0b100, mask=pm.ShapeFilter.ALL_MASKS ^ 0b100)
The mask=pm.ShapeFilter.ALL_MASKS ^ 0b100 argument means objects in this category should be ignored.

Related

How to rotate pymunk joints at will?

I'm trying to create a walking spider like this:
I considered using a SimpleMotor at the pink and red joints and control them using the rate function. But when I tried, I get an error that the function is not callable.
self.motorJoint1.rate(0.0) TypeError: 'float' object is not callable
I don't see any other functions in the pymunk API that allow controlling the joints at will. Is there really no function or am I missing something?
Basically in the run loop I want to specify rotations to the joints at certain points of time, to not just make the spider walk, but to eventually be able to use Neural Networks to allow it to experiment with various configurations of leg positions and figure out which ones can make it walk:
angle1 = 30
angle2 = 10
redJoint1.rotate(angle1)
pinkJoint2.rotate(angle2)
if angle1 < 50:
angle1 = angle1 + 1
Is it possible at all to achieve such a level of control over joints using Pymunk? To be able to stop moving the legs (without needing to put the body to sleep), or to rotate the leg joints to whatever angle the spider 'wishes to' at any point in time?
Sample code would be a great help.
From the servo example I took a hint and implemented this basic leg:
import sys
import pygame
from pygame.locals import USEREVENT, QUIT, KEYDOWN, KEYUP, K_s, K_r, K_q, K_ESCAPE, K_UP, K_DOWN, K_RIGHT, K_LEFT
from pygame.color import THECOLORS
import pymunk
from pymunk import Vec2d
import pymunk.pygame_util
class Simulator(object):
def __init__(self):
self.display_flags = 0
self.display_size = (600, 600)
self.space = pymunk.Space()
self.space.gravity = (0.0, -1900.0)
#self.space.damping = 0.999 # to prevent it from blowing up.
# Pymunk physics coordinates start from the lower right-hand corner of the screen.
self.ground_y = 100
ground = pymunk.Segment(self.space.static_body, (5, self.ground_y), (595, self.ground_y), 1.0)
ground.friction = 1.0
self.space.add(ground)
self.screen = None
self.draw_options = None
def reset_bodies(self):
for body in self.space.bodies:
if not hasattr(body, 'start_position'):
continue
body.position = Vec2d(body.start_position)
body.force = 0, 0
body.torque = 0
body.velocity = 0, 0
body.angular_velocity = 0
body.angle = body.start_angle
def draw(self):
self.screen.fill(THECOLORS["white"])### Clear the screen
self.space.debug_draw(self.draw_options)### Draw space
pygame.display.flip()### All done, lets flip the display
def main(self):
pygame.init()
self.screen = pygame.display.set_mode(self.display_size, self.display_flags)
width, height = self.screen.get_size()
self.draw_options = pymunk.pygame_util.DrawOptions(self.screen)
def to_pygame(p):
return int(p.x), int(-p.y+height) #Small hack to convert pymunk to pygame coordinates
def from_pygame(p):
return to_pygame(p)
clock = pygame.time.Clock()
running = True
font = pygame.font.Font(None, 16)
# Create the spider
chassisXY = Vec2d(self.display_size[0]/2, self.ground_y+100)
chWd = 70; chHt = 50
chassisMass = 10
legWd_a = 50; legHt_a = 5
legWd_b = 100; legHt_b = 5
legMass = 1
relativeAnguVel = 0
#---chassis
chassis_b = pymunk.Body(chassisMass, pymunk.moment_for_box(chassisMass, (chWd, chHt)))
chassis_b.position = chassisXY
chassis_shape = pymunk.Poly.create_box(chassis_b, (chWd, chHt))
chassis_shape.color = 200, 200, 200, 100
print("chassis position");print(chassis_b.position)
#---first left leg a
leftLeg_1a_body = pymunk.Body(legMass, pymunk.moment_for_box(legMass, (legWd_a, legHt_a)))
leftLeg_1a_body.position = chassisXY - ((chWd/2)+(legWd_a/2), 0)
leftLeg_1a_shape = pymunk.Poly.create_box(leftLeg_1a_body, (legWd_a, legHt_a))
leftLeg_1a_shape.color = 255, 0, 0, 100
#---first left leg b
leftLeg_1b_body = pymunk.Body(legMass, pymunk.moment_for_box(legMass, (legWd_b, legHt_b)))
leftLeg_1b_body.position = leftLeg_1a_body.position - ((legWd_a/2)+(legWd_b/2), 0)
leftLeg_1b_shape = pymunk.Poly.create_box(leftLeg_1b_body, (legWd_b, legHt_b))
leftLeg_1b_shape.color = 0, 255, 0, 100
#---first right leg a
rightLeg_1a_body = pymunk.Body(legMass, pymunk.moment_for_box(legMass, (legWd_a, legHt_a)))
rightLeg_1a_body.position = chassisXY + ((chWd/2)+(legWd_a/2), 0)
rightLeg_1a_shape = pymunk.Poly.create_box(rightLeg_1a_body, (legWd_a, legHt_a))
rightLeg_1a_shape.color = 255, 0, 0, 100
#---first right leg b
rightLeg_1b_body = pymunk.Body(legMass, pymunk.moment_for_box(legMass, (legWd_b, legHt_b)))
rightLeg_1b_body.position = rightLeg_1a_body.position + ((legWd_a/2)+(legWd_b/2), 0)
rightLeg_1b_shape = pymunk.Poly.create_box(rightLeg_1b_body, (legWd_b, legHt_b))
rightLeg_1b_shape.color = 0, 255, 0, 100
#---link left leg b with left leg a
pj_ba1left = pymunk.PinJoint(leftLeg_1b_body, leftLeg_1a_body, (legWd_b/2,0), (-legWd_a/2,0))#anchor point coordinates are wrt the body; not the space
motor_ba1Left = pymunk.SimpleMotor(leftLeg_1b_body, leftLeg_1a_body, relativeAnguVel)
#---link left leg a with chassis
pj_ac1left = pymunk.PinJoint(leftLeg_1a_body, chassis_b, (legWd_a/2,0), (-chWd/2, 0))
motor_ac1Left = pymunk.SimpleMotor(leftLeg_1a_body, chassis_b, relativeAnguVel)
#---link right leg b with right leg a
pj_ba1Right = pymunk.PinJoint(rightLeg_1b_body, rightLeg_1a_body, (-legWd_b/2,0), (legWd_a/2,0))#anchor point coordinates are wrt the body; not the space
motor_ba1Right = pymunk.SimpleMotor(rightLeg_1b_body, rightLeg_1a_body, relativeAnguVel)
#---link right leg a with chassis
pj_ac1Right = pymunk.PinJoint(rightLeg_1a_body, chassis_b, (-legWd_a/2,0), (chWd/2, 0))
motor_ac1Right = pymunk.SimpleMotor(rightLeg_1a_body, chassis_b, relativeAnguVel)
self.space.add(chassis_b, chassis_shape)
self.space.add(leftLeg_1a_body, leftLeg_1a_shape, rightLeg_1a_body, rightLeg_1a_shape)
self.space.add(leftLeg_1b_body, leftLeg_1b_shape, rightLeg_1b_body, rightLeg_1b_shape)
self.space.add(pj_ba1left, motor_ba1Left, pj_ac1left, motor_ac1Left)
self.space.add(pj_ba1Right, motor_ba1Right, pj_ac1Right, motor_ac1Right)
#---prevent collisions with ShapeFilter
shape_filter = pymunk.ShapeFilter(group=1)
chassis_shape.filter = shape_filter
leftLeg_1a_shape.filter = shape_filter
rightLeg_1a_shape.filter = shape_filter
leftLeg_1b_shape.filter = shape_filter
rightLeg_1b_shape.filter = shape_filter
simulate = False
rotationRate = 2
while running:
for event in pygame.event.get():
if event.type == QUIT or (event.type == KEYDOWN and event.key in (K_q, K_ESCAPE)):
#running = False
sys.exit(0)
elif event.type == KEYDOWN and event.key == K_s:
# Start/stop simulation.
simulate = not simulate
elif event.type == KEYDOWN and event.key == K_r:
# Reset.
# simulate = False
self.reset_bodies()
elif event.type == KEYDOWN and event.key == K_UP:
motor_ba1Left.rate = rotationRate
elif event.type == KEYDOWN and event.key == K_DOWN:
motor_ba1Left.rate = -rotationRate
elif event.type == KEYDOWN and event.key == K_LEFT:
motor_ac1Left.rate = rotationRate
elif event.type == KEYDOWN and event.key == K_RIGHT:
motor_ac1Left.rate = -rotationRate
elif event.type == KEYUP:
motor_ba1Left.rate = 0
motor_ac1Left.rate = 0
self.draw()
### Update physics
fps = 50
iterations = 25
dt = 1.0/float(fps)/float(iterations)
if simulate:
for x in range(iterations): # 10 iterations to get a more stable simulation
self.space.step(dt)
pygame.display.flip()
clock.tick(fps)
if __name__ == '__main__':
sim = Simulator()
sim.main()
It can be controlled with the up, left, right and down arrow keys after first pressing the s key to start the simulation. I've also made sure the variables are created properly linked with each other and named well.
The part about making the joints move to a desired angle is yet to be implemented, but perhaps that could be calculated by taking the x,y positions of the ends of the joints and using a formula to calculate the angle and then move the motor until it reaches a desired angle.
If there's a better way, do let me know by posting an answer or editing this one.

Non colliding objects which has Colliding Pairs, Pymunk Pygame

I would like to implement a code which has non colliding pairs with colliding objects. My pairs are 2 balls which are connected to each other. I want those 2 pair ball to collide. However I don't want those 2 balls to collide with other pairs.
How can I implement a mask with this much of categories in pymunk ShapeFilter? Should I use bitwise operators? As you can see in my shape filter I tried to ignore values which is out of their category except their pairwise catergory, BUT it doesnt work for 4 + number of balls?
My code cannot handle those states of balls with each other.
import pygame
from pygame.locals import *
from pygame.color import *
import pymunk
import pymunk.pygame_util
from pymunk import Vec2d
import sys
#import tensorflow as tf
from time import sleep
import time
import numpy as np
from math import exp
from random import seed
from random import random
import datetime
import operator
class Game:
def __init__(self):
# initialize game window
pygame.init()
self.screen_x= 1500
self.screen_y= 200
# Pool Hyper Parameters
# BE CAREFULL CHANGING THESE VARIABLES
self.pool_size = 2
self.pool_time = 15
#########################################################################
# NN lists
#Pygame fonts
self.font = pygame.font.SysFont("Arial", 16)
self.screen = pygame.display.set_mode((self.screen_x,self.screen_y+200)) #screen display
self.clock = pygame.time.Clock() ## init clock
self.running = True
# pymunk init
self.space = pymunk.Space()
self.space.gravity = (0.0, -1200.0) #gravity setup
self.draw_options = pymunk.pygame_util.DrawOptions(self.screen)#adds add physics to the screen
def new(self):
# start a new game
## Balls
self.balls = []
## creating walls
self.static_body = self.space.static_body
self.static_lines = [pymunk.Segment(self.static_body, (0.0,50.0), (1500.0, 50.0), 0.0) ## road
,pymunk.Segment(self.static_body, (1499.0, 150.0), (1499.0, 700.0), 0.0)
,pymunk.Segment(self.static_body, (1800, 50.0), (1800, 170.0), 0.0)
,pymunk.Segment(self.static_body, (0.0,50.0), (0.0, 700.0), 0.0) ## wall 1
]
## set walls
for line in self.static_lines:
line.elasticity = 0.95
line.friction = 01.5
#line.filter = pymunk.ShapeFilter(categories=np.uint8(0))
self.space.add(self.static_lines)
# Go to run
self.run()
def run(self):
# Game Loop
self.playing = True
self.no_ball = True
while self.running:
self.events()
if self.no_ball == True:
self.unit(self.pool_size)
self.update()
def update(self):
self.screen.fill(THECOLORS["white"])
### Draw stuff
self.balls_to_remove = []
for ball in self.balls:
if ball.body.position.y < 0: self.balls_to_remove.append(ball)
for ball in self.balls_to_remove:
self.space.remove(ball, ball.body)
self.balls.remove(ball)
self.space.debug_draw(self.draw_options)
### Update physics
self.dt = 1.0/60.0
for k in range(1):
self.space.step(self.dt)
### Flip screen
pygame.display.flip()
self.clock.tick(50)
pygame.display.set_caption("fps: " + str(self.clock.get_fps()))
def events(self):
for event in pygame.event.get():
if event.type == QUIT:
self.running = False
if event.type == KEYDOWN:
if event.key == K_y: ## Creates a ball
self.running = False
pass
elif event.type == pygame.MOUSEMOTION:
(self.mouse_x, self.mouse_y) = pymunk.pygame_util.get_mouse_pos(self.screen)
def unit (self, number_balls=None):
#Mass And Radius units
self.mass = 20
self.radius = 10
#Mass and Radius for joint
self.mass_joint = 2
self.radius_joint = 2
#for n in number_balls
self.objs = list()
for i in range(number_balls):
self.objs.append(pymunk.Body())
self.objs.append(pymunk.Body())
self.objs.append(pymunk.Body())
#Inertia
self.inertia = pymunk.moment_for_circle(self.mass, 0, self.radius, (0,0))
self.inertia_joint = pymunk.moment_for_circle(self.mass_joint , 0, self.radius_joint, (0,0))
#Body
self.objs[i], self.objs[i+1] = pymunk.Body(self.mass, self.inertia), pymunk.Body(self.mass, self.inertia)
self.objs[i+2] = pymunk.Body(self.mass_joint, self.inertia_joint)
#Position
x = 100
self.objs[i].position = x , 90
self.objs[i+1].position = x+24, 90
self.objs[i+2].position = x+12, 90
#Links
self.link_1 = pymunk.PinJoint(self.objs[i], self.objs[i+2], (0, 0), (0, 0))
self.link_2 = pymunk.PinJoint(self.objs[i+1], self.objs[i+2], (0, 0), (0, 0))
# Adding Body links
self.space.add(self.link_1)
self.space.add(self.link_2)
#First ball shape
self.shape_first = pymunk.Circle(self.objs[i], self.radius, (0,0))
self.shape_first.elasticity = 0.4
self.shape_first.friction = 0.9
self.space.add(self.objs[i], self.shape_first)
#Fsecond ball shape
self.shape_second = pymunk.Circle(self.objs[i+1], self.radius, (0,0))
self.shape_second.elasticity = 0.4
self.shape_second.friction = 0.9
self.space.add(self.objs[i+1], self.shape_second)
#Joint shape
self.shape_joint = pymunk.Circle(self.objs[i+2], self.radius_joint, (0,0))
self.shape_joint.elasticity = 0.4
self.shape_joint.friction = 0.9
#self.shape_joint.sensor == True
self.space.add(self.objs[i+2], self.shape_joint)
body_first_category = (i*3)+1#"{0:b}".format(int(i+1))
body_second_category = (i*3)+2
body_joint_category = (i*3)+3
print (body_first_category )
print(body_second_category )
print(body_joint_category )
#"{0:b}".format(int(i+2))
self.shape_first.filter = pymunk.ShapeFilter(categories=body_first_category, mask=(body_joint_category and body_second_category) )
self.shape_second.filter = pymunk.ShapeFilter(categories=body_second_category, mask=(body_first_category and body_joint_category) )
self.shape_joint.filter = pymunk.ShapeFilter(categories=body_joint_category, mask=(body_first_category and body_second_category))
self.balls.append(self.shape_first)
self.balls.append(self.shape_second)
self.balls.append(self.shape_joint)
self.no_ball = False
g = Game()
while g.running:
g.new()
##pg.quit()
Please help :)
P.S: Example Library shape filter class:
http://www.pymunk.org/en/latest/pymunk.html#pymunk.ShapeFilter
You can solve this with collision callbacks, I think begin callback is a good option for you. On each pair of shapes you want to collide you set a common identifier, and then check that in the callback, and return True only when the two objects colliding belong to the same pair.
Something like this:
def only_collide_same(arbiter, space, data):
a, b = arbiter.shapes
return a.pair_index == b.pair_index
h = space.add_collision_handler(1,1)
h.begin = only_collide_same
for i in range(10):
# create shapes and bodies ...
# then for each pair of shapes:
shape1.pair_index = i
shape1.collision_type = 1
shape2.pair_index = i
shape2.collision_type = 1

Pymunk servo joint

How do you implement a "servo" joint in Pymunk?
I'm trying to create a simple model where a box is balanced on a single thin "leg" below it. I've been able create a box and join it to the ground using a PinJoint, but there doesn't seem to be any way to control the angle where the join attaches to the box. I want to be able to specify the angle of attachment. None of the other joints seem to support this. They all seem to be passive joints, with the exception of the SimpleMotor joint, but even that is only a constant spinning joint that you can't control.
I've managed to cobble something together, by using a PinJoint to attach two thin boxes together at their ends, as well as a SimpleMotor, to make them rotate relative to each other in response to the user pressing the "up" and "down" arrow keys. Below is the code:
import sys
import pygame
from pygame.locals import USEREVENT, QUIT, KEYDOWN, KEYUP, K_s, K_r, K_q, K_ESCAPE, K_UP, K_DOWN
from pygame.color import THECOLORS
import pymunk
from pymunk import Vec2d
import pymunk.pygame_util
class Simulator(object):
def __init__(self):
self.display_flags = 0
self.display_size = (600, 600)
self.space = pymunk.Space()
self.space.gravity = (0.0, -1900.0)
self.space.damping = 0.999 # to prevent it from blowing up.
# Pymunk physics coordinates start from the lower right-hand corner of the screen.
self.ground_y = 100
ground = pymunk.Segment(self.space.static_body, (5, self.ground_y), (595, self.ground_y), 1.0)
ground.friction = 1.0
self.space.add(ground)
self.screen = None
self.draw_options = None
def reset_bodies(self):
for body in self.space.bodies:
if not hasattr(body, 'start_position'):
continue
body.position = Vec2d(body.start_position)
body.force = 0, 0
body.torque = 0
body.velocity = 0, 0
body.angular_velocity = 0
body.angle = body.start_angle
def draw(self):
### Clear the screen
self.screen.fill(THECOLORS["white"])
### Draw space
self.space.debug_draw(self.draw_options)
### All done, lets flip the display
pygame.display.flip()
def main(self):
pygame.init()
self.screen = pygame.display.set_mode(self.display_size, self.display_flags)
width, height = self.screen.get_size()
self.draw_options = pymunk.pygame_util.DrawOptions(self.screen)
def to_pygame(p):
"""Small hack to convert pymunk to pygame coordinates"""
return int(p.x), int(-p.y+height)
def from_pygame(p):
return to_pygame(p)
clock = pygame.time.Clock()
running = True
font = pygame.font.Font(None, 16)
# Create the torso box.
box_width = 50
box_height = 100
leg_length = 100
mass = 1
points = [(-100, -1), (0, -1), (0, 1), (-100, 1)]
moment = pymunk.moment_for_poly(mass, points)
body1 = pymunk.Body(mass, moment)
# body1.position = (0, 0)
body1.position = (self.display_size[0]/2, self.ground_y+100)
body1.start_position = Vec2d(body1.position)
body1.start_angle = body1.angle
shape1 = pymunk.Poly(body1, points)
shape1.friction = 0.8
self.space.add(body1, shape1)
# Create bar 2 extending from the right to the origin.
mass = 1
points = [(100, -1), (0, -1), (0, 1), (100, 1)]
moment = pymunk.moment_for_poly(mass, points)
body2 = pymunk.Body(mass, moment)
# body2.position = (0, 0)
body2.position = (self.display_size[0]/2, self.ground_y+100)
body2.start_position = Vec2d(body2.position)
body2.start_angle = body2.angle
shape2 = pymunk.Poly(body2, points)
shape2.friction = 0.8
self.space.add(body2, shape2)
# Link bars together at end.
pj = pymunk.PinJoint(body1, body2, (0, 0), (0, 0))
self.space.add(pj)
motor_joint = pymunk.SimpleMotor(body1, body2, 0)
self.space.add(motor_joint)
pygame.time.set_timer(USEREVENT+1, 70000) # apply force
pygame.time.set_timer(USEREVENT+2, 120000) # reset
pygame.event.post(pygame.event.Event(USEREVENT+1))
pygame.mouse.set_visible(False)
simulate = False
while running:
for event in pygame.event.get():
if event.type == QUIT or (event.type == KEYDOWN and event.key in (K_q, K_ESCAPE)):
#running = False
sys.exit(0)
elif event.type == KEYDOWN and event.key == K_s:
# Start/stop simulation.
simulate = not simulate
elif event.type == KEYDOWN and event.key == K_r:
# Reset.
# simulate = False
self.reset_bodies()
elif event.type == KEYDOWN and event.key == K_UP:
motor_joint.rate = 1
elif event.type == KEYDOWN and event.key == K_DOWN:
motor_joint.rate = -1
elif event.type == KEYUP:
motor_joint.rate = 0
self.draw()
### Update physics
fps = 50
iterations = 25
dt = 1.0/float(fps)/float(iterations)
if simulate:
for x in range(iterations): # 10 iterations to get a more stable simulation
self.space.step(dt)
pygame.display.flip()
clock.tick(fps)
if __name__ == '__main__':
sim = Simulator()
sim.main()
However, the behavior is somewhat strange. When you press up/down, that dynamically sets the rate on the SimpleMotor joint, causing the two boxes to pivot at their common "servo joint", like:
except over time the two bars will flip onto one end, and otherwise defy gravity and look like:
Why is this? I'm still fairly new to the Pymunk/Chipmunk physics simulator, so I'm not sure I'm using these joints correctly.
A couple of things that can cause problems:
Ignore collisions between the two shapes. Since the motor and pin joint force them together, but collision resolution pushes them apart strange things might happen. You can do this by setting the two shapes to the same group:
shape_filter = pymunk.ShapeFilter(group=1)
shape1.filter = shape_filter
shape2.filter = shape_filter
The center of gravity for the two shapes are at their ends, not in the center. Try to move it to center ([(-50, -1), (50, -1), (50, 1), (-50, 1)]).
(In this case I think 1 is enough to fix the problem, but I added 2 in case you notice other strange things)

Pygame: Colliding Rectangle on multiple other rectangles

I am attempting to create a game in which a block moves back and forth until the player presses space. Upon which, the block jumps to the next line up and stops.
Currently i am having problems with the collision code.
The error being thrown up by the shell is:
if doRectsOverlap(j['rect'], floors['line']):
TypeError: list indices must be integers, not str
I am stuck with understanding where my code has gone wrong. My knowledge of how python works is very limited.
There is also code i have commented out to do with the floor moving dowards when the player jumps. it has been commented out until i can get the collisions working, but still included
Code Below:
import pygame, sys, time
from pygame.locals import *
def doRectsOverlap(rect1, rect2):
for a, b in [(rect1, rect2), (rect2, rect1)]:
# Check if a's corners are inside b
if ((isPointInsideRect(a.left, a.top, b)) or
(isPointInsideRect(a.left, a.bottom, b)) or
(isPointInsideRect(a.right, a.top, b)) or
(isPointInsideRect(a.right, a.bottom, b))):
return True
return False
def isPointInsideRect(x, y, rect):
if (x > rect.left) and (x < rect.right) and (y > rect.top) and (y < rect.bottom):
return True
else:
return False
# set up pygame
pygame.init()
mainClock = pygame.time.Clock()
# set up the window
WINDOWWIDTH = 480
WINDOWHEIGHT = 800
windowSurface = pygame.display.set_mode((WINDOWWIDTH, WINDOWHEIGHT), 0, 32)
pygame.display.set_caption('Jumper')
#Directions
LEFT = 4
RIGHT = 6
UP = 8
DOWN = 2
STILL = 5
#blocks location for jumping
#BLOCKLOCY = 700
#Binary for stopping movement
#STOPPER = 0
MOVESPEED = 1
# set up the colors
BLACK = (0, 0, 0)
RED = (255, 0, 0)
GREEN = (0, 255, 0)
BLUE = (0, 0, 255)
j = {'rect':pygame.Rect(240, 700, 20, 20), 'color':GREEN, 'dir':LEFT, 'jump':STILL}
f1 = {'line':pygame.Rect(0,720,480,2), 'color':GREEN, 'dir':STILL}
f2 = {'line':pygame.Rect(0,650,480,2), 'color':GREEN, 'dir':STILL}
floors = [f1,f2]
# run the game loop
while True:
# check for the QUIT event
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
# draw the black background onto the surface
windowSurface.fill(BLACK)
# move the block data structure
if j['dir'] == LEFT:
j['rect'].left -= MOVESPEED
if j['dir'] == RIGHT:
j['rect'].left += MOVESPEED
if j['jump'] == UP:
j['rect'].bottom -= MOVESPEED
#BLOCKLOCY -= MOVESPEED
if j['rect'].left < 0:
j['dir'] = RIGHT
if j['rect'].left > WINDOWWIDTH-j['rect'].width:
j['dir'] = LEFT
if event.type == KEYDOWN:
if event.key == K_SPACE:
j['jump'] = UP
if doRectsOverlap(j['rect'], floors['line']):
j['jump'] = STILL
#Floor controll code for moving level - not working currently
# for f in floors:
#if f['dir'] == DOWN:
# f['line'].y += MOVESPEED
# if event.type == KEYDOWN:
# if event.key == K_SPACE:
# f['dir'] = DOWN
# if f['line'].top == BLOCKLOCY:
# f['dir'] = STILL
# STOPPER = 1
#if f['line'].bottom == BLOCKLOCY:
# f['dir'] = STILL
# STOPPER = 1
# draw the block onto the surface
pygame.draw.rect(windowSurface, j['color'], j['rect'])
pygame.draw.rect(windowSurface, f['color'], f['line'])
# draw the window onto the screen
pygame.display.update()
mainClock.tick(40)
You are creating floors as a list:
f1 = {'line':pygame.Rect(0,720,480,2), 'color':GREEN, 'dir':STILL}
f2 = {'line':pygame.Rect(0,650,480,2), 'color':GREEN, 'dir':STILL}
floors = [f1,f2]
So when you call:
if doRectsOverlap(j['rect'], floors['line']):
j['jump'] = STILL
You're message is telling you that you need an index as an int:
for n in range(len(floors)):
if doRectsOverlap(j['rect'], floors[n]['line']):
j['jump'] = STILL

Adding gradient to moving objects in pygame

I want to add gradient to the ball in this program & also possibly the waves drawn to fade into the colour of the background (as if glowing) instead of one colour fills.
I've looked at tons of tutorials however none of them are making much sense to my syntax, the general idea to me is confusing as I have moving objects that draw the space I want to add gradient to quite slowly. Can anyone give an insight into how I can do this?
code:
import sys, pygame, math
from pygame.locals import *
# set up of constants
WHITE = (255, 255, 255)
DARKRED = (128, 0, 0)
RED = (255, 0, 0)
BLACK = ( 0, 0, 0)
GREEN = ( 0, 255, 0)
BLUE = ( 0, 0, 255)
BGCOLOR = WHITE
screen = pygame.display.set_mode()
WINDOWWIDTH = 800 # width of the program's window, in pixels
WINDOWHEIGHT = 800 # height in pixels
WIN_CENTERX = int(WINDOWWIDTH / 2) # the midpoint for the width of the window
WIN_CENTERY = int(WINDOWHEIGHT / 2) # the midpoint for the height of the window
screen = pygame.display.get_surface()
FPS = 160 # frames per second to run at
AMPLITUDE = 80 # how many pixels tall the waves with rise/fall.
# standard pygame setup code
pygame.init()
FPSCLOCK = pygame.time.Clock()
DISPLAYSURF = pygame.display.set_mode((WINDOWWIDTH, WINDOWHEIGHT), pygame.RESIZABLE)
pygame.display.set_caption('Window title')
fontObj = pygame.font.Font('freesansbold.ttf', 16)
# variables that track visibility modes
showSine = True
showSquare = True
pause = False
xPos = 0
step = 0 # the current input f
posRecord = {'sin': [], 'square': []} # keeps track of the ball positions for drawing the waves
yPosSquare = AMPLITUDE # starting position
# main application loop
while True:
# event handling loop for quit events
for event in pygame.event.get():
if event.type == QUIT or (event.type == KEYUP and event.key == K_ESCAPE):
pygame.quit()
sys.exit()
# fill the screen to draw from a blank state
DISPLAYSURF.fill(BGCOLOR)
# sine wave
yPos = -1 * math.sin(step) * AMPLITUDE
posRecord['sin'].append((int(xPos), int(yPos) + WIN_CENTERY))
if showSine:
# draw the sine ball and label
pygame.draw.circle(DISPLAYSURF, RED, (int(xPos), int(yPos) + WIN_CENTERY), 10)
sinLabelRect.center = (int(xPos), int(yPos) + WIN_CENTERY + 20)
DISPLAYSURF.blit(sinLabelSurf, sinLabelRect)
# draw the waves from the previously recorded ball positions
if showSine:
for x, y in posRecord['sin']:
pygame.draw.circle(DISPLAYSURF, DARKRED, (x,y), 4)
#drawing horizontal lines
# square
posRecord['square'].append((int(xPos), int(yPosSquare) + WIN_CENTERY))
if showSquare:
# draw the sine ball and label
pygame.draw.circle(DISPLAYSURF, GREEN, (int(xPos), int(yPosSquare) + WIN_CENTERY), 10)
squareLabelRect.center = (int(xPos), int(yPosSquare) + WIN_CENTERY + 20)
DISPLAYSURF.blit(squareLabelSurf, squareLabelRect)
# draw the waves from the previously recorded ball positions
if showSquare:
for x, y in posRecord['square']:
pygame.draw.circle(DISPLAYSURF, BLUE, (x, y), 4)
# draw the border
pygame.draw.rect(DISPLAYSURF, BLACK, (0, 0, WINDOWWIDTH, WINDOWHEIGHT), 1)
pygame.display.update()
FPSCLOCK.tick(FPS)
if not pause:
xPos += 1
#wave movement
if xPos > WINDOWWIDTH:
#sine
xPos = 0
posRecord['sin'] = []
step = 0
# square
yPosSquare = AMPLITUDE
posRecord['square'] = []
else:
#sine
step += 0.008
#step %= 2 * math.pi
# square
# jump top and bottom every 100 pixels
if xPos % 100 == 0:
yPosSquare *= -1
# add vertical line
for x in range(-AMPLITUDE, AMPLITUDE):
posRecord['square'].append((int(xPos), int(x) + WIN_CENTERY))
Use SPACE to change background color.
First line use only transparency - and has no problem with different background color.
Second line changes only circles color - and depends on background color.
Third and fourth line (it is the same line with different starting color) change circles color and transparency - and depends on background color.
Second and last line look good on one color background and need more work to find good-looking fading.
import pygame
pygame.init()
screen = pygame.display.set_mode((600,200))
#--------------------------------------
# circles positions and transparency (x,y, alpha)
circles = []
for x in range(100):
circles.append( [100+x*3, 200, x*2] )
#--------------------------------------
white = True # background color
#--------------------------------------
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
running = False
elif event.key == pygame.K_SPACE:
white = not white
#--------------------------------------
if white:
screen.fill((255,255,255))
else:
screen.fill((0,0,0))
#--------------------------------------
# first
circle_img = pygame.Surface((20,20))
pygame.draw.circle(circle_img, (255,0,0), (10,10), 10)
circle_img.set_colorkey(0)
for x in circles:
circle_img.set_alpha(x[2])
screen.blit(circle_img, (x[0],40))
#--------------------------------------
# second
circle_img = pygame.Surface((20,20))
for x in circles:
pygame.draw.circle(circle_img, (255,255-x[2],255-x[2]), (10,10), 10)
circle_img.set_colorkey(0)
screen.blit(circle_img, (x[0],90))
#--------------------------------------
# last
circle_img = pygame.Surface((20,20))
for x in circles:
pygame.draw.circle(circle_img, (255,255-x[2],255-x[2]), (10,10), 10)
circle_img.set_colorkey(0)
circle_img.set_alpha(x[2])
screen.blit(circle_img, (x[0],140))
#--------------------------------------
pygame.display.flip()
pygame.quit()

Categories

Resources