A web-based copy of this assignment, and all the necessary support files can be found on the web at:
The player is the commander of a warship in an ocean infested by enemy submarines. The submarines fire torpedos at the warship in an attempt to sink it. The commander's defenses are evasion, and to drop explosive depth charges. If a depth charge explodes close to a submarine then it is destroyed. The game ends when the ship is sunk.
The game displays the message "Press ESC key to start game"
The player presses ESC to start the game.
The game background shows a sideways view of the sea surface, the water under the surface and the sea bed. The game starts with the warship floating on the surface. Soon after the game starts, the first submarine appears from either the left or right of the screen. The submarine moves to the other side of the screen at a fixed speed and depth.
The player presses the left or right arrow key to make the warship sail to the left or right. When the down arrow is pressed, a depth charge is thrown from the rear of the ship so that it travels through the air in an arc until it hits the water. The depth charge sinks until it reaches the submarine's depth when it explodes. If the submarine is close to the explosion then it is destroyed and the player's score is increased by 20. Only one depth charge can be deployed at a time.
Once the submarine has been destroyed, or has safely crossed from one side of the screen to the other, there will be a short pause and a new submarine will appear. The submarine appears at a random depth and randomly appears from the left or the right of the screen. Only one submarine can appear at a time.
Periodically, the submarine will launch a torpedo at the warship. The torpedo is aimed towards the centre position of the warship. The torpedo will continue towards this position even if the warship is moved, hence the player can evade destruction by moving the warship away from the torpedo's target point. If the torpedo strikes the warship then it sinks and the game ends. If the torpedo misses the ship then it is removed from the screen without exploding. Only one torpedo can be deployed at a time, but as the submarine crosses the screen there is sufficient time for it to shoot several torpedos. Torpedos have a limited rate of turn and hence the submarine can only launch a torpedo when the ship is ahead of, not above or behind, the submarine.
The game ends when the warship is destroyed and the current submarine has moved off the edge of the screen (or has been destroyed).
The game background and score remain on the screen, with the message "GAME OVER" appearing in Red. This message remains for 2 seconds after which the game goes back to the "Starting the Game" state.
You are supplied with a C# project containing the following complete and incomplete classes:
BasicSprite, MovingSprite, VectoredSprite - complete
classes as described in sections 7-8 of your notesShipSprite, SubmarineSprite, TorpedoSprite and DepthChargeSprite classes
in various states of completion.Game1 boilerplate class - for you to complete.The project is also pre-loaded with a number of images and sprite sheets for you to use:
Download assignment resources:
The behaviour of each sprite is described by a separate Finite State Machine which you are required to implement using the techniques described in Section 9 of your lecture notes.
You are also required to develop your code using the supplied Object Oriented sprite classes
(BasicSprite, MovingSprite, VectoredSprite) which
are described in Sections 7 and 8 of your lecture notes. Each sprite class should "extend" one
of these of these classes, and provide (at least) a customised Update() method,
which will be called from the Game1 class Update() method.
Important: The customised Update() method for each sprite must make an explicit
call to base.Update() so that any default animation and sprite movement takes
place!
The warship is the launching platform for the depth charge. While the user presses the Left or Right arrow key the warship moves in the corresponding direction. The sprite image must be horizontally flipped when the ship is moving from right to left. The ship is not allowed to sail off the edge of the screen.
C# Class Heading: class ShipSprite : BasicSprite
Design notes:
ShipSprite class should inherit from the BasicSprite class
rather than the MovingSprite class.Game1 class.public property named HitByTorpedo.
Writing true to this property triggers transition T1.2.1 in the diagram below.int _timer field must be incremented
on every call to ShipSprite Update(). The ship remains in the
Destroyed state for a few seconds so that the game does not end abruptly.Update() method must call base.Update() before
returning.FlipHorizontal property
must be set to true.Finite State Diagram:
| State | Transition | Trigger | Actions | Next State |
|---|---|---|---|---|
| Start |
T1.1
|
No Trigger
|
set X, Y to start position; set Show flag to true |
Sailing
|
| Sailing |
T1.2.1
|
Hit By Torpedo
|
start animation from frame 1 (ship breaking up) |
Sinking
|
| Sailing |
T1.2.2
|
Right Arrow && not near right edge of screen
|
add const velocity to X; do not flip sprite image |
Sailing
|
| Sailing |
T1.2.3
|
Left Arrow && not near left edge of screen | subtract const velocity from X; flip sprite image |
Sailing
|
| Sinking |
T1.3 |
Animation Finished
|
start timer |
Destroyed
|
| Destroyed |
T1.4
|
Time expired
|
set Finished flag to true; set Show flag to false |
End
|
A submarine appears at a random depth at one side of the screen and sails at the same depth across to the other side of the screen. The game software randomly chooses whether or not the submarine appears from the left or the right. The torpedo launch is triggered when a timer reaches a threshold value (which you should choose) and the ship is ahead of the submarine's position. The timer is reset to zero after each launch so that subsequent torpedos may be launched when the first one has finished.
C# Class Heading: class SubmarineSprite : MovingSprite
Design Notes:
MovingSprite class described in your notes.Update().Finite State Diagram:
| State | Transition | Trigger | Actions | Next State |
|---|---|---|---|---|
| Start | T2.1.1 | Random number < 0.5 |
set X position to far left off edge of screen; |
Sailing |
| Start | T2.1.2 | Random number >= 0.5 |
set start position to far right off edge of screen; |
Sailing |
| Sailing | T2.2.1 | Edge of screen | set Finished flag to true; set Show flag to false | End |
| Sailing | T2.2.2 | Hit by depth charge | start animation from frame 1 (sub breaking up); set velocity to zero |
Sinking |
| Sailing | T2.2.3 | Ready to launch torpedo | tell torpedo to launch | Sailing |
| Sinking | T2.3 | Animation finished | set Destroyed flag to true; start timer | Destroyed |
| Destroyed | T2.4 | Time expired | set Finished flag to true; set Show flag to false | End |
The torpedo launch is triggered when the submarine sets the Launch property
to true. The torpedo should remember the current position of the warship as
its target X and Y. The torpedo's starting position is the torpedo launch tube on the submarine,
which varies depending on whether the submarine is facing left or right.
On each update, the torpedo should calculate the angle from its current position to the target position, and then move a short distance in that direction; however to make the torpedo look more realistic it may only change its angle by a short amount each update. This causes the torpedo to leave the submarine in a horizontal direction and then move in an arc until it's heading directly towards the target point.
C# Class Heading: class TorpedoSprite : VectoredSprite
Design Notes:
TorpedoSprite class should inherit from the VectoredSprite class
described in your lecture notes.public property named Launch.
Writing true to this property causes the torpedo run to start (see transition
T3.1.1 and T3.1.2 in figure below).public Running property which returns true when
the torpedo is in the Running state.HitByTorpedo property
to true.Finite State Diagram:
| State | Transition | Trigger | Actions | Next State |
|---|---|---|---|---|
| Start | T3.1.1 | Launch && Sub Facing Right | set start position to submarine plus X offset for torpedo tube position; set Angle to Math.PI/2; set target X, Y to ship X, Y position; set Velocity to const value; set Scale to 0.5; set Show flag to true |
Running |
| Start | T3.1.2 | Launch && Sub Facing Left | set start position to submarine minus X offset for torpedo tube position; set Angle to -Math.PI/2; set target X, Y to ship X, Y position; set Velocity to const value; set Scale to 0.5; set Show flag to true |
Running |
| Running |
T3.2.1 |
Hit the ship | set the ship's HitByTorpedo flag to true; start animation from frame 1 (explosion); set Scale to 1; set Velocity and Angle to zero |
Hit Target |
| Running | T3.2.2 | Reached target point but did no hit the ship | set Show flag to false; set Finished flag to true |
End |
| Running | T3.2.3 | Passed edge of screen | set Show flag to false; set Finished flag to true |
End |
| Running | T3.2.4 | (else no other trigger) |
calculate angle to target; |
Running |
| Hit Target | T3.3 | Animation finished | set Show flag to false; set Finished flag to true |
End |
A depth charge is "dropped" (or, more accurately, thrown backwards from the rear of the ship) when the player presses the Down arrow key. It travels through the air in an arc until it drops into the sea. Once in the sea, it sinks vertically downward until it reaches the current submarine's Y position, when it explodes. The submarine is destroyed if it is within the range of the explosion, or moves into range while the explosion animation is in progress.
C# Class Heading: class DepthChargeSprite : VectoredSprite
Design notes:
Velocity and Rotation for
the VectoredSprite class. When the depth charge has turned through 180 degrees, the Rotation should
be changed to zero and the Angle changed to Math.PI, forcing
it to move downward through the sea.public property named Drop.
Writing true to this property causes the depth charge launch/drop sequence
to start (see transition T4.1.1 and T4.1.2 in figure below).Finite State Diagram:
| State | Transition | Trigger | Actions | Next State |
|---|---|---|---|---|
| Start | T4.1.1 | Drop && ship facing right |
set start position to ship minus X offset of |
In Air |
| Start | T4.1.2 | Drop && ship facing left | set start position to ship plus X offset of launcher position; set Angle to 0.0; // Upwards set Velocity to const value; set Rotation to positive const value; set Scale to 0.3; set Show flag to true |
In Air |
| In Air | T4.2.1 | Y >= sea level | set Angle to Math.PI; set Rotation to zero; set Velocity to const value |
Sinking |
| Sinking | T4.3 | Y >= submarine Y | start explosion animation; set Velocity to zero; set Angle to zero; set Scale to 1.0 |
Exploding |
| Exploding | T4.4.1 | Submarine X in range of explosion |
set submarine HitByDepthCharge flag to true | Exploding |
| Exploding | T4.4.2 | Animation finished | set Finished to true; set Show to false | End |
The Update() method in the Game1 class oversees the whole game
process, whilst the Draw() method sequences the drawing order for the background,
sprites and score.
The code within the Update() method is (believed to be) correct, but each line
has been commented out to allow separate development of each sprite class without causing
compilation errors. As you work on each sprite class you will need to remove the comment
markers to allow the sprite to operate correctly. At the same time you will need to add statements
to the Draw() method so you can see each sprite in action.
Finite State Diagram:
| State | Transition | Trigger | Actions | Next State |
|---|---|---|---|---|
| Insert Coin | T0.1 | User presses ESC (simulates insert coin) |
Initialise all game variables and objects | Playing |
| Playing | T0.2.1 | Ship destroyed && no submarines on screen | Start timer | Game Over |
| Playing | T0.2.2 | (no trigger) |
Game play continues | Playing |
| Game Over | T0.3 | Timer running for 2 seconds |
(none) | Insert Coin |
Whilst the game is in each state, the Draw() method should display graphics
as follows:
| State | Draw() method displays |
|---|---|
| Insert Coin | "Press ESC key to start game" |
| Playing | Normal game operation including score |
| Game Over | Normal game background, "GAME OVER" and final score |
Using XNA 3.1, you must complete the supplied project so that the game operates as described above. Your code must conform to these guidelines:
Game1 Update() method.consts for constant numeric values and (in particular)
the names of each state. Avoid usages such as if (Y > 150) preferring instead: if
(Y > SEA_LEVEL)const to maximise the "playability" of
the game.| Consts: | const int SEA_LEVEL = 150; |
All capitals |
| Fields: | bool _hitByTorpedo; |
Leading underscore |
| Properties: | public bool HitByTorpedo { get... set ...} |
Leading capital |
| Methods: | public void Update() |
Leading capital |
| Variables: | double distanceToTarget; |
Leading lower case letter |
Marks are available for each class you complete and get working. The following table shows the maximum marks available for each class - partial marks will be given if appropriate:
| Class | C# Coding | Comments | Choice of Names | Use of consts |
|---|---|---|---|---|
| ShipSprite | 10 | 4 | 3 | 3 |
| SubmarineSprite | 10 | 4 | 3 | 3 |
| TorpedoSprite | 10 | 4 | 3 | 3 |
| DepthChargeSprite | 10 | 4 | 3 | 3 |
| Game1 | 10 | 4 | 3 | 3 |
To submit your work you should copy the entire top-level project folder onto a full-size CD-ROM, DVD-ROM or USB memory stick and submit it with a coursework submission form.
I recommend the following ways to submit your work:
If you use option 2 or 3 then you should seal the A4 clear envelope using two or three paperclips across the top. Do NOT use sticky tape or staples.
The following submissions are completely unacceptable:
Bob Lang
October 2010