Strike Tactics Tournament #2 Results

Congratulations to ZertoN for being the champion of the second official Strike Tactics tournament.  It was a grueling best of 3 final set of matches between ZertoN and kthocken with back and fourth Manta trades that seemed to go on forever. It was mentally exhausting to watch so I can only imagine how mentally exhausting it was to play.

Watch the full tournament below!

Standing and final results.

v1.065 patch notes

Features

  • Added new harpy gun sound and peregrine machine gun sound. 

Fixes

  • Fixed AI not being able to construct anything in the beginning of the game because an enemy scout was nearby. 
  • Fixed bullets appearing visible earlier than they should when leaving the gun. 
  • Computer no longer builds an necessary number of silos in the early game and will build a mech factory and bombard cannons before building silos. 
  • Game found desktop notification no longer appears if you are already in the tab. 
  • Changed the full screen icon into something more intelligible. 
  • Fixed AI sometimes not seeing enemy units in multiplayer games. 
  • Fixed some unit targeting issues. 
  • Fixed bullets sometimes not being recycled properly (i.e. being weaker or stronger than they should be). 

Gameplay

  • Pulsar cannons damage reduced from 175 to 100. Pulsar cannons continue to have area of effect damage. 
  • Harpy firing rate improved (fires every 100 milliseconds instead of 150).
Tags: 

Announcing: stba.io

Yesterday I launched stba.io, an official spin-off which stands for Strike Tactics Battle Arena. In stba.io, spawn as any Strike Tactics unit and work to destroy the enemy command center before the opposing team destroys yours. Your unit levels up and has abilities, like a MOBA hero. Increase your kill count to access more powerful units like the Harpy and Battleship. 

stba.io multiplayer HTML5 game

The game only took a few weeks to make, mostly because I forked it from the Strike Tactics codebase and utilized all of the same art assets. I intend to continue to improve it in the coming months. 

Enjoy!

New io game coming soon

I've been working on an io version of Strike Tactics which will be called stba (or Strike Tactics Battle Arena). The game will be completely free (like Strike Tactics) and sort of a MOBA/Battlefront style game with hero abilities and unlockable units. Sort of like these io games. You'll be able to control and play as most (if not all) of the Strike Tactics units, including super units like the Battleship and Ion Cannon. 

More details coming soon!

v1.06 patch notes

Features

  • Added game timer. 
  • You will now receive desktop notifications when a match is found and you are not in the game tab. This allows people to safely go to another tab while searching for a match using the "find game" button. 
  • You can now destroy your own units with the delete key. 
  • C key will cancel ground unit movement. Current selected air units return to last destination if you hit C. 
  • You must now be logged in to use the find game button (auto-matchmaking). 
  • Added "view global rankings" and tournament info to the lobby info box. 

Fixes

  • Added back in the ability to change idle worker hotkey. 
  • Fixed units not spawning in Survival mode. 
  • Fixed sometimes not seeing what your ally could see.
  • Removed FFA as a game type (just use standard game type and set teams appropriately for FFA). 
  • You should no longer see "host cannot start the game ..." messages in the lobby. 
  • Reduced volume of the droid laser sounds.

Gameplay

  • Gladiator now requires tech lab to be built; cost changed from 100 ore / 50 carbon to 150 carbon. 
  • Gladiator primary weapon can no longer hit air units.
  • Gladiator Pulsar Cannon tech damage reduced from 250 to 175 and can no longer hit air units. 
  • Harpy ore cost reduced from 150 to 100; health increased from 1,930 to 2,500. 
  • Bomber ore cost reduced from 100 to 75; health increased from 830 to 1,200.
  • Gnat costs 50 carbon instead of 25 ore; build time reduced from 15 to 8 seconds. 
  • Roller ore cost reduced from 150 to 100. 
  • Command center cost reduced from 250 to 100 carbon. 
  • Javelin fire rate decreased from 4 to 3 sec.
  • Tech Lab build time increased from 40 to 60 seconds.
Tags: 

Starcraft 1 Pathfinding: A technical analysis

Imagine a Starcraft map as one big grid which is divided into hundreds of little squares. Most units, the smaller units (like marines and zerglings) occupy a single square while the larger units (such as dragoons and ultralisks) occupy multiple squares.

Starcraft 1 pathfinding grid

When a unit is issued a move command, the parameters of that command (the current location and destination in the grid) are run through the pathfinding algorithm which spits out an array of path coordinates. The unit then moves along the path, but it only goes 1 square at a time, one set of coordinates at a time. Each time it travels to a new square, it asks “is the next square along the path occupied?” If the answer is “no,” the unit keeps moving along the path. If the answer is “yes,” the unit waits a fraction of a second, and checks again. If the path is still unoccupied after a certain time increment, a new path is generated from the algorithm and the unit walks around the square that was unwalkable.

Another circumstance in which the path is re-calculated is when a new move command is issued while the unit is en route. This behavior has given rise to spam-clicking. The path is literally re-calculated each time you click, so technically a unit is finding the most efficient path at the point of time closest to the click. Because the grid (remember the starcraft map is just 1 big grid) which marks the walkable and unwalkable areas is constantly changing, so also are the results of the pathfinding algorithm. And the older those results are, the less efficient they will be. Hence: spam-clicking!

If you clicked your marine to go across the map, and a building gets placed in the middle of the map while the marine was en route, the original path calculated can no longer be considered accurate (because it was generated before the building was placed). A helper function detects when a path is no longer “accurate”. It asks “is the square in front of me occupied?” If no, it will continue along the path. If yes, it will wait, check again, and generate a new path if it is still occupied. All of this happens very quickly between animation frames.

At one point in the development of Strike Tactics, I utilized this same technique for pathfinding.

Notice how the units stop when they detect an object in front and politely wait for the object to move before continuing along the path? This is Starcraft 1 pathfinding. Units always remain visually separated at the expense of pathfinding efficiency. In other words, units take longer to get from point A to point B but they do so without walking on top of each other.

Here's a look at what the "helper function" which asks "is this node in front of me occupied?" looks like in Javascript. Each time a new node is walked to, the next node in the path is checked. If it's occupied, an interval begins (unit.waitInt) which waits for the node to become un-occupied. If it takes too long, the path is thrown out and a new one is calculated (in my game, setting the unit.goToTarget will cause the unit to find a new path). 

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
function checkGoToNextNode(unit) {

    if (unit.path[0] != undefined) {

        var grid = staticGrid;
        var findPathMatrixNodeSize = matrixNodeSize;

        if (unitDefinitions[unit.unitName].size == 'lg') {
            var findPathMatrixNodeSize = matrixNodeSizeLG;
            var grid = getGridCloneOfStaticLGFromStatic(unit);
        }

        // lg units should reserve all 9 rather than just center 1
        var gridX = fnRound((unit.path[0] - (findPathMatrixNodeSize / 2)) / findPathMatrixNodeSize);
        var gridY = fnRound((unit.path[1] - (findPathMatrixNodeSize / 2)) / findPathMatrixNodeSize);

        // check if next path is walkable, if not, wait till it is
        if (grid.nodes[gridY][gridX].walkable || smoothPaths) {

            if (unit.nextWalkToNode != undefined) {
                var goToNodeCopy = [unit.nextWalkToNode.x, unit.nextWalkToNode.y];


                game.time.events.add(500, (function(goToNodeCopy) {
                    return function() {
                        setNode(goToNodeCopy);
                    };
                })(goToNodeCopy), this);

            }

            if (unitDefinitions[unit.unitName].size == 'lg') {
                // large units must reserve a node in the staticGrid to prevent other large units from going there
                var gridXInStatic = fnRound((unit.path[0] - (matrixNodeSize / 2)) / matrixNodeSize);
                var gridYInStatic = fnRound((unit.path[1] - (matrixNodeSize / 2)) / matrixNodeSize);

                staticGrid.nodes[gridYInStatic][gridXInStatic].walkable = false;

                unit.nextWalkToNode = staticGrid.nodes[gridYInStatic][gridXInStatic];

            } else {
                grid.nodes[gridY][gridX].walkable = false;

                unit.nextWalkToNode = grid.nodes[gridY][gridX];

            }
            moveToNext(unit);
        } else {


            if (unit.unitName != 'drone') {
                stopAnimationsNetwork(unit, false, 0);
            }
            unit.waitInt = setInterval(function() {
                unit.timesWaited++;

                var distanceFromEnd = Phaser.Math.distance(unit.x, unit.y, unit.goingX, unit.goingY);

                if ((distanceFromEnd <= 100) && (unit.timesWaited > 3)) {
                    clearInterval(unit.waitInt);
                    actionsAfterCompletingPath(unit);
                    return;
                } else if ((distanceFromEnd >= 100) && (unit.timesWaited > 20)) {
                    // find a new path
                    actionsAfterCompletingPath(unit);
                    clearInterval(unit.waitInt);
                    unit.goToTarget = {
                        'x': unit.goingX,
                        'y': unit.goingY

                    }
                    return;
                }

                if (grid.nodes[gridY][gridX].walkable) {
                    if (unit.nextWalkToNode != undefined) {
                        unit.nextWalkToNode.walkable = true;
                    }
                    unit.timesWaited = 0;
                    grid.nodes[gridY][gridX].walkable = false;
                    unit.nextWalkToNode = grid.nodes[gridY][gridX];

                    clearInterval(unit.waitInt);
                    walkMech(unit);

                    moveToNext(unit);

                }

            }, 50);

        }

    }

}

If you think that's complicated and messy, consider that this is just one small component of the system. That to me, was a big red flag. The more complicated a system is, the more likely it will fail. Simpler systems work better because there are fewer things in them that can fail. 

I discovered this technique on my own through experimentation and had no idea Starcraft used it until I saw Day9’s video. Although Day9 doesn't appear to understand what is going on under the hood, he explains what the pathfinding system feels like to the player and what the gameplay implications are - it just made me think hard about what the units were doing when looking for a path. I came to realize the units were constantly stopping and going because they were asking "is this square occupied?" just like in my own implementation.

At some point in pre-alpha, I ditched this entire approach and revamped pathfinding to something much simpler. Instead of units constantly checking if the node they are about to walk to is occupied, the units simply maintain relative distance from each other when they walk. The only nodes which are marked as unwalkable are the start and end destinations. Even though the same grid structure is used, units don't move like they are playing hopskotch because a second algorithm (independent of the pathfinding algorithm) smooths the paths. This is the system currently used in Strike Tactics.

Early feedback from alpha testers was the impetus to overhaul pathfinding in this way, and as soon as I made the change, “pathinding” ceased to even be a topic of discussion among alpha testers. That to me proved the new pathfinding was good, because it did its job unnoticed. My reasoning is that If players notice your pathfinding, that’s when you know it’s bad. The contrapositive is that you don’t get praise for good pathfinding, because no one notices it. SC2 pathfinding is probably the best pathfinding system ever devised for a dynamic world. Units of all sizes miraculously find their way to destinations, without overlapping each other and without stopping. Despite this, the only discussions surrounding SC2 pathfinding are in relation to brood war pathfinding, and how it just doesn’t have the same charm to it. Brood War pathfinding is considered "fun" for some players, because it requires more micro-management to move your units effectively. 

Anyway, I don’t recall the last time someone complained about pathfinding in Strike Tactics, so I like to think it’s a solved problem at this point. The units simply go directly to their destination in the fastest way mathematically possible. It might not look as good as the original system where units always remain visually separated, but it certainly feels better. And if there’s anything I’ve learned, feel is much more important than looks. Players prefer more efficient unit movement and pathfinding over all else. They don't care how it looks. Truthfully, I don’t think anyone (other than me) has noticed that units occasionally walk on top of each other in Strike Tactics. Yet that was one of my greatest fears and where i spend 99% of my energy writing pathfinding. Funny, the things developers feel are important don’t always align with the things players feel are important.

In Starcraft 1, you will also notice that units move in grid-fashion. In simpler terms, units move like they are playing one giant game of hop scotch. A unit can move to the square in front, the square to the left, the square behind, etc. But what units can’t do is move forward 1 degrees, back 2 degrees, left 3 degrees, etc. Movement is strictly limited to cardinal direction: N, S, E, W and NE, NW, SE, SW, etc. This is why the movement feels so “blocky.” Units need to move like this because they need to be able to ask "is this node i am walking to occupied?" If they moved outside the grid (like in sc2), they would not be able to ask that question. 

If the path the algorithm spits out is most accurate when it is newly created, why didn’t Blizzard automatically recalculate the path instead of only recalculating it on click or when a unit bangs into another?

Because these calculations are expensive, even by modern computing standards. Depending on the size of the grid, and the algorithm used calculating hundreds of paths for hundreds of units 10 times a second adds up. Thus algorithms like A* are only run when needed, on click or when a unit gets stuck.

The difficulties in implementing pathfinding is never a simple as “determining the quickest route to get from point a to point b,” although gamers - and people who have never worked on pathfinding - probably assume it as such. A lot of devs seem to think good pathfinding is all about choosing good pathfinding algorithms, but that's an oversimplification. It's sort of like assuming Chevy can design the best car by simply realizing they need to use wheels to move the car. The wheel part is already a solved problem. The algorithm part is already a solved problem. The difficulty is in implementation. 

Since in an RTS game, the world is constantly changing, the problem is never as simple as determining the fastest route to get from point a to point b. In a changing world, the problem is determining the fastest route from point a to point b  while not bumping into objects c, d, e, f, g, etc, which are  by the way, constantly moving at various speeds an in various directions. The difference between solving dynamic world pathfinding and static world pathfinding is the difference between shooting a moving target and one which stands still.

Many modern RTS games avoid the problem altogether by simply doing overlap/collision checks on every frame and separating units which get too close (think of it like bumper cars). Starcraft 2 uses this technique to some extent, but the technique is CPU intensive. With SC1 pathfinding, the only real CPU-heavy stuff (computing the path with the algorithm) happens when you issue a click command or when a unit gets stuck and needs to generate a new path. But with collision detection, the CPU intensive stuff is happening every millisecond. It absolutely would not be possible with 1999 tech.

Ranking changes, monthly tournaments with cash prizes

  • Beginning September 1st, the ELO system will reset monthly, with each player going back to 1,200 ELO at the start of each new month. The match history in your profile will stay the same, but I may put a space to indicate when a monthly ELO reset has taken place. 
  • At the end of each month, an official tournament will be held for the top 6 ELO players or for players further down the list if one or more of the top 6 are unable to play.  
  • The champion of the monthly tournament will receive a cash prize, the amount of which will be announced each month. The amount for September will be $50 USD.
  • The winner will also have his or her's username immortalized on the ladder page with a special section for "Champions," along with the ELO they achieved that month and a link to the tournament VOD. 

All of this stuff is subject to change in the future, but that is the plan right now.

v1.05 patch notes

Strike Tactics is now 100% free-to-play, with all content (including ranking and the map editor) being accessible to registered users. To become a registered user, create a free account here

Anyone who purchased or pre-ordered Strike Tactics can receive a 100% full refund. Just ask using the email contact link at the bottom of the website. 

Features

  • You can now zoom out with the mouse wheel while in observer mode. To easily test this functionality, enter into a game with yourself set to an observer and 2 AI on opposing teams. 
  • Selected units now have circles underneath to indicate their selection status.
  • Lobby now shows 10 most recent messages upon joining.
  • Added text to join Discord from the lobby. 

Fixes

  • Made improvements to ground unit movement net code.
  • Fixed AI not shooting at some players in multiplayer games.
  • Fixed heal unit sometimes not healing when the health was near max in deathmatch.
  • Droid laser sounds are more audible. 
  • Increased default game and music volume.
  • Fixed units sometimes not dying on all clients. 

Gameplay

  • Most upgrades are significantly cheaper. 

Hotfixes/Updates 8/18/17

  • Fixed "registration successful" message not disappearing after creating an account.
  • Gladiator build time reduced from 35 to 20 seconds; ore cost reduced from 150 to 100 and cannon damage increased from 100 to 150. 
  • Fixed ELO not graphing correctly.
  • Made tech upgrades even cheaper. 

Updates 8/19/17

  • Victory condition changed from destroy all enemy units and buildings to destroy all enemy buildings.
  • Adjusted sizes of currently selected unit circles - battleship has no circle.
Tags: 

v.104 patch notes

Features

  • Revamped transport/networking layer by switching from socket.io to ws as a websocket library. Network performance should signifigantly improve with disconnects being extremely rare and reconnect logic working properly. 
  • In the change server dialog, the ping of the server you are currently connected to will up date in real time as opposed to only on page load. 
  • Now showing logged in (paid) users at the top of the lobby list with links to the account profile and orange underlined text. Guests names are displayed in white with no link (as they do not have account pages), below logged in users.

Fixes

  • Fixed victory/defeat conditions in 2v2 games.
  • Ping updates more frequently.
  • Fixed lines sometimes not connecting in the end game stat charts.
  • Fixed map name sometimes showing as N/A in lobby games list.
  • You can now highlight text in lobby and pre-game root chat. 
  • Total players count in lobby should be more accurate. 
  • Fixed "you did not beat your best wave of undefined" in survival. 

Updates 8/9/17

  • Survival mode is now enabled on most ground maps. Instead of stuff spawning at spawn locations on 4-player maps, the spawn locations are always in the center of the map.
  • If a guest chooses a map with survival mode enabled, the default game type will be survival and an AI will automatically be added to the room (as an AI is required to play survival single player).
  • [Experimental] Find game button is hidden for guests.
  • Made survival mode easier. You start out with more units and face less in the first waves.
  • Fixed buildings/units sometimes spawning on top of each other in survival, especially in multiplayer.
  • Removed some of the trees in the center of the "Enclave" map.
  • Removed some of the volcanoes in the center of the "Burning Divide" map.

Updates 8/10/17

  • Camera now focuses on first units in survival. 

Hotfixes 8/11/17

  • Fixed lobby layout breaking and buttons appearing twice in some circumstances.

Hotfixes 8/13/17

  • Game rooms should properly get deleted after the host has left.
  • Guests now see the find game button again and no longer have game type set to survival on default (that was experimental).
  • Fixed production menu sometimes not appearing when you click a production building. 
  • Total players should never be lower than players here (that happened because total players only updated on page load).
  • You should no longer get "you were kicked from the game room" message when changing servers.  
  • Multiplayer game should now properly reconnect if your router or wifi device resets. 
Tags: 

v1.03 patch notes

Features

  • Added option to disable unit info window. 
  • Max players per server increased from 70 to 100.
  • Added error handling for when a map does not load properly. 
  • Translated more text to Russian and Spanish. 
  • Added a "Basic Controls" video which appears in a dialog box for users that are not logged in. 

Fixes

  • Fixed games list automatically going back to the first page when some of the data in the games list table changed. 
  • "Restart" button changed to "Return to lobby" in menu options for users not logged in.
  • Fixed room not opening when clicked in the games list.
  • Fixed hovering units flying off the map during lag spikes.
  • Fixed crash caused by moving units to a position not on the map. 
Tags: 

Pages