Skip to content

Commit

Permalink
Use active layer
Browse files Browse the repository at this point in the history
  • Loading branch information
kayhide committed Jan 17, 2020
1 parent e40c429 commit 20c2f9c
Show file tree
Hide file tree
Showing 10 changed files with 104 additions and 34 deletions.
13 changes: 4 additions & 9 deletions app/frontend/packs/App/App.purs
Expand Up @@ -22,16 +22,14 @@ import App.Logger as Logger
import App.Model.Puzzle (Puzzle)
import App.Model.Puzzle as Puzzle
import App.Utils as Utils
import Control.Monad.Error.Class (try)
import Control.Monad.Loops (iterateUntil)
import Data.Argonaut (jsonParser)
import Data.Array as Array
import Data.Int as Int
import Data.String (Pattern(..))
import Data.String as String
import Data.Time.Duration (Milliseconds(..))
import Debug.Trace (traceM)
import Effect.Aff (Aff, delay, launchAff_, parallel, sequential)
import Effect.Aff (Aff, launchAff_, parallel, sequential)
import Effect.Class (liftEffect)
import Effect.Class.Console (log)
import Effect.Ref as Ref
Expand Down Expand Up @@ -170,12 +168,8 @@ updateOnlineGame gi sub = do
when (Array.any Command.isMerge cmds) do
GameChannel.reportProgress sub =<< Game.progress gi.game

void $ iterateUntil isRight do
res <- try (GameChannel.requestUpdate sub)
when (isLeft res) do
delay $ Milliseconds 5000.0
pure res

Utils.retryOnFailAfter (Milliseconds 5000.0) do
GameChannel.requestUpdate sub

setupLogger :: App -> Effect Unit
setupLogger app = do
Expand All @@ -194,6 +188,7 @@ setupUi game app = do
>>= Element.toNode
>>> Node.setTextContent (show $ Int.round fps)

Utils.fadeInSlow app.activeCanvas
Utils.fadeInSlow app.baseCanvas

query "#log-button" >>= \btn -> do
Expand Down
3 changes: 1 addition & 2 deletions app/frontend/packs/App/EaselJS/Container.js
Expand Up @@ -6,7 +6,6 @@ exports.addChild = e => c => () => c.addChild(e);
exports.addShape = e => c => () => c.addChild(e);
exports.addContainer = e => c => () => c.addChild(e);

exports.getShapes = e => () =>
e.children;
exports.getShapes = e => () => e.children;

exports.toDisplayObject = e => e;
18 changes: 18 additions & 0 deletions app/frontend/packs/App/EaselJS/DisplayObject.js
@@ -1,3 +1,5 @@
const EaselJS = require("@createjs/easeljs");

exports.update = attrs => obj => () => {
if (attrs.position) {
if (attrs.position.x) obj.x = attrs.position.x;
Expand All @@ -20,9 +22,25 @@ exports.getMatrix = obj =>
exports._getParent = obj =>
obj.parent;

exports._getStage = obj => {
let obj_ = obj;
while (obj_.parent) {
obj_ = obj_.parent;
}
return (obj_ instanceof EaselJS.Stage) ? obj_ : null;
};

exports.setHitArea = area => obj => () =>
obj.hitArea = area;

exports.hitTest = pt => obj => () =>
obj.hitTest(pt.x, pt.y);


exports.setShadow = shadow => obj => () =>
obj.shadow = new EaselJS.Shadow(shadow.color, shadow.offsetX, shadow.offsetY, shadow.blur);


exports.cache = rect => scale => obj => () =>
obj.cache(rect.x, rect.y, rect.width, rect.height, scale);

Expand Down
15 changes: 14 additions & 1 deletion app/frontend/packs/App/EaselJS/DisplayObject.purs
Expand Up @@ -5,7 +5,7 @@ import AppPrelude
import App.EaselJS.Matrix2D (Matrix2D)
import App.EaselJS.Point (Point)
import App.EaselJS.Rectangle (Rectangle)
import App.EaselJS.Type (Container, DisplayObject)
import App.EaselJS.Type (Container, DisplayObject, Stage)
import Data.Nullable (Nullable)
import Data.Nullable as Nullable
import Web.DOM (Element)
Expand All @@ -14,8 +14,18 @@ import Web.DOM (Element)
foreign import update :: forall attrs. attrs -> DisplayObject -> Effect Unit
foreign import getMatrix :: DisplayObject -> Matrix2D
foreign import _getParent :: DisplayObject -> Nullable Container
foreign import _getStage :: DisplayObject -> Nullable Stage

foreign import setHitArea :: DisplayObject -> DisplayObject -> Effect Unit
foreign import hitTest :: Point -> DisplayObject -> Effect Boolean

type Shadow =
{ color :: String
, offsetX :: Number
, offsetY :: Number
, blur :: Number
}
foreign import setShadow :: Shadow -> DisplayObject -> Effect Unit

foreign import cache :: Rectangle -> Number -> DisplayObject -> Effect Unit
foreign import localToGlobal :: Point -> DisplayObject -> Effect Point
Expand All @@ -26,6 +36,9 @@ foreign import getCanvas :: DisplayObject -> Effect Element
getParent :: DisplayObject -> Maybe Container
getParent = Nullable.toMaybe <<< _getParent

getStage :: DisplayObject -> Maybe Stage
getStage = Nullable.toMaybe <<< _getStage

copyTransform :: DisplayObject -> DisplayObject -> Effect Unit
copyTransform src dst = update src dst

Expand Down
5 changes: 5 additions & 0 deletions app/frontend/packs/App/EaselJS/Stage.js
Expand Up @@ -19,4 +19,9 @@ exports.update = stage => () => {
exports._getObjectUnderPoint = pt => stage => () =>
stage.getObjectUnderPoint(pt.x, pt.y);

exports.setNextStage = stage => next => () =>
stage.nextStage = next;

exports.toDisplayObject = stage => stage;

exports.toContainer = stage => stage;
3 changes: 3 additions & 0 deletions app/frontend/packs/App/EaselJS/Stage.purs
Expand Up @@ -15,6 +15,9 @@ foreign import invalidate :: Stage -> Effect Unit
foreign import update :: Stage -> Effect Unit
foreign import _getObjectUnderPoint :: Point -> Stage -> Effect (Nullable DisplayObject)

foreign import setNextStage :: Stage -> Stage -> Effect Unit

foreign import toDisplayObject :: Stage -> DisplayObject
foreign import toContainer :: Stage -> Container

getObjectUnderPoint :: Point -> Stage -> Effect (Maybe DisplayObject)
Expand Down
16 changes: 8 additions & 8 deletions app/frontend/packs/App/Interactor/BrowserInteractor.purs
Expand Up @@ -21,16 +21,16 @@ onWindowResize gi = do
Logger.info
$ "window resized: width: " <> show width <> ", height: " <> show height

let stage = gi.baseStage
canvas <- HTMLCanvasElement.fromElement stage.canvas
# throwOnNothing "Not Canvas element"
[gi.activeStage, gi.baseStage] # traverse_ \stage -> do
canvas <- HTMLCanvasElement.fromElement stage.canvas
# throwOnNothing "Not Canvas element"

Utils.setWidth (Int.toNumber width) canvas
Utils.setHeight (Int.toNumber height) canvas
HTMLCanvasElement.setWidth width canvas
HTMLCanvasElement.setHeight height canvas
Utils.setWidth (Int.toNumber width) canvas
Utils.setHeight (Int.toNumber height) canvas
HTMLCanvasElement.setWidth width canvas
HTMLCanvasElement.setHeight height canvas

Stage.invalidate stage
Stage.invalidate stage

attach :: GameInteractor -> Effect Unit
attach gi = do
Expand Down
42 changes: 32 additions & 10 deletions app/frontend/packs/App/Interactor/GameInteractor.purs
Expand Up @@ -22,9 +22,9 @@ import App.EaselJS.Type (Stage, DisplayObject)
import App.Game (Game)
import App.Game as Game
import App.Logger as Logger
import Control.Monad.Maybe.Trans (MaybeT(..), runMaybeT)
import Data.Array as Array
import Data.Int as Int
import Debug.Trace (traceM)
import Effect.Random (randomRange)
import Effect.Ref (Ref)
import Effect.Ref as Ref
Expand All @@ -49,6 +49,8 @@ create :: Game -> Element -> Element -> Effect GameInteractor
create game baseCanvas activeCanvas = do
baseStage <- Stage.create baseCanvas
activeStage <- Stage.create activeCanvas
Stage.toDisplayObject activeStage
# DisplayObject.setShadow { color: "#333", offsetX: 0.0, offsetY: 0.0, blur: 4.0 }
let translationTolerance = game.puzzleActor.body.linearMeasure / 4.0
let rotationTolerance = 24.0
dragger <- Ref.new emptyDragger
Expand All @@ -61,11 +63,13 @@ create game baseCanvas activeCanvas = do
game.pieceActors # traverse_ \actor -> do
Container.addShape actor.shape game.puzzleActor.container
PieceDrawer.draw actor $ PieceDrawer.withImage game.picture
boundary <- Rectangle.inflate 4.0 <$> Ref.read actor.localBoundary
boundary <- Rectangle.inflate 8.0 <$> Ref.read actor.localBoundary
DisplayObject.cache boundary 2.0 $ Shape.toDisplayObject actor.shape

Ticker.setFramerate 60
Ticker.onTick $ Stage.update baseStage
Ticker.onTick $ do
Stage.update activeStage
Stage.update baseStage

CommandManager.onPost \cmd -> do
actor <- Game.findPieceActor game $ Command.pieceId cmd
Expand All @@ -87,7 +91,9 @@ contain rect gi = do
let x = width / 2.0 - scale * (rect'.x + rect'.width / 2.0)
let y = height / 2.0 - scale * (rect'.y + rect'.height / 2.0)
DisplayObject.update { x, y, scaleX: scale, scaleY: scale } obj
DisplayObject.copyTransform obj $ Stage.toDisplayObject gi.activeStage
Stage.invalidate gi.baseStage
Stage.invalidate gi.activeStage


fit :: GameInteractor -> Effect Unit
Expand Down Expand Up @@ -174,7 +180,7 @@ movePointerTo pt gi = do
pt1 <- DisplayObject.fromGlobalTo obj pt
let vec = Point.subtract pt1 pt0
CommandManager.post $ Command.translate actor.body.id vec
Stage.invalidate gi.baseStage
Stage.invalidate gi.activeStage
Ref.modify_ (_{ pointer = pt }) gi.dragger


Expand All @@ -192,7 +198,7 @@ spinPointer angle gi = do
let obj = Container.toDisplayObject gi.game.puzzleActor.container
pt0 <- DisplayObject.fromGlobalTo obj dragger.pointer
CommandManager.post $ Command.rotate actor.body.id pt0 (angle - dragger.spinner)
Stage.invalidate gi.baseStage
Stage.invalidate gi.activeStage

pegZoomer :: Number -> GameInteractor -> Effect Unit
pegZoomer scale gi =
Expand All @@ -217,10 +223,17 @@ zoomPointer scale gi = do

resume :: Point -> GameInteractor -> Effect Unit
resume pt gi = do
piece <- runMaybeT do
obj <- MaybeT $ Stage.getObjectUnderPoint pt gi.baseStage
MaybeT $ lookupPieceActor gi obj
dragger <- Ref.read gi.dragger
piece <- do
p <- join <$> for dragger.piece \p' -> do
obj <- PieceActor.getFace p'
pt' <- DisplayObject.fromGlobalTo obj pt
bool Nothing (Just p') <$> DisplayObject.hitTest pt' obj
case p of
Nothing -> do
obj <- Stage.getObjectUnderPoint pt gi.baseStage
join <$> traverse (lookupPieceActor gi) obj
Just _ -> pure p
when ((_.body.id <$> dragger.piece) /= (_.body.id <$> piece)) do
release gi
traverse_ (capture gi) piece
Expand All @@ -238,6 +251,7 @@ attempt gi = do
pt0 <- DisplayObject.fromGlobalTo obj dragger.pointer
findMeargeableOn gi pt0 mergee
>>= traverse_ \merger -> do
release gi
CommandManager.post $ Command.merge merger.body.id mergee.body.id
CommandManager.commit
Ref.modify_ (_{ active = false, piece = Nothing }) gi.dragger
Expand All @@ -254,15 +268,23 @@ capture gi actor = do
when (isNothing dragger.piece) do
Logger.info $ "capture: " <> show actor.body.id
obj <- PieceActor.getFace actor
parent <- DisplayObject.getParent obj # throwOnNothing "No parent"
Container.addChild obj parent
Container.addChild obj $ Stage.toContainer gi.activeStage
DisplayObject.copyTransform
(Container.toDisplayObject gi.game.puzzleActor.container)
(Stage.toDisplayObject gi.activeStage)
Stage.invalidate gi.activeStage
Stage.invalidate gi.baseStage
Ref.write dragger{ piece = pure actor } gi.dragger

release :: GameInteractor -> Effect Unit
release gi = do
dragger <- Ref.read gi.dragger
dragger.piece # traverse_ \actor -> do
Logger.info $ "release: " <> show actor.body.id
obj <- PieceActor.getFace actor
Container.addChild obj $ gi.game.puzzleActor.container
Stage.invalidate gi.activeStage
Stage.invalidate gi.baseStage
CommandManager.commit
Ref.write dragger{ piece = Nothing } gi.dragger

Expand Down
17 changes: 16 additions & 1 deletion app/frontend/packs/App/Utils.purs
Expand Up @@ -2,8 +2,11 @@ module App.Utils where

import AppPrelude

import Control.Monad.Error.Class (try)
import Control.Monad.Loops (untilJust)
import Data.Array as Array
import Effect.Aff (Aff)
import Data.Time.Duration (Milliseconds(..))
import Effect.Aff (Aff, delay)
import Effect.Aff.Compat (EffectFnAff, fromEffectFnAff)
import Web.DOM (DOMTokenList)
import Web.DOM.DOMTokenList as DOMTokenList
Expand All @@ -23,6 +26,18 @@ foreign import _loadImage :: String -> EffectFnAff Element
loadImage :: String -> Aff Element
loadImage url = fromEffectFnAff $ _loadImage url


retryOnFailAfter
:: forall a.
Milliseconds -> Aff a -> Aff a
retryOnFailAfter ms action =
untilJust do
res <- try action
when (isLeft res) do
delay ms
pure $ hush res


selectElements :: String -> Effect (Array Element)
selectElements q = do
doc <- Window.document =<< HTML.window
Expand Down
6 changes: 3 additions & 3 deletions app/frontend/styles/playboard.scss
Expand Up @@ -26,9 +26,9 @@ body {

#active-canvas {
position: absolute;
filter:
drop-shadow(0 0 2px rgba(255, 255, 255, 0.8))
drop-shadow(0 6px 6px rgba(0, 0, 0, 0.4));
/* filter: */
/* drop-shadow(0 0 2px rgba(255, 255, 255, 0.8)) */
/* drop-shadow(0 6px 6px rgba(0, 0, 0, 0.4)); */

@extend .no-interaction;
}
Expand Down

0 comments on commit 20c2f9c

Please sign in to comment.