Last active
December 2, 2024 11:43
-
-
Save 8Observer8/0d79634a5b98fb8e86427e721429e16f to your computer and use it in GitHub Desktop.
PyBox2D collision detection using Pygame
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# 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