diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/Board.elm | 15 | ||||
-rw-r--r-- | src/Display.elm | 79 | ||||
-rw-r--r-- | src/Enemy.elm | 27 | ||||
-rw-r--r-- | src/EnemyState.elm | 29 | ||||
-rw-r--r-- | src/Game.elm | 25 | ||||
-rw-r--r-- | src/Geometry.elm | 23 | ||||
-rw-r--r-- | src/Input.elm | 39 | ||||
-rw-r--r-- | src/Main.elm | 10 | ||||
-rw-r--r-- | src/Physics.elm | 33 | ||||
-rw-r--r-- | src/Player.elm | 14 | ||||
-rw-r--r-- | src/RandomValues.elm | 7 | ||||
-rw-r--r-- | src/Step.elm | 72 | ||||
-rw-r--r-- | src/Vec2.elm | 36 | ||||
-rwxr-xr-x | src/genGame | 1 |
14 files changed, 410 insertions, 0 deletions
diff --git a/src/Board.elm b/src/Board.elm new file mode 100644 index 0000000..fa544d8 --- /dev/null +++ b/src/Board.elm @@ -0,0 +1,15 @@ +module Board where + +import Vec2 (Vec2) + +boardSize : Vec2 +boardSize = + { x = 500 + , y = 500 + } + +boardDiagonal : Float +boardDiagonal = + let x = boardSize.x + y = boardSize.y + in sqrt(x^2 + y^2) diff --git a/src/Display.elm b/src/Display.elm new file mode 100644 index 0000000..cb9fb86 --- /dev/null +++ b/src/Display.elm @@ -0,0 +1,79 @@ +module Display where + +import Vec2 (..) +import Player (..) +import Game (Game) +import Enemy (..) +import Board (boardSize) + +display : Game -> Element +display {time, player, enemyState, bestTime} = + let enemyForms = map (enemyForm time) enemyState.enemies + forms = boardForms + ++ playerForms player + ++ enemyForms + ++ bestTimeForms bestTime + ++ timeForms time + in collage (truncate boardSize.x) (truncate boardSize.y) forms + +boardForms : [Form] +boardForms = [filled boardColor (rect boardSize.x boardSize.y)] + +boardColor : Color +boardColor = rgb 34 122 34 + +playerForms : Player -> [Form] +playerForms player = [circleForm player.pos playerSize playerColor] + +playerColor : Color +playerColor = rgb 224 224 224 + +enemyForm : Float -> Enemy -> Form +enemyForm time enemy = + let pos = enemyMove enemy time + in circleForm pos enemySize enemyColor + +enemyColor : Color +enemyColor = rgb 170 0 0 + +circleForm : Vec2 -> Float -> Color -> Form +circleForm pos size color = + let outline = circle size + |> filled black + inside = circle (size - 2) + |> filled color + in group [outline, inside] + |> move (pos.x, pos.y) + +bestTimeForms : Float -> [Form] +bestTimeForms bestTime = + if(bestTime > 0) then + let seconds = truncate (bestTime / 1000) + text = "Record: " ++ (show seconds) + pos = + { x = boardSize.x / 2 - 65 + , y = -boardSize.y / 2 + 30 + } + in [textForm text pos rightAligned] + else [] + +timeForms : Float -> [Form] +timeForms time = + let seconds = truncate (time / 1000) + text = (show seconds) + pos = { x = 0.0, y = boardSize.y / 2 - 30 } + in [textForm text pos centered] + +textForm : String -> Vec2 -> (Text -> Element) -> Form +textForm content pos alignment = + let textElement = toText content + |> typeface ["calibri", "arial"] + |> Text.color textColor + |> bold + |> alignment + in textElement + |> toForm + |> move (pos.x, pos.y) + +textColor : Color +textColor = rgb 224 224 224 diff --git a/src/Enemy.elm b/src/Enemy.elm new file mode 100644 index 0000000..2c80f0a --- /dev/null +++ b/src/Enemy.elm @@ -0,0 +1,27 @@ +module Enemy where + +import Vec2 (..) +import Board (boardDiagonal) + +type Enemy = + { initTime : Float + , initPos : Vec2 + , initDest : Vec2 + , move : Float -> Vec2 -> Vec2 -> Float -> Vec2 + } + +enemyMove : Enemy -> Float -> Vec2 +enemyMove enemy time = + enemy.move enemy.initTime enemy.initPos enemy.initDest time + +enemySize : Float +enemySize = 8 + +enemySpeed : Float -> Float +enemySpeed dt = dt / 25 + +enemySpawnDist : Float +enemySpawnDist = boardDiagonal * 3 / 5 + +enemyAwayDist : Float +enemyAwayDist = boardDiagonal diff --git a/src/EnemyState.elm b/src/EnemyState.elm new file mode 100644 index 0000000..81766bf --- /dev/null +++ b/src/EnemyState.elm @@ -0,0 +1,29 @@ +module EnemyState where + +import Enemy (..) +import Player (..) +import Geometry (distance) + +type EnemyState = + { enemies : [Enemy] + , spawn : Float + , lastSpawn : Float + } + +initEnemyState : EnemyState +initEnemyState = + let spawn = 200 + in { enemies = [] + , spawn = spawn + , lastSpawn = -spawn + } + +playerEnemyCollision : Float -> Player -> Enemy -> Bool +playerEnemyCollision time player enemy = + let enemyPos = enemyMove enemy time + in (distance enemyPos player.pos) < enemySize + playerSize + +playerEnemiesCollision : Float -> Player -> [Enemy] -> Bool +playerEnemiesCollision time player enemies = + let collision = playerEnemyCollision time player + in length (filter collision enemies) > 0 diff --git a/src/Game.elm b/src/Game.elm new file mode 100644 index 0000000..c86af26 --- /dev/null +++ b/src/Game.elm @@ -0,0 +1,25 @@ +module Game where + +import Player (..) +import Enemy (..) +import EnemyState (..) +import Vec2 (Vec2) + +type Game = + { time : Float + , player : Player + , enemyState : EnemyState + , bestTime : Float + } + +initialGame : Vec2 -> Float -> Game +initialGame playerPos bestTime = + let initPlayer = + { pos = playerPos + , speed = { x = 0, y = 0 } + } + in { time = 0 + , player = initPlayer + , enemyState = initEnemyState + , bestTime = bestTime + } diff --git a/src/Geometry.elm b/src/Geometry.elm new file mode 100644 index 0000000..73e8d1f --- /dev/null +++ b/src/Geometry.elm @@ -0,0 +1,23 @@ +module Geometry where + +import Vec2 (..) +import Board (boardSize) + +polarToCartesian : Float -> Float -> Vec2 +polarToCartesian angle dist = + { x = dist * (cos angle) + , y = dist * (sin angle) + } + +distance : Vec2 -> Vec2 -> Float +distance v1 v2 = sqrt((v2.x - v1.x)^2 + (v2.y - v1.y)^2) + +inBoard : Float -> Vec2 -> Vec2 +inBoard size pos = + let leftX = -boardSize.x / 2 + size + rightX = boardSize.x / 2 - size + bottomY = -boardSize.y / 2 + size + topY = boardSize.y / 2 - size + in { x = clamp leftX rightX pos.x + , y = clamp bottomY topY pos.y + } diff --git a/src/Input.elm b/src/Input.elm new file mode 100644 index 0000000..d8614b0 --- /dev/null +++ b/src/Input.elm @@ -0,0 +1,39 @@ +module Input where + +import Keyboard +import Random +import RandomValues (RandomValues) + +import Vec2 (Vec2) + +type Input = + { dir : Vec2 + , delta : Time + , randomValues : RandomValues + } + +getInput : Signal Input +getInput = + let dtSignal = delta + dirSignal = lift recordIntToVec2 Keyboard.arrows + randomFloatsSignal = Random.floatList (lift (\_ -> 3) dtSignal) + randomValuesSignal = lift floatsToRandomValues randomFloatsSignal + in sampleOn dtSignal <| Input <~ dirSignal + ~ dtSignal + ~ randomValuesSignal + +delta : Signal Time +delta = lift (\ms -> ms) (fps 25) + +recordIntToVec2 : {x : Int, y : Int} -> Vec2 +recordIntToVec2 {x, y} = + { x = toFloat x + , y = toFloat y + } + +floatsToRandomValues : [Float] -> RandomValues +floatsToRandomValues [enemyAngle, enemyX, enemyY] = + { enemyAngle = enemyAngle + , enemyX = enemyX + , enemyY = enemyY + } diff --git a/src/Main.elm b/src/Main.elm new file mode 100644 index 0000000..267bb8c --- /dev/null +++ b/src/Main.elm @@ -0,0 +1,10 @@ +module Main where + +import Game (initialGame) +import Display (display) +import Step (step) +import Input (getInput) +import Vec2 (originVec) + +main : Signal Element +main = lift display (foldp step (initialGame originVec 0) getInput) diff --git a/src/Physics.elm b/src/Physics.elm new file mode 100644 index 0000000..b59b3e1 --- /dev/null +++ b/src/Physics.elm @@ -0,0 +1,33 @@ +module Physics where + +import Vec2 (..) + +getNewPosAndSpeed : Float -> Vec2 -> (Float -> Float) -> (Vec2, Vec2) -> (Vec2, Vec2) +getNewPosAndSpeed dt dir computeSpeed (pos, speed) = + let move = getMove (computeSpeed dt) dir + acc = getAcc move speed + newPos = getNewPos dt acc speed pos + newSpeed = getNewSpeed dt acc speed + in ( newPos + , newSpeed + ) + +getMove : Float -> Vec2 -> Vec2 +getMove speed dir = + if (isNull dir) + then {x = 0, y = 0} + else + let angle = atan2 dir.y dir.x + in { x = speed * cos angle + , y = speed * sin angle + } + +getAcc : Vec2 -> Vec2 -> Vec2 +getAcc move speed = (move `div` 800) `sub` (speed `div` 1000) + +getNewPos : Float -> Vec2 -> Vec2 -> Vec2 -> Vec2 +getNewPos dt acc speed pos = + ((dt^2 / 2) `mul` acc) `add` ((dt `mul` speed) `add` pos) + +getNewSpeed : Float -> Vec2 -> Vec2 -> Vec2 +getNewSpeed dt acc speed = add (mul dt acc) speed diff --git a/src/Player.elm b/src/Player.elm new file mode 100644 index 0000000..b64655e --- /dev/null +++ b/src/Player.elm @@ -0,0 +1,14 @@ +module Player where + +import Vec2 (..) + +type Player = + { pos : Vec2 + , speed : Vec2 + } + +playerSize : Float +playerSize = 10 + +playerSpeed : Float -> Float +playerSpeed dt = dt / 500 diff --git a/src/RandomValues.elm b/src/RandomValues.elm new file mode 100644 index 0000000..4638037 --- /dev/null +++ b/src/RandomValues.elm @@ -0,0 +1,7 @@ +module RandomValues where + +type RandomValues = + { enemyAngle : Float + , enemyX : Float + , enemyY : Float + } diff --git a/src/Step.elm b/src/Step.elm new file mode 100644 index 0000000..7894e45 --- /dev/null +++ b/src/Step.elm @@ -0,0 +1,72 @@ +module Step where + +import Vec2 (..) +import Game (..) +import Player (..) +import EnemyState (..) +import Player (playerSpeed) +import Enemy (enemySpeed, enemyMove, enemyAwayDist) +import Input (Input) +import Physics (getNewPosAndSpeed, getMove) +import Board (boardSize, boardDiagonal) +import Geometry (..) +import RandomValues (RandomValues) + +step : Input -> Game -> Game +step {dir, delta, randomValues} {time, player, enemyState, bestTime} = + if(playerEnemiesCollision time player enemyState.enemies) then + let newBestTime = if(time > bestTime) then time else bestTime + in initialGame player.pos newBestTime + else + let newTime = time + delta + newPlayer = playerStep delta dir player + newEnemyState = enemyStep time randomValues enemyState + in { time = newTime + , player = newPlayer + , enemyState = newEnemyState + , bestTime = bestTime + } + +playerStep : Float -> Vec2 -> Player -> Player +playerStep dt dir player = + let (pos, speed) = getNewPosAndSpeed dt dir playerSpeed (player.pos, player.speed) + in { pos = inBoard playerSize pos + , speed = speed + } + +enemyStep : Float -> RandomValues -> EnemyState -> EnemyState +enemyStep time randomValues {enemies, spawn, lastSpawn} = + let isPresent enemy = (distance (enemyMove enemy time) originVec) < enemyAwayDist + presentEnemies = filter isPresent enemies + in if time > lastSpawn + spawn then + let newEnemy = + { initTime = time + , initPos = enemyInitPos randomValues + , initDest = enemyDestination randomValues + , move initTime initPos initDest time = + let delta = time - initTime + move = getMove (enemySpeed delta) (initDest `sub` initPos) + in initPos `add` move + } + in { enemies = newEnemy :: presentEnemies + , spawn = spawn - sqrt(spawn) / 50 + , lastSpawn = time + } + else { enemies = presentEnemies + , spawn = spawn + , lastSpawn = lastSpawn + } + +enemyInitPos : RandomValues -> Vec2 +enemyInitPos randomValues = + let angle = randomValues.enemyAngle * (degrees 360) + dist = boardDiagonal * 3 / 5 + in polarToCartesian angle dist + +enemyDestination : RandomValues -> Vec2 +enemyDestination randomValues = + let destWidth = boardSize.x + destHeight = boardSize.y + in { x = destWidth * randomValues.enemyX - destWidth / 2 + , y = destHeight * randomValues.enemyY - destHeight / 2 + } diff --git a/src/Vec2.elm b/src/Vec2.elm new file mode 100644 index 0000000..a77b372 --- /dev/null +++ b/src/Vec2.elm @@ -0,0 +1,36 @@ +module Vec2 where + +type Vec2 = + { x : Float + , y : Float + } + +add : Vec2 -> Vec2 -> Vec2 +add v1 v2 = + { x = v1.x + v2.x + , y = v1.y + v2.y + } + +sub : Vec2 -> Vec2 -> Vec2 +sub v1 v2 = + { x = v1.x - v2.x + , y = v1.y - v2.y + } + +mul : Float -> Vec2 -> Vec2 +mul m v = + { x = m * v.x + , y = m * v.y + } + +div : Vec2 -> Float -> Vec2 +div v d = + { x = v.x / d + , y = v.y / d + } + +isNull : Vec2 -> Bool +isNull v = (v.x == 0) && (v.y == 0) + +originVec : Vec2 +originVec = { x = 0, y = 0 } diff --git a/src/genGame b/src/genGame new file mode 100755 index 0000000..0b71849 --- /dev/null +++ b/src/genGame @@ -0,0 +1 @@ +elm --make --only-js Main.elm |