From 3a1cbfe23a3d06c3c30828c623a089868cff0670 Mon Sep 17 00:00:00 2001 From: Joris Date: Sun, 2 Oct 2016 15:34:27 +0200 Subject: Add saw-tooth move and multiple moves per level --- elm-package.json | 3 +- src/Model/Color.elm | 22 ---------- src/Model/Level.elm | 105 +++++++++++++++++++-------------------------- src/Model/Player.elm | 2 +- src/Update/CloudUpdate.elm | 11 ++++- src/Utils/Color.elm | 23 ++++++++++ src/Utils/Physics.elm | 24 ++++++++--- src/View.elm | 9 +++- 8 files changed, 106 insertions(+), 93 deletions(-) delete mode 100644 src/Model/Color.elm create mode 100644 src/Utils/Color.elm diff --git a/elm-package.json b/elm-package.json index 3552bc1..35c1e52 100644 --- a/elm-package.json +++ b/elm-package.json @@ -11,7 +11,8 @@ "elm-lang/html": "1.1.0 <= v < 2.0.0", "elm-lang/svg": "1.1.1 <= v < 2.0.0", "elm-lang/keyboard": "1.0.0 <= v < 2.0.0", - "mgold/elm-random-pcg": "3.0.1 <= v < 4.0.0", + "mgold/elm-random-pcg": "3.0.4 <= v < 4.0.0", + "mgold/elm-nonempty-list": "2.0.1 <= v < 3.0.0", "ohanhi/keyboard-extra": "1.1.0 <= v < 2.0.0" } } diff --git a/src/Model/Color.elm b/src/Model/Color.elm deleted file mode 100644 index 49ece2b..0000000 --- a/src/Model/Color.elm +++ /dev/null @@ -1,22 +0,0 @@ -module Model.Color exposing - ( Color - , htmlOutput - , mergeColors - ) - -type alias Color = - { red : Int - , green : Int - , blue : Int - } - -htmlOutput : Color -> String -htmlOutput color = "rgb(" ++ (toString color.red) ++ ", " ++ (toString color.green) ++ ", " ++ (toString color.blue) ++ ")" - -mergeColors : Float -> Color -> Color -> Color -mergeColors ratio c1 c2 = - let mergePart x y = truncate (ratio * (toFloat x) + (1 - ratio) * (toFloat y)) - in { red = mergePart c1.red c2.red - , green = mergePart c1.green c2.green - , blue = mergePart c1.blue c2.blue - } diff --git a/src/Model/Level.elm b/src/Model/Level.elm index 9a60b9a..9daa60a 100644 --- a/src/Model/Level.elm +++ b/src/Model/Level.elm @@ -1,26 +1,27 @@ module Model.Level exposing - ( currentLevel + ( levelScoreDuration + , currentLevel , currentLevelScore , currentLevelNumber , progressiveColor - , levelScoreDuration ) import Time exposing (Time) -import Debug +import Color as Color exposing (Color) +import List.Nonempty as NE exposing (Nonempty(..), (:::)) -import Model.Color exposing (..) -import Model.Vec2 exposing (..) -import Model.Point exposing (pointSpeed) +import Model.Vec2 as Vec2 exposing (Vec2) -import Utils.Physics exposing (getMove, getWaveMove) +import Utils.Physics as Physics +import Utils.Color as Color levelScoreDuration : Int levelScoreDuration = 20 +type alias Move = Vec2 -> Vec2 -> Time -> Vec2 + type alias Level = - { color : Color - , move : Vec2 -> Vec2 -> Time -> Vec2 + { moves : Nonempty Move } currentLevelScore : Int -> Int @@ -28,17 +29,10 @@ currentLevelScore currentScore = currentScore - (currentLevelNumber currentScore - 1) * levelScoreDuration currentLevelNumber : Int -> Int -currentLevelNumber currentScore = - min - (List.length levels + 1) - (currentScore // levelScoreDuration + 1) +currentLevelNumber currentScore = currentScore // levelScoreDuration + 1 currentLevel : Int -> Level -currentLevel currentScore = - levels - |> List.drop (currentScore // levelScoreDuration) - |> List.head - |> Maybe.withDefault lastLevel +currentLevel currentScore = NE.get (currentScore // levelScoreDuration) levels nextLevel : Int -> Level nextLevel currentScore = currentLevel (currentScore + levelScoreDuration) @@ -47,50 +41,41 @@ progressiveColor : Int -> Color progressiveColor currentScore = let reminder = currentScore `rem` levelScoreDuration ratio = progressiveRatio reminder levelScoreDuration - currentColor = (currentLevel currentScore).color - nextColor = (nextLevel currentScore).color - in mergeColors ratio nextColor currentColor + currentColor = color currentScore + nextColor = color (currentScore + levelScoreDuration) + in Color.merge ratio nextColor currentColor progressiveRatio : Int -> Int -> Float progressiveRatio a b = (toFloat a ^ 7) / (toFloat b ^ 7) --- Hue + 35 with gimp each time from the first color -levels : List Level -levels = - [ { color = { red = 156, green = 168, blue = 233 } - , move = \initPos initDest delta -> getMove (delta / 20) (initDest `sub` initPos) - } - , { color = { red = 190, green = 156, blue = 233 } - , move = \initPos initDest delta -> getWaveMove (delta / 20) (initDest `sub` initPos) 10 10 - } - , { color = { red = 233, green = 156, blue = 232 } - , move = \initPos initDest delta -> getMove (delta / 18) (initDest `sub` initPos) - } - , { color = { red = 233, green = 156, blue = 187 } - , move = \initPos initDest delta -> getWaveMove (delta / 18) (initDest `sub` initPos) 20 20 - } - , { color = { red = 233, green = 171, blue = 156 } - , move = \initPos initDest delta -> getMove (delta / 13) (initDest `sub` initPos) - } - , { color = { red = 233, green = 215, blue = 156 } - , move = \initPos initDest delta -> getWaveMove (delta / 16) (initDest `sub` initPos) 10 50 - } - , { color = { red = 206, green = 233, blue = 156 } - , move = \initPos initDest delta -> getMove (delta / 11) (initDest `sub` initPos) - } - , { color = { red = 162, green = 233, blue = 156 } - , move = \initPos initDest delta -> getWaveMove (delta / 14) (initDest `sub` initPos) 30 15 - } - , { color = { red = 156, green = 233, blue = 196 } - , move = \initPos initDest delta -> getMove (delta / 8) (initDest `sub` initPos) - } - , { color = { red = 156, green = 225, blue = 233 } - , move = \initPos initDest delta -> getWaveMove (delta / 12) (initDest `sub` initPos) 30 30 - } - ] +initialColor : Color +initialColor = Color.rgb 156 168 233 -lastLevel : Level -lastLevel = - { color = { red = 156, green = 225, blue = 233 } - , move = \initPos initDest delta -> getWaveMove (delta / 5) (initDest `sub` initPos) 30 30 - } +color : Int -> Color +color score = Color.spin (toFloat <| 20 * (score // levelScoreDuration)) initialColor + +levels : Nonempty Level +levels = + let ma1 = \initPos initDest delta -> Physics.getMove (delta / 20) (initDest `Vec2.sub` initPos) + ma2 = \initPos initDest delta -> Physics.getWaveMove (delta / 20) (initDest `Vec2.sub` initPos) 10 10 + ma3 = \initPos initDest delta -> Physics.getSawToothMove (delta / 25) (initDest `Vec2.sub` initPos) 30 10 + mb1 = \initPos initDest delta -> Physics.getMove (delta / 18) (initDest `Vec2.sub` initPos) + mb2 = \initPos initDest delta -> Physics.getWaveMove (delta / 18) (initDest `Vec2.sub` initPos) 20 20 + mb3 = \initPos initDest delta -> Physics.getSawToothMove (delta / 20) (initDest `Vec2.sub` initPos) 30 15 + mc1 = \initPos initDest delta -> Physics.getMove (delta / 13) (initDest `Vec2.sub` initPos) + mc2 = \initPos initDest delta -> Physics.getWaveMove (delta / 16) (initDest `Vec2.sub` initPos) 10 50 + mc3 = \initPos initDest delta -> Physics.getSawToothMove (delta / 25) (initDest `Vec2.sub` initPos) 100 15 + in Nonempty + { moves = NE.fromElement ma1 } + [ { moves = NE.fromElement ma2 } + , { moves = NE.fromElement ma3 } + , { moves = Nonempty ma1 [ ma2, ma3 ] } + , { moves = NE.fromElement mb1 } + , { moves = NE.fromElement mb2 } + , { moves = NE.fromElement mb3 } + , { moves = Nonempty mb1 [ mb2, mb3 ] } + , { moves = NE.fromElement mc1 } + , { moves = NE.fromElement mc2 } + , { moves = NE.fromElement mc3 } + , { moves = Nonempty mc1 [ mc2, mc3 ] } + ] diff --git a/src/Model/Player.elm b/src/Model/Player.elm index 37a1a7f..50efb4b 100644 --- a/src/Model/Player.elm +++ b/src/Model/Player.elm @@ -24,7 +24,7 @@ initPlayer = getPlayerSize : Int -> Float getPlayerSize score = - (levelCurve Level.levelScoreDuration 15 (Level.currentLevelScore score)) + 15 + 15 + (levelCurve Level.levelScoreDuration 15 (Level.currentLevelScore score)) levelCurve : Int -> Int -> Int -> Float levelCurve maxAbs maxOrd x = diff --git a/src/Update/CloudUpdate.elm b/src/Update/CloudUpdate.elm index 559acc9..d8ccf36 100644 --- a/src/Update/CloudUpdate.elm +++ b/src/Update/CloudUpdate.elm @@ -3,6 +3,7 @@ module Update.CloudUpdate exposing ) import List +import List.Nonempty as NE exposing (Nonempty(..), (:::)) import Random.Pcg as Random exposing (Seed, Generator) import Model.Vec2 exposing (..) @@ -58,17 +59,23 @@ getNewPoint : Float -> Vec2 -> Seed -> Int -> (Point, Seed) getNewPoint elapsedTime boardSize seed currentScore = let (initPos, seed') = pointInitPos boardSize seed (initDest, seed'') = pointDestination boardSize seed' + (randomMove, seed''') = Random.step (nonemptySample << .moves <| currentLevel currentScore) seed'' in ( { initTime = elapsedTime , initPos = initPos , initDest = initDest , move = \initTime initPos initDest elapsedTime -> let delta = elapsedTime - initTime - move = (currentLevel currentScore).move initPos initDest delta + move = randomMove initPos initDest delta in initPos `add` move } - , seed'' + , seed''' ) +nonemptySample : Nonempty a -> Random.Generator a +nonemptySample nonempty = + Random.int 0 (NE.length nonempty - 1) + |> Random.map (\i -> NE.get i nonempty) + pointInitPos : Vec2 -> Seed -> (Vec2, Seed) pointInitPos boardSize seed = let (rand, seed') = Random.step (Random.float 0 1) seed diff --git a/src/Utils/Color.elm b/src/Utils/Color.elm new file mode 100644 index 0000000..f9e344f --- /dev/null +++ b/src/Utils/Color.elm @@ -0,0 +1,23 @@ +module Utils.Color exposing + ( merge + , spin + ) + +import Color as Color exposing (Color) + +merge : Float -> Color -> Color -> Color +merge ratio c1 c2 = + let rgb1 = Color.toRgb c1 + rgb2 = Color.toRgb c2 + mergePartFloat x y = ratio * x + (1 - ratio) * y + mergePartInt x y = truncate <| ratio * (toFloat x) + (1 - ratio) * (toFloat y) + in Color.rgba + (mergePartInt rgb1.red rgb2.red) + (mergePartInt rgb1.green rgb2.green) + (mergePartInt rgb1.blue rgb2.blue) + (mergePartFloat rgb1.alpha rgb2.alpha) + +spin : Float -> Color -> Color +spin d color = + let { hue, saturation, lightness, alpha } = Color.toHsl color + in Color.hsla (hue + degrees d) saturation lightness alpha diff --git a/src/Utils/Physics.elm b/src/Utils/Physics.elm index 5da3737..88a4434 100644 --- a/src/Utils/Physics.elm +++ b/src/Utils/Physics.elm @@ -2,6 +2,7 @@ module Utils.Physics exposing ( getNewPosAndSpeed , getMove , getWaveMove + , getSawToothMove ) import Model.Vec2 exposing (..) @@ -17,24 +18,37 @@ getNewPosAndSpeed dt dir computeSpeed (pos, speed) = ) getMove : Float -> Vec2 -> Vec2 -getMove speed dir = +getMove dist 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 + in { x = dist * cos angle + , y = dist * sin angle } getWaveMove : Float -> Vec2 -> Float -> Float -> Vec2 -getWaveMove speed dir amplitude period = - let move = getMove speed dir +getWaveMove dist dir amplitude period = + let move = getMove dist dir perpendMove = getMove (amplitude * (sin ((norm move) / period))) (clockwiseRotate90 move) in move `add` perpendMove +getSawToothMove : Float -> Vec2 -> Float -> Float -> Vec2 +getSawToothMove dist dir amplitude period = + let move = getMove dist dir + perpendMove = + getMove + ( let max = 1000 / period + middle = max / 2 + modulo = toFloat <| round (norm move) % round max + in amplitude * (if modulo < middle then modulo else max - modulo) / middle + ) + (clockwiseRotate90 move) + in move `add` perpendMove + getAcc : Vec2 -> Vec2 -> Vec2 getAcc move speed = (move `div` 300) `sub` (speed `div` 300) diff --git a/src/View.elm b/src/View.elm index 822c2d2..d6265f6 100644 --- a/src/View.elm +++ b/src/View.elm @@ -6,6 +6,7 @@ import Html exposing (Html) import Svg exposing (..) import Svg.Attributes exposing (..) import List +import Color as Color exposing (Color) import Time exposing (Time) @@ -16,7 +17,6 @@ import Model.Point exposing (..) import Model.Config exposing (..) import Model.Round exposing (..) import Model.Level exposing (..) -import Model.Color exposing (htmlOutput) import View.Round exposing (roundView) @@ -103,10 +103,15 @@ renderBoard currentScore = [ y (toString headerHeight) , width "100%" , height "100%" - , fill (htmlOutput (progressiveColor currentScore)) + , fill (colorRgba (progressiveColor currentScore)) ] [] +colorRgba : Color -> String +colorRgba color = + let c = Color.toRgb color + in "rgba(" ++ (toString c.red) ++ ", " ++ (toString c.green) ++ ", " ++ (toString c.blue) ++ "," ++ (toString c.alpha) ++ ")" + renderPlayer : Vec2 -> Player -> Float -> Svg msg renderPlayer boardSize player playerSize = renderCircle boardSize player.pos playerSize (playerColor player.config) -- cgit v1.2.3