Skip to content

AaronJRubin/dart-tank-battle

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Versions

Compile this code against version 1.7.2 of the Dart SDK, downloadable from https://www.dartlang.org/tools/sdk/archive (newer versions are not compatible with the three.dart library).

Overview

This is the source code for the browser-based game hosted at http://aarons-website.appspot.com/game-settings.html, built with Dart and WebGL (more specifically, the three.dart port of the three.js library that abstracts away some of WebGL's complexity).

#Rationale

The inspiration of this project was to demonstrate the ease of making 3D browser games in Dart. For many programmers who come from a desktop gaming background, the dynamic typing of Javascript and absence of Java/C#/C++ style classical inheritance provides a significant barrier to entry, and Dart provides an excellent alternative. There are, of course, other ways to write games that run in the browser using statically typed, object-oriented languages, such as the Unity game engine and Typescript. Unity, however, requires a browser plugin, which for some users can be a barrier to entry. Typescript is a superscript of Javascript, rather than a clean break, and lacks support for some features that many developers are used to such as abstract classes. Additionally, Dart has the advantage of performing better than Javascript when run in the Dart VM, and while no browsers have embedded the Dart VM as of the time that this document was last updated, there are hopes that we'll eventually see it in Chrome, at least.

#Overview

The intended entry point for the user of this application is game-settings.html, where the user selects the number of players, their color, the desired control scheme (although the default key configuration is probably optimal for most machines), and the game stage to be used. After choosing settings and pressing the "Play" button, the settings are saved in HTML5 local browser storage and the user is taken to bouncy-ball-battle.html, where the script in bouncy_ball_battle.dart is run. This script reads the settings from local storage, initializes a list of RealisticMovementPlayers and a Stage accordingly, and uses them to initialize a Game. Game's update function, called with the time elapsed since the previous call, updates game objects (including players, bullets, and items) and then renders the scene. This function is called every animation frame, and the time elapsed since the previous call is obtained via a top-level instance of the built-in Stopwatch class. Game has an instance of the Keyboard class, which keeps track of currently pressed keys, as an instance variable. The keyboard is passed to the players on each update, and that is how keyboard input is handled.

#How to Run the Code

The tank-battle-workspace directory contains the full directory tree for a Dart project, and can be imported into Dart Editor and run as-is, with game-settings.html as the entry point (though test.html and bouncy-ball-battle.html can also be run if you're not interested in custom settings). The darttopy.sh script (which assumes that pub, the dart package and build manager, is on your PATH) runs darttojs and then copies the generated files into a new directory in app-engine-site called "static" to allow them to be served using Google App Engine (Python SDK). The app engine site will not work unless that script is run first! You probably don't need to pay any attention to the app engine site, though, since the code of interest is all in tank-battle-workspace and it can be freely deployed to the server of your choice. It should be noted that because I use appcache to cache resources and allow for offline play, changes in the code will not be reflected in your browser unless you change dart-tank-battle.appcache, probably by changing the version comment at the top. Also note that game-settings.html is generated by the python script in tank-battle-workspace/generate_settings.py, which uses the Jinja2 templating engine. This approach allowed me to avoid repeating code for the many select boxes on that page, but it means that changes that you want to make to that file should be made by changing the template, rather than by changing the generated file in web. You might ask why I committed this generated file into the repository, in violation of standard version control practices. My reasoning was that some people who might want to explore this code might not have Python or the Jinja2 library installed, and I wanted there to be an option for someone to fork this repository and play around with it right out of the box without requiring any dependencies other than Dart.

#Why not use Polymer?

You might wonder why I used a Python templating engine to generate game-settings.html, rather than a Dart solution like polymer.dart. In fact, I did originally use Polymer for the user interface elements for the game settings. However, while I liked the semantic markup that Polymer provided, I found that the quirks and bugs associated with CSS encapsulation made responsive design difficult, that cross-browser support wasn't where I wanted it to be, and that there was a hefty performance overhead due to the dependencies involved. These problems might have been with Polymer itself, or they might been with my implementation of it, but in any event, I found Jinja2 to be a better solution for me.

For reference, this is the kind of markup that Polymer made possible, and that I used in a previous iteration of this project.

 <player-input id="player-1" leftKey="A" rightKey="D" accelerateKey="W" reverseKey="S" color="ORANGE" name="Player 1" use="true"></player-input>
 <player-input id="player-2" leftKey="LEFT" rightKey="RIGHT" accelerateKey="UP" reverseKey="DOWN" color="RED" name="Player 2" use="true"></player-input>
 <player-input id="player-3" leftKey="G" rightKey="J" accelerateKey="Y" reverseKey="H" color="YELLOW" name="Player 3"></player-input>
 <player-input id="player-4" leftKey="7" rightKey="9" accelerateKey="8" reverseKey="0" color="GREEN" name="Player 4"></player-input>

#Known Issues

WebGL has issues with transparency, in that sometimes textures with transparent backgrounds (needed for particle effects) fail to render at all. This results in the Lightning Fields in Nine Pillar Lightning Stage suddenly seeming to vanish for no reason. This problem seems to occur much more frequently when running this game as compiled Javascript, rather than in the Dart VM, which suggests to me that performance issues are responsible. In addition, this problem seems to occur much more frequently when running on a computer with a relatively unimpressive GPU (like the Macbook Air), though more testing is needed to confirm this. If you encounter this problem when playing the game, just use a different stage! And if you have any ideas about how this issue could be addressed, I'd love to hear them.

If you look at the Javascript console while playing this game, you might see some complaints like "WebGL: INVALID_VALUE: texImage2D: invalid image" and "WebGL: drawElements: texture bound to texture unit 0 is not renderable." These complaints arise from rendering a pure white (i.e., invisible) texture on top of the players, which WebGL doesn't seem to like. The reason that I use this invisible texture is to "bake" UVs into the player meshes; if a mesh does not have a texture on the first time that it is rendered, it becomes impossible to add a texture later, as I do to indicate that a player has been burned in the Lava Death Stage. While the renderer complains, this use of an invisible texture does what it needs to do, at no detriment to game performance. So this is not a bug!

About

The source code for the Dart/WebGL game hosted (and playable) at http://aarons-website.appspot.com/

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published