Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- // Math utility object, define these in terms of libgdx or whatever
- object MathU {
- def sqrt(a: Float) = Math.sqrt(a).toFloat
- def cos(theta: Float) = Math.cos(theta).toFloat
- def sin(theta: Float) = Math.sin(theta).toFloat
- def min(a: Float, b: Float) = if (a < b) a else b
- def max(a: Float, b: Float) = if (a > b) a else b
- def minmax(values: List[Float]): Tuple2[Float, Float] = {
- def f(v: List[Float], mini: Float, maxi: Float): Tuple2[Float, Float] = v match {
- case Nil => (mini, maxi)
- case x :: xs => f(xs, min(x, mini), max(x, maxi))
- }
- f(values.tail, values.head, values.head)
- }
- def clamp(v: Float, a: Float, b: Float) = v match {
- case x if (x < a) => a
- case x if (x > b) => b
- case _ => v
- }
- }
- import MathU._
- class Vec(var x: Float, var y: Float) {
- def +(that: Vec) = Vec(x+that.x, y+that.y)
- def -(that:Vec) = Vec(x-that.x, y-that.y)
- def *(s: Float) = Vec(s*x, s*y)
- def *(that: Vec) = Vec(x*that.x, y*that.y)
- def dot(that:Vec) = that.x*x + that.y*y
- def normal = Vec(y, -x).normalize
- def length = sqrt(x*x+y*y)
- def normalize = this * (1/length)
- def proj(b: Vec) = b * ((this dot b)/(b dot b))
- def rej(b: Vec) = this - proj(b)
- //Destructive variants, saves the resulting vector in the current vector
- def +!(that: Vec) = {
- x += that.x
- y += that.y
- }
- def -!(that: Vec) = {
- x -= that.x
- y -= that.y
- }
- def *!(s: Float) = {
- x *= s
- y *= s
- }
- def *!(that: Vec) = {
- x *= that.x
- y *= that.y
- }
- def normalize_! = this *! (1/length)
- override def toString = "[" + x + " " + y + "]"
- }
- object Vec{
- def apply(x: Float, y: Float) = new Vec(x,y)
- val i = new Vec(1, 0)
- val j = new Vec(0, 1)
- }
- class Mat(private val arr: Array[Float]){
- def apply(i: Int, j: Int) = arr(i+j*3)
- def update(i: Int, j: Int, f: Float) = {
- arr(i+j*3) = f
- }
- def +(that: Mat) = Mat(this(0,0)+that(0,0), this(1,0)+that(1,0), this(2,0)+that(2,0),
- this(0,1)+that(0,1), this(1,1)+that(1,1), this(2,1)+that(2,1),
- this(0,2)+that(0,2), this(1,2)+that(1,2), this(2,2)+that(2,2))
- def *(s: Float) = Mat(this(0,0)*s, this(1,0)*s, this(2,0)*s,
- this(0,1)*s, this(1,1)*s, this(2,1)*s,
- this(0,2)*s, this(1,2)*s, this(2,2)*s)
- def *(v: Vec) = Vec(this(0,0)*v.x + this(1,0)*v.y+this(2,0), this(0,1)*v.x + this(1,1)*v.y+this(1,2))
- def *(that: Mat) = Mat(this(0,0)*that(0,0) + this(1,0)*that(0,1) + this(2,0)*that(0,2),
- this(0,0)*that(1,0) + this(1,0)*that(1,1) + this(2,0)*that(1,2),
- this(0,0)*that(2,0) + this(1,0)*that(2,1) + this(2,0)*that(2,2),
- this(0,1)*that(0,0) + this(1,1)*that(0,1) + this(2,1)*that(0,2),
- this(0,1)*that(1,0) + this(1,1)*that(1,1) + this(2,1)*that(1,2),
- this(0,1)*that(2,0) + this(1,1)*that(2,1) + this(2,1)*that(2,2),
- this(0,2)*that(0,0) + this(1,2)*that(0,1) + this(2,2)*that(0,2),
- this(0,2)*that(1,0) + this(1,2)*that(1,1) + this(2,2)*that(1,2),
- this(0,2)*that(2,0) + this(1,2)*that(2,1) + this(2,2)*that(2,2))
- //Destructive variants, saves the resulting matrix in the current matrix
- def +!(that: Mat) = {
- this(0,0) += that(0,0); this(1,0) += that(1,0); this(2,0) += that(2,0)
- this(0,1) += that(0,1); this(1,1) += that(1,1); this(2,1) += that(2,1)
- this(0,2) += that(0,2); this(1,2) += that(1,2); this(2,2) += that(2,2)
- }
- def *!(s: Float) = {
- this(0,0) *= s; this(1,0) *= s; this(2,0) *= s
- this(0,1) *= s; this(1,1) *= s; this(2,1) *= s
- this(0,2) *= s; this(1,2) *= s; this(2,2) *= s
- }
- // Saves result into the vector
- def *!(v: Vec) = {
- v.x = this(0,0)*v.x + this(1,0)*v.y + this(2,0)
- v.y = this(0,1)*v.x + this(1,1)*v.y + this(1,2)
- }
- def *!(that: Mat) = {
- this(0,0) = this(0,0)*that(0,0) + this(1,0)*that(0,1) + this(2,0)*that(0,2)
- this(1,0) = this(0,0)*that(1,0) + this(1,0)*that(1,1) + this(2,0)*that(1,2)
- this(2,0) = this(0,0)*that(2,0) + this(1,0)*that(2,1) + this(2,0)*that(2,2)
- this(0,0) = this(0,1)*that(0,0) + this(1,1)*that(0,1) + this(2,1)*that(0,2)
- this(1,0) = this(0,1)*that(1,0) + this(1,1)*that(1,1) + this(2,1)*that(1,2)
- this(2,0) = this(0,1)*that(2,0) + this(1,1)*that(2,1) + this(2,1)*that(2,2)
- this(0,0) = this(0,2)*that(0,0) + this(1,2)*that(0,1) + this(2,2)*that(0,2)
- this(1,0) = this(0,2)*that(1,0) + this(1,2)*that(1,1) + this(2,2)*that(1,2)
- this(2,0) = this(0,2)*that(2,0) + this(1,2)*that(2,1) + this(2,2)*that(2,2)
- }
- override def toString = "[" + arr(0) + " " + arr(1) + " " + arr(2) + " | " +
- arr(3) + " " + arr(4) + " " + arr(5) + " | " +
- arr(6) + " " + arr(7) + " " + arr(8) + "]"
- }
- object Mat{
- def apply(m00: Float, m10: Float, m20: Float,
- m01: Float, m11: Float, m21: Float,
- m02: Float, m12: Float, m22: Float): Mat = new Mat(Array(m00, m10, m20, m01, m11, m21, m02, m12, m22))
- def apply(arr: Array[Float]): Mat = if (arr.size == 9) new Mat(arr) else I
- //Transformation matrices, compose transformations out of these
- val I = Mat(1, 0, 0, 0, 1, 0, 0, 0, 1)
- def translate(x: Float, y: Float) = Mat(1, 0, x, 0, 1, y, 0, 0, 1)
- def scale(w: Float, h: Float) = Mat(w, 0, 0, 0, h, 0, 0, 0, 1)
- def rotate(theta: Float) = {val c = cos(theta); val s = sin(theta); Mat(c, -s, 0, s, c, 0, 0, 0, 1)}
- def shear(x: Float, y: Float) = Mat(1, x, 0, y, 1, 0, 0, 0, 1)
- def reflect(v: Vec) = {val n = v.normalize; Mat(n.x*n.x-n.y*n.y, 2*n.x*n.y, 0, 2*n.x*n.y, n.y*n.y-n.x*n.x, 0, 0, 0, 1)}
- def project(v: Vec) = {val n = v.normalize; Mat(n.x*n.x, n.x*n.y, 0, n.x*n.y, n.y*n.y, 0, 0, 0, 1)}
- }
- import MathU._
- sealed abstract class Shape
- case class Point(p: Vec) extends Shape
- case class Circle(p: Vec, r: Float) extends Shape
- case class AABB(p: Vec, w: Float, h: Float) extends Shape
- case class Polygon(p: Vec, vertices: List[Vec], normals: List[Vec]) extends Shape
- object Polygon{
- def apply(p: Vec, vs: List[Vec]): Polygon = new Polygon(p, vs,
- getNormals(vs.head, vs.tail, (vs.head-vs(1)).normal :: Nil) reverse)
- def getNormals(f: Vec, vs: List[Vec], r: List[Vec]): List[Vec] = vs match {
- case x :: Nil => (f-x).normal :: r
- case x :: xs => getNormals(f, xs, (xs.head-x).normal :: r)
- }
- }
- object CollisionQ{
- // ORTHOGONAL PROJETION OF A VECTOR v ON A LINE DESCRIBED BY A VECTOR l
- // v dot l
- // p = ------- * l or p = (v dot l) * l if l is a unit vector
- // l dot l
- // All projection vectors should be normalized for these functions to work
- //Scalar shadows, shadow(a, l)*l would be the cartesian vector
- def shadow(p: Point, line: Vec) = {
- val po = p.p dot line
- (po, po)
- }
- def shadow(cir: Circle, line: Vec) = {
- val po = cir.p dot line
- (-cir.r + po, +cir.r + po)
- }
- def shadow(box: AABB, line: Vec) = {
- val s = minmax(List((box.p.x+box.w)*line.x+(box.p.y+box.h)*line.y,
- (box.p.x-box.w)*line.x+(box.p.y+box.h)*line.y,
- (box.p.x+box.w)*line.x+(box.p.y-box.h)*line.y,
- (box.p.x-box.w)*line.x+(box.p.y-box.h)*line.y))
- val po = box.p dot line
- (s._1 + po, s._2 + po)
- }
- def shadow(poly: Polygon, line: Vec) = {
- val s = minmax(poly.vertices map (a => a dot line))
- val po = poly.p dot line
- (s._1 + po, s._2 + po)
- }
- //Tests if two shadows intersect
- def between(f: Float, r: Tuple2[Float, Float]) = (r._1 < f) && (f < r._2)
- def intersects(a: Tuple2[Float, Float], b: Tuple2[Float, Float]) = between(a._1, b) || between(b._1, a)
- //Tests for intersection
- def collides(p: Point, p2: Point): Boolean = (p.p.x == p2.p.x && p.p.y == p2.p.y)
- def collides(p: Point, c: Circle): Boolean = {
- val dist = p.p - c.p
- dist.x*dist.x + dist.y*dist.y < c.r*c.r
- }
- def collides(p: Point, b: AABB): Boolean = {
- val diff = p.p - b.p
- (diff.x < b.w) && (diff.y < b.h)
- }
- def collides(p: Point, po: Polygon): Boolean = po.normals forall (n => between(p.p dot n, shadow(po, n)))
- def collides(b: AABB, b2: AABB): Boolean = {
- val diff = b.p - b2.p
- (diff.x < b.w+b2.w) && (diff.y < b.h+b2.h)
- }
- def collides(b: AABB, c: Circle): Boolean = {
- val x = clamp(c.p.x, b.p.x-b.w, b.p.x+b.w)
- val y = clamp(c.p.y, b.p.y-b.h, b.p.y+b.h)
- x*x+y*y < c.r*c.r
- }
- def collides(b: AABB, po: Polygon): Boolean = {
- val p = b.p; val w = b.w; val h = b.h
- collides(Polygon(p, Vec(w, h) :: Vec(-w, h) :: Vec(-w, -h) :: Vec(w, -h) :: Nil), po)
- }
- def collides(c: Circle, c2: Circle): Boolean = {
- val dist = c.p - c2.p; val rs = c.r+c2.r
- dist.x*dist.x + dist.y*dist.y < rs*rs
- }
- def collides(c: Circle, po: Polygon): Boolean = {
- def voronoi(p: Vec, poly: Polygon) = {
- def d2(a: Vec, b: Vec) = {
- val x = (a.x-b.x)
- val y = (a.y-b.y)
- x*x+y*y
- }
- var closest = poly.vertices.head + poly.p
- var cd2 = d2(closest, p)
- for(v <- poly.vertices.tail) {
- val vd2 = d2(v + poly.p, p)
- if(vd2 < cd2) {
- closest = v + poly.p
- cd2 = vd2
- }
- }
- closest
- }
- val sep = po.p - c.p
- def f(ns: List[Vec]): Boolean = ns match{
- case Nil => true
- case x :: xs => {
- val sp = sep dot x
- val sa = shadow(c, x)
- if(intersects((sa._1 + sp, sa._2 + sp), shadow(po, x))) f(xs) else false
- }
- }
- f(po.normals) && {val sep = voronoi(c.p, po) - po.p
- sep.normalize_!
- f(sep :: Nil)}
- }
- def collides(po: Polygon, po2: Polygon): Boolean = {
- val sep = po2.p - po.p
- def f(ns: List[Vec]): Boolean = ns match {
- case Nil => true
- case x :: xs => {
- val sp = sep dot x
- val sa = shadow(po, x)
- if (intersects( (sa._1 + sp, sa._2 + sp) , shadow(po2, x))) f(xs) else false
- }
- }
- f(po.normals) && f(po2.normals)
- }
- def collides(a: Shape, b: Shape): Boolean = (a, b) match {
- case(a: Point, b: Point) => collides(a,b)
- case(a: Point, b: Circle) => collides(a,b)
- case(a: Point, b: AABB) => collides(a,b)
- case(a: Point, b: Polygon) => collides(a,b)
- case(a: AABB, b: AABB) => collides(a,b)
- case(a: AABB, b: Circle) => collides(a,b)
- case(a: AABB, b: Polygon) => collides(a,b)
- case(a: Circle, b: Circle) => collides(a,b)
- case(a: Circle, b: Polygon) => collides(a,b)
- case(a: Polygon, b: Polygon) => collides(a,b)
- case(a, b) => collides(b,a)
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement