Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
svalair committed Jan 8, 2018
0 parents commit 17f6799
Show file tree
Hide file tree
Showing 141 changed files with 17,444 additions and 0 deletions.
46 changes: 46 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# Logs
logs
*.log

# Runtime data
pids
*.pid
*.seed

# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov

# Coverage directory used by tools like istanbul
coverage

# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
.grunt

# Compiled binary addons (http://nodejs.org/api/addons.html)
build/Release

# Dependency directory
# Commenting this out is preferred by some people, see
# https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git-
node_modules

# Output directory
release/

# Users Environment Variables
.lock-wscript

# IDE metadata
.idea/

# OS X metadata
**/.DS_Store

# all map files
**/*.js.map

# any transpiled javascript files
/src/**/*.js
/test/**/*.js

package-lock.json
28 changes: 28 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
Copyright (c) 2014, Florian Rappl
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.

* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.

* Neither the name of GulpSamples nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

210 changes: 210 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,210 @@
Mario5 TS
=========

This repository contains the code for the TypeScript version of the Mario5 demo application.

* This repository was forked from [https://github.com/FlorianRappl/Mario5TS] and adapted to:
* Use TypeScript 2.0+.
* Be buildable inside IDEs.
* Not depend on `gulp` (e.g., be buildable with `tsc` alone).
* Be testable with automated unit tests.
* The original JavaScript code is available in `reference/`.
* The description below hints, where features of TypeScript have been placed.
* An article describing the original code is available on [CodeProject](http://www.codeproject.com/Articles/396959/Mario).
* The system is built by using `gulp`.

Requirements
------------

For compiling the code you will need the following applications:

* npm (tested with v5.0.3) for installation

Installation
------------

First you should clone the repository. Then in the directory of the repository run:

`npm install`

To build the application, run:

`npm run configure`

And then:

`webpack`

This will compile everything and copy resources a subfolder called `release`. If you want to play the game from this version you can:

`npm run serve`

During development, you can build the application with either of the two following commands:

`npm run build`
`tsc`

Either of these commands will cause the browser-version to refresh, if you have run the `serve` command above.


TypeScript Features
-------------------

This section contains a list of features that have been used in the transformation process. Each feature usage is shortly described, and decorated with a concrete example comparing old (vanilla JS) code to new (TS annotated) code.

### Type annotations

Type annotations are the core concept of TypeScript. There is no equivalent in JavaScript, and even though some people propose type annotations to ES for a while, it will probably never be part of the standard. That being said: TypeScript uses a compile-time type system. Every annotation will disappear during the compilation process and won't be present in the final JavaScript output.

Therefore there is no comparison. However, there are some important hints. First example:

var basepath = 'Content/';

There is nothing to do. The variable `basepath` is already infered to be of type `string`. Nevertheless, sometimes it makes sense.

var definedLevels: LevelFormat[] = /* ... */;

The type `LevelFormat` is an interface. This brings us to the next feature.

### Interfaces

Interfaces describe how objects should look like. They are quite close to interfaces in C#, Java and similar languages, however, they do not represent a runtime type and cannot be used for real type detection with an `instanceof` operator. Again, this is a TypeScript only feature and necessary due to TypeScript's desire to specify as much as possible.

The interface for the `LevelFormat` looks as follows:

interface LevelFormat {
width: number;
height: number;
id: number;
background: number;
data: string[][];
}

Interfaces can also be extended in TypeScript. This is really useful, since in ES no instantiated object is every finished. No designed class is cut in stone. In case of Mario5 the `Math` object (let's call it a static class, just for comparison to C# or Java) is extended with the `sign` method. This is not allowed unless we extend the specification of the `Math` object's underlying interface definition:

interface Math {
sign(x: number): number;
}

This merging makes it possible to allow, e.g., jQuery plugins, i.e. scripts that extend the original definition with further functionality.

### Classes

Here is where it gets more interesting. Previously I used some kind of custom "OOP" script to allow easier definition of "class"-like objects and inheritance. However, TypeScript has everything I need included.

The original code was:

var Gauge = Base.extend({
init: function(id, startImgX, startImgY, fps, frames, rewind) {
this._super(0, 0);
this.view = $('#' + id);
this.setSize(this.view.width(), this.view.height());
this.setImage(this.view.css('background-image'), startImgX, startImgY);
this.setupFrames(fps, frames, rewind);
},
});

In the new version that becomes:

class Gauge extends Base {
constructor(id: string, startImgX: number, startImgY: number, fps: number, frames: number, rewind: boolean) {
super(0, 0);
this.view = $('#' + id);
this.setSize(this.view.width(), this.view.height());
this.setImage(this.view.css('background-image'), startImgX, startImgY);
this.setupFrames(fps, frames, rewind);
}
};

I already use annotations to limit the usage of the constructor. In the end that is really useful for preventing bugs. A really tricky bug might be to forget that the `this` pointer is a contextual pointer, not an instance/object pointer. However, this is solved by the fat-arrow operator.

### Fat-Arrow operator

The Fat-Arrow operator is another ES6 feature that made it into TypeScript. The syntax should be familiar to C# developers. It is also quite close to the one used in Java. Both languages name it a lambda expression. In TypeScript / ES6 this kind of function definition has also the advantage of preserving the current `this`.

Let's see an example in the old code:

var Level = Base.extend({
/* ... */
start: function() {
var me = this;
me.loop = setInterval(function() {
me.tick.apply(me);
}, constants.interval);
},
/* ... */
}

With TypeScript this can be even simplified. The new version is shorter, easier to read and does not require the explicit capturing. TypeScript is, however, of course solving the problem like we did before. Nevertheless, if one is not sure about what `this` might be, the fat-arrow function is definitely a robust solution.

class Level extends Base {
/* ... */
start() {
this.loop = setInterval(() => this.tick(), setup.interval);
}
/* ... */
};

Another feature that makes TypeScript worth using is the modules system. It only plays well with AMD and CommonJS structured modules, but is independent of a concrete implementation.

### Modules

The basic currency in a TypeScript file is definitions. First, TypeScript checks for any syntax errors. If that validation is okay, then the infered types will be checked. Naturally we will also use types, that are not defined within that one file. TypeScript knows about this and implicitely uses the definitions of the JavaScript standard library. But what if we want to include, e.g., jQuery?

We can tell TypeScript that a specific file will have access to more globally available variables by including a reference to a file that defines the available functionality. The functionality may be defined through the original file (including the implementations), or a special kind of file called a *definition file*.

We achieve this by placing a special kind of comment at the top of a file:

/// <reference path="def/interfaces.d.ts"/>

That way we can have a lot of independent files, which will be required to be placed / loaded by us in an optimal order. However, this has nothing to do with modules directly.

The path described earlier is great for web-development, but cannot be used with node. Here our only hope is to load modules using the CommonJS pattern. Therefore we need to define the external legs of a file. Everything else is internal only. These external legs form the exported parts of a module.

TypeScript distinguished between two kinds of modules: internal modules and external modules. While external ones bridge between files, internal modules alias within files.

The code has not been modularized before. Therefore there is no equivalent, however, there could have been. This is an improved design, that is decoupled from a specific module pattern (such as CommonJS or AMD) by TypeScript.

We use external modules. Declarations have been placed like the following:

export = definedLevels;

Here the whole file exports just a single object. But this object is everything that is imported. See:

import levels = require('./testlevels');

This is equivalent to the former notation (with a global `definedLevels`):

var levels = definedLevels;

Difference: No polluation of the global namespace, less coupling. There are also other examples:

export function run(levelData: LevelFormat, controls: Keys) {
var level = new Level('world', controls);
level.load(levelData);
level.start();
};

This can be found in the *main.ts*. We use it as follows:

import game = require('./main');
/* ... */

$(document).ready(function() {
game.run(levels[0], controls);
});

Before we only had one document ready function that basically did both things. More coupled, less extension friendly.

What about internal modules? They are used as well!

import constants = require('./constants');
import Direction = constants.Direction;

Usually we would be required to rename all occurrences of `Direction` to `constants.Direction`. It is not possible to use

var Direction = constants.Direction;

even though this brings in the correct value at runtime. The problem is, that TypeScript's metasystem will not accept dynamic variables as such types. Therefore we need to alias it correctly. This is done via the `import` statement. Nevertheless, here we use it on a module (`constants`). This is different to the first line, where we use it with `require`, which brings in an (external) module.

The great thing about this modular approach: We do not need to include the references as described above. They will be resolved automatically.
Binary file added assets/audio/coin.mp3
Binary file not shown.
Binary file added assets/audio/coin.ogg
Binary file not shown.
Binary file added assets/audio/die.mp3
Binary file not shown.
Binary file added assets/audio/die.ogg
Binary file not shown.
Binary file added assets/audio/editor.mp3
Binary file not shown.
Binary file added assets/audio/editor.ogg
Binary file not shown.
Binary file added assets/audio/ending.mp3
Binary file not shown.
Binary file added assets/audio/ending.ogg
Binary file not shown.
Binary file added assets/audio/enemy_die.mp3
Binary file not shown.
Binary file added assets/audio/enemy_die.ogg
Binary file not shown.
Binary file added assets/audio/game.mp3
Binary file not shown.
Binary file added assets/audio/game.ogg
Binary file not shown.
Binary file added assets/audio/gameover.mp3
Binary file not shown.
Binary file added assets/audio/gameover.ogg
Binary file not shown.
Binary file added assets/audio/grow.mp3
Binary file not shown.
Binary file added assets/audio/grow.ogg
Binary file not shown.
Binary file added assets/audio/hurt.mp3
Binary file not shown.
Binary file added assets/audio/hurt.ogg
Binary file not shown.
Binary file added assets/audio/invincible.mp3
Binary file not shown.
Binary file added assets/audio/invincible.ogg
Binary file not shown.
Binary file added assets/audio/jump.mp3
Binary file not shown.
Binary file added assets/audio/jump.ogg
Binary file not shown.
Binary file added assets/audio/lifeupgrade.mp3
Binary file not shown.
Binary file added assets/audio/lifeupgrade.ogg
Binary file not shown.
Binary file added assets/audio/menu.mp3
Binary file not shown.
Binary file added assets/audio/menu.ogg
Binary file not shown.
Binary file added assets/audio/mushroom.mp3
Binary file not shown.
Binary file added assets/audio/mushroom.ogg
Binary file not shown.
Binary file added assets/audio/peach.mp3
Binary file not shown.
Binary file added assets/audio/peach.ogg
Binary file not shown.
Binary file added assets/audio/shell.mp3
Binary file not shown.
Binary file added assets/audio/shell.ogg
Binary file not shown.
Binary file added assets/audio/shoot.mp3
Binary file not shown.
Binary file added assets/audio/shoot.ogg
Binary file not shown.
Binary file added assets/audio/success.mp3
Binary file not shown.
Binary file added assets/audio/success.ogg
Binary file not shown.
Binary file added assets/backgrounds/01.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/backgrounds/02.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/backgrounds/03.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/backgrounds/04.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/backgrounds/05.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/backgrounds/06.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/backgrounds/07.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/backgrounds/08.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/fonts/Super Mario Bros.ttf
Binary file not shown.
41 changes: 41 additions & 0 deletions assets/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8"/>
<title>Super Mario HTML5 Test</title>
<link href="./style.css" rel="stylesheet"/>
</head>
<body>
<div id="game">
<div id="world">
</div>
<div id="coinNumber" class="gauge">0</div>
<div id="coin" class="gaugeSprite"></div>
<div id="liveNumber" class="gauge">0</div>
<div id="live" class="gaugeSprite"></div>
</div>
<script src="./lib/jquery.js"></script>
<script src="./mario.js"></script>
<!-- <script src="./lib/system.src.js"></script> -->
<script>
/*
System.config({
packages: {
'./': {defaultExtension: 'js'}
}
});
SystemJS.import('./js/src/game.js').then(function (code) {
console.log('index starting app');
// window.appGeo = new code.App();
console.log('index starting app - done');
}).catch(function (err) {
console.log('index load error: ' + err);
});
*/
</script>
<!-- <script data-main="Scripts/game" src="Scripts/require.js"></script> -->

</body>
</html>
4 changes: 4 additions & 0 deletions assets/lib/jquery.js

Large diffs are not rendered by default.

Loading

0 comments on commit 17f6799

Please sign in to comment.