@@ 1,276 1,7 @@
# Qwerty War
-Qwerty War is a JavaScript typing game inspired by [Qwerty Warriors].
-
-# Design: day 1
-
-Goal is to build a text-only version of the game, without persistent, server-side leaderboard or any kind of sound and graphics. -If I have time, I might build a front-end to the leaderboard that just stores scores in memory.- Makes more sense to use a normal post/redirect with server-side template, so no point building much outside the server side code.
-
-Each main loop, these things will happen. Most can be independent, so actually I don't see any need to actually write a main loop; the browser can send events and let us set up timers.
-
-* If player presses enter
- * done: the original only accepts the enter key, but I think it would be nice to accept space as well
- * done: clear the text entry box
- * done: if the word typed matches an enemy, kill the enemy
- * done: if the word matches a "fullhealth", refill player's health and remove the fullhealth
- * done: if the word matches a "detonate", kill everything on the field, including fullhealths and detonates
- * done: (ish) score based on killed enemy difficulty
- * done: (ish) As a first cut, enemy difficulty can be based only on word length. I think it should not increase linearly with the length of the word, rather with the chance of making an error typing the word. Do some math to figure out what the increase should be. A more sophisticated system might take into account the total difficulty of the word by letter/n-gram frequency or something like that. For now, word length should be fine.
- * done: (ish) Should enemies killed by a "detonate" score less than enemies shot normally? That would give some bonus to saving your detonates. For now, I will have them score the same.
-* done: Each enemy out of range moves closer to the player
- * done: (ish) Should enemies all have the same range? In the original, they do not. For now I'm just picking from a uniform random distribution between a min and max shooting radius, but consider weighting by distance so that fewer enemies get close, to avoid clumping.
- * done: (ish) Should they all move at the same speed?
-* done: Each enemy in range shoots the player
- * done: (ish) Do they all do the same damage? Maybe enemies with longer ranges can do less damage. Varying the range will be useful visually so you don't have get lots or enemies in a ring overlapping each other.
- * done: Take away player health
- * done: If player health reaches zero, game ends
-* Generate new enemies
- * done: Enemies should get generated more frequently as the player's score goes up
- * done: Also, as the player's score goes up, the proportion of more difficult enemies should go up
- * done: Should never generate an enemy with the same word as one currently visible
- though having multiples of the same word at a time might make for an interesting aspect to the game...
- * done: Where can I get a dictionary? Scrabble dictionary, maybe?
-* done: generate fullhealth and detonate items
- * done: I think these show up at uniform random intervals, both can be on the field at once, but never two of one kind
- * Make sure that these don't land on top of each other (this is a visual thing, really, under the covers these items don't need to have any position at all)
-
-For now, I'm ignoring the difficulty levels, but I think that they only affect how quickly enemies get generated and the proportion of difficult enemies.
-
-The probably distributions for enemy generation speed and difficulty scaling may need adjustment, but they feel about right to me as is.
-
-## Looping options
-
-I see several possible ways to design this: first, it could be a single main loop on a setInterval. This seems silly, since the steps are independent and it would probably make responses to the player's fire keypress less responsive. Could make the fire keypress event-driven and the rest on a loop.
-
-It feels a bit cleaner to put each major step on its own timer though, as they really are independent. Difficulty could easily be increased just by speeding up the enemy generation timer, for example. There shouldn't be any problem with timers not firing quickly enough, as [minimum timer intervals] were hitting under 20ms six years ago.
-
-A third option would be to make a timer per enemy and destroy the timer when the enemy gets killed. This feels unnecessarily complicated.
-
-## Pausing and starting
-
-When focus leaves the typing box, the game should pause (though you can't pause a real war, so maybe not?). The original lets you pause by pressing ctrl, so -I guess this should do that as well- removed because ctrl+backspace is used for deleting entire words and I found that I accidentally paused the game that way.
-
-The game should start when focus is in the input area and the player presses enter. The original Qwerty Warriors starts as soon as you focus the input box, but I find that annoying.
-
-When the game starts, it should generate the first enemy immediately, then start the random generation.
-
-## When game ends
-
-Offer the player an input box to enter a name. When submitted, save the player's score and show the leaderboard.
-
-## User interface elements
-
-* A table of enemies with two columns: word and range
-* An input box for typing
-* A div for player score
-* A div for player health
-* A div (or maybe the label on the input box) to show game status: that is, paused, running or ended
-
-After the game ends
-
-* A form with a text box for entering your name
-
-In the leaderboard
-
-* A table of player names and scores
-** Some way to indicate which is you
-** If we show, say, the top 1000 scores, and you are near the bottom, hide those between the top and you
-** use a guid cookie for this? what if you share the computer? might be overthinking the problem, could just highlight the score from the last game
-* A link to return to the main game
-
-# Design: day 2
-
-For day 2, I want to build the graphical front end with generic shapes for players, no fancy drawings. Maybe some basic sounds.
-
-The original has a volume control and a quality toggle, when paused. I don't see the point.
-
-I could use ordinary html elements, moving them around with position absolute, or do the entire thing as svg, but canvas seems like the obvious choice.
-
-It doesn't strictly require a background, but I think it would be visually interesting to start with a completely white page and leave explosion splatter for each killed enemy. So the background will be mostly static, only sometimes adding to its content. Probably that should be its own canvas, and another canvas will all the moving elements should be on top.
-
-Build the moving elements first. They are:
-
-* Player: doesn't really need to move, but I think it will be more dynamic if he rotates to face the enemy being targetted. Can do this just by calculating the rotation to the enemy who matches the most characters at the beginning of the word being typed.
-* Enemies: these are coming in from the edges and facing the player
-* Bombs
-* Healthpacks
-
-I want the look to be sort of photo-like, so I'll plan to use bitmap sprites as opposed to svg or otherwise using the canvas api to draw primitive shapes. Eventually, I'll get nice looking drawings, maybe from somebody on Fiverr, but for now I'll start with some simple. The moving elements, player and enemies should have a clear front direction, as they'll rotate (canvas translate and rotate functions should be useful). The bombs and healthpacks should not be rotated toward the player.
-
-Once these are in, do the visual effects:
-
-* Explosions: start with one for each type of enemy and one for the player. In the future, might be nice to add more and maybe some randomness, but for now I'll just make four sprite strips on http://explosiongenerator.com/
- * An easy randomization might be to rotate the explosion a random amount
- * Near the end of the generated explosions, there is a point where most of what's left is "smoke", that is dark stuff. If I stop the animation at that point and draw the remainder of the background, I think I'll get a good scorched earth effect on the background.
-* Bullets: when you shoot an enemy, it should look like a bullet travels from you to the enemy, and vice versa when you are shot
- * This implies that the explosion timing will need to come a little bit after the player actually shoots. In the text-only version, the kill is immediate, so that will take some tweaking. My first thought is just to make this visual: so move "dead" enemies from the live enemy collection to a dead enemy collection, with a time of death. The animation loop can then calculate when the dying effect should actually happen. This means the scoring and health changes would be slightly ahead of the visuals. The time difference would be based on distance to enemy, but if I keep bullet speed fast enough that the farthest possible distance is within a tenth of a second or so, I don't think the discrepency will be noticeable.
- * May need to adjust how ending the game works, since it will be neat to follow through with animating the final shots that hit the player, even after the game has ended.
- * For this, I probably use the line drawing available in canvas. I think bullets can just be a bright line in the right direction, possibly with a gradient to fade out the tail.
- * When the player misses, a bullet should go off the edge of the screen in whatever direction the player is facing at the time.
-* Powerup effects. For now, I think no powerup visuals. The effect of exploding a bunch of enemies when you hit a bomb should be interesting enough. I'm not sure what a nice effect is for hitting fullhealth.
-* Damage. Might be fun to have damage animations on the player, so a blood splatter, for example, when you get hit. Will do try this if I have enough time. I later realized this is fairly important so it's more obvious when you're hit.
-* Muzzle flash: would be useful to see who is shooting.
-
-Also, need to reposition the score, health and input boxes. The original has these at the bottom, but I think putting health above the player and input below makes more sense. Score can be somewhere in the margin. Words associated with enemies can go below the enemies. -Since I will keep these regular html elements, need a calculation for converting canvas coordinates to page coordinates.- Should be fairly easy if I just make everything position:fixed, but remember to check how it resizes.
-
-After a bit of consideration, I think that drawing the text using canvas api will be simpler than displaying and positioning the table cells. Should pick up a nice open source font so that metrics can be consistent across browsers.
-
-I decided that it was cleaner to do the scoring of shots when the shot hits, instead of scoring the shot immediately and animating it later. So, will need to consider how to finish up the game still, by keeping animations running and finalize the scores.
-
-Hint: the imagemagick command to making a sprite strip for animating explosions looks like this:
-
- montage images/*.png -geometry +0+0 -tile 49x4 -background none explosion.png
-
-I originally made the explosion just a single horizontal strip, but found that once the .png got too wide, Firefox could not load it. Pinta also had trouble with it. So I make each explosion sprite strip 4 frames tall.
-
-Or to make the file smaller, use only every fourth frame:
-
- montage images/explosion0{000..191..4}.png -geometry +0+0 -tile 12x4 -background none explosion1.png
-
-# Design: day 4 - audio
-
-Use the Web Audio api, there are a good number of free (Creative Commons attribution) sounds available online.
-
-Simplest thing:
-
-* Gunshot sound when player or enemy fires
-* Explosion sound when enemy blows up
-* -Some sort of ping or thud when player gets hit- after testing plain shooting sounds, I think this is unnecessary. It'll just get lost in the cacophony.
-
-For starters, just need one explosion and one shot, but it probably will be more interesting to have a variety. Should be easy to use a different explosion depending on enemy type.
-
-* Whiz sound for bullets
-* Movement sounds for enemies
-* Sound when powerups appear
-* Alarm sound when health is low?
-* Delay by distance? When multiple enemies explode at once, particularly in the bomb scenario, each explosion sound will just fall on top of the other. This probably will be a fairly boring effect. A slight delay, maybe proportional to distance from player might make it more interesting. Or could delay each enemy explosion by some amount based on distance from the bomb. That would pair well with a visual effect of some sort of concentric explosion moving out from the bomb over the whole surface, but I think that is probably too much effort for this project.
-* Vary volume by distance? I think this could give variety to the sounds, making them more interesting.
-* Echo? Some amount of random echo could also make things interesting.
-* Music? The original has music and its intensity seems to build and fall depending on the number of enemies on the field, though that could be an illusion. Music would be fun, but I think too much effort for this project.
-* A mute button
-
-# Design: day 5 - leaderboard
-
-I think build on Django, deploy on Heroku. Python 3. A very simple crud app, has two operations:
-
-* Post a score + name (remember to put in csrf protection - not really important, but why leave it out?)
-* Retrieve list of scores + names
-
-Also, build in different leaderboards per difficutly level, even though that's not implemented in the game yet. So store this info for each post:
-
-* Name
-* Date/Time
-* Difficutly level
-
-When serving the leaderboard, show the most recent 1000 entries, ordered by score, descending. Focus the entry just submitted.
-
-Using Django's startproject gives a ton of organizational structures that I just don't need for an app of this size. So, looking at [Django as a micro framework], I figure I can roll this all from stratch. I had to start the app a little differently from in the article, probably because that was for an older Django version.
-
-Notably, to get started:
-
- django-admin runserver --settings settings --pythonpath .
-
-Update: Heroku requires a manage.py, so that is now available. For local development, run:
-
- export DJANGO_DEBUG=1
- python manage.py runserver
-
-From there, there will be other errors, but they are easy enough to figure out.
-
-# Finishing touches
-
-Day 6
-
-* done: Auto-player
-* done: Collision detection
-* done: Make sure score submission form doesn't activate too quickly after game ends & requires a name input
-* done: Styling the score submission form
-* done: Fonts: metrics matter, so a predictable font will be useful. Baron http://www.fontfabric.com/baron-free-font/ [turns out I didn't like how this looked once I had it in for the headings] probably will look good for the title and DejaVu Sans, http://dejavu-fonts.org/wiki/Main_Page, should be good for the rest
-* reported: Motion animation (wheels turning, etc)
-* done: Better sprites
-* done: Adjust sprite center offsets
-* reported: Muzzle flash animation
-* done: Performance testing
-** on Android mobile, framerate is bad
-** on by Lenovo Y50-70 (ff, Kubuntu), hdpi screen, framerate is really bad
-** Can't see most of the bullets in Chrome on my Lenovo laptop (framerate probably too low)
-* done: Styling leaderboard
-* Difficulty levels (and separate leaderboards)
-* done: Footer note when audio is unsupported
-* done: License
-* done: About page
-* done: Cross-browser testing
-* done: Favicon
-* done: Loading spinner
-* done: Back button from leaderboard. Behavior is a bit different depending on the broser - ff takes you back to the score submission form, but chrome reloads the game. Either way is fine, so I don't see any reason to change it.
-* done: -Associate time zones with sessions: timezones are ok when you submit your score, but not when you go straight to a leaderboard link- Used humanize on the leaderboard dates instead so don't need to know user time zone.
-* done: Set up bug tracker
-* done: Purchase domain
-* Go through production checklists (Heroku & Django docs)
-* Send log errors by email
-* reported: Bug where the first enemy sometimes doesn't get his word drawn
-* reported:_Handle window resizes
-* reported: Draw enemies below explosions
-* reported: Error pages
-* reported: No sound with ff on my Lenovo laptop?
-* reported: Explosion when player dies
-* skip: Styling the user inputs
-* skip: Styling the health slider
-* reported: Add words per minute calculation
-* reported: Add errors calculation
-* reported: Text-only mode
-* done: Link to bug tracker in error message
-* reported: Powerup sounds
-
-# Credits
-
-## Sound
-
-Gunshots from [layered gunshot collection]
-Explosions from https://www.freesound.org/people/unfa/sounds/352143/
-
-# Notes about Python3 Linux
-
-On Kubunutu:
-
- sudo apt install python3-pip
- sudo -H pip3 install --upgrade pip
- sudo -H pip3 install virtualenv
- virtualenv venv
- source venv/vin/activate
- pip install django # for development, for production-like -r requirements.txt
- export DJANGO_DEBUG=1 # development only
-
-For Heroku deployment:
-
- sudo apt install python-pip
- sudo pip install hg-git
-
-And add to ~/.hgrc:
-
- hgext.bookmarks =
- hggit =
-
-Then, assuming you've set up your ssh access to Heroku and a project, add in the .hg/hgrc:
-
- [paths]
- ...
- heroku = git+ssh://git@heroku.com:[app name].git
-
-And deploy:
-
- hg push heroku
-
-This seemed to more or less work the first time, but I didn't have a Heroku Procfile or wsgi.py, so I added them and the next push said nothing was found. So, I tried to pull from the repo listed in Heroku's control panel proper - substituting "ssh" for "https" - with git proper, and it waited for a long time before finally timing out. Pulling from the https url fails because it wants me to have the Heroku command line client.
-
-So I start looking for alternatives. [Gondor] looks pretty nice, but also much more expensive. Starts at $100 per month.
-
-After poking around a bit, I decided to try Heroku again, deleted and recreated the app. Then used hg archive to export without history and created this as a new git repo. I removed the comparatively large original sound files and then set up as described in http://stackoverflow.com/a/27102190. This was more successful. I suspect that either hg-git or Heroku disliked the large files.
+Qwerty War is a JavaScript typing game inspired by [Qwerty Warriors]. Play at http://www.qwertywar.com/.
---
-[minimum timer intervals]: http://www.adequatelygood.com/Minimum-Timer-Intervals-in-JavaScript.html
[Qwerty Warriors]: http://www.crazymonkeygames.com/QWERTY-Warriors.html
-[layered gunshot collection]: https://www.freesound.org/people/Xenonn/packs/8014/
-[Django as a micro framework]: http://softwaremaniacs.org/blog/2011/01/07/django-micro-framework/en/
-[Gondor]: https://gondor.io/