Code: Select all
-- Variables para los polígonos
local polygons = {
-- Primer polígono
{
{200, 400},
{200, 250},
{560, 250},
{650, 400}
},
-- Segundo polígono (un triángulo)
{
{0, 400},
{200, 250},
{400, 500}
}
}
local playerDirection = 1 -- Inicialmente se mueve hacia la derecha
local playerVerticalDirection = 0 -- Inicialmente sin movimiento vertical
local lastRectY = 0 -- Para almacenar la última posición vertical del rectángulo
-- Variables para el rectángulo
local rectX, rectY = 260, 0 -- Empieza fuera de la pantalla
local rectW, rectH = 40, 60
local rectVelocityY = 0
local gravity = 500 -- Aceleración debida a la gravedad
local jumpForce = -600 -- Fuerza del salto
local moveSpeed = 200 -- Velocidad de movimiento horizontal
local collisionTolerance = 0 -- Tolerancia de colisión en píxeles
local isColliding = false -- Variable para controlar si hay colisión
local anclar = false
local saltando = false
-- Colores
local polygonColor = {0, 1, 0} -- Verde
local rectColor = {1, 0, 0} -- Rojo
local collisionColor = {1, 1, 0} -- Amarillo
-- Estado de las teclas
local keysPressed = {
left = false,
right = false,
jump = false
}
-- Inicializa LÖVE
function love.load()
-- Define el rectángulo y la gravedad
rectY = 0 -- Empieza desde arriba
rectVelocityY = 0
lastRectY = rectY -- Guarda la posición inicial
end
-- Actualiza la lógica del juego
function love.update(dt)
-- Verifica si se está presionando alguna tecla de movimiento
keysPressed.left = love.keyboard.isDown("left")
keysPressed.right = love.keyboard.isDown("right")
keysPressed.jump = love.keyboard.isDown("space")
if anclar then
moveSpeed = 250
end
if playerVerticalDirection == 0 then
gravity = 1500
end
-- Determina la dirección horizontal
if keysPressed.right then
playerDirection = 1
elseif keysPressed.left then
playerDirection = -1
else
playerDirection = 0
end
if anclar and playerDirection == 0 then
-- gravity = 0
end
-- Aplica la gravedad
rectVelocityY = rectVelocityY + gravity * dt
rectY = rectY + rectVelocityY * dt
-- Verifica colisión con todos los polígonos
local collides = false
for _, polygon in ipairs(polygons) do
local currentCollision, _ = rectCollidesWithPolygon(rectX, rectY, rectW, rectH, polygon)
if currentCollision then
collides = true
-- Ajusta la posición del rectángulo para evitar la colisión y posicionarlo en la arista con tolerancia
rectX, rectY = adjustPositionToEdge(rectX, rectY, rectW, rectH, polygon)
rectVelocityY = 0 -- Detener la velocidad vertical
isOnGround = true -- El rectángulo está en el suelo
playerVerticalDirection = 0 -- No se mueve verticalmente
anclar = true
break
end
end
if not collides then
isOnGround = false -- El rectángulo no está en el suelo
-- Determina la dirección vertical comparando la posición actual con la anterior
if rectY > lastRectY then
playerVerticalDirection = 1 -- Está cayendo
elseif rectY < lastRectY then
playerVerticalDirection = -1 -- Está subiendo
end
-- Nuevo bloque: Bajar 1 píxel hasta colisionar
if not keysPressed.jump and anclar then
-- gravity = 10000
moveSpeed = 0
for i = 1, 4 do
rectY = rectY + 1 -- Baja 1 píxel en cada iteración
collides = false
for _, polygon in ipairs(polygons) do
local currentCollision, _ = rectCollidesWithPolygon(rectX, rectY, rectW, rectH, polygon)
if currentCollision then
collides = true
rectX, rectY = adjustPositionToEdge(rectX, rectY, rectW, rectH, polygon)
rectVelocityY = 0
isOnGround = true
playerVerticalDirection = 0
break
end
end
if collides then
break
end
end
anclar = false
end
end
-- Mueve el rectángulo con las teclas de flecha si se está presionando alguna tecla
if playerDirection == 1 then
rectX = rectX + moveSpeed * dt
elseif playerDirection == -1 then
rectX = rectX - moveSpeed * dt
end
-- Realiza el salto si la barra espaciadora está presionada y el rectángulo está en el suelo
if keysPressed.jump and isOnGround then
rectVelocityY = jumpForce
isOnGround = false -- Después de saltar, el rectángulo ya no está en el suelo
playerVerticalDirection = -1 -- Empezar a subir
anclar = false
end
-- Actualiza la posición vertical anterior
lastRectY = rectY
end
-- Dibuja los objetos en la pantalla
function love.draw()
-- Dibuja todos los polígonos
love.graphics.setColor(polygonColor)
for _, polygon in ipairs(polygons) do
love.graphics.polygon("line", getPolygonVertices(polygon))
end
-- Dibuja el rectángulo
love.graphics.setColor(rectColor)
love.graphics.rectangle("line", rectX, rectY, rectW, rectH)
-- Si hay colisión, cambia el color del polígono y el rectángulo
if isColliding then
love.graphics.setColor(collisionColor)
for _, polygon in ipairs(polygons) do
love.graphics.polygon("line", getPolygonVertices(polygon))
end
love.graphics.rectangle("line", rectX, rectY, rectW, rectH)
end
-- Imprime las variables en pantalla
love.graphics.setColor(1, 1, 1) -- Cambia el color del texto a blanco
love.graphics.print("Player Direction: " .. playerDirection, 10, 10)
love.graphics.print("Player Vertical Direction: " .. playerVerticalDirection, 10, 30)
love.graphics.print("Anclado: " .. tostring(anclar), 10, 60)
end
-- Funciones auxiliares
function getPolygonVertices(polygon)
local vertices = {}
for _, v in ipairs(polygon) do
table.insert(vertices, v[1])
table.insert(vertices, v[2])
end
return vertices
end
function getRectangleVertices(rx, ry, rw, rh)
return {
{rx, ry},
{rx + rw, ry},
{rx + rw, ry + rh},
{rx, ry + rh}
}
end
function pointInPolygon(px, py, polygon)
local c = false
local j = #polygon
for i = 1, #polygon do
local vi = polygon[i]
local vj = polygon[j]
if ((vi[2] > py) ~= (vj[2] > py)) and (px < (vj[1] - vi[1]) * (py - vi[2]) / (vj[2] - vi[2]) + vi[1]) then
c = not c
end
j = i
end
return c
end
function rectCollidesWithPolygon(rx, ry, rw, rh, polygon)
local rectVertices = getRectangleVertices(rx, ry, rw, rh)
for _, vertex in ipairs(rectVertices) do
local px, py = vertex[1], vertex[2]
if pointInPolygon(px, py, polygon) then
return true, nil
end
end
for i = 1, #polygon do
local nextIndex = (i % #polygon) + 1
local x1, y1 = polygon[i][1], polygon[i][2]
local x2, y2 = polygon[nextIndex][1], polygon[nextIndex][2]
if rectEdgesIntersectPolygon(x1, y1, x2, y2, rx, ry, rw, rh, polygon) then
local normal = lineNormal(x1, y1, x2, y2)
return true, normal
end
end
return false, nil
end
function rectEdgesIntersectPolygon(x1, y1, x2, y2, rx, ry, rw, rh, polygon)
local rectEdges = {
{rx, ry, rx + rw, ry},
{rx + rw, ry, rx + rw, ry + rh},
{rx + rw, ry + rh, rx, ry + rh},
{rx, ry + rh, rx, ry}
}
for _, edge in ipairs(rectEdges) do
local ex1, ey1, ex2, ey2 = edge[1], edge[2], edge[3], edge[4]
for i = 1, #polygon do
local nextIndex = (i % #polygon) + 1
local px1, py1 = polygon[i][1], polygon[i][2]
local px2, py2 = polygon[nextIndex][1], polygon[nextIndex][2]
if linesIntersect(ex1, ey1, ex2, ey2, px1, py1, px2, py2) then
return true
end
end
end
return false
end
function linesIntersect(x1, y1, x2, y2, x3, y3, x4, y4)
local function ccw(Ax, Ay, Bx, By, Cx, Cy)
return (Cy - Ay) * (Bx - Ax) > (By - Ay) * (Cx - Ax)
end
return ccw(x1, y1, x3, y3, x4, y4) ~= ccw(x2, y2, x3, y3, x4, y4) and
ccw(x1, y1, x2, y2, x3, y3) ~= ccw(x1, y1, x2, y2, x4, y4)
end
-- Ajusta la posición del rectángulo sobre la arista del polígono con tolerancia
function adjustPositionToEdge(rectX, rectY, rectW, rectH, polygon)
local minDist = math.huge
local edgeX1, edgeY1, edgeX2, edgeY2
local closestVertex
-- Revisar cada arista del polígono
for i = 1, #polygon do
local nextIndex = (i % #polygon) + 1
local x1, y1 = polygon[i][1], polygon[i][2]
local x2, y2 = polygon[nextIndex][1], polygon[nextIndex][2]
-- Revisar cada vértice del rectángulo
for _, vertex in ipairs(getRectangleVertices(rectX, rectY, rectW, rectH)) do
local dist = pointToLineDistance(vertex[1], vertex[2], x1, y1, x2, y2)
if dist < minDist then
minDist = dist
edgeX1, edgeY1, edgeX2, edgeY2 = x1, y1, x2, y2
closestVertex = vertex
end
end
end
-- Calcular el punto de intersección en la arista con tolerancia
local normalX, normalY = lineNormal(edgeX1, edgeY1, edgeX2, edgeY2)
local overlap = minDist - collisionTolerance
-- Ajustar el rectángulo para que quede justo en la arista, con la tolerancia aplicada
return rectX - normalX * overlap, rectY - normalY * overlap
end
-- Calcula la distancia desde un punto a una línea
function pointToLineDistance(px, py, x1, y1, x2, y2)
local A = px - x1
local B = py - y1
local C = x2 - x1
local D = y2 - y1
local dot = A * C + B * D
local len_sq = C * C + D * D
local param = -1
if len_sq ~= 0 then
param = dot / len_sq
end
local xx, yy
if param < 0 then
xx, yy = x1, y1
elseif param > 1 then
xx, yy = x2, y2
else
xx = x1 + param * C
yy = y1 + param * D
end
local dx = px - xx
local dy = py - yy
return math.sqrt(dx * dx + dy * dy)
end
-- Calcula la normal de una línea y la longitud
function lineNormal(x1, y1, x2, y2)
local dx = x2 - x1
local dy = y2 - y1
local length = math.sqrt(dx * dx + dy * dy)
return -dy / length, dx / length
end