get player to react to wall quad tree

This commit is contained in:
2024-12-13 22:48:34 +00:00
parent 9d42e14b2f
commit 9144c97fba
6 changed files with 741 additions and 308 deletions

View File

@@ -5,53 +5,100 @@ struct
(* width/height *) (* width/height *)
val size = 35 val size = 35
val realSize = 35.0
val moveBy = 5 val moveBy = 5
val jumpLimit = 55 val jumpLimit = 150
type t = {yAxis: y_axis, xAxis: x_axis, health: int, x: int, y: int} type t = {yAxis: y_axis, xAxis: x_axis, health: int, x: int, y: int}
(* placeholder *)
val initial: t =
{yAxis = JUMPING 0, xAxis = STAY_STILL, health = 3, x = 500, y = 500}
(* placeholder *)
fun getVec ({x, y, ...}: t) =
Block.lerp (x, y, realSize, realSize, 1920.0, 1080.0, 0.5, 0.5, 0.5)
fun mkPlayer (health, xAxis, yAxis, x, y) = fun mkPlayer (health, xAxis, yAxis, x, y) =
{yAxis = yAxis, xAxis = xAxis, health = health, x = x, y = y} {yAxis = yAxis, xAxis = xAxis, health = health, x = x, y = y}
fun move (player: t) = fun checkWalls (yAxis, xAxis, x, y, health, lst) =
let let
val {yAxis, xAxis, x, y, health} = player open QuadTree
in
case lst of
(QUERY_ON_LEFT_SIDE, wallID) :: tl =>
let
val {x = wallX, width = wallWidth, ...} = Wall.getID wallID
val newX = wallX + wallWidth
in
checkWalls (yAxis, xAxis, newX, y, health, tl)
end
| (QUERY_ON_RIGHT_SIDE, wallID) :: tl =>
let
val {x = wallX, width = wallWidth, ...} = Wall.getID wallID
val newX = wallX - size
in
checkWalls (yAxis, xAxis, newX, y, health, tl)
end
| (QUERY_ON_BOTTOM_SIDE, wallID) :: tl =>
let
val {y = wallY, ...} = Wall.getID wallID
val newY = wallY - size
in
checkWalls (yAxis, xAxis, x, newY, health, tl)
end
| (QUERY_ON_TOP_SIDE, wallID) :: tl =>
checkWalls (yAxis, xAxis, x, y, health, tl)
| [] => mkPlayer (health, xAxis, yAxis, x, y)
end
(* todo: check for wall and platform collisions fun move ({x, y, xAxis, yAxis, health}: t) =
* in case analysis for both axis let
* *) (* check against wall quad tree *)
val x = val desiredX =
case xAxis of case xAxis of
MOVE_LEFT => STAY_STILL => x
(* todo: check if we are trying to move left | MOVE_LEFT => x - moveBy
* even though player is against wall. | MOVE_RIGHT => x + moveBy
* In that case, keep same action (it is a sign for us to animate),
* but don't actually move leftwards. *)
x - moveBy
| MOVE_RIGHT => (* todo: check against wall *) x + moveBy
| STAY_STILL => x
in in
case yAxis of case yAxis of
JUMPING jumped => ON_GROUND =>
(* check if we hit jump limit; let
* if we did, change to falling case. val collisions = QuadTree.getCollisionSides
* *) (desiredX, y, size, size, 0, 0, 1920, 1080, 0, Wall.tree)
if jumped + moveBy <= jumpLimit then in
checkWalls (yAxis, xAxis, desiredX, y, health, collisions)
end
| FALLING =>
let
val desiredY = y + moveBy
val collisions = QuadTree.getCollisionSides
(desiredX, desiredY, size, size, 0, 0, 1920, 1080, 0, Wall.tree)
in
checkWalls (yAxis, xAxis, desiredX, desiredY, health, collisions)
end
| JUMPING jumped =>
if jumped + moveBy > jumpLimit then
(* if we are above the jump limit, trigger a fall *)
let let
val jumped = jumped + moveBy val collisions = QuadTree.getCollisionSides
val yAxis = JUMPING jumped (desiredX, y, size, size, 0, 0, 1920, 1080, 0, Wall.tree)
val y = y + moveBy
in in
mkPlayer (health, xAxis, yAxis, x, y) checkWalls (FALLING, xAxis, desiredX, y, health, collisions)
end end
else else
mkPlayer (health, xAxis, FALLING, x, y) (* jump *)
| FALLING => let
(* todo: keep decrementing and falling down val newJumped = jumped + moveBy
* until we hit ground or platform val yAxis = JUMPING newJumped
* *) val desiredY = y - moveBy
mkPlayer (health, xAxis, yAxis, x, y - moveBy)
| ON_GROUND => mkPlayer (health, xAxis, yAxis, x, y) val collisions = QuadTree.getCollisionSides
(desiredX, desiredY, size, size, 0, 0, 1920, 1080, 0, Wall.tree)
in
checkWalls (yAxis, xAxis, desiredX, desiredY, health, collisions)
end
end end
end end

View File

@@ -8,20 +8,18 @@ sig
| QUERY_ON_RIGHT_SIDE | QUERY_ON_RIGHT_SIDE
| QUERY_ON_BOTTOM_SIDE | QUERY_ON_BOTTOM_SIDE
val insert : int * int * int * int * val insert: int * int * int * int * int * int * int * int * int * t -> t
int * int * int * int *
int * t -> t
val getCollisions : int * int * int * int * val fromItem: int * int * int * int * int -> t
int * int * int * int *
int * t -> int list
val getCollisionSides : int * int * int * int * val getCollisions: int * int * int * int * int * int * int * int * int * t
int * int * int * int * -> int list
int * t -> (collision_side * int) list
val getCollisionSides: int * int * int * int * int * int * int * int * int * t
-> (collision_side * int) list
end end
structure QuadTree : QUAD_TREE = structure QuadTree: QUAD_TREE =
struct struct
type item = {itemID: int, startX: int, startY: int, width: int, height: int} type item = {itemID: int, startX: int, startY: int, width: int, height: int}
@@ -43,6 +41,14 @@ struct
} }
| LEAF of item vector | LEAF of item vector
fun fromItem (itemID, startX, startY, width, height) =
let
val item = mkItem (itemID, startX, startY, width, height)
val elements = Vector.fromList [item]
in
LEAF elements
end
(* max size of vector before we split it further *) (* max size of vector before we split it further *)
val maxSize = 3 val maxSize = 3
@@ -68,23 +74,47 @@ struct
val middleY = quadY + halfHeight val middleY = quadY + halfHeight
val isInTopLeft = isItemInQuad val isInTopLeft = isItemInQuad
( itemX, itemY, itemWidth, itemHeight ( itemX
, quadX, quadY, halfWidth, halfHeight , itemY
, itemWidth
, itemHeight
, quadX
, quadY
, halfWidth
, halfHeight
) )
val isInTopRight = isItemInQuad val isInTopRight = isItemInQuad
( itemX, itemY, itemWidth, itemHeight ( itemX
, middleX, quadY, halfWidth, halfHeight , itemY
, itemWidth
, itemHeight
, middleX
, quadY
, halfWidth
, halfHeight
) )
val isInBottomLeft = isItemInQuad val isInBottomLeft = isItemInQuad
( itemX, itemY, itemWidth, itemHeight ( itemX
, quadX, middleY, halfWidth, halfHeight , itemY
, itemWidth
, itemHeight
, quadX
, middleY
, halfWidth
, halfHeight
) )
val isInBottomRight = isItemInQuad val isInBottomRight = isItemInQuad
( itemX, itemY, itemWidth, itemHeight ( itemX
, middleX, middleY, halfWidth, halfHeight , itemY
, itemWidth
, itemHeight
, middleX
, middleY
, halfWidth
, halfHeight
) )
in in
if isInTopLeft then TOP_LEFT if isInTopLeft then TOP_LEFT
@@ -135,9 +165,16 @@ struct
end end
fun insert fun insert
( itemX, itemY, itemWidth, itemHeight ( itemX
, quadX, quadY, quadWidth, quadHeight , itemY
, itemID, tree: t , itemWidth
, itemHeight
, quadX
, quadY
, quadWidth
, quadHeight
, itemID
, tree: t
) = ) =
case tree of case tree of
NODE {topLeft, topRight, bottomLeft, bottomRight, elements} => NODE {topLeft, topRight, bottomLeft, bottomRight, elements} =>
@@ -146,8 +183,14 @@ struct
* Else, add to elements vector in current node. *) * Else, add to elements vector in current node. *)
(case (case
whichQuadrant whichQuadrant
( itemX, itemY, itemWidth, itemHeight ( itemX
, quadX, quadY, quadWidth, quadHeight , itemY
, itemWidth
, itemHeight
, quadX
, quadY
, quadWidth
, quadHeight
) )
of of
TOP_LEFT => TOP_LEFT =>
@@ -160,9 +203,16 @@ struct
val halfHeight = quadHeight div 2 val halfHeight = quadHeight div 2
val newTopLeft = insert val newTopLeft = insert
( itemX, itemY, itemWidth, itemHeight ( itemX
, quadX, quadY, halfWidth, halfHeight , itemY
, itemID, topLeft , itemWidth
, itemHeight
, quadX
, quadY
, halfWidth
, halfHeight
, itemID
, topLeft
) )
in in
NODE NODE
@@ -180,9 +230,16 @@ struct
val middleX = quadX + halfWidth val middleX = quadX + halfWidth
val newTopRight = insert val newTopRight = insert
( itemX, itemY, itemWidth, itemHeight ( itemX
, middleX, quadY, halfWidth, halfHeight , itemY
, itemID, topRight , itemWidth
, itemHeight
, middleX
, quadY
, halfWidth
, halfHeight
, itemID
, topRight
) )
in in
NODE NODE
@@ -200,9 +257,16 @@ struct
val middleY = quadY + halfHeight val middleY = quadY + halfHeight
val newBottomLeft = insert val newBottomLeft = insert
( itemX, itemY, itemWidth, itemHeight ( itemX
, quadX, middleY, halfWidth, halfHeight , itemY
, itemID, bottomLeft , itemWidth
, itemHeight
, quadX
, middleY
, halfWidth
, halfHeight
, itemID
, bottomLeft
) )
in in
NODE NODE
@@ -221,9 +285,16 @@ struct
val middleY = quadY + halfHeight val middleY = quadY + halfHeight
val newBottomRight = insert val newBottomRight = insert
( itemX, itemY, itemWidth, itemHeight ( itemX
, middleX, middleY, halfWidth, halfHeight , itemY
, itemID, bottomRight , itemWidth
, itemHeight
, middleX
, middleY
, halfWidth
, halfHeight
, itemID
, bottomRight
) )
in in
NODE NODE
@@ -258,39 +329,85 @@ struct
in in
(case (case
whichQuadrant whichQuadrant
( itemX, itemY, itemWidth, itemHeight ( itemX
, quadX, quadY, quadWidth, quadHeight , itemY
, itemWidth
, itemHeight
, quadX
, quadY
, quadWidth
, quadHeight
) )
of of
TOP_LEFT => TOP_LEFT =>
splitLeaf splitLeaf
( quadX, quadY, quadWidth, quadHeight ( quadX
, [item], [], [], [], [] , quadY
, elements, pos , quadWidth
, quadHeight
, [item]
, []
, []
, []
, []
, elements
, pos
) )
| TOP_RIGHT => | TOP_RIGHT =>
splitLeaf splitLeaf
( quadX, quadY, quadWidth, quadHeight ( quadX
, [], [item], [], [], [] , quadY
, elements, pos , quadWidth
, quadHeight
, []
, [item]
, []
, []
, []
, elements
, pos
) )
| BOTTOM_LEFT => | BOTTOM_LEFT =>
splitLeaf splitLeaf
( quadX, quadY, quadWidth, quadHeight ( quadX
, [], [], [item], [], [] , quadY
, elements, pos , quadWidth
, quadHeight
, []
, []
, [item]
, []
, []
, elements
, pos
) )
| BOTTOM_RIGHT => | BOTTOM_RIGHT =>
splitLeaf splitLeaf
( quadX, quadY, quadWidth, quadHeight ( quadX
, [], [], [], [item], [] , quadY
, elements, pos , quadWidth
, quadHeight
, []
, []
, []
, [item]
, []
, elements
, pos
) )
| PARENT_QUADRANT => | PARENT_QUADRANT =>
splitLeaf splitLeaf
( quadX, quadY, quadWidth, quadHeight ( quadX
, [], [], [], [], [item] , quadY
, elements, pos , quadWidth
, quadHeight
, []
, []
, []
, []
, [item]
, elements
, pos
)) ))
end end
else else
@@ -310,11 +427,8 @@ struct
val endX = startX + width val endX = startX + width
val endY = startY + height val endY = startY + height
in in
iX < endX iX < endX andalso itemEndX > startX andalso iY < endY
andalso itemEndX > startX andalso itemEndY > startY andalso itemID <> checkID
andalso iY < endY
andalso itemEndY > startY
andalso itemID <> checkID
end end
fun getCollisionsVec (iX, iY, iW, iH, itemID, pos, elements, acc) = fun getCollisionsVec (iX, iY, iW, iH, itemID, pos, elements, acc) =
@@ -324,97 +438,124 @@ struct
let let
val item = Vector.sub (elements, pos) val item = Vector.sub (elements, pos)
val acc = val acc =
if isColliding (iX, iY, iW, iH, itemID, item) if isColliding (iX, iY, iW, iH, itemID, item) then #itemID item :: acc
then #itemID item :: acc
else acc else acc
in in
getCollisionsVec (iX, iY, iW, iH, itemID, pos + 1, elements, acc) getCollisionsVec (iX, iY, iW, iH, itemID, pos + 1, elements, acc)
end end
fun getCollisionsAll fun getCollisionsAll (iX, iY, iW, iH, qW, qH, itemID, acc, tree) =
( iX, iY, iW, iH, qW, qH
, itemID, acc, tree
) =
case tree of case tree of
NODE {topLeft, topRight, bottomLeft, bottomRight, elements} => NODE {topLeft, topRight, bottomLeft, bottomRight, elements} =>
let let
val acc = val acc = getCollisionsVec (iX, iY, iW, iH, itemID, 0, elements, acc)
getCollisionsVec (iX, iY, iW, iH, itemID, 0, elements, acc)
val halfWidth = qW div 2 val halfWidth = qW div 2
val halfHeight = qH div 2 val halfHeight = qH div 2
val acc = val acc = getCollisionsAll
getCollisionsAll (iX, iY, iW, iH, halfWidth, halfHeight, itemID, acc, topLeft)
( iX, iY, iW, iH, halfWidth, halfHeight
, itemID, acc, topLeft
)
val acc = val acc = getCollisionsAll
getCollisionsAll (iX, iY, iW, iH, halfWidth, halfHeight, itemID, acc, topRight)
( iX, iY, iW, iH, halfWidth, halfHeight
, itemID, acc, topRight
)
val acc = val acc = getCollisionsAll
getCollisionsAll (iX, iY, iW, iH, halfWidth, halfHeight, itemID, acc, bottomLeft)
( iX, iY, iW, iH, halfWidth, halfHeight
, itemID, acc, bottomLeft
)
in in
getCollisionsAll getCollisionsAll
( iX, iY, iW, iH, halfWidth, halfWidth (iX, iY, iW, iH, halfWidth, halfWidth, itemID, acc, bottomRight)
, itemID, acc, bottomRight
)
end end
| LEAF elements => | LEAF elements =>
getCollisionsVec (iX, iY, iW, iH, itemID, 0, elements, acc) getCollisionsVec (iX, iY, iW, iH, itemID, 0, elements, acc)
fun helpGetCollisions fun helpGetCollisions
( itemX, itemY, itemWidth, itemHeight ( itemX
, quadX, quadY, quadWidth, quadHeight , itemY
, itemID, acc, tree: t , itemWidth
, itemHeight
, quadX
, quadY
, quadWidth
, quadHeight
, itemID
, acc
, tree: t
) = ) =
case tree of case tree of
NODE {topLeft, topRight, bottomLeft, bottomRight, elements} => NODE {topLeft, topRight, bottomLeft, bottomRight, elements} =>
let let
(* get colliding elements in this node first *) (* get colliding elements in this node first *)
val acc = val acc = getCollisionsVec
getCollisionsVec (itemX, itemY, itemWidth, itemHeight, itemID, 0, elements, acc)
( itemX, itemY, itemWidth, itemHeight
, itemID, 0, elements, acc
)
val halfWidth = quadWidth div 2 val halfWidth = quadWidth div 2
val halfHeight = quadHeight div 2 val halfHeight = quadHeight div 2
in in
(case whichQuadrant (case
( itemX, itemY, itemWidth, itemHeight whichQuadrant
, quadX, quadY, quadWidth, quadHeight ( itemX
) , itemY
, itemWidth
, itemHeight
, quadX
, quadY
, quadWidth
, quadHeight
)
of of
TOP_LEFT => TOP_LEFT =>
helpGetCollisions helpGetCollisions
( itemX, itemY, itemWidth, itemHeight ( itemX
, quadX, quadY, halfWidth, halfHeight , itemY
, itemID, acc, topLeft , itemWidth
, itemHeight
, quadX
, quadY
, halfWidth
, halfHeight
, itemID
, acc
, topLeft
) )
| TOP_RIGHT => | TOP_RIGHT =>
helpGetCollisions helpGetCollisions
( itemX, itemY, itemWidth, itemHeight ( itemX
, quadX + halfWidth, quadY, halfWidth, halfHeight , itemY
, itemID, acc, topRight , itemWidth
, itemHeight
, quadX + halfWidth
, quadY
, halfWidth
, halfHeight
, itemID
, acc
, topRight
) )
| BOTTOM_LEFT => | BOTTOM_LEFT =>
helpGetCollisions helpGetCollisions
( itemX, itemY, itemWidth, itemHeight ( itemX
, quadX, quadY + halfHeight, halfWidth, halfHeight , itemY
, itemID, acc, bottomLeft , itemWidth
, itemHeight
, quadX
, quadY + halfHeight
, halfWidth
, halfHeight
, itemID
, acc
, bottomLeft
) )
| BOTTOM_RIGHT => | BOTTOM_RIGHT =>
helpGetCollisions helpGetCollisions
( itemX, itemY, itemWidth, itemHeight ( itemX
, quadX + halfWidth, quadY + halfHeight , itemY
, halfWidth, halfHeight , itemWidth
, itemID, acc, bottomRight , itemHeight
, quadX + halfWidth
, quadY + halfHeight
, halfWidth
, halfHeight
, itemID
, acc
, bottomRight
) )
| PARENT_QUADRANT => | PARENT_QUADRANT =>
(* In this function, PARENT_QUADRANT means (* In this function, PARENT_QUADRANT means
@@ -423,50 +564,84 @@ struct
* it may be in any of the child quadrants. * it may be in any of the child quadrants.
* So descend down on all the children, accumulating acc. * So descend down on all the children, accumulating acc.
* *) * *)
let let
val acc = val acc = getCollisionsAll
getCollisionsAll ( itemX
( itemX, itemY, itemWidth, itemHeight , itemY
, halfWidth, halfHeight , itemWidth
, itemID, acc, topLeft , itemHeight
) , halfWidth
, halfHeight
, itemID
, acc
, topLeft
)
val acc = val acc = getCollisionsAll
getCollisionsAll ( itemX
( itemX, itemY, itemWidth, itemHeight , itemY
, halfWidth, halfHeight , itemWidth
, itemID, acc, topRight , itemHeight
) , halfWidth
, halfHeight
, itemID
, acc
, topRight
)
val acc = val acc = getCollisionsAll
getCollisionsAll ( itemX
( itemX, itemY, itemWidth, itemHeight , itemY
, halfWidth, halfHeight , itemWidth
, itemID, acc, bottomLeft , itemHeight
) , halfWidth
in , halfHeight
getCollisionsAll , itemID
( itemX, itemY, itemWidth, itemHeight , acc
, halfWidth, halfHeight , bottomLeft
, itemID, acc, bottomRight )
) in
end) getCollisionsAll
( itemX
, itemY
, itemWidth
, itemHeight
, halfWidth
, halfHeight
, itemID
, acc
, bottomRight
)
end)
end end
| LEAF elements => | LEAF elements =>
getCollisionsVec getCollisionsVec
( itemX, itemY, itemWidth, itemHeight (itemX, itemY, itemWidth, itemHeight, itemID, 0, elements, acc)
, itemID, 0, elements, acc
)
fun getCollisions fun getCollisions
( itemX, itemY, itemWidth, itemHeight ( itemX
, quadX, quadY, quadWidth, quadHeight , itemY
, itemID, tree , itemWidth
, itemHeight
, quadX
, quadY
, quadWidth
, quadHeight
, itemID
, tree
) = ) =
helpGetCollisions helpGetCollisions
( itemX, itemY, itemWidth, itemHeight ( itemX
, quadX, quadY, quadWidth, quadHeight , itemY
, itemID, [], tree , itemWidth
, itemHeight
, quadX
, quadY
, quadWidth
, quadHeight
, itemID
, []
, tree
) )
(* no variant to represent 'no collision' case (* no variant to represent 'no collision' case
@@ -505,26 +680,16 @@ struct
val minXDist = iHalfW + cHalfW val minXDist = iHalfW + cHalfW
val minYDist = iHalfH + cHalfH val minYDist = iHalfH + cHalfH
val depthX = val depthX = if diffX > 0 then minXDist - diffX else (~minXDist) - diffX
if diffX > 0
then minXDist - diffX
else (~minXDist) - diffX
val depthY = val depthY = if diffY > 0 then minYDist - diffY else (~minYDist) - diffY
if diffY > 0
then minYDist - diffY
else (~minYDist) - diffY
in in
if abs depthX < abs depthY then if abs depthX < abs depthY then
if depthX > 0 then if depthX > 0 then QUERY_ON_LEFT_SIDE else QUERY_ON_RIGHT_SIDE
QUERY_ON_LEFT_SIDE else if depthY > 0 then
else QUERY_ON_TOP_SIDE
QUERY_ON_RIGHT_SIDE
else else
if depthY > 0 then QUERY_ON_BOTTOM_SIDE
QUERY_ON_TOP_SIDE
else
QUERY_ON_BOTTOM_SIDE
end end
(* like getCollisionsVec, but instead of consing just the itemID, (* like getCollisionsVec, but instead of consing just the itemID,
@@ -538,100 +703,128 @@ struct
val item = Vector.sub (elements, pos) val item = Vector.sub (elements, pos)
val acc = val acc =
if isColliding (iX, iY, iW, iH, itemID, item) then if isColliding (iX, iY, iW, iH, itemID, item) then
let let val side = getCollisionSide (iX, iY, iW, iH, item)
val side = getCollisionSide (iX, iY, iW, iH, item) in (side, #itemID item) :: acc
in
(side, #itemID item) :: acc
end end
else acc else
acc
in in
getCollisionSideVec (iX, iY, iW, iH, itemID, pos + 1, elements, acc) getCollisionSideVec (iX, iY, iW, iH, itemID, pos + 1, elements, acc)
end end
fun getCollisionSidesAll fun getCollisionSidesAll (iX, iY, iW, iH, qW, qH, itemID, acc, tree) =
( iX, iY, iW, iH, qW, qH
, itemID, acc, tree
) =
case tree of case tree of
NODE {topLeft, topRight, bottomLeft, bottomRight, elements} => NODE {topLeft, topRight, bottomLeft, bottomRight, elements} =>
let let
val acc = val acc = getCollisionSideVec
getCollisionSideVec (iX, iY, iW, iH, itemID, 0, elements, acc) (iX, iY, iW, iH, itemID, 0, elements, acc)
val halfWidth = qW div 2 val halfWidth = qW div 2
val halfHeight = qH div 2 val halfHeight = qH div 2
val acc = val acc = getCollisionSidesAll
getCollisionSidesAll (iX, iY, iW, iH, halfWidth, halfHeight, itemID, acc, topLeft)
( iX, iY, iW, iH, halfWidth, halfHeight
, itemID, acc, topLeft
)
val acc = val acc = getCollisionSidesAll
getCollisionSidesAll (iX, iY, iW, iH, halfWidth, halfHeight, itemID, acc, topRight)
( iX, iY, iW, iH, halfWidth, halfHeight
, itemID, acc, topRight
)
val acc = val acc = getCollisionSidesAll
getCollisionSidesAll (iX, iY, iW, iH, halfWidth, halfHeight, itemID, acc, bottomLeft)
( iX, iY, iW, iH, halfWidth, halfHeight
, itemID, acc, bottomLeft
)
in in
getCollisionSidesAll getCollisionSidesAll
( iX, iY, iW, iH, halfWidth, halfWidth (iX, iY, iW, iH, halfWidth, halfWidth, itemID, acc, bottomRight)
, itemID, acc, bottomRight
)
end end
| LEAF elements => | LEAF elements =>
getCollisionSideVec (iX, iY, iW, iH, itemID, 0, elements, acc) getCollisionSideVec (iX, iY, iW, iH, itemID, 0, elements, acc)
fun helpGetCollisionSides fun helpGetCollisionSides
( itemX, itemY, itemWidth, itemHeight ( itemX
, quadX, quadY, quadWidth, quadHeight , itemY
, itemID, acc, tree: t , itemWidth
, itemHeight
, quadX
, quadY
, quadWidth
, quadHeight
, itemID
, acc
, tree: t
) = ) =
case tree of case tree of
NODE {topLeft, topRight, bottomLeft, bottomRight, elements} => NODE {topLeft, topRight, bottomLeft, bottomRight, elements} =>
let let
(* get colliding elements in this node first *) (* get colliding elements in this node first *)
val acc = val acc = getCollisionSideVec
getCollisionSideVec (itemX, itemY, itemWidth, itemHeight, itemID, 0, elements, acc)
( itemX, itemY, itemWidth, itemHeight
, itemID, 0, elements, acc
)
val halfWidth = quadWidth div 2 val halfWidth = quadWidth div 2
val halfHeight = quadHeight div 2 val halfHeight = quadHeight div 2
in in
(case whichQuadrant (case
( itemX, itemY, itemWidth, itemHeight whichQuadrant
, quadX, quadY, quadWidth, quadHeight ( itemX
) , itemY
, itemWidth
, itemHeight
, quadX
, quadY
, quadWidth
, quadHeight
)
of of
TOP_LEFT => TOP_LEFT =>
helpGetCollisionSides helpGetCollisionSides
( itemX, itemY, itemWidth, itemHeight ( itemX
, quadX, quadY, halfWidth, halfHeight , itemY
, itemID, acc, topLeft , itemWidth
, itemHeight
, quadX
, quadY
, halfWidth
, halfHeight
, itemID
, acc
, topLeft
) )
| TOP_RIGHT => | TOP_RIGHT =>
helpGetCollisionSides helpGetCollisionSides
( itemX, itemY, itemWidth, itemHeight ( itemX
, quadX + halfWidth, quadY, halfWidth, halfHeight , itemY
, itemID, acc, topRight , itemWidth
, itemHeight
, quadX + halfWidth
, quadY
, halfWidth
, halfHeight
, itemID
, acc
, topRight
) )
| BOTTOM_LEFT => | BOTTOM_LEFT =>
helpGetCollisionSides helpGetCollisionSides
( itemX, itemY, itemWidth, itemHeight ( itemX
, quadX, quadY + halfHeight, halfWidth, halfHeight , itemY
, itemID, acc, bottomLeft , itemWidth
, itemHeight
, quadX
, quadY + halfHeight
, halfWidth
, halfHeight
, itemID
, acc
, bottomLeft
) )
| BOTTOM_RIGHT => | BOTTOM_RIGHT =>
helpGetCollisionSides helpGetCollisionSides
( itemX, itemY, itemWidth, itemHeight ( itemX
, quadX + halfWidth, quadY + halfHeight , itemY
, halfWidth, halfHeight , itemWidth
, itemID, acc, bottomRight , itemHeight
, quadX + halfWidth
, quadY + halfHeight
, halfWidth
, halfHeight
, itemID
, acc
, bottomRight
) )
| PARENT_QUADRANT => | PARENT_QUADRANT =>
(* In this function, PARENT_QUADRANT means (* In this function, PARENT_QUADRANT means
@@ -640,49 +833,83 @@ struct
* it may be in any of the child quadrants. * it may be in any of the child quadrants.
* So descend down on all the children, accumulating acc. * So descend down on all the children, accumulating acc.
* *) * *)
let let
val acc = val acc = getCollisionSidesAll
getCollisionSidesAll ( itemX
( itemX, itemY, itemWidth, itemHeight , itemY
, halfWidth, halfHeight , itemWidth
, itemID, acc, topLeft , itemHeight
) , halfWidth
, halfHeight
, itemID
, acc
, topLeft
)
val acc = val acc = getCollisionSidesAll
getCollisionSidesAll ( itemX
( itemX, itemY, itemWidth, itemHeight , itemY
, halfWidth, halfHeight , itemWidth
, itemID, acc, topRight , itemHeight
) , halfWidth
, halfHeight
, itemID
, acc
, topRight
)
val acc = val acc = getCollisionSidesAll
getCollisionSidesAll ( itemX
( itemX, itemY, itemWidth, itemHeight , itemY
, halfWidth, halfHeight , itemWidth
, itemID, acc, bottomLeft , itemHeight
) , halfWidth
in , halfHeight
getCollisionSidesAll , itemID
( itemX, itemY, itemWidth, itemHeight , acc
, halfWidth, halfHeight , bottomLeft
, itemID, acc, bottomRight )
) in
end) getCollisionSidesAll
( itemX
, itemY
, itemWidth
, itemHeight
, halfWidth
, halfHeight
, itemID
, acc
, bottomRight
)
end)
end end
| LEAF elements => | LEAF elements =>
getCollisionSideVec getCollisionSideVec
( itemX, itemY, itemWidth, itemHeight (itemX, itemY, itemWidth, itemHeight, itemID, 0, elements, acc)
, itemID, 0, elements, acc
)
fun getCollisionSides fun getCollisionSides
( itemX, itemY, itemWidth, itemHeight ( itemX
, quadX, quadY, quadWidth, quadHeight , itemY
, itemID, tree , itemWidth
, itemHeight
, quadX
, quadY
, quadWidth
, quadHeight
, itemID
, tree
) = ) =
helpGetCollisionSides helpGetCollisionSides
( itemX, itemY, itemWidth, itemHeight ( itemX
, quadX, quadY, quadWidth, quadHeight , itemY
, itemID, [], tree , itemWidth
, itemHeight
, quadX
, quadY
, quadWidth
, quadHeight
, itemID
, []
, tree
) )
end end

View File

@@ -1,9 +1,52 @@
structure Wall = structure Wall =
struct struct
(* Wall or platform, where player can land after falling. type t = {id: int, x: int, y: int, width: int, height: int}
* Difference between wall and platform is that one can jump to a platform
* and go below it, but wall is completely opaque. *)
datatype wall_type = WALL | PLATFORM
val wall1 = {id = 1, x = 0, y = 0, width = 100, height = 1080}
val wall2 = {id = 2, x = 1820, y = 0, width = 100, height = 1080}
val wall3 = {id = 3, x = 0, y = 980, width = 1920, height = 108}
val wallVec = Vector.fromList [wall1, wall2, wall3]
fun getID n =
Vector.sub (wallVec, n - 1)
fun generateTree (pos, wallVec, acc) =
if pos = Vector.length wallVec then
acc
else
let
val {id, x, y, width, height} = Vector.sub (wallVec, pos)
val acc = QuadTree.insert
(x, y, width, height, 0, 0, 1920, 1080, id, acc)
in
generateTree (pos + 1, wallVec, acc)
end
val tree =
let
val {id, x, y, width, height} = Vector.sub (wallVec, 0)
val acc = QuadTree.fromItem (id, x, y, width, height)
in
generateTree (1, wallVec, acc)
end
fun helpGenerateWalls (pos, wallVec, acc, winWidth, winHeight) =
if pos = Vector.length wallVec then
Vector.concat acc
else
let
val wall = Vector.sub (wallVec, pos)
val {x, y, width, height, ...} = wall
val width = Real32.fromInt width
val height = Real32.fromInt height
val block = Block.lerp
(x, y, width, height, winWidth, winHeight, 0.0, 0.0, 0.0)
val acc = block :: acc
in
helpGenerateWalls (pos + 1, wallVec, acc, winWidth, winHeight)
end
fun generateWalls () =
helpGenerateWalls (0, wallVec, [], 1920.0, 1080.0)
end end

View File

@@ -0,0 +1,11 @@
signature INPUT_MSG =
sig
datatype t =
RESIZE_WINDOW of {width: int, height: int}
end
structure InputMsg =
struct
datatype t =
RESIZE_WINDOW of {width: int, height: int}
end

View File

@@ -1,6 +1,8 @@
$(SML_LIB)/basis/basis.mlb $(SML_LIB)/basis/basis.mlb
(* fcore *) (* fcore *)
message-types/input-msg.sml
ann ann
"allowVectorExps true" "allowVectorExps true"
in in
@@ -8,8 +10,8 @@ in
end end
fcore/quad-tree.sml fcore/quad-tree.sml
fcore/player.sml
fcore/wall.sml fcore/wall.sml
fcore/player.sml
(* shell *) (* shell *)
$(SML_LIB)/basis/mlton.mlb $(SML_LIB)/basis/mlton.mlb

View File

@@ -2,7 +2,16 @@ structure GlDraw =
struct struct
open CML open CML
type t = { window: MLton.Pointer.t } type t =
{ window: MLton.Pointer.t
, mbox: InputMsg.t Mailbox.mbox
, wallVertexBuffer: Word32.word
, wallProgram: Word32.word
, wallLength: int
, playerVertexBuffer: Word32.word
, playerProgram: Word32.word
, playerLength: int
}
fun createShader (shaderType, shaderString) = fun createShader (shaderType, shaderString) =
let let
@@ -25,17 +34,86 @@ struct
fun create window = fun create window =
let let
val mbox = Mailbox.mailbox ()
(* create vertex buffer, program, etc. *) (* create vertex buffer, program, etc. *)
val textVertexBuffer = Gles3.createBuffer ()
val xyrgbVertexShader = createShader val xyrgbVertexShader = createShader
(Gles3.VERTEX_SHADER, GlShaders.xyrgbVertexShaderString) (Gles3.VERTEX_SHADER, GlShaders.xyrgbVertexShaderString)
val rgbFragmentShader = createShader val rgbFragmentShader = createShader
(Gles3.FRAGMENT_SHADER, GlShaders.rgbFragmentShaderString) (Gles3.FRAGMENT_SHADER, GlShaders.rgbFragmentShaderString)
val placeholderProgram = createProgram (xyrgbVertexShader, rgbFragmentShader) (* wall here includes both walls and platforms *)
val wallVertexBuffer = Gles3.createBuffer ()
val wallProgram = createProgram (xyrgbVertexShader, rgbFragmentShader)
val playerVertexBuffer = Gles3.createBuffer ()
val playerProgram = createProgram (xyrgbVertexShader, rgbFragmentShader)
in in
{window = window} { window = window
, mbox = mbox
, wallVertexBuffer = wallVertexBuffer
, wallProgram = wallProgram
, wallLength = 0
, playerVertexBuffer = playerVertexBuffer
, playerProgram = playerProgram
, playerLength = 0
}
end
fun uploadWall (shellState: t, vec) =
let
val
{ window
, mbox
, playerVertexBuffer
, playerProgram
, playerLength
, wallVertexBuffer
, wallProgram
, wallLength = _
} = shellState
val _ = Gles3.bindBuffer wallVertexBuffer
val _ = Gles3.bufferData (vec, Vector.length vec, Gles3.STATIC_DRAW)
val newWallLength = Vector.length vec div 5
in
{ window = window
, mbox = mbox
, playerVertexBuffer = playerVertexBuffer
, playerProgram = playerProgram
, playerLength = playerLength
, wallVertexBuffer = wallVertexBuffer
, wallProgram = wallProgram
, wallLength = newWallLength
}
end
fun uploadPlayer (shellState: t, vec) =
let
val
{ window
, mbox
, wallVertexBuffer
, wallProgram
, wallLength
, playerVertexBuffer
, playerProgram
, playerLength = _
} = shellState
val _ = Gles3.bindBuffer playerVertexBuffer
val _ = Gles3.bufferData (vec, Vector.length vec, Gles3.STATIC_DRAW)
val newPlayerLength = Vector.length vec div 5
in
{ window = window
, mbox = mbox
, wallVertexBuffer = wallVertexBuffer
, wallProgram = wallProgram
, wallLength = wallLength
, playerVertexBuffer = playerVertexBuffer
, playerProgram = playerProgram
, playerLength = newPlayerLength
}
end end
fun drawXyrgb (vertexBuffer, program, drawLength) = fun drawXyrgb (vertexBuffer, program, drawLength) =
@@ -57,7 +135,21 @@ struct
else else
() ()
fun helpLoop (shellState as {window, ...}: t) = fun drawWall ({wallVertexBuffer, wallProgram, wallLength, ...}: t) =
drawXyrgb (wallVertexBuffer, wallProgram, wallLength)
fun drawPlayer ({playerVertexBuffer, playerProgram, playerLength, ...}: t) =
drawXyrgb (playerVertexBuffer, playerProgram, playerLength)
fun draw (shellState: t) =
let
val _ = drawWall shellState
val _ = drawPlayer shellState
in
()
end
fun helpLoop (shellState as {window, ...}: t, player) =
case Glfw.windowShouldClose window of case Glfw.windowShouldClose window of
false => false =>
let let
@@ -69,15 +161,26 @@ struct
* - consume draw messages * - consume draw messages
* - finally, draw * - finally, draw
* *) * *)
val wallVec = Wall.generateWalls ()
val shellState = uploadWall (shellState, wallVec)
val player = Player.move player
val playerVec = Player.getVec player
val shellState = uploadWall (shellState, wallVec)
val shellState = uploadPlayer (shellState, playerVec)
val _ = draw shellState
val _ = Glfw.swapBuffers window val _ = Glfw.swapBuffers window
val _ = Glfw.waitEvents () val _ = Glfw.waitEvents ()
in in
helpLoop shellState helpLoop (shellState, player)
end end
| true => Glfw.terminate () | true => Glfw.terminate ()
fun loop window = fun loop window =
let val shellState = create window let val shellState = create window
in helpLoop shellState in helpLoop (shellState, Player.initial)
end end
end end