summaryrefslogtreecommitdiff
path: root/book/src/main/scalatex/book/handson/CanvasApp.scalatex
diff options
context:
space:
mode:
Diffstat (limited to 'book/src/main/scalatex/book/handson/CanvasApp.scalatex')
-rw-r--r--book/src/main/scalatex/book/handson/CanvasApp.scalatex19
1 files changed, 10 insertions, 9 deletions
diff --git a/book/src/main/scalatex/book/handson/CanvasApp.scalatex b/book/src/main/scalatex/book/handson/CanvasApp.scalatex
index 230ae67..b49f1e5 100644
--- a/book/src/main/scalatex/book/handson/CanvasApp.scalatex
+++ b/book/src/main/scalatex/book/handson/CanvasApp.scalatex
@@ -1,4 +1,5 @@
@import BookData._
+@val canvasapp = wd/'examples/'demos/'src/'main/'scala/'canvasapp
@p
By this point, you've already cloned and got your hands dirty fiddling around with the toy @lnk("workbench-example-app", "https://github.com/lihaoyi/workbench-example-app"). You have your editor set up, SBT installed, and have published the example application in a way you can host online for other people to see. Maybe you've even made some changes to the application to see what happens. Hopefully you're curious, and want to learn more.
@@ -21,7 +22,7 @@
@p
To begin with, lets remove all the existing stuff in our @code{.scala} file and leave only the @hl.scala{object} and the @hl.scala{main} method. Let's start off with some necessary boilerplate:
- @hl.ref("examples/demos/src/main/scala/canvasapp/ScratchPad.scala", "/*setup*/", end = "/*code*/")
+ @hl.ref(canvasapp/"ScratchPad.scala", "/*setup*/", end = "/*code*/")
@p
As described earlier, this code uses the @lnk.dom.getElementById} function to fish out the @code{canvas} element that we interested in from the DOM. It then gets a rendering context from that @code{canvas}, and sets the height and width of the canvas to completely fill its containing element. Lastly, it fills out the canvas light-gray, so that we can see it on the page.
@@ -31,7 +32,7 @@
@split
@more
- @hl.ref("examples/demos/src/main/scala/canvasapp/ScratchPad.scala", "/*code*/")
+ @hl.ref(canvasapp/"ScratchPad.scala", "/*code*/")
@less
@BookData.example(canvas, "ScratchPad().main")
@@ -55,7 +56,7 @@
@p
Again, we need roughly the same boilerplate as just now to set up the canvas:
- @hl.ref("examples/demos/src/main/scala/canvasapp/Clock.scala", "/*setup*/", "/*code*/")
+ @hl.ref(canvasapp/"Clock.scala", "/*setup*/", "/*code*/")
@p
The only thing unusual here is that I'm going to create a @hl.scala{linearGradient} in order to make the stopwatch look pretty. This is by no means necessary, and you could simply make the @hl.scala{fillStyle} @hl.scala{"black"} if you want to keep things simple.
@@ -65,7 +66,7 @@
@split
@more
- @hl.ref("examples/demos/src/main/scala/canvasapp/Clock.scala", "/*code*/")
+ @hl.ref(canvasapp/"Clock.scala", "/*code*/")
@less
@BookData.example(canvas, "Clock().main")
@@ -97,7 +98,7 @@
It's a relatively simple game, but there should be enough "business logic" in here that we won't be simply gluing together APIs. Let's start!
@sect{Setting Up the Canvas}
- @hl.ref("examples/demos/src/main/scala/canvasapp/FlappyLine.scala", "/*setup*/", end="/*variables*/")
+ @hl.ref(canvasapp/"FlappyLine.scala", "/*setup*/", end="/*variables*/")
@p
This section of the code is peripherally necessary, but not core to the implementation or logic of Flappy Box. We see the same @hl.scala{canvas}/@hl.scala{renderer} logic we've seen in all our examples, along with some logic to make the canvas a reasonable size, and some configuration of how we will render text to the canvas.
@@ -106,7 +107,7 @@
In general, code like this will usually end up being necessary in a Scala.js program: the Javascript APIs that the browser provides to do things often ends up being somewhat roundabout and verbose. It's somewhat annoying to have to do for a small program such as this one, but in a larger application, the cost is both spread out over thousands of lines of code and also typically hidden away in helper functions, so the verbosity and non-idiomatic-scala-ness doesn't bother you much.
@sect{Defining our State}
- @hl.ref("examples/demos/src/main/scala/canvasapp/FlappyLine.scala", "/*variables*/", end="def runLive")
+ @hl.ref(canvasapp/"FlappyLine.scala", "/*variables*/", end="def runLive")
@p
This is where we start defining things that are relevant to Flappy Box. There are roughly two groups of values here: immutable constants in the top group, and mutable variables in the bottom. The rough meaning of each variable is documented in the comments, and we'll see exactly how we use them later.
@@ -115,7 +116,7 @@
One notable thing is that we're using a @lnk("collection.mutable.Queue", "http://docs.scala-lang.org/overviews/collections/concrete-mutable-collection-classes.html") to store the list of obstacles. This is defined in the Scala standard library; in general, all the collections in the Scala standard library can be used without issue in Scala.js.
@sect{Game Logic}
- @hl.ref("examples/demos/src/main/scala/canvasapp/FlappyLine.scala", "def runLive", "def runDead")
+ @hl.ref(canvasapp/"FlappyLine.scala", "def runLive", "def runDead")
@p
The @hl.scala{runLive} function is the meat of Flappy Box. In it, we
@@ -135,13 +136,13 @@
@p
This function basically contains all the game logic, from motion, to collision-detection, to rendering, so it's pretty large. Not that large though! And entirely understandable, even if it takes a few moments to read through.
- @hl.ref("examples/demos/src/main/scala/canvasapp/FlappyLine.scala", "def runDead", "def run()")
+ @hl.ref(canvasapp/"FlappyLine.scala", "def runDead", "def run()")
@p
This is the function that handles what happens when you're dead. Essentially, we reset all the mutable variables to their initial state, and just count down the @hl.scala{dead} counter until it reaches zero and we're considered alive again.
@sect{A Working Product}
- @hl.ref("examples/demos/src/main/scala/canvasapp/FlappyLine.scala", "def run()")
+ @hl.ref(canvasapp/"FlappyLine.scala", "def run()")
@p
And finally, this is the code that kicks everything off: we define the @hl.scala{run} function to swap between @hl.scala{runLive} and @hl.scala{runDead}, register an @lnk.dom.onclick handler to make the player jump by tweaking his velocity, and we call @lnk.dom.setInterval to run the @hl.scala{run} function every 20 milliseconds.