PRACTICA 3: COLISIONES.
Me base en el método SAT que estaba en los recursos, investigué un poco
mas y lo implemente al anterior de rotaciones.
Básicamente una vez separadas las figuras ya no puedo volver a juntarlas,
es una desventaja del método.
CÓDIGO FUENTE:
from OpenGL.GL import *
from OpenGL.GLU import *
from OpenGL.GLUT import *
import sys
import math
ShapeID = 0
jump = 0.05
rotation_jump = 15.0
rotations = {
1: 0.0, 2: 0.0, 3: 0.0, 4: 0.0,
5: 0.0, 6: 0.0, 7: 0.0
}
rotation_direction = 1
positions = {
1: [0.0, 0.0],
2: [0.0, 0.0],
3: [0.25, 0.25],
4: [0.0, 0.0],
5: [0.0, 0.0],
6: [-0.25, -0.25],
7: [0.5, 0.0]
}
shape_vertices = {}
shape_centroids = {}
def BlueTriangle():
inc = 0.5
vertices = [(0.0, 0.0), (-inc, inc), (inc, inc)]
centroid = (0.0, inc * 2/3)
glColor3f(0.0, 1.0, 1.0)
glBegin(GL_TRIANGLES)
for v in vertices: glVertex2f(*v)
glEnd()
return vertices, centroid
def RedTriangle():
inc = 0.5
vertices = [(0.0, 0.0), (-inc, -inc), (-inc, inc)]
centroid = (-inc * 2/3, 0.0)
glColor3f(1.0, 0.0, 0.0)
glBegin(GL_TRIANGLES)
for v in vertices: glVertex2f(*v)
glEnd()
return vertices, centroid
def GreenTriangle():
inc = 0.25
vertices = [(0.0, 0.0), (inc, inc), (inc, -inc)]
centroid = (inc * 2/3, 0.0)
glColor3f(0.0, 1.0, 0.0)
glBegin(GL_TRIANGLES)
for v in vertices: glVertex2f(*v)
glEnd()
return vertices, centroid
def YellowSquare():
inc = 0.25
vertices = [(0.0, 0.0), (inc, inc), (2.0 * inc, 0.0), (inc, -inc)]
centroid = ((0.0 + 2.0*inc)/2, (0.0 + 0.0)/2) # = (inc, 0.0)
glColor3f(1.0, 1.0, 0.0)
glBegin(GL_QUADS)
for v in vertices: glVertex2f(*v)
glEnd()
return vertices, centroid
def PinkTriangle():
inc = 0.25
vertices = [(0.0, 0.0), (inc, -inc), (-inc, -inc)]
centroid = (0.0, -inc * 2/3)
glColor3f(1.0, 0.0, 0.5)
glBegin(GL_TRIANGLES)
for v in vertices: glVertex2f(*v)
glEnd()
return vertices, centroid
def WhiteRhomboid():
inc = 0.25
vertices = [(0.0, 0.0), (2.0 * inc, 0.0), (inc, -inc), (-inc, -inc)]
centroid = ((0.0 + inc)/2, (0.0 - inc)/2) # (inc/2, -inc/2)
glColor3f(1.0, 1.0, 1.0)
glBegin(GL_QUADS)
for v in vertices: glVertex2f(*v)
glEnd()
return vertices, centroid
def NavyTriangle():
inc = 0.5
vertices = [(0.0, 0.0), (0.0, -inc), (-inc, -inc)]
centroid = (-inc / 3, -inc * 2/3) # Revisado
glColor3f(0.3, 0.6, 1.0)
glBegin(GL_TRIANGLES)
for v in vertices: glVertex2f(*v)
glEnd()
return vertices, centroid
def init_shapes():
global shape_vertices, shape_centroids
shape_vertices[1], shape_centroids[1] = BlueTriangle()
shape_vertices[2], shape_centroids[2] = RedTriangle()
shape_vertices[3], shape_centroids[3] = GreenTriangle()
shape_vertices[4], shape_centroids[4] = YellowSquare()
shape_vertices[5], shape_centroids[5] = PinkTriangle()
shape_vertices[6], shape_centroids[6] = WhiteRhomboid()
shape_vertices[7], shape_centroids[7] = NavyTriangle()
def GetCentroid(shape_id):
return shape_centroids.get(shape_id, (0.0, 0.0))
def DrawShape(shape_id):
if shape_id == 1: BlueTriangle()
elif shape_id == 2: RedTriangle()
elif shape_id == 3: GreenTriangle()
elif shape_id == 4: YellowSquare()
elif shape_id == 5: PinkTriangle()
elif shape_id == 6: WhiteRhomboid()
elif shape_id == 7: NavyTriangle()
def DrawScene():
glClear(GL_COLOR_BUFFER_BIT)
glMatrixMode(GL_MODELVIEW)
glLoadIdentity()
for shape_id, (x, y) in positions.items():
centroid_x, centroid_y = GetCentroid(shape_id)
glPushMatrix()
glTranslatef(x, y, 0.0)
glTranslatef(centroid_x, centroid_y, 0.0)
glRotatef(rotations[shape_id], 0.0, 0.0, 1.0)
glTranslatef(-centroid_x, -centroid_y, 0.0)
DrawShape(shape_id)
glPopMatrix()
glutSwapBuffers()
def get_transformed_vertices(shape_id, pos=None, rot=None):
if pos is None:
pos = positions[shape_id]
if rot is None:
rot = rotations[shape_id]
base_vertices = shape_vertices[shape_id]
centroid = shape_centroids[shape_id]
angle_rad = math.radians(rot)
cos_a = math.cos(angle_rad)
sin_a = math.sin(angle_rad)
transformed = []
for vx, vy in base_vertices:
vx_c = vx - centroid[0]
vy_c = vy - centroid[1]
vx_rot = vx_c * cos_a - vy_c * sin_a
vy_rot = vx_c * sin_a + vy_c * cos_a
vx_rc = vx_rot + centroid[0]
vy_rc = vy_rot + centroid[1]
final_x = vx_rc + pos[0]
final_y = vy_rc + pos[1]
transformed.append((final_x, final_y))
return transformed
def get_axes(vertices):
axes = []
for i in range(len(vertices)):
p1 = vertices[i]
p2 = vertices[(i + 1) % len(vertices)]
edge_x = p2[0] - p1[0]
edge_y = p2[1] - p1[1]
normal_x = -edge_y
normal_y = edge_x
mag = math.sqrt(normal_x**2 + normal_y**2)
if mag != 0:
axes.append((normal_x / mag, normal_y / mag))
return axes
def project_polygon(axis, vertices):
min_proj = float('inf')
max_proj = float('-inf')
for vx, vy in vertices:
projection = vx * axis[0] + vy * axis[1]
min_proj = min(min_proj, projection)
max_proj = max(max_proj, projection)
return min_proj, max_proj
def check_collision(shape_id1, shape_id2, pos1=None, rot1=None,
pos2=None, rot2=None):
verts1 = get_transformed_vertices(shape_id1, pos1, rot1)
verts2 = get_transformed_vertices(shape_id2, pos2, rot2)
axes1 = get_axes(verts1)
axes2 = get_axes(verts2)
for axis in axes1 + axes2:
min1, max1 = project_polygon(axis, verts1)
min2, max2 = project_polygon(axis, verts2)
if max1 < min2 or max2 < min1:
return False
return True
def handle_key(key, x, y):
global ShapeID, rotation_direction
if isinstance(key, bytes):
key = key.decode("utf-8")
if key.isdigit():
new_id = int(key)
if new_id in positions:
ShapeID = new_id
if ShapeID in positions:
if key == 'r':
potential_rotation = rotations[ShapeID] + rotation_direction *
rotation_jump
collides = False
for other_id in positions:
if other_id != ShapeID:
if check_collision(ShapeID, other_id, rot1=potential_rotation):
collides = True
break
if not collides:
rotations[ShapeID] = potential_rotation % 360 # Mantener en 0-
360
glutPostRedisplay()
elif key == 'd':
rotation_direction *= -1
def handle_special_key(key, x, y):
global ShapeID
if ShapeID in positions:
current_x, current_y = positions[ShapeID]
potential_x, potential_y = current_x, current_y
if key == GLUT_KEY_UP:
potential_y += jump
elif key == GLUT_KEY_DOWN:
potential_y -= jump
elif key == GLUT_KEY_RIGHT:
potential_x += jump
elif key == GLUT_KEY_LEFT:
potential_x -= jump
else:
return
potential_pos = [potential_x, potential_y]
collides = False
for other_id in positions:
if other_id != ShapeID:
if check_collision(ShapeID, other_id, pos1=potential_pos):
collides = True
break
if not collides:
positions[ShapeID] = potential_pos
glutPostRedisplay()
def init():
glClearColor(0.1, 0.1, 0.1, 1.0)
gluOrtho2D(-1.5, 1.5, -1.125, 1.125)
init_shapes()
def main():
glutInit(sys.argv)
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB)
glutInitWindowSize(800, 600)
glutCreateWindow(b"Tangram 2D")
init()
glutDisplayFunc(DrawScene)
glutKeyboardFunc(handle_key)
glutSpecialFunc(handle_special_key)
glutMainLoop()
if __name__ == "__main__":
main()