SQUAD COMMANDER Last modified on 07 December 1999 13:06:38 PST by yph ----------------------------------------------------- Brought to you by: Will Buck Erika Chuang Yu Ping Hu Basic gameplay and controls --------------------------- In Squad Commander, you control a squad of space fighters to do battle with an enemy, computer controlled squadron of ships. Each ship is capable of independent thrust in each of three axes (up/down, fore/aft, port/starboard), as well as independent rotation in each direction (pitch, roll, and yaw). Thus, movement will take some time to get used to. Additionally, the other fighters may appear to move in funny ways, since they are not always facing the way they are moving. The first thing to learn is the HUD. The HUD is an overlay at the bottom of the display which tells you what mode you're currently in, what commands are available in the current mode, and other game state such as your score, and your position. To toggle the HUD on and off, press 'h'. The HUD is your friend: all commands are listed there. (All commands in this game are keyboard commands.) There are 4 modes in Squad Commander, as described below. You can always switch to any of the modes, using the appropriate key. When in a particular mode, you can only use the commands of that mode, plus the mode switching commands. Flight mode: 'g' In flight mode, you control the squad leader of your squad (the purple one). You can thrust using the keys under your left hand (w/r for up/down, e/d for fore/aft, s/f for port/starboard), and rotate with the keys under the right hand (i/k for pitch, j/l for yaw, u/o for roll). You can full stop your motion with 'q'. To fire your gun, use the space bar. Squad mode: 't' In squad mode, you issue commands to your squad. These include formations and orders. To switch formations, use the following keys (left home row): Broad: a Delta: s X: d Claw: f To switch orders, use the right home row: Tight formation: j Escort: k Half attack: l Full attack: ; Envelop: ' Squad commands will be more fully explained with the AI. Camera mode: 'v' While in camera mode, you can control the angle the camera takes while looking at your ship. You use the same rotation keys as in flight mode. You also zoom in and out using the fore/aft thrust keys. Note that any angle changes are wiped out when you go into flight mode, because in flight mode the camera always stays behind your ship. Zoom changes stick, though. Options mode: 'b' You can turn rendering options on or off here. Toggle wall textures: w Toggle ship textures: s Toggle camera lag: c Toggle lighting: l Note that toggling ship textures will make it difficult to distinguish your ships from the enemy, since the only difference between the two types of ship is the texture used. Revive/Respawn: When a squad leader dies, his squad will be not be able to fight very effectively (although they will continue with their last orders until they die). Therefore, when a squad leader dies, you can reset that entire squad. If your squad dies, you revive using the '\' key, and if the enemy dies, you respawn him using ']' key. The HUD uses the word "revive" to refer to you, and "respawn" to refer to the enemy. Scoring: Every enemy ship shot down is worth 10 points. However, for every ship in your squad which buys it, you lose 10 points. Since there are infinitely many ships available, the goal is to rack up as many points as possible, which means shooting down more of theirs than you lose of yours. The score is displayed at the bottom middle of the HUD. Other HUD readouts: Your location is your location in absolute coordinates. Not actually all the useful in the game. If you want to try to figure out your velocity: the big nebula is in the negative x direction, the small one is the positive x direction, and the cluster of stars is in the positive x, negative y, positive z direction. (It's probably not worth trying to use it this way.) The enemy direction can be read relative to your current facing. The three numbers represent how much fore, port, and above you the enemy squad leader is. The numbers are 100 times the components of a unit vector from you to the enemy. Thus, 100 0 0 means the enemy is straight ahead. Quitting the game: The esc key will quit the game. Not thay you'd ever want to use this feature, mind you, but just to let you know. Details of features ------------------- Rotations: Rotations are implemented using quaternions, in order to allow for correct composition of rotations in a relative space (that is, ship rotations), and for allowing correct rotation interpolation (for camera lag, e.g.). We started with the code found at Gamasutra: http://www.gamasutra.com/features/programming/19980703/quaternions_01.htm but it turns out that code is buggy and incomplete, so we had to implement the rest correctly. We used another reference for a mathematically accurate description of quaternions: http://www.cs.berkeley.edu/~laura/cs184/quat/quaternion.html Rotations are of course not an advanced feature, but since it's one of the few places where I borrowed heavily from some sample code, I include it here to provide a citation. AI: You only directly control one ship; the other ships in your squad, as well as the enemy ships, are computer controlled. Each squad ship (that is, non-squad leader) is governed by the same AI. This AI is essentially a state machine: each ship is in an AI state, and depending on its orders and the state of the world around it, each frame it will take some action and possibly change states. Every frame, each fighter is passed as an argument to the FighterControl() function, which looks up in the dispatch table the appropriate AI function to apply to the ship based on which AI state it is in. This AI function furthermore will look at other parts of the world to determine what to do next. "Taking some action" consists of up to three things: 1) Figure out what the ship's desired position and velocity is, and thrust to match that desired position and velocity. It needs to match velocity in addition to position to avoid the problem of flying past the desired location because it was going too fast. There is a maximum thrust that a ship may apply per unit time. 2) Figure out what the ship's desired orientation is in order to fire on its target. This calculation will lead the target; that is, a ship will turn to face the position it thinks the target will be in next. There is also a cap on the amount a ship may turn per unit time. Since ships can move independently of facing, this calculation is done independent of matching a desired position and velocity. 3) If the ship's target is within a certain angle in front of the ship, the ship will fire a bullet. There is a maximum rate at which AI ships may fire. Note that the AI does *not* cheat, in the sense that it follows the same rules the player does in terms of thrusting, rotating, and firing. In fact, the player ship has slightly more thrust, rotational ability, and firepower (currently, player bullets are 20x "bigger" when checking for collisions, do 5x as much damage, and can be fired about 4x faster) than any other ship. We made the player ship better to make the game less frustrating to play: the computer controlled ships may not cheat, but they are much better at calculating angles and thrusts than humans, and so are much more apt to be in the right place to shoot and dodge than the human is. The rest of the AI documentation explains the current setup of the state machine, and so may be useful to understanding how to play the game, since it explains how the ships are currently programmed to behave. However, keep in mind that these things are mostly constants tweaking; the fundamental AI engine is simply the state machine, which is defined by some AI state variables for each ship and the dispatch table. The AI functions govern behavior directly, but are easy to change or swap. The possible AI states are as follows: Formation: In this state, a ship will try to stay in formation, which means it will set desired velocity to match the squad leader's, and position to be the squad leader's position plus some formation offset. The offset is determined by the formation, and the ship's number in the squad. Ships in this state will rotate to take opportunity shots at enemies but will not try to break formation in order to attack. Wingman: Ships in the squad are also split up into pairs. Each pair has a commander and a wingman. The wingman's task is to stay close to his commander and fire on whatever ships are closest to the pair. Assess: Whenever a pair commander is unsure of what to do next, because his target was destroyed, e.g., he will go in to assess state. Ships should only be in this state for one frame, since it will immediately dispatch to another state. Pursue: When a pair commander has a target which isn't within firing range, it pursues, which means it attempts to match velocity and line up on the target. Depending on its orders, the ship in pursue mode will attempt to line up to one side or the other of the target (left, right, up, down, or behind; lining up in front is possible but stupid). Attack: When a pair commander is close enough, it rotates to match the enemy, and attempts to fire if it has a good shot. Each ship also has orders which help determine how it moves from state to state. Since these orders are currently hidden beneath the interface, I will not specifically discuss them all here. However, I will explain the orders you can give in squad mode: Tight: stay in formation. Escort: stay in formation, until we get close to the enemy. Then, break and attack. Half: half of the pairs escort, the other half attacks. Attack: break and attack right now. Envelop: break and attack, but each pair is assigned a different angle from which to approach their targets. Please note that the AI state machine can support other behaviors very easily, and there are even hooks for providing for a retreat behavior and such. For example, each ship currently keeps track of its aggressiveness, which can be used to determine at what range it will break and attack and at what range it will attempt to flee. However, due to lack of time, we did not complete all these possible states. The main task left is playtesting these new states, and making sure that ships flee appropriately when the new states are added. The enemy squad leader has a much simpler AI, again because of time pressure. He picks a random direction in which to offset from your ship, and attempts to fly to that location, while shooting at whatever target is available. Since his squad always has escort orders, this behavior should force an engagement pretty easily. View frustum culling: We implement view frustum culling of ships by using a single function, IsOutOfViewFrustum(), defined in camera.c. The function's documentation includes a detailed description of the algorithm employed. The basic approach of the algorithm is to generate a sphere around a ship, and check if the point on that sphere which is at the most acute angle to the camera is within the frustum's bounds. Level of detail control: Level of detail control is implemented in model.{c,h}. Each ship is given pointers to several different models, each derived from the same original model but simplified to differing degrees of complexity, and when we render the ship, we choose which model to use based on the ships's distance from the camera. The "whitstar" models were obtained as follows: 1) the original model was found in 3ds format at www.mateengreenway.simplenet.com/files/whitstar.zip 2) the 3ds file was converted to a VRML 1.0 file via AC3D, which can be found at www.comp.lancs.ac.uk/computing/users/andy/ac3d.html 3) the VRML 1.0 file was decimated into several files with differing Levels of Detail by using LODestar, found at www.cg.tuwien.ac.at/research/vr/lodestar 4) these VRML 1.0 files were edited and converted to Wavefront .obj files using 3D explorer, found at www.xdsoft.com/explorer 5) finally, the .obj files are converted to OpenGL display lists at run time by using glm.{c,h}, available in the cs248 directory. The "gunstar" models, which are not used in the current executable but which were used extensively during testing, were obtained by taking the "gunstar" VRML file from the cs348 directory and applying steps 3-5 above. Collision detection: Collisions are detected by comparing the distance between the centers of two spheres to the sum of the radii of the spheres. Currently, collisions are detected between ships and bullets, but not between ships and ships, to simplify the ship AI (so that they don't try to account for avoiding ship collisions). Note that our collision detection algorithm could theoretically fail to detect a collision between two objects moving quickly enough, if they "past through" each other between calls to Idle(). Given our current bullet speed and maximum ship speed, however, this condition should never occur. collision.c and collision.h implement this algorithm. On screen control panel: The on screen control panel is on by default. It can be toggled on/off by pressing 'h'. It keeps the game information, such as the score, ship location, enemy location, remaining ships, and current game mode. In addition, it also displays the the keymap according to the current mode. Sound: We've added special sound effects to the game (bullets, explosions, etc). It is implemented in DirectSound (Special thanks to Lucas for sample code and help). Explosions: Explosion is implemented by texturing mapping a square with a sequence of animated explosion images. As the camera moves around the scene, the square is rotated so it's always facing the viewer (billboarding). The alpha value of the background are altered so that only the explosion part of the image can be seen. Game content/inspiration ------------------------ The original game idea was heavily influenced by the Sierra game Homeworld and the book _Ender's Game_ by Orson Scott Card. Homeworld is a real time strategy game in space, and in _Ender's Game_, the main character Ender must control a space fleet using a 3D computer generated interface. The original idea was to have a game where you could control a fleet completely from the squad control level. However, when we realized the difficulties with interface, we decided to go with direct control of one ship in order to keep things simple. Squad control ideas were kept, though. As for ship movement, this was basically modelled on what I thought real physics in space should be. Since the television show Babylon 5 uses such a ship movement model, we looked for 3D models based on the ships in the show. In fact, many of the ideas about controls were inspired by reading through the webpages for the Babylon 5 flight sim, Into the Fire (the game, which was close to completion, has since been cancelled by Sierra Studios; I think they're looking for a new publisher). These pages can be found at www.firtones.com. The model we eventually settled on, the Whitestar, is from the show, and done by Kier Darby. (More details on the models can be found in the level of detail docs.) As noted above, quaternion code was originally taken from Gamasutra, but was extremely buggy (notably, the routine for multiplying quaternions was completely wrong) and had to be fixed. Mike Hough first suggested their use to solve the problem I was encountering. glm code, used for reading in models, was taken from the sample code directory. The three textures for the "walls" were taken from NASA's website. All our sounds were taken from Starcraft, a fine game by Blizzard Entertainment. Aside from what we note above, all code was basically written from scratch. Notably, the entire ship movement, control, and rendering model was basically written from scratch: we didn't start from other sample program and adapt as needed.