Skip to content

Instantly share code, notes, and snippets.

@decagondev
Created July 18, 2024 15:38
Show Gist options
  • Save decagondev/6b6814405401f630f562d761226f9068 to your computer and use it in GitHub Desktop.
Save decagondev/6b6814405401f630f562d761226f9068 to your computer and use it in GitHub Desktop.

Collisions

Box Collisions

Box collisions are an essential concept in game development, particularly when dealing with 2D physics. A box collision occurs when two boxes (game objects) overlap or intersect with each other in a game world. To handle box collisions, you typically follow these steps:

  1. Defining collision boxes: First, you need to define the collision boxes for your game objects. These boxes are usually rectangles or axially-aligned bounding boxes (AABBs) that enclose the objects. You can store the position (x, y), width, and height of each collision box.

  2. Checking for collisions: Next, you need to check for collisions between the boxes in your game world. You can do this by comparing the position and dimensions of each box. If two boxes overlap, you have a collision.

  3. Responding to collisions: After detecting a collision, you need to decide how your game objects should respond. This usually involves changing the objects' velocities or positions, playing sound effects, or triggering specific game events.

Here's a basic example of a box collision function in Python:

def check_collision(box1, box2):
    if box1['x'] < box2['x'] + box2['width'] and \
       box1['x'] + box1['width'] > box2['x'] and \
       box1['y'] < box2['y'] + box2['height'] and \
       box1['y'] + box1['height'] > box2['y']:
        return True
    else:
        return False

# Example game objects with collision boxes
object1 = {'x': 10, 'y': 10, 'width': 30, 'height': 30}
object2 = {'x': 25, 'y': 20, 'width': 20, 'height': 20}

# Check for collision between object1 and object2
if check_collision(object1, object2):
    print("Collision detected!")
else:
    print("No collision.")

In this example, the check_collision function checks if two boxes (game objects) overlap. You can use this function to detect collisions in your game and handle them accordingly.

Keep in mind that there are more sophisticated collision detection techniques, like sweep testing and separating axes theorem (SAT). However, the simple box collision method described here should be sufficient for many basic 2D games.

In the previous example, we used a simple method to check if two rectangles (game objects) overlap. However, this method has a limitation: it only works for axis-aligned bounding boxes (AABBs), which are rectangles that don't rotate and have their edges parallel to the x and y axes.

For more complex situations, such as rotated rectangles or circles, you'll need more advanced collision detection methods. One such method is the Separating Axis Theorem (SAT). SAT is a general-purpose method for detecting collisions between convex polygons (shapes with all angles less than 180 degrees) and other shapes like circles.

SAT Collisions

Here's a high-level overview of how SAT works for detecting collisions between two convex polygons:

  1. Find the normal vectors for each edge of the first polygon.
  2. For each normal vector, calculate the distance from the polygon's edges to the origin (0, 0). This creates a "projection" of the polygon onto the normal vector.
  3. Repeat the process for the second polygon.
  4. Compare the projections of the two polygons along each normal vector. If the projections don't overlap, there's no collision. If they do overlap, continue testing the other normal vectors.
  5. If none of the normal vectors separate the polygons, there's a collision.

While SAT can be more computationally expensive than simple AABB collisions, it's a powerful and versatile method for detecting collisions in games.

Another collision detection method for circles is to calculate the distance between their centers and check if it's smaller than the sum of their radii. If it is, the circles overlap, and there's a collision.

Now, let's revisit the original example using AABB collisions and add a rotation to one of the rectangles. We'll need to calculate the vertices of the rotated rectangle and check if any of them overlap with the other rectangle.

import math

def rotate_point(point, angle_in_radians):
    ox, oy = point
    ox_new = ox * math.cos(angle_in_radians) - oy * math.sin(angle_in_radians)
    oy_new = ox * math.sin(angle_in_radians) + oy * math.cos(angle_in_radians)
    return ox_new, oy_new

def check_collision(box1, box2):
    for x1, y1 in box1:
        for x2, y2 in box2:
            if x1 == x2 and y1 == y2:
                return True
    return False

object1 = {
    'x': 10, 'y': 10, 'width': 30, 'height': 30,
    'rotation': 0  # in radians
}
object2 = {
    'x': 25, 'y': 20, 'width': 20, 'height': 20,
    'rotation': 0  # in radians
}

vertices_object1 = [
    (object1['x'], object1['y']),
    (object1['x'] + object1['width'], object1['y']),
    (object1['x'] + object1['width'], object1['y'] + object1['height']),
    (object1['x'], object1['y'] + object1['height'])
]

for vertex in vertices_object1:
    rotated_vertex = rotate_point(vertex, object1['rotation'])
    vertices_object1[vertices_object1.index(vertex)] = rotated_vertex

if check_collision(vertices_object1, [
    (object2['x'], object2['y']),
    (object2['x'] + object2['width'], object2['y']),
    (object2['x'] + object2['width'], object2['y'] + object2['height']),
    (object2['x'], object2['y'] + object2['height'])
]):
    print("Collision detected!")
else:
    print("No collision.")

In this example, we've added a rotation Your reply: can you explain the rotation? Of course! In the provided code, we added a rotation to the first rectangle (object1). The rotation is defined in radians using the rotation` key in the object's dictionary.

To apply the rotation, we first calculate the vertices (corners) of the rectangle using its position, width, and height. Then, we use a function called rotate_point to rotate each vertex around the rectangle's center (which is at position x, y).

The rotate_point function takes two arguments: a point (a tuple of x and y coordinates) and an angle in radians. It calculates the new position of the point after rotating it by the given angle around the origin (0, 0). To make the rotation happen around the rectangle's center, we need to translate the rectangle's center to the origin, apply the rotation, and then translate it back to its original position.

In our example, we only perform the rotation and don't translate the points back since we want to check for collisions with the rotated rectangle.

After calculating the rotated vertices, we check for collisions using the same function as before (check_collision). However, since we are now dealing with rotated rectangles, we need to compare each rotated vertex of object1 with the vertices of object2.

In the check_collision function, we iterate over all vertices of the first rectangle and check if any of them have the same x and y coordinates as the vertices of the second rectangle. If there's at least one pair of matching vertices, the rectangles overlap, and a collision is detected.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment