Skip to content

Instantly share code, notes, and snippets.

@8Observer8
Last active December 2, 2024 11:43
Show Gist options
  • Save 8Observer8/0d79634a5b98fb8e86427e721429e16f to your computer and use it in GitHub Desktop.
Save 8Observer8/0d79634a5b98fb8e86427e721429e16f to your computer and use it in GitHub Desktop.
PyBox2D collision detection using Pygame
import math
import pygame
from Box2D import b2Draw
class DebugDrawer(b2Draw):
def __init__(self, window, pixelsPerMeter, thickness=3):
super().__init__()
self.window = window
self.pixelsPerMeter = pixelsPerMeter
self.thickness = thickness
def DrawSolidPolygon(self, vertices, color):
pygame.draw.line(self.window, (color.r * 255, color.g * 255, color.b * 255),
(vertices[0][0] * self.pixelsPerMeter, vertices[0][1] * self.pixelsPerMeter),
(vertices[1][0] * self.pixelsPerMeter, vertices[1][1] * self.pixelsPerMeter),
self.thickness)
pygame.draw.line(self.window, (color.r * 255, color.g * 255, color.b * 255),
(vertices[1][0] * self.pixelsPerMeter, vertices[1][1] * self.pixelsPerMeter),
(vertices[2][0] * self.pixelsPerMeter, vertices[2][1] * self.pixelsPerMeter),
self.thickness)
pygame.draw.line(self.window, (color.r * 255, color.g * 255, color.b * 255),
(vertices[2][0] * self.pixelsPerMeter, vertices[2][1] * self.pixelsPerMeter),
(vertices[3][0] * self.pixelsPerMeter, vertices[3][1] * self.pixelsPerMeter),
self.thickness)
pygame.draw.line(self.window, (color.r * 255, color.g * 255, color.b * 255),
(vertices[3][0] * self.pixelsPerMeter, vertices[3][1] * self.pixelsPerMeter),
(vertices[0][0] * self.pixelsPerMeter, vertices[0][1] * self.pixelsPerMeter),
self.thickness)
def DrawSolidCircle(self, center, radius, axis, color):
pass
def DrawPolygon(self, vertices, color):
pass
def DrawSegment(self, p1, p2, color):
pass
def DrawPoint(self, p, size, color):
pass
def DrawCircle(self, center, radius, color, drawwidth=1):
pass
def DrawTransform(self, xf):
pass
# pip install Box2D Pygame
import math
import pygame
from Box2D import (b2_dynamicBody, b2_kinematicBody, b2_staticBody, b2BodyDef,
b2ContactListener, b2FixtureDef, b2PolygonShape, b2Vec2,
b2World)
from debug_drawer import DebugDrawer
class ContactListener(b2ContactListener):
def BeginContact(self, contact):
userDataA = contact.fixtureA.userData
userDataB = contact.fixtureB.userData
print(userDataA["name"], "<--->", userDataB["name"])
def main():
pygame.init()
# Create a window of a given size with a title
window = pygame.display.set_mode((268, 268))
pygame.display.set_caption("PyBox2D and Pygame")
# Create a physical world with zero gravity
gravity=b2Vec2(0, 0)
world = b2World(gravity)
# The size of the physical world must be between 0.1 and 10
# so a constant pixelsPerMeter is created to
# translate from the pixel world to the Box2D physical world
pixelsPerMeter = 30
# Create DebugDrawer and configure it
debugDrawer = DebugDrawer(window, pixelsPerMeter)
debugDrawer.flags = { "drawShapes": True }
world.renderer = debugDrawer
# Create a ContactListener
world.contactListener = ContactListener()
# Creating a player body
playerBodyDef = b2BodyDef() # Object for setting the position and type of the object
# Set player position and type
playerBodyDef.position = b2Vec2(200 / pixelsPerMeter, 100 / pixelsPerMeter)
playerBodyDef.type = b2_dynamicBody
# Prevent player from spinning
playerBodyDef.fixedRotation = True
# Create a player body
playerBody = world.CreateBody(playerBodyDef)
# The player must not fall asleep
playerBody.sleepingAllowed = False
# Create a player shape in the form of a rectangle
playerShape = b2PolygonShape()
playerShape.SetAsBox(10 / pixelsPerMeter, 20 / pixelsPerMeter)
# Linking the player's body and form
playerFixtureDef = b2FixtureDef()
playerFixtureDef.shape = playerShape
# Player density. This is analogous to mass
playerFixtureDef.density = 1
playerFixture = playerBody.CreateFixture(playerFixtureDef)
playerFixture.userData = { "name": "player" }
# Create a wall similar to the player, but now
# the body type is static and density = 0
wallBodyDef = b2BodyDef()
# Set the position and type of the wall
wallBodyDef.position = b2Vec2(100 / pixelsPerMeter, 150 / pixelsPerMeter)
wallBodyDef.type = b2_staticBody
wallBodyDef.angle = math.radians(30)
# Create the body of the wall
wallBody = world.CreateBody(wallBodyDef)
# Create a player shape in the form of a rectangle
wallShape = b2PolygonShape()
wallShape.SetAsBox(10 / pixelsPerMeter, 50 / pixelsPerMeter)
# Combine wall body and shape
wallFixtureDef = b2FixtureDef()
wallFixtureDef.shape = wallShape
# Wall density. This is analogous to mass.
wallFixtureDef.density = 0
wallFixture = wallBody.CreateFixture(wallFixtureDef)
wallFixture.userData = { "name": "wall" }
# Create a kinematic fan
# with a static body and density = 0
fanBodyDef = b2BodyDef()
# Set the position and type of the fan
fanBodyDef.position = b2Vec2(200 / pixelsPerMeter, 200 / pixelsPerMeter)
fanBodyDef.type = b2_kinematicBody
fanBodyDef.angle = math.radians(0)
# Create the body of the fan
fanBody = world.CreateBody(fanBodyDef)
# Create a rectangular fan shape
fanShape = b2PolygonShape()
fanShape.SetAsBox(5 / pixelsPerMeter, 30 / pixelsPerMeter)
# Connect the fan body and the shape
fanFixtureDef = b2FixtureDef()
fanFixtureDef.shape = fanShape
# Fan density. This is analogous to mass.
fanFixtureDef.density = 0
fanFixture = fanBody.CreateFixture(fanFixtureDef)
fanFixture.userData = { "name": "fan" }
# Dictionary for storing pressed keys
keys = { "left": False, "right": False, "up": False, "down": False }
clock = pygame.time.Clock()
playerSpeed = 5
fanSpeed = 180
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
quit()
if event.type == pygame.KEYDOWN:
key = pygame.key.name(event.key)
keys[key] = True
if event.type == pygame.KEYUP:
key = pygame.key.name(event.key)
keys[key] = False
if keys["left"]:
playerBody.linearVelocity.x = -playerSpeed
if keys["right"]:
playerBody.linearVelocity.x = playerSpeed
if keys["up"]:
playerBody.linearVelocity.y = -playerSpeed
if keys["down"]:
playerBody.linearVelocity.y = playerSpeed
# Set the number of frames per second (60) and
# calculate the time interval between frames dt (~0.16)
dt = clock.tick(60) / 1000
# Set the angle of the fan
fanBody.angle += math.radians(fanSpeed * dt)
# Take physics simulation one step further
world.Step(dt, 3, 2)
# Stop the player
playerBody.linearVelocity = b2Vec2(0, 0)
# Fill the screen with black color
window.fill(0)
# Drawing colliders
world.DrawDebugData()
# Updating the display
pygame.display.flip()
if __name__ == '__main__':
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment