Skip to content

Simple HTML5 Canvas game ported to Scala,and cross compiled targeting the browser's HTML5 Canvas.

License

Notifications You must be signed in to change notification settings

amsterdam-scala/Sjs-Simple-HTML5-canvas-game

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

88 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

HTML5 Powered with CSS3 / Styling, Graphics, 3D & Effects, and Semantics[![Scala.js](https://img.shields.io/badge/scala.js-0.6.10%2B-blue.svg?style=flat)](https://www.scala-js.org) [![Build Status](https://travis-ci.org/amsterdam-scala/Sjs-Simple-HTML5-canvas-game.svg?branch=master_V2)](https://travis-ci.org/amsterdam-scala/Sjs-Simple-HTML5-canvas-game)

Simple HTML5 Canvas game ported to Scala.js

Featuring Scala.js "in browser testing" by ScalaTest 3.x

A Scala hardcore action game where you possess and play as a Hero 😄.

The focus is on showcasing the use of several Functional Programming technologies and therefore it's heavily violating on purpose the Principle of Least Power Strategic Scala Style.

Please rate this repository.

Project

This "Simple HTML5 Canvas Game" is a Scala.js project which targets a browser capable displaying HTML5, especially the <canvas> element. Stored on GitHub.com, due to sbt the code is also remote tested on Travis-CI. Also possible on an other continuous integration service.

This quite super minimalistic and simple game is heavily über engineered. It's certainly not the game that counts but the technology around this, it features:

  1. HTML5 Canvas controlled by Scala.js
  2. Headless canvas Selenium 2 "in browser testing" with the recently released ScalaTest 3.x
  3. ScalaTest 3.x featuring "async" testing styles.
  4. Test running on Continuous Integration service. Travis CI
  5. Scala 2.12 compiler.
  6. Exhaustive use of a variety of Scala features, e.g.:
  7. Reactive design, event driven instead of continuous polling.
  8. Eliminating a power-draining continuously redrawn of the canvas saves cpu time and (mobile) power.
  9. Tackling Cross-origin resource sharing CORS enabled images.
  10. Scala generated HTML.
  11. CSS rendered Corner Ribbon (as fastOptJS version).
  12. Scala 2.12 fresh Scaladoc look..

Motivation

Scala.js compile-to-Javascript language is by its compile phase ahead of runtime errors in production. It prevents you of nasty runtime errors because everything must be ok in the compile phase, specially the types of the functions and variables.

In the original tutorial in Javascript: How to make a simple HTML5 Canvas game, a continuous redraw of the canvas was made, which is a simple solution, but resource costly.

Usage

Play the live demo. Scaladoc you will find here. Installation instructions here

Architecture

class diagram

Discussion:

By the initial call from SimpleCanvas.main to Game.play its (private) gameLoop will periodic started given its framesPerSec frequency. There the status of eventually pressed arrow keys will be tested and per GameState.keyEffect converted to a move of the Hero. In an instance of GameState the position of the CanvasComponents are immutable recorded. When a change has to be made a new instance will be generated with only the changed variables adjusted and leaving the rest unchanged by copying the object.

With the changes in this CanvasState a render method of Page is only called if the instance is found changed.

The render method repaints the canvas completely. Successively the background, monster and hero will be painted, so the last image is at the foreground. The images found are the respectively instances of CanvasComponent subclasses Playground, Monster and Hero. They are asynchronously loaded once at startup by means of the use of Futures.

In spite of the fact that the application is technically one-tier in an MVC design pattern perspective, everything runs in the browser, the following parts can be identified:

Part Class Auxiliary
Model GameState Position
View Page CanvasComponents (Playground, Monster and Hero)
Controller Game GameState

Communication from Game to Page is done by calling with a modified GameState to Page.

Unit Testing

Unit testing is done with ScalaTest 3.x which is completely detached from the JVM system and Java runtime. Although running sbt, the test code will be executed in a browser. This is enabled by a Selenium environment interface direct running to Firefox and via Chrome Driver to a Google Chrome browser.

The necessary resources are downloaded from a external server because the test environment lacks a server for this this task.

The test tasks can be invoked by chrome:test for the Google Chrome browser and firefox:test, separated configs constructed in InbrowserTesting.scala. As proposed by this article.

Unfortunately at Travis-CI it's not possible to run Google Chrome, so firefox:test is the only option. Also unfortunately chrome:test fails on test 10, so if executed locally test 10 must be comment out.

Test Class file Coverage Remarks
CanvasComponentSuite canvasComponent Playground, Monster and Hero are concrete classes of CanvasComponent
GameStateSuite GameState
GameSuite Game
PageSuite Page
CanvasComponentSuite

This excercises a Hero instance against border limitations.

GameStateSuite

E.g. GameState equality.

GameSuite

Test the effect of the arrow keys on the Hero moves.

PageSuite

This is the most interesting unit test, it features:

  • Asynchronous non-blocking testing
  • Canvas testing
Asynchronous non-blocking testing

ScalaTest 3.x supports asynchronous non-blocking testing by returning a Future[Assertion] type. With this the assertion is postponed as long if the Future is not completed.

Canvas testing

Because of the difference of processing between various render engines in browsers, is it hard to test the content of a canvas. One pixel difference becomes immediately a negative test result. However, a couple of techniques can be used by hashing the canvas to a hash value. The techniques are:

  • Exact comparison, only possible if a complete image is rendered in the same sized canvas. In this case no processing (cropping, resizing) is required and therefor not tainted. Only the pixels of original source are used which gives the same result, even in different browsers. Actual it's a property of the source.
  • A different hash value per different browser. In this case there are multiple hash values valid, one per browser.
  • Tainted canvas. E.g. text on a canvas gives sometimes a slightly different result in pixels by e.g. rounding errors. The only test we can do is to test if the canvas has changed.

Installation instructions

  1. Clone the Github project to a new directory. This is the project directory which become the working directory of current folder.
  2. Naturally, at least a Java SE Runtime Environment (JRE) is installed on your platform and has a path to it enables execution.
  3. (Optional) Test this by submitting a java -version command in a Command Line Interface (CLI, terminal). The output should look like this:
java version "1.8.0_102"
Java(TM) SE Runtime Environment (build 1.8.0_102-b14)
Java HotSpot(TM) 64-Bit Server VM (build 25.102-b14, mixed mode)
  1. Make sure sbt is runnable from almost any work directory, use eventually one of the platform depended installers:
    1. Installing sbt on Mac or
    2. Installing sbt on Windows or
    3. Installing sbt on Linux or
    4. Manual installation (not recommended)
  2. (Optional ) To test if sbt is effective submit the sbt sbtVersion command. The response could look like as this:
[info] Set current project to fransdev (in build file:/C:/Users/FransDev/)
[info] 0.13.13

Remember shells (CLI's) are not reactive. To pick up the new environment variables the CLI must be closed and restarted.

  1. Run sbt in one of the next modes in a CLI in the working directory or current folder, a compilation will be started and a local web server will be spinned up using:
    1. Inline mode on the command line: sbt fastOptJS or
    2. Interactive mode, start first the sbt by hitting in the CLI sbt followed by fastOptJS on the sbt prompt, or
    3. Triggered execution by a ~ before the command, so ~fastOptJS. This command will execute and wait after the target code is in time behind the source code (Auto build).
    4. chrome:test will run the ScalaTest test scripts in the test directory in a Google Chrome browser.
    5. firefox:test will start the ScalaTest test scripts in the test directory in a FireFox browser. (preferred)
  2. sbt will give a notice that the server is listening by the message: Bound to localhost/127.0.0.1:12345 (Ignore the dead letter notifications with the enter key.)
  3. Open this application in a browser on this given URL

When running this way a tool "workbench" also will be running in the browser, noticeable by opening the console of the browser.

Licence

Licensed under the EUPL-1.1

Language                     files          blank        comment           code
-------------------------------------------------------------------------------
Scala                            6             96            113            261


game.js
-------------------------------------------------------------------------------
Language                     files          blank        comment           code
-------------------------------------------------------------------------------
JavaScript                       1             21             16             93

Scala.js minimal project
-------------------------------------------------------------------------------
Language                     files          blank        comment           code
-------------------------------------------------------------------------------
JavaScript                       1             26              1            572

-------------------------------------------------------------------------------
Language                     files          blank        comment           code
-------------------------------------------------------------------------------
JavaScript                       2            795              1          15423
HTML                             2             13             25             51
CSS                              1             14              0             49
-------------------------------------------------------------------------------
SUM:                             5            822             26          15523
-------------------------------------------------------------------------------