Pymunk servo joint - python

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)

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.

Python Pygame and Pymunk game library Non-colliding Shapes

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.

Pygame Rectangle and Mouse pos Collidepoint not working

I'm making a basic game where I have a surface and everytime I click on the surface it moves 5 pixels to the right. The program is working just fine without the checkCollide(event) function, but when I put the that condition it doesn't move. What is wrong?
My code until now is this
import pygame, sys
from pygame.locals import *
pygame.init()
DISPLAYSURF = pygame.display.set_mode((300,300))
def checkCollide(event):
k = 0
a,b = event.pos
x = P1[0].get_rect()
if x.collidepoint(a,b):
return True
return False
CP1 = [(150, 150)
,(155, 150)
,(160, 150)
,(165, 150)
,(170, 150)
,(175, 150)
,(180, 150)
,(185, 150)
,(190, 150)]
statp1_1 = 0
WHITE = (255,255,255)
DISPLAYSURF.fill(WHITE)
while True: # the main game loop
P1 = [pygame.image.load('PAzul.png'),CP1[statp1_1],statp1_1]
DISPLAYSURF.blit(P1[0], P1[1])
e = pygame.event.get()
for event in e:
if event.type == MOUSEBUTTONUP:
a = checkCollide(event)
if a:
DISPLAYSURF.fill(WHITE)
statp1_1 +=1
if event.type == QUIT:
pygame.quit()
sys.exit()
pygame.display.update()
Thank you
Check your logic in these lines of your function:
x = P1[0][0].get_rect()
if x.collidepoint(a,b):
return True
return False
Your code hinges on this bit:
a = checkCollide(event)
if a:
DISPLAYSURF.fill(WHITE)
So you're never evaluating this piece to be true.
I just realized what was wrong. When I do x = P1[0].get_rect() it creates a surface with topleft at (0,0).
What I needed to do was change the position of the rectangle using x.topleft = P1[1]
I've got some tips for you. First store the rect in the P1 list (it contains only the image and the rect in the following example, but maybe you could also add the statp1_1 index to it). Now we can just move this rect, if the user clicks on it (in the example I set the topleft attribute to the next point). Read the comments for some more tips. One thing you need to fix is to prevent the game from crashing when the statp1_1 index gets too big.
import sys
import pygame
pygame.init()
DISPLAYSURF = pygame.display.set_mode((300, 300))
WHITE = (255, 255, 255)
# Don't load images in your while loop, otherwise they have to
# be loaded again and again from your hard drive.
# Also, convert loaded images to improve the performance.
P1_IMAGE = pygame.image.load('PAzul.png').convert() # or .convert_alpha()
# Look up `list comprehension` if you don't know what this is.
CP1 = [(150+x, 150) for x in range(0, 41, 5)]
statp1_1 = 0
# Now P1 just contains the image and the rect which stores the position.
P1 = [P1_IMAGE, P1_IMAGE.get_rect(topleft=CP1[statp1_1])]
clock = pygame.time.Clock() # Use this clock to limit the frame rate.
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
if event.type == pygame.MOUSEBUTTONUP:
if P1[1].collidepoint(event.pos):
print('clicked')
statp1_1 += 1
# Set the rect.topleft attribute to CP1[statp1_1].
P1[1].topleft = CP1[statp1_1]
DISPLAYSURF.fill(WHITE)
DISPLAYSURF.blit(P1[0], P1[1]) # Blit image at rect.topleft.
pygame.display.update()
clock.tick(30) # Limit frame rate to 30 fps.

I get an incorrect position from .get_rect()?

I'm currently working on a school project where I'm making a "hexcells" similar game in pygame and now I'm trying to blit an a new image if the user has clicked a current image. It will blit an image in the top left area, if clicked in the top left area, but not if I click any of the existing images. I told the program to print the coordinates from the images with help of the .get_rect() function, but it remains the same whereever I click and the coordinates aren't even where a image is. Can someone help me understand how this works and help me blit the new images on top of the existing images? Code below is not the entire document, however there is so much garbage/trash/unused code so I'd thought I spare you the time of looking at irrelevant code. Also sorry if the formatting is wrong or the information isn't enough, I tried my best.
import pygame, sys
from pygame.locals import *
#Magic numbers
fps = 30
winW = 640
winH = 480
boxSize = 40
gapSize = 75
boardW = 3
boardH = 3
xMargin = int((winW - (boardW * (boxSize + gapSize))) / 2)
yMargin = int((winW - (boardW * (boxSize + gapSize))) / 2)
#Lil bit o' color R G B
NAVYBLUE = ( 60, 60, 100)
correctCords = [[175,275,375],[375,275,175]]
bgColor = NAVYBLUE
unC = pygame.image.load("unC.png")
cor = pygame.image.load("correct.png")
inc = pygame.image.load("wrong.png")
correct = "Correct"
inCorrect = "Incorrect"
def main():
global FPSCLOCK, DISPLAYSURF
pygame.init()
FPSCLOCK = pygame.time.Clock()
DISPLAYSURF = pygame.display.set_mode((winW, winH))
mousex = 0 #stores x-coordinate of mouse event
mousey = 0 #stores y-coordinate of mouse event
pygame.display.set_caption("Branches")
DISPLAYSURF.fill(bgColor)
gridGame(inCorrect, correct,gapSize,xMargin,yMargin,boxSize)
while True:
mouseClicked = False
for event in pygame.event.get():
if event.type == QUIT or (event.type == KEYUP and event.key == K_ESCAPE):
pygame.quit()
sys.exit()
elif event.type == MOUSEMOTION:
mousex,mousey = event.pos
elif event.type == MOUSEBUTTONUP:
mousex, mousey = event.pos
pos = pygame.mouse.get_pos()
mouseClicked = True
unCa = unC.get_rect()
corA = cor.get_rect()
print unCa
print corA
print pos
if unCa.collidepoint(pos):
DISPLAYSURF.blit(cor,(mousey,mousex))
"""lada = unC.get_rect()
lada =
if mousex and mousey == lada:
for x in correctCords:
for y in x:
for z in x:
if mousey and mousex == z and y:
DISPLAYSURF.blit(cor,(mousey,mousex))
print lada"""
pygame.display.update()
FPSCLOCK.tick(fps)
def gridGame(inCorrect, correct,gapSize,xMargin,yMargin,boxSize):
grid = []
cordX = []
cordY = []
correctRecs = []
#cordinates = []
#cordinates.append([])
#cordinates.append([])
#cordinates.append([])
#this is basically getBoard() all over again
#This part will arrange the actual backend grid
for row in range(3):
grid.append([])
#cordinates[0].append(gapSize+(row+1)*100)
#cordinates[1].append(gapSize+(row+1)*100)
#cordinates[2].append(gapSize+(row+1)*100)
for column in range(3):
grid[row].append(inCorrect)
for row in range(3):
cordX.append([])
for column in range(3):
cordX[row].append(gapSize+(row+1)*100)
for row in range(3):
cordY.append([])
for column in range(3):
cordY[row].append(gapSize+(column+1)*100)
#print cordX[0][0], cordY[0][0]
grid[0][2] = correct
grid[1][1] = correct
grid[2][0] = correct
#Y-AXEL SKRIVS FoRST ([Y][X])
#print cordinates[2][1]
DISPLAYSURF.blit(cor,(100,100))
#Let's draw it as well
for row in range(3):
for column in range(3):
DISPLAYSURF.blit(unC,(gapSize+(row+1)*100,gapSize+(column+1)*100))
main()
Also real sorry about the horrible variable naming and occasional swedish comments.
unCa = unC.get_rect() gives you only image size - so use it only once at start (before while True) - and later use the same unCa all the time to keep image position and change it.
btw: better use more readable names - like unC_rect
ie.
# move 10 pixel to the right
unC_rect.x += 10
# set new position
unC_rect.x = 10
unC_rect.right = 100
unC_rect.topleft = (10, 200)
unC_rect.center = (10, 200)
# center on screen
unC_rect.center = DISPLAYSURF.get_rect().center
etc.
And then use this rect to blit image
blit(unC, unC_rect)
and check collision with other rect
if unC_rect.colliderect(other_rect):
or with point - like mouse position
elif event.type == MOUSEMOTION:
if unC_rect.collidepoint(pygame.mouse.get_pos()):
hover = True
# shorter
elif event.type == MOUSEMOTION:
hover = unC_rect.collidepoint(pygame.mouse.get_pos()):

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

Categories

Resources