How to rotate pymunk joints at will? - python

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.

Related

Pygame: How do I fix the issue of randomly generated platforms on PyGame moving in the wrong direction in the wrong section of the screen?

so I have been following some guides, and taking some of my own initiative, but I've now gotten stuck. I am at a point where platforms are being generated randomly (yay) and are appearing on the screen (double yay), but are going from the bottom of the screen to the top instead of right to left which I would like. I am finding it difficult to understand how to modify this.
I have (foolishly) tried changing a variable name.
I tried changing what's within randint and the append parts. But there's not much I want to tinker around with like the "pos", for example, as I am just not too sure what's even going on with it.
# For the program, it was necessary to import the following.
import pygame, sys, random
import pygame.locals as GAME_GLOBALS
import pygame.event as GAME_EVENTS
import pygame.time as GAME_TIME
pygame.init() # To initialise the program, we need this command. Else nothing will get started.
StartImage = pygame.image.load("Assets/Start-Screen.png")
GameOverImage = pygame.image.load("Assets/Game-Over-Screen.png")
# Window details are here
windowWidth = 1000
windowHeight = 400
surface = pygame.display.set_mode((windowWidth, windowHeight))
pygame.display.set_caption('GAME NAME HERE')
oneDown = False
gameStarted = False
gameEnded = False
gamePlatforms = []
platformSpeed = 3
platformDelay = 4000
lastPlatform = 0
gameBeganAt = 0
timer = 0
player = {
"x": 10,
"y": 200,
"height": 25,
"width": 10,
"vy": 5
}
def drawingPlayer():
pygame.draw.rect(surface, (248, 255, 6), (player["x"], player["y"], player["width"], player["height"]))
def movingPlayer():
pressedKey = pygame.key.get_pressed()
if pressedKey[pygame.K_UP]:
player["y"] -= 5
elif pressedKey[pygame.K_DOWN]:
player["y"] += 5
def creatingPlatform():
global lastPlatform, platformDelay
platformY = windowWidth
gapPosition = random.randint(0, windowWidth - 100)
gamePlatforms.append({"pos": [0, platformY], "gap": gapPosition})
lastPlatform = GAME_TIME.get_ticks()
def movingPlatform():
for idx, platform in enumerate(gamePlatforms):
platform["pos"][1] -= platformSpeed
if platform["pos"][1] < -10:
gamePlatforms.pop(idx)
def drawingPlatform():
global platform
for platform in gamePlatforms:
pygame.draw.rect(surface, (214, 200, 253), (platform["gap"], platform["pos"][1], 40, 10))
def gameOver():
global gameStarted, gameEnded, platformSpeed
platformSpeed = 0
gameStarted = False
gameEnded = True
def quitGame():
pygame.quit()
sys.exit()
def gameStart():
global gameStarted
gameStarted = True
while True:
surface.fill((95, 199, 250))
pressedKey = pygame.key.get_pressed()
for event in GAME_EVENTS.get():
if event.type == pygame.KEYDOWN:
# Event key for space should initiate sound toggle
if event.key == pygame.K_1:
oneDown = True
gameStart()
if event.type == pygame.KEYUP:
if event.key == pygame.K_1:
oneDown = False
#KEYUP for the space bar
if event.type == GAME_GLOBALS.QUIT:
quitGame()
if gameStarted is True:
drawingPlayer()
movingPlayer()
creatingPlatform()
movingPlatform()
drawingPlatform()
elif gameEnded is True:
surface.blit(GameOverImage, (0, 0))
else:
surface.blit(StartImage, (0, 0))
pygame.display.update()
Expected result: Platforms approaching the yellow rectangle from the right side of the screen to the left, also the rectangle being tall instead of wide.
Actual result: Platforms coming from the bottom of the screen to the top, and the platforms being wide. But I can probably fix the latter, I just want to work on the direction first.
OK, so here were the changes I made:
In creatingPlatform() I created a variable to hold the vertical position of the platforms. I also renamed your platformY to platformX, because it's a random x-position, not a random y-position.
I used the new vertical position as part of the "pos" attribute of the platform, and put them in the conventional (x, y) ordering. Here's the code for the modified function:
def creatingPlatform():
global lastPlatform, platformDelay
platformX = windowWidth
gapPosition = random.randint(0, windowWidth - 100)
verticalPosition = random.randint(0, windowHeight)
gamePlatforms.append({"pos": [platformX, verticalPosition], "gap": gapPosition})
lastPlatform = GAME_TIME.get_ticks()
Next, I had to modify movingPlatform() so that it updated the x-position, and not the y-position. That just involved changing the index of platform["pos"] from 1 to 0:
def movingPlatform():
for idx, platform in enumerate(gamePlatforms):
platform["pos"][0] -= platformSpeed
if platform["pos"][0] < -10:
gamePlatforms.pop(idx)
Lastly, I just passed the platform positions into the draw function:
def drawingPlatform():
global platform
for platform in gamePlatforms:
pygame.draw.rect(surface, (214, 200, 253), (platform["pos"][0], platform["pos"][1], 40, 10))
This produced platforms moving right-to-left, and they are also wide and not tall!

How do I find the distance from the goal node named target, when I have the below mentioned start node named seeker?

I am trying to find the distance from the start node named seeker to the goal node named target. I have already done most of the implementation of the algorithm and each of the nodes have a coordinate or box on a grid. My python code is lacking and I cannot find the coordinates and distance.
I have tried using the vector in the math class which gave me logical errors.
I also tried sending the actual objects hoping I could use those to reference the coordinates as I'd done in the code but got a TypeError: expected sequence object with len >= 0 or a single integer.
import numpy as np
import pygame as pg
import sys
from Settings import *
from Sprites import *
vec = pg.math.Vector2
class Game:
# initialise game window, etc
def __init__(self):
self.playing = True
pg.init()
self.mover = 'target'
self.screen = pg.display.set_mode((WIDTH, HEIGHT))
pg.display.set_caption(Title)
self.clock = pg.time.Clock()
pg.key.set_repeat(500, 100)
self.load_data()
# pg.mouse.set_pos(0, 0)
self.walls = []
def load_data(self):
pass
# start a new game
def new(self):
self.all_sprites = pg.sprite.Group()
self.player = Player(self, 10, 10)
self.target = Target(self, 5, 5)
def load_data(self):
pass
# game loop
def run(self):
while self.playing:
self.dt = self.clock.tick(FPS) / 10000
self.events()
self.update()
self.draw()
def draw_grid(self):
for x in range(0, WIDTH, TILESIZE):
pg.draw.line(self.screen, LIGHTGREY, (x, 0), (x, HEIGHT))
for y in range(0, HEIGHT, TILESIZE):
pg.draw.line(self.screen, LIGHTGREY, (0, y), (WIDTH, y))
def quit(self):
pg.quit()
sys.exit()
def update(self):
# game loop update
self.all_sprites.update()
def events(self):
# game loop events
for event in pg.event.get():
if event.type == pg.QUIT:
self.quit()
if event.type == pg.MOUSEBUTTONDOWN:
mpos = vec(pg.mouse.get_pos()) // TILESIZE
if event.button == 1:
if mpos in g.walls:
g.walls.remove(mpos)
else:
g.walls.append(mpos)
if event.type == pg.KEYDOWN:
if event.key == pg.K_b:
# start breadth first
breadthfirst(self.target, self.player, self.walls, self.screen)
if event.key == pg.K_d:
# start depth first
depthfirst(self.target, self.player, self.walls, self.screen)
if event.key == pg.K_a:
# start A* search
astarsearch(self.target, self.player, self.walls, self.screen)
if event.key == pg.K_ESCAPE:
self.quit()
if event.key == pg.K_t:
self.mover = 'target'
if event.key == pg.K_s:
self.mover = 'seeker'
if self.mover == 'target':
if event.key == pg.K_LEFT:
self.target.move(dx=-1)
if event.key == pg.K_RIGHT:
self.target.move(dx=1)
if event.key == pg.K_UP:
self.target.move(dy=-1)
if event.key == pg.K_DOWN:
self.target.move(dy=1)
else:
if event.key == pg.K_LEFT:
self.player.move(dx=-1)
if event.key == pg.K_RIGHT:
self.player.move(dx=1)
if event.key == pg.K_UP:
self.player.move(dy=-1)
if event.key == pg.K_DOWN:
self.player.move(dy=1)
def draw(self):
# game loop - draw
self.screen.fill(BGCOLOR)
self.draw_grid()
self.all_sprites.draw(self.screen)
for wall in self.walls:
rect = pg.Rect(wall * TILESIZE, (TILESIZE, TILESIZE))
pg.draw.rect(self.screen, GREEN, rect)
# always do the flip after drawing everything
pg.display.flip()
def show_start_screen(self):
# game splash/start screen
pass
def show_go_screen(self):
# game over/continue screen
pass
def breadthfirst(target, seeker, walls, maingrid):
pass
def depthfirst(target, seeker, wall, maingrid):
pass
def astarsearch(target, seeker, wall, maingrid):
# array to store path locations
direct_graph = {}
# target location, returns a tuple
target = np.where(target.pos) # problem area
# seeker location, returns locations
start = np.where(seeker.pos) # problem area
# array of cost to travel so far
g_cost_array = np.zeros(seeker) # problem area
g_cost_array[start] = 0
total_g_cost = 0
# array for heuristic cost
h_cost_array = np.zeros(seeker) # problem area
# need to use a loop unfortunately...
t = 0
# possible steps
steps = ((-1, 0), (+1, 0), (0, -1), (0, +1))
for rows in h_cost_array:
s = 0
for cols in rows:
# check if it's a wall! if not - get the distance to target
loc = (t, s)
if (maingrid[loc]):
pass
else:
dist = abs(target[0] - s) + abs(target[1] - t)
h_cost_array[t, s] = dist
s += 1
t += 1
# total cost = h + g
f_cost_array = g_cost_array + h_cost_array
# closed and open sets
open_set = []
open_set.append(start)
closed_set = []
# actual path
path = []
path.append([tuple(target[0]), tuple(target[1])])
solution_found = False
while (open_set):
open_f_cost = []
# get the heuristic cost for the candidates in the open set
for vals in open_set:
open_f_cost.append(f_cost_array[vals])
# the shortest heuristic now
# the index of the candidate with the lowest distance/heuristic
best_dist_now = open_f_cost.index(min(open_f_cost))
# the current best position
best_pos_now = open_set[best_dist_now]
# if the destination is reached, finish!
if (tuple(best_pos_now) == target):
solution_found = True
break
else:
# remove the best guy from the open_set and add it to the closed set
closed_set.append(open_set.pop(best_dist_now))
# analyze the steps from the current best
for step in steps:
cand = (best_pos_now[0] + step[0], best_pos_now[1] + step[1])
# check if there's a wall or beyond the screen
if cand[0] < 0 or cand[1] < 0 or cand[0] > 39 or cand[1] > 23:
pass
# skip this candidate because it's a wall!
elif maingrid[cand]:
pass
# need an else clause here to weed out the off-screen locations
else:
# check if the candidate is in the closed set
already_seen = False
for dead in closed_set:
if np.all(dead == cand):
already_seen = True
break
# if the cell is in the closed set, skip it
if already_seen:
pass
else:
approx_g_score = g_cost_array[best_pos_now] + 1
# check if it's in the open list:
new = True
for others in open_set:
if np.all(others == cand):
new = False
break
# if a new cell or improved
if (new or approx_g_score < g_cost_array[cand]):
direct_graph[tuple(cand[0]), tuple(cand[1])] = (
tuple(best_pos_now[0]), tuple(best_pos_now[1]))
g_cost_array[cand] = approx_g_score
f_cost_array[cand] = g_cost_array[cand] + h_cost_array[cand]
if new:
open_set.append(cand)
if not solution_found:
return None
else:
recurrentPath(path, direct_graph, target, start)
return path
# takes a dictionary as input
def recurrentPath(final_path, raw_path, dest, origin):
a = raw_path[tuple(dest[0]), tuple(dest[1])]
final_path.append(a)
if (a != origin):
recurrentPath(final_path, raw_path, a, origin)
else:
return final_path
g = Game()
g.show_start_screen()
while True:
g.new()
g.run()
g.show_go_screen()
pg.QUIT
the expected results is to return the correct path to the target object from the seeker object after you press the keyboard character a. Note that with a left click, a wall can be constructed to add a hindrance to the seeking of the goal.

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)

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