This is an alternative site for discovering Elm packages. You may be looking for the official Elm package site instead.
README

Collision2D

Detect collision/intersection of geometry in a defined 2D coordinate space AKA tell me when objects are touching or overlapping.

All objects use the same coordinate system you might see in an algebra or physics problem, origin (0,0) is at the center of the object, so they're compatible with the core Graphics.Collage coordinate system.

Basic geometry

type Rectangle = Rectangle { cx: Float, cy: Float, w : Float, h : Float }

Represents rectangular hitbox geometry.

rectangle : Float -> Float -> Float -> Float -> Rectangle

Create a Rectangle hitbox from coordinates (cx, cy) and geometry (width and height)

Arguments:

rectangle centerX centerY width height

Example:

rectangle 5 5 10 10
-- a 10 x 10 rectangle centered on coordinates 5,5
type Circle = Circle { cx: Float, cy: Float, radius : Float }

Represents circular geometry.

circle : Float -> Float -> Float -> Circle

Create a Circle Hitbox from from coordinates (cx, cy) and geometry (radius)

Arguments:

circle centerX centerY radius

Example:

circle 5 5 10 -- a radius 10 circle centered on coordinates 5,5

Rectangle to Rectangle Collision

axisAlignedBoundingBox : Rectangle -> Rectangle -> Bool

Super efficient collision detection between two Rectangles that are axis aligned — meaning no rotation.

rect1 = rectangle 5 5 10 10
rect2 = rectangle 7 5 10 10

axisAlignedBoundingBox rect1 rect2 -- True
-- rect1 is coliding with rect2
rectangleSide : Rectangle -> Rectangle -> Maybe Side

Very efficiently detect which side of a Rectangle is colliding with another Rectangle

rect1 = rectangle 5 5 10 10
rect2 = rectangle 7 5 10 10

rectangleSide rect1 rect2 -- Just Right
-- rect1 is coliding with it's right side onto rect2
type Side = Top | Right | Bottom | Left

Represents sides of a Rectangle

Circle to Circle Collision

circleToCircle : Circle -> Circle -> Bool

Super efficient collision detection between two Circles

circle1 = circle 5 5 5
circle2 = circle 7 5 5

circleToCircle circle1 circle2 -- True
-- circle1 is coliding with circle2
module Collision2D exposing
  ( axisAlignedBoundingBox
  , circleToCircle
  , Side(Top, Right, Bottom, Left)
  , rectangleSide
  , Rectangle
  , rectangle
  , Circle
  , circle
  )

{-| Detect collision/intersection of geometry in a defined 2D coordinate space
AKA tell me when objects are touching or overlapping.

All objects use the same coordinate system you might see in an algebra or
physics problem, origin (0,0) is at the center of the object,
so they're compatible with the core Graphics.Collage coordinate system.

# Basic geometry
@docs Rectangle, rectangle, Circle, circle

# Rectangle to Rectangle Collision
@docs axisAlignedBoundingBox, rectangleSide, Side

# Circle to Circle Collision
@docs circleToCircle
-}


{-| Represents rectangular hitbox geometry.
-}
type Rectangle = Rectangle { cx: Float, cy: Float, w : Float, h : Float }


{-| Create a Rectangle hitbox from coordinates (cx, cy) and geometry (width and height)

Arguments:

    rectangle centerX centerY width height

Example:

    rectangle 5 5 10 10
    -- a 10 x 10 rectangle centered on coordinates 5,5
-}
rectangle : Float -> Float -> Float -> Float -> Rectangle
rectangle centerX centerY width height =
  Rectangle { cx = centerX, cy = centerY, w = width, h = height }


{-| Represents circular geometry.
-}
type Circle = Circle { cx: Float, cy: Float, radius : Float }


{-| Create a Circle Hitbox from from coordinates (cx, cy) and geometry (radius)

Arguments:

    circle centerX centerY radius

Example:

    circle 5 5 10 -- a radius 10 circle centered on coordinates 5,5
-}
circle : Float -> Float -> Float -> Circle
circle centerX centerY radius =
  Circle { cx = centerX, cy = centerY, radius = radius }


{-| Super efficient collision detection between
two Rectangles that are axis aligned — meaning no rotation.

    rect1 = rectangle 5 5 10 10
    rect2 = rectangle 7 5 10 10

    axisAlignedBoundingBox rect1 rect2 -- True
    -- rect1 is coliding with rect2
-}
axisAlignedBoundingBox : Rectangle -> Rectangle -> Bool
axisAlignedBoundingBox (Rectangle rect1) (Rectangle rect2) =
  let
    startingPoint centerPoint length = centerPoint - (length / 2)
    x1 = startingPoint rect1.cx rect1.w
    x2 = startingPoint rect2.cx rect2.w
    y1 = startingPoint rect1.cy rect1.h
    y2 = startingPoint rect2.cy rect2.h
  in
    if x1 < x2 + rect2.w &&
       x1 + rect1.w > x2 &&
       y1 < y2 + rect2.h &&
       rect1.h + y1 > y2 then
      True
    else
      False


{-| Super efficient collision detection between two Circles

    circle1 = circle 5 5 5
    circle2 = circle 7 5 5

    circleToCircle circle1 circle2 -- True
    -- circle1 is coliding with circle2
-}
circleToCircle : Circle -> Circle -> Bool
circleToCircle (Circle circle1) (Circle circle2) =
  let
    dx = circle1.cx - circle2.cx
    dy = circle1.cy - circle2.cy
    distance = sqrt ((dx * dx) + (dy * dy))
  in
    if distance < circle1.radius + circle2.radius then
      True
    else
      False


{-| Represents sides of a Rectangle
-}
type Side
  = Top
  | Right
  | Bottom
  | Left


{-| Very efficiently detect which side of a Rectangle is colliding with another Rectangle

    rect1 = rectangle 5 5 10 10
    rect2 = rectangle 7 5 10 10

    rectangleSide rect1 rect2 -- Just Right
    -- rect1 is coliding with it's right side onto rect2
-}
rectangleSide : Rectangle -> Rectangle -> Maybe Side
rectangleSide (Rectangle rect1) (Rectangle rect2) =
  {-
    Calculate which side of a rectangle is colliding w/ another, it works by
    getting the Minkowski sum of rect2 and rect1, then checking where the centre of
    rect1 lies relatively to the new rectangle (from Minkowski) and to its diagonals
    * thanks to sam hocevar @samhocevar for the formula!
  -}
  let
    w = 0.5 * (rect1.w + rect2.w)
    h = 0.5 * (rect1.h + rect2.h)
    dx = rect2.cx - rect1.cx
    dy = rect2.cy - rect1.cy
    wy = w * dy
    hx = h * dx

  in
    if abs dx <= w && abs dy <= h then
      if (wy > hx) then
        if (wy > -hx) then
          Just Top
        else
          Just Left
      else
        if (wy > -hx) then
          Just Right
        else
          Just Bottom
    else
      Nothing