Files
sml-projects/fcore/player.sml

243 lines
7.0 KiB
Standard ML
Raw Normal View History

2024-12-09 04:37:40 +00:00
structure Player =
struct
open GameType
2024-12-09 04:37:40 +00:00
(* width/height *)
val size = 35
2024-12-13 22:48:34 +00:00
val realSize = 35.0
2024-12-09 04:37:40 +00:00
val moveBy = 5
2024-12-13 22:48:34 +00:00
val jumpLimit = 150
val floatLimit = 3
2024-12-09 04:37:40 +00:00
fun mkPlayer (health, xAxis, yAxis, x, y, jumpPressed) =
{ yAxis = yAxis
, xAxis = xAxis
, health = health
, x = x
, y = y
, jumpPressed = jumpPressed
}
2024-12-09 04:37:40 +00:00
fun checkWalls (yAxis, xAxis, x, y, health, jumpPressed, lst, game: game_type) =
2024-12-09 04:37:40 +00:00
let
2024-12-13 22:48:34 +00:00
open QuadTree
in
case lst of
(QUERY_ON_LEFT_SIDE, wallID) :: tl =>
let
val {walls, ...} = game
val {x = wallX, width = wallWidth, ...} =
Vector.sub (walls, wallID - 1)
2024-12-13 22:48:34 +00:00
val newX = wallX + wallWidth
in
checkWalls (yAxis, xAxis, newX, y, health, jumpPressed, tl, game)
2024-12-13 22:48:34 +00:00
end
| (QUERY_ON_RIGHT_SIDE, wallID) :: tl =>
let
val {walls, ...} = game
val {x = wallX, width = wallWidth, ...} =
Vector.sub (walls, wallID - 1)
2024-12-13 22:48:34 +00:00
val newX = wallX - size
in
checkWalls (yAxis, xAxis, newX, y, health, jumpPressed, tl, game)
2024-12-13 22:48:34 +00:00
end
| (QUERY_ON_BOTTOM_SIDE, wallID) :: tl =>
let
val {walls, ...} = game
val {y = wallY, ...} = Vector.sub (walls, wallID - 1)
2024-12-13 22:48:34 +00:00
val newY = wallY - size
in
checkWalls
(ON_GROUND, xAxis, x, newY, health, jumpPressed, tl, game)
2024-12-13 22:48:34 +00:00
end
| (QUERY_ON_TOP_SIDE, wallID) :: tl =>
checkWalls (yAxis, xAxis, x, y, health, jumpPressed, tl, game)
| [] => mkPlayer (health, xAxis, yAxis, x, y, jumpPressed)
2024-12-13 22:48:34 +00:00
end
2024-12-09 04:37:40 +00:00
fun helpMove (x, y, xAxis, yAxis, health, jumpPressed, game: game_type) =
2024-12-13 22:48:34 +00:00
let
(* check against wall quad tree *)
val desiredX =
2024-12-09 04:37:40 +00:00
case xAxis of
2024-12-13 22:48:34 +00:00
STAY_STILL => x
| MOVE_LEFT => x - moveBy
| MOVE_RIGHT => x + moveBy
2024-12-09 04:37:40 +00:00
in
case yAxis of
2024-12-13 22:48:34 +00:00
ON_GROUND =>
let
val collisions = QuadTree.getCollisionSides
(desiredX, y, size, size, 0, 0, 1920, 1080, 0, #wallTree game)
2024-12-13 22:48:34 +00:00
in
checkWalls
(yAxis, xAxis, desiredX, y, health, jumpPressed, collisions, game)
2024-12-13 22:48:34 +00:00
end
| FLOATING floated =>
let
val collisions = QuadTree.getCollisionSides
(desiredX, y, size, size, 0, 0, 1920, 1080, 0, #wallTree game)
val yAxis =
if floated = floatLimit then FALLING else FLOATING (floated + 1)
in
checkWalls
(yAxis, xAxis, desiredX, y, health, jumpPressed, collisions, game)
end
2024-12-13 22:48:34 +00:00
| FALLING =>
let
val desiredY = y + moveBy
val collisions = QuadTree.getCollisionSides
( desiredX
, desiredY
, size
, size
, 0
, 0
, 1920
, 1080
, 0
, #wallTree game
)
2024-12-13 22:48:34 +00:00
in
checkWalls
( yAxis
, xAxis
, desiredX
, desiredY
, health
, jumpPressed
, collisions
, game
)
2024-12-13 22:48:34 +00:00
end
| JUMPING jumped =>
if jumped + moveBy > jumpLimit then
(* if we are above the jump limit, trigger a fall *)
2024-12-09 04:37:40 +00:00
let
2024-12-13 22:48:34 +00:00
val collisions = QuadTree.getCollisionSides
(desiredX, y, size, size, 0, 0, 1920, 1080, 0, #wallTree game)
2024-12-09 04:37:40 +00:00
in
checkWalls
( FLOATING 0
, xAxis
, desiredX
, y
, health
, jumpPressed
, collisions
, game
)
2024-12-09 04:37:40 +00:00
end
else
2024-12-13 22:48:34 +00:00
(* jump *)
let
val newJumped = jumped + moveBy
val yAxis = JUMPING newJumped
val desiredY = y - moveBy
val collisions = QuadTree.getCollisionSides
( desiredX
, desiredY
, size
, size
, 0
, 0
, 1920
, 1080
, 0
, #wallTree game
)
2024-12-13 22:48:34 +00:00
in
checkWalls
( yAxis
, xAxis
, desiredX
, desiredY
, health
, jumpPressed
, collisions
, game
)
2024-12-13 22:48:34 +00:00
end
2024-12-09 04:37:40 +00:00
end
fun getXAxis (lh, rh) =
case (lh, rh) of
(false, false) => STAY_STILL
| (false, true) => MOVE_RIGHT
| (true, false) => MOVE_LEFT
| (true, true) => STAY_STILL
(* function returns default yAxis when neither up/down are pressed
* or both are pressed.
*
* In the case where the user was previously jumping,
* we enter the floating stage, because it's normal for games
* to have a very brief floating/gliding period before applying gravity.
*
* In the case where the user was previously floating, we want the player to
* keep floating at this point (another function will apply gravity if we
* floated enough).
*
* In every other case, we return the FALLING variant,
* which has the same effect as returning the ON_GROUND variant,
* except that it means gravity is applied if we walk off a platform.
* *)
fun defaultYAxis prevAxis =
case prevAxis of
JUMPING _ => FLOATING 0
| FLOATING _ => prevAxis
| _ => FALLING
(* We want to prevent a double jump
* or jumping while the player is falling
* so we only switch to the JUMPING case if the player
* is on the ground. *)
fun onJumpPressed (prevAxis, jumpPressed) =
case prevAxis of
ON_GROUND => if jumpPressed then prevAxis else JUMPING 0
| _ => prevAxis
fun move (game: game_type, input) =
let
val {x, y, yAxis, health, jumpPressed, ...} = #player game
val {leftHeld, rightHeld, upHeld, downHeld} = input
val xAxis = getXAxis (leftHeld, rightHeld)
in
case (upHeld, downHeld) of
(false, false) =>
let
val yAxis = defaultYAxis yAxis
val jumpPressed = false
in
helpMove (x, y, xAxis, yAxis, health, jumpPressed, game)
end
| (true, true) =>
let val yAxis = defaultYAxis yAxis
in helpMove (x, y, xAxis, yAxis, health, jumpPressed, game)
end
| (true, false) =>
let
val yAxis = onJumpPressed (yAxis, jumpPressed)
val jumpPressed = true
in
helpMove (x, y, xAxis, yAxis, health, jumpPressed, game)
end
| (false, true) =>
(* todo: should move down if on platform *)
let val jumpPressed = false
in helpMove (x, y, xAxis, yAxis, health, jumpPressed, game)
end
end
(* placeholder *)
fun getDrawVec ({x, y, ...}: player) =
Block.lerp (x, y, realSize, realSize, 1920.0, 1080.0, 0.5, 0.5, 0.5)
2024-12-09 04:37:40 +00:00
end