aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Board.elm15
-rw-r--r--src/Display.elm79
-rw-r--r--src/Enemy.elm27
-rw-r--r--src/EnemyState.elm29
-rw-r--r--src/Game.elm25
-rw-r--r--src/Geometry.elm23
-rw-r--r--src/Input.elm39
-rw-r--r--src/Main.elm10
-rw-r--r--src/Physics.elm33
-rw-r--r--src/Player.elm14
-rw-r--r--src/RandomValues.elm7
-rw-r--r--src/Step.elm72
-rw-r--r--src/Vec2.elm36
-rwxr-xr-xsrc/genGame1
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