Nowotwór jamy ustnej
Etiologia i przyczyny
Nowotwór jamy ustnej jest szóstym najczęściej występującym nowotworem złośliwym na świecie, z roczną liczbą diagnoz w USA wynoszącą około 53 000-59 000 przypadków. Choroba dotyka głównie mężczyzn po 40. roku życia, a ponad 90% przypadków stanowią raki płaskonabłonkowe, powstające z mutacji komórek nabłonka płaskiego w obrębie warg i jamy ustnej. Kluczowymi czynnikami ryzyka są używanie tytoniu (wszystkie formy, w tym tytoń bezdymny, który zwiększa ryzyko nawet 50-krotnie) oraz nadmierne spożycie alkoholu, które podnosi ryzyko 5-krotnie. Synergistyczne działanie tytoniu i alkoholu może zwiększyć ryzyko rozwoju nowotworu jamy ustnej nawet 30-50-krotnie, a u kobiet nawet 100-krotnie. Zmiany genetyczne w genach p53 i H-ras są powiązane z ekspozycją na kancerogeny zawarte w dymie tytoniowym.
Nowotwór jamy ustnej – etiologia
Nowotwór jamy ustnej stanowi poważny problem zdrowotny, będący szóstym najczęściej występującym nowotworem złośliwym na świecie1. W Stanach Zjednoczonych każdego roku diagnozuje się około 53 000-59 000 nowych przypadków nowotworów jamy ustnej i części ustnej gardła234. Nowotwór ten dotyka mężczyzn ponad dwukrotnie częściej niż kobiety i najczęściej diagnozowany jest u osób powyżej 40 roku życia56.
Patogeneza nowotworów jamy ustnej
Nowotwór jamy ustnej powstaje, gdy komórki na wargach lub wewnątrz jamy ustnej ulegają mutacji. Najczęściej proces ten rozpoczyna się w płaskich, cienkich komórkach nabłonkowych (nabłonek płaski) wyściełających wargi i wnętrze jamy ustnej, zwanych komórkami płaskonabłonkowymi7. Ponad 90% nowotworów jamy ustnej to właśnie raki płaskonabłonkowe89.
Proces nowotworowy zaczyna się, gdy w DNA komórek nabłonkowych zachodzą zmiany, które powodują nieprawidłowe instrukcje dla komórek. W zdrowych komórkach DNA zawiera informacje mówiące komórce, jak rosnąć i rozmnażać się w określonym tempie oraz kiedy umrzeć. W komórkach nowotworowych zmiany w DNA dają inne instrukcje – nakazują komórkom nowotworowym szybko rosnąć i mnożyć się, a także utrzymywać się przy życiu, gdy zdrowe komórki powinny obumrzeć10.
W rezultacie powstaje zbyt wiele komórek, które mogą tworzyć masę zwaną guzem. Guz może rosnąć, naciekać i niszczyć zdrowe tkanki. Z czasem komórki nowotworowe mogą oderwać się i rozprzestrzenić do innych części ciała, co określa się jako nowotwór przerzutowy1112.
Główne czynniki ryzyka
Tytoń jako podstawowy czynnik ryzyka
Używanie tytoniu jest najważniejszym czynnikiem ryzyka rozwoju nowotworów jamy ustnej, odpowiadającym za znaczącą większość przypadków13. Wszystkie formy tytoniu zwiększają ryzyko, w tym papierosy, cygara, fajki, tytoń do żucia oraz tabaka14. Dym tytoniowy zawiera liczne kancerogeny chemiczne, w tym węglowodory aromatyczne takie jak benzopiren i nitrozoaminy, które mogą powodować specyficzne zmiany genetyczne w genach p53 i H-ras15.
Badania pokazują, że około 75% osób, u których rozwija się nowotwór jamy ustnej, używa tytoniu16. Według Fundacji Nowotworów Jamy Ustnej, osoby używające tytoniu mają 6-krotnie wyższe ryzyko rozwoju nowotworów głowy i szyi, a 75% nowotworów jamy ustnej i gardła występuje u użytkowników tytoniu17. Palacze mają 20-krotnie wyższe ryzyko rozwoju nowotworów jamy ustnej niż osoby niepalące18.
Szczególnie niebezpieczny jest tytoń bezdymny (do żucia), który zwiększa ryzyko nowotworów policzka, dziąseł i warg nawet 50-krotnie w porównaniu do osób nieużywających1920. W Wielkiej Brytanii około 17% nowotworów jamy ustnej jest spowodowanych paleniem tytoniu21.
Alkohol jako istotny czynnik ryzyka
Nadmierne spożycie alkoholu jest drugim najważniejszym czynnikiem ryzyka nowotworów jamy ustnej22. Osoby nadużywające alkoholu mają 5-krotnie wyższe ryzyko rozwoju nowotworów jamy ustnej23. Według badań, około 70% osób z diagnozą nowotworu jamy ustnej to osoby intensywnie spożywające alkohol24.
W Wielkiej Brytanii alkohol jest przyczyną około 35% przypadków nowotworów jamy ustnej25, a w Australii odpowiada za około 31% przypadków26. Mechanizm kancerogenny alkoholu związany jest z jego działaniem drażniącym na komórki jamy ustnej oraz z osłabieniem układu odpornościowego, co utrudnia organizmowi walkę z nieprawidłowymi komórkami27.
Synergistyczne działanie tytoniu i alkoholu
Szczególnie niebezpieczne jest łączne używanie tytoniu i alkoholu, gdyż te czynniki działają synergistycznie, znacząco zwiększając ryzyko rozwoju nowotworu jamy ustnej2829. Osoby, które zarówno palą tytoń, jak i intensywnie spożywają alkohol, mają nawet 30-50-krotnie wyższe ryzyko rozwoju nowotworów jamy ustnej niż osoby, które nie stosują tych używek3031.
Alkohol może działać jako rozpuszczalnik ułatwiający przenikanie kancerogenów z tytoniu do tkanek jamy ustnej, a także wspiera działanie kancerogenne tytoniu poprzez wpływ na komórki i prowokowanie zmian nowotworowych32. Według badań, kombinacja intensywnego palenia i intensywnego picia alkoholu zwiększa ryzyko 100-krotnie u kobiet i 38-krotnie u mężczyzn33.
Zakażenia wirusowe jako czynnik etiologiczny
Wirus brodawczaka ludzkiego (HPV)
Zakażenie wirusem brodawczaka ludzkiego (HPV), szczególnie typem HPV-16, zostało zidentyfikowane jako istotny czynnik ryzyka nowotworów jamy ustnej i gardła3435. Związek między HPV a nowotworami części ustnej gardła (oropharynx) jest silniejszy niż w przypadku nowotworów jamy ustnej36.
HPV odpowiada za około 50% nowotworów części ustnej gardła w Wielkiej Brytanii37 i nawet 70% w Stanach Zjednoczonych38. Wirus HPV jest przenoszony głównie poprzez kontakt seksualny, w tym seks oralny39.
HPV może zmieniać normalne cechy komórkowe nabłonka jamy ustnej, co może prowadzić do rozwoju nowotworów40. W ostatnich latach wzrosła liczba przypadków nowotworów jamy ustnej związanych z HPV, szczególnie u młodszych osób, które nigdy nie paliły tytoniu4142.
Inne wirusy jako potencjalne czynniki ryzyka
Poza HPV, inne wirusy również mogą odgrywać rolę w rozwoju nowotworów jamy ustnej:
- Wirus Epsteina-Barr (EBV) – został powiązany z nowotworami gardła nosowego i może zwiększać ryzyko nowotworów jamy ustnej4344
- Wirusy z grupy Herpes – były impliko• Author — Allen Antony Ukani
• Contact — auks256ATcs.washington.edu
• Created Date — 08.2.2012
• Last Modified Date — 10.10.2012
• Last Modified By — Allen Antony Ukani
*/using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;namespace LegendOfZelda
{
public static class GameContext
{
////// Store the current state of the game.
///public static class State
{
////// The screen displayed in-game
///public enum Screen
{
Title,
FileSelect,
Game,
Inventory,
GameOver,
Win,
Credits
}///
/// The current screen displayed to the user.
///public static Screen CurrentScreen = Screen.Title;
///
/// True if the game is paused, false otherwise.
///public static bool Paused = false;
///
/// True if the Link is moving between screens, false otherwise
///public static bool TransitioningScreens = false;
public enum MovementDirection
{
None, North, South, East, West
}///
/// The direction that Link is moving towards while transitioning between screens
///public static MovementDirection TransitionDirection = MovementDirection.None;
///
/// Flag to state if the door movement has started or not
///public static bool DoorTransitionStarted = false;
///
/// True if Link is frozen in place (can’t move).
///public static bool LinkIsFrozen = false;
///
/// Key Value pair to check whether transitions is happening in both directions or not by storing the entering room’s keys
///public static Dictionary<Tuple, IList<Tuple>> transitionCache = new Dictionary<Tuple, IList<Tuple>>();
///
/// True if Link is dying
///public static bool IsDying = false;
///
/// Transitioning from the Link Death screen to the Game Over screen
///public static bool LinkDeathToGameOver = false;
}/* Tracking game world and level information */
public static class World
{
////// Gets the room at the given row and column.
////// The row of the room
/// The column of the room
/// The room at the given row and column
public static Room GetRoom(int row, int col)
{
if (CurrentWorldRoom == null)
{
CurrentWorldRoom = RoomFactory.CreateRoom(row, col);
CurrentRoomTileSet = new TileSet(CurrentWorldRoom.TileMap, row, col);
}
else if (CurrentWorldRoom.RoomRow != row || CurrentWorldRoom.RoomCol != col)
{
CurrentWorldRoom = RoomFactory.CreateRoom(row, col);
CurrentRoomTileSet = new TileSet(CurrentWorldRoom.TileMap, row, col);
}
return CurrentWorldRoom;
}///
/// The current room being explored (lazily-evaluated)
///private static Room currentWorldRoom = null;
public static Room CurrentWorldRoom
{
get
{
if (currentWorldRoom == null)
{
currentWorldRoom = RoomFactory.CreateRoom(CurrentRoomRow, CurrentRoomCol);
}
return currentWorldRoom;
}
set
{
currentWorldRoom = value;
}
}///
/// Get the tileset for the current room
///private static TileSet currentRoomTileSet = null;
public static TileSet CurrentRoomTileSet
{
get
{
if (currentRoomTileSet == null && CurrentWorldRoom != null)
{
currentRoomTileSet = new TileSet(CurrentWorldRoom.TileMap, CurrentRoomRow, CurrentRoomCol);
}
return currentRoomTileSet;
}
set
{
currentRoomTileSet = value;
}
}///
/// The row of the current room
///public static int CurrentRoomRow = 7;
///
/// The column of the current room
///public static int CurrentRoomCol = 7;
}///
/// Provide information about the game Window
///public static class Window
{
////// The horizontal size (in pixels) of the game window.
///public static int Width = 768; //512; //768; //512; //768
///
/// The vertical size (in pixels) of the game window.
///public static int Height = 672; //448; //672; //448; //672
///
/// Get the horizontal center of the game window.
///public static int CenterX
{
get
{
return Width / 2;
}
}///
/// Get the vertical center of the game window.
///public static int CenterY
{
get
{
return Height / 2;
}
}///
/// Get the width of the in-game room
///public static int RoomWidth
{
get
{
return 256 * Scale;
}
}///
/// Get the width of the in-game room * the sprite scale
///public static int ScaledRoomWidth
{
get
{
return 256 * Scale;
}
}///
/// Get the height of the in-game room
///public static int RoomHeight
{
get
{
return 176 * Scale;
}
}///
/// Get the height of the in-game room * the sprite scale
///public static int ScaledRoomHeight
{
get
{
return 176 * Scale;
}
}///
/// Get the X coordinate of the top-left corner of the in-game room
///public static int RoomX
{
get
{
return (Width – ScaledRoomWidth) / 2;
}
}///
/// Get the Y coordinate of the top-left corner of the in-game room
///public static int RoomY
{
get
{
return ((Height – ScaledRoomHeight) / 2) + 56;
}
}///
/// The scale at which sprites should be rendered in the window.
///public static int Scale = 3;
}
}
}# auks256/cse3902
/* Author — Allen Antony Ukani
* Contact — auks256ATcs.washington.edu
* Created Date — 10.15.2012
* Last Modified Date — 10.17.2012
* Last Modified By — Allen Antony Ukani
*/using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;namespace LegendOfZelda
{
public class PlayerState : ICloneable
{
#region Constants
// Default values taken from NES version of Zelda///
/// This is the cap on Link’s health. All values should match this.
///public static readonly int MAX_HEALTH = 16;
///
/// Link’s maximum health with no Heart Containers
///public static readonly int MAX_HEALTH_BASE = 3;
///
/// Link’s default health
///public static readonly int DEFAULT_HEALTH = 3;
///
/// Number of Rupees that Link starts out with
///public static readonly int DEFAULT_RUPEE_COUNT = 0;
///
/// Max number of Keys that Link can have
///public static readonly int MAX_KEY_COUNT = 9;
///
/// Max number of Bombs that Link can have
///public static readonly int MAX_BOMB_COUNT = 9;
///
/// Default number of arrows for Link to have
///public static readonly int DEFAULT_ARROW_COUNT = 0;
///
/// The maximum number of arrows Link can carry
///public static readonly int MAX_ARROW_COUNT = 30;
///
/// Which item slot the boomerang goes in (0-indexed)
///public static readonly int BOOMERANG_SLOT = 0;
///
/// Which item slot the bomb goes in (0-indexed)
///public static readonly int BOMB_SLOT = 1;
///
/// Which item slot the bow goes in (0-indexed)
///public static readonly int BOW_SLOT = 2;
///
/// Which item slot the candle goes in (0-indexed)
///public static readonly int CANDLE_SLOT = 3;
///
/// Which item slot the whistle goes in (0-indexed)
///public static readonly int WHISTLE_SLOT = 4;
///
/// Which item slot the meat goes in (0-indexed)
///public static readonly int MEAT_SLOT = 5;
///
/// Which item slot the potion goes in (0-indexed)
///public static readonly int POTION_SLOT = 6;
///
/// Which item slot the wand goes in (0-indexed)
///public static readonly int WAND_SLOT = 7;
///
/// The total number of equippable item slots available
///public static readonly int NUM_ITEM_SLOTS = 8;
///
/// The max number of lives that Link can have
///public static readonly int MAX_LIFE_COUNT = 9;
///
/// Max number of rupees that Link can hold
///public static readonly int MAX_RUPEE_COUNT = 255;
///
/// The number of Triforce segments to collect
///public static readonly int MAX_TRIFORCE_COUNT = 8;
#endregion
public enum Weapon
{
None,
Sword,
WhiteSword,
MagicalSword,
Wand
}// Life and equipment info
private int health;///
/// Link’s current health
///public int Health
{
get { return health; }
set
{
if (value > MaxHealth) health = MaxHealth;
else health = value;
}
}private int maxHealth;
///
/// Link’s current max health
///public int MaxHealth
{
get { return maxHealth; }
set
{
if (value > MAX_HEALTH)
maxHealth = MAX_HEALTH;
else
maxHealth = value;
}
}///
/// Number of life hearts Link has
///public int LifeCount { get; set; }
///
/// Number of Rupees Link has
///public int RupeeCount { get; set; }
///
/// Number of Keys Link has
///public int KeyCount { get; set; }
///
/// Number of Bombs Link has
///public int BombCount { get; set; }
///
/// Number of Arrows Link has
///public int ArrowCount { get; set; }
///
/// Which weapon is Link using
///public Weapon CurrentWeapon { get; set; }
// Item inventory info
private bool[] hasItemInSlot;///
/// Access the inventory slot for a specific item, retrieved by index
////// The index of the slot to check
/// True if Link has the item in the given slot, false otherwise
public bool HasItemInSlot(int slotIndex)
{
return hasItemInSlot[slotIndex];
}///
/// Set whether Link has the item in a specific slot
////// The index of the slot to set
/// True if Link should have the item, false otherwise
public void SetItemInSlot(int slotIndex, bool value)
{
hasItemInSlot[slotIndex] = value;
}///
/// Clear Link’s inventory
///public void ClearInventory()
{
for (int i = 0; i < hasItemInSlot.Length; i++)
{
hasItemInSlot[i] = false;
}
}///
/// The currently selected item’s inventory slot
///public int CurrentItemSlot { get; set; }
// Game world info
protected bool[] hasDungeonMap;///
/// Get whether Link has the dungeon map for a specific dungeon ID
////// Which dungeon’s map to check (0-indexed)
/// True if Link has the map for the given dungeon, false otherwise
public bool HasDungeonMap(int dungeonId)
{
return hasDungeonMap[dungeonId];
}///
/// Set whether Link has the map for a specific dungeon
////// Which dungeon’s map to set (0-indexed)
/// True if Link should have the dungeon map, false otherwise
public void SetDungeonMap(int dungeonId, bool value)
{
hasDungeonMap[dungeonId] = value;
}///
/// Clear all dungeon maps from Link’s inventory.
///public void ClearDungeonMaps()
{
for (int i = 0; i < hasDungeonMap.Length; i++)
{
hasDungeonMap[i] = false;
}
}protected bool[] hasCompass;
///
/// Get whether Link has the compass for a specific dungeon ID
////// Which dungeon’s compass to check (0-indexed)
/// True if Link has the compass for the given dungeon, false otherwise
public bool HasCompass(int dungeonId)
{
return hasCompass[dungeonId];
}///
/// Set whether Link has the compass for a specific dungeon
////// Which dungeon’s compass to set (0-indexed)
/// True if Link should have the dungeon’s compass, false otherwise
public void SetCompass(int dungeonId, bool value)
{
hasCompass[dungeonId] = value;
}///
/// Clear all compass items from Link’s inventory.
///public void ClearCompasses()
{
for (int i = 0; i < hasCompass.Length; i++)
{
hasCompass[i] = false;
}
}protected bool[] hasTriforcePiece;
///
/// Get whether Link has a specific Triforce piece
////// Which Triforce piece to check (0-indexed)
/// True if Link has the specific Triforce piece, false otherwise
public bool HasTriforcePiece(int pieceId)
{
return hasTriforcePiece[pieceId];
}///
/// Set whether Link has a specific Triforce piece
////// Which Triforce piece to set (0-indexed)
/// True if Link should have the piece, false otherwise
public void SetTriforcePiece(int pieceId, bool value)
{
hasTriforcePiece[pieceId] = value;
}///
/// Count how many Triforce pieces Link has collected
////// The number of Triforce pieces Link has
public int GetTriforceCount()
{
int result = 0;
for (int i = 0; i < hasTriforcePiece.Length; i++)
{
if (hasTriforcePiece[i]) result++;
}
return result;
}///
/// Clear all Triforce pieces from Link’s inventory
///public void ClearTriforces()
{
for (int i = 0; i < hasTriforcePiece.Length; i++)
{
hasTriforcePiece[i] = false;
}
}///
/// Returns true if Link has the blue candle, false otherwise.
///public bool HasBlueCandle { get; set; }
///
/// Returns true if Link has the red candle, false otherwise.
///public bool HasRedCandle { get; set; }
///
/// Returns true if Link has the blue boomerang, false otherwise.
///public bool HasBlueBoomerang { get; set; }
///
/// Returns true if Link has the blue boomerang, false otherwise.
///public bool HasMagicBoomerang { get; set; }
///
/// Returns true if Link has the blue ring, false otherwise
///public bool HasBlueRing { get; set; }
///
/// Returns true if Link has the red ring, false otherwise
///public bool HasRedRing { get; set; }
///
/// Returns true if Link has the bow, false otherwise.
///public bool HasBow { get; set; }
///
/// Returns true if Link has the raft.
///public bool HasRaft { get; set; }
///
/// Returns true if Link has the ladder.
///public bool HasLadder { get; set; }
///
/// Resets the player state to the starting state of the game.
///public void Reset()
{
// Set up vitals
Health = DEFAULT_HEALTH;
MaxHealth = MAX_HEALTH_BASE;
LifeCount = 0;// Set up items
RupeeCount = DEFAULT_RUPEE_COUNT;
KeyCount = 0;
BombCount = 0;
ArrowCount = 0;// Set up item inventory
for (int i = 0; i < hasItemInSlot.Length; i++)
{
hasItemInSlot[i] = false;
}
CurrentItemSlot = 0;// Set up weapon
CurrentWeapon = Weapon.None;// Set up game world information
for (int i = 0; i < hasDungeonMap.Length; i++)
{
hasDungeonMap[i] = false;
}
for (int i = 0; i < hasCompass.Length; i++)
{
hasCompass[i] = false;
}
for (int i = 0; i < hasTriforcePiece.Length; i++)
{
hasTriforcePiece[i] = false;
}HasBlueCandle = false;
HasRedCandle = false;
HasBlueBoomerang = false;
HasMagicBoomerang = false;
HasBlueRing = false;
HasRedRing = false;
HasBow = false;
HasRaft = false;
HasLadder = false;
}///
/// Set up a debug testing environment for Link
///public void SetupDebugState()
{
MaxHealth = MAX_HEALTH;
Health = MAX_HEALTH;
RupeeCount = 255;
BombCount = 9;
KeyCount = 9;
ArrowCount = MAX_ARROW_COUNT;
HasBow = true;
HasItemInSlot(BOW_SLOT, true);
CurrentWeapon = Weapon.Sword;
HasLadder = true;
HasBlueBoomerang = true;
SetItemInSlot(BOOMERANG_SLOT, true);
SetItemInSlot(BOMB_SLOT, true);
SetItemInSlot(BOW_SLOT, true);
}///
/// Initializes a player state object with the default values
///public PlayerState()
{
// Create arrays for equipment
hasItemInSlot = new bool[NUM_ITEM_SLOTS];
hasDungeonMap = new bool[MAX_TRIFORCE_COUNT];
hasCompass = new bool[MAX_TRIFORCE_COUNT];
hasTriforcePiece = new bool[MAX_TRIFORCE_COUNT];// Set the default state
Reset();
}///
/// Copy constructor
////// PlayerState object to copy from
public PlayerState(PlayerState copy)
{
// Create arrays for equipment
hasItemInSlot = new bool[NUM_ITEM_SLOTS];
hasDungeonMap = new bool[MAX_TRIFORCE_COUNT];
hasCompass = new bool[MAX_TRIFORCE_COUNT];
hasTriforcePiece = new bool[MAX_TRIFORCE_COUNT];// Copy over life info
this.Health = copy.Health;
this.MaxHealth = copy.MaxHealth;
this.LifeCount = copy.LifeCount;// Copy over equipment
this.RupeeCount = copy.RupeeCount;
this.KeyCount = copy.KeyCount;
this.BombCount = copy.BombCount;
this.ArrowCount = copy.ArrowCount;// Copy over weapons
this.CurrentWeapon = copy.CurrentWeapon;// Copy over item inventory
for (int i = 0; i < copy.hasItemInSlot.Length; i++)
{
this.hasItemInSlot[i] = copy.hasItemInSlot[i];
}
this.CurrentItemSlot = copy.CurrentItemSlot;// Copy over game world info
for (int i = 0; i < hasDungeonMap.Length; i++)
{
this.hasDungeonMap[i] = copy.hasDungeonMap[i];
}
for (int i = 0; i < hasCompass.Length; i++)
{
this.hasCompass[i] = copy.hasCompass[i];
}
for (int i = 0; i < hasTriforcePiece.Length; i++)
{
this.hasTriforcePiece[i] = copy.hasTriforcePiece[i];
}// Copy over item state
this.HasBlueCandle = copy.HasBlueCandle;
this.HasRedCandle = copy.HasRedCandle;
this.HasBlueBoomerang = copy.HasBlueBoomerang;
this.HasMagicBoomerang = copy.HasMagicBoomerang;
this.HasBlueRing = copy.HasBlueRing;
this.HasRedRing = copy.HasRedRing;
this.HasBow = copy.HasBow;
this.HasRaft = copy.HasRaft;
this.HasLadder = copy.HasLadder;
}///
/// Clone the current player state
////// A copy of the current PlayerState object
public object Clone()
{
return new PlayerState(this);
}
}
}/* Original Author — Allen Antony Ukani
* Original Contact — auks256ATcs.washington.edu
* Created Date — 10.9.2012
* Last Modified Date — 10.17.2012
* Last Modified By — Allen Antony Ukani
*/using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using LegendOfZelda.Items;
using Microsoft.Xna.Framework;namespace LegendOfZelda
{
/**
* Singleton class that manages global game state such as player information.
*
* Pattern: Singleton
* Collaborators: ProjectileManager – manages in-game projectiles
* CollisionDetector – controls collision detection
* BlockManager – manages in-game blocks
*/
public class GameManager
{
#region Singleton Instance
/**
* Creates a singleton instance of the GameManager. No parameters can be used during creation
*/
private static GameManager instance;public static GameManager Instance
{
get
{
if (instance == null)
{
instance = new GameManager();
}
return instance;
}
}
#endregion#region Delegates and Events
// Event fired when Link collects a triforce piece
public delegate void TriforceCollectedEventHandler(object source, EventArgs args);
public event TriforceCollectedEventHandler TriforceCollected;
protected virtual void OnTriforceCollected()
{
if (TriforceCollected != null)
{
TriforceCollected(this, EventArgs.Empty);
}
}#endregion
#region Properties
private ILink link;
public ILink Link
{
get
{
return link;
}
set
{
link = value;
}
}///
/// Gets the player’s state
///private PlayerState player;
public PlayerState Player
{
get { return player; }
}///
/// The total number of lives Link has (GAME OVER if < 0)
///private SchedulableStopWatch activeStopWatch;
public SchedulableStopWatch ActiveStopWatch
{
get { return activeStopWatch; }
set { activeStopWatch = value; }
}///
/// Gets the ProjectileManager for the application.
///private ProjectileManager projectileManager;
public ProjectileManager ProjectileManager
{
get { return projectileManager; }
}///
/// Gets the BlockManager for the application.
///private BlockManager blockManager;
public BlockManager BlockManager
{
get { return blockManager; }
}///
/// Gets the collision detector for the application
///private CollisionDetector collisionDetector;
public CollisionDetector CollisionDetector
{
get { return collisionDetector; }
}///
/// Gets the score keeper for the application.
///private ScoreKeeper scoreKeeper;
public ScoreKeeper ScoreKeeper
{
get { return scoreKeeper; }
}///
/// Gets the ParticleManager for the application.
///private ParticleManager particleManager;
public ParticleManager ParticleManager
{
get { return particleManager; }
}private Dictionary gameFiles = null;
///
/// Gets/sets the dictionary of game files
///public Dictionary GameFiles
{
get
{
if (gameFiles == null) ResetGameFiles();
return gameFiles;
}
set { gameFiles = value; }
}#endregion
#region Methods
///
/// Reset all game files to a blank slate
///public void ResetGameFiles()
{
gameFiles = new Dictionary();
gameFiles.Add(„file1”, new PlayerState());
gameFiles.Add(„file2”, new PlayerState());
gameFiles.Add(„file3”, new PlayerState());
}///
/// Check whether the player can have the item based on an enum
////// The item from the ItemSprite.ItemType being checked
/// Returns true if the player can have the item (needs or doesn’t have), or false otherwise
public bool CanHaveItem(ItemSprite.ItemType type)
{
// Check by item type
switch (type)
{
case ItemSprite.ItemType.Bomb:
return Player.BombCount < PlayerState.MAX_BOMB_COUNT;
case ItemSprite.ItemType.BonusBombs:
return Player.BombCount < PlayerState.MAX_BOMB_COUNT;
case ItemSprite.ItemType.Rupee:
case ItemSprite.ItemType.RedRupee:
return Player.RupeeCount < PlayerState.MAX_RUPEE_COUNT;
case ItemSprite.ItemType.Heart:
return Player.Health < Player.MaxHealth;
case ItemSprite.ItemType.Key:
return Player.KeyCount < PlayerState.MAX_KEY_COUNT;
case ItemSprite.ItemType.HeartContainer:
return Player.MaxHealth < PlayerState.MAX_HEALTH;
case ItemSprite.ItemType.Fairy:
return Player.Health < Player.MaxHealth;
case ItemSprite.ItemType.BlueBoomerang:
return !Player.HasBlueBoomerang;
case ItemSprite.ItemType.MagicBoomerang:
return !Player.HasMagicBoomerang;
case ItemSprite.ItemType.Candle:
return !Player.HasBlueCandle && !Player.HasRedCandle;
case ItemSprite.ItemType.Arrow:
return Player.ArrowCount < PlayerState.MAX_ARROW_COUNT;
case ItemSprite.ItemType.TriforcePiece:
return !Player.HasTriforcePiece(0);
case ItemSprite.ItemType.Bow:
return !Player.HasBow;
case ItemSprite.ItemType.BlueRing:
return !Player.HasBlueRing;
case ItemSprite.ItemType.Raft:
return !Player.HasRaft;
case ItemSprite.ItemType.Ladder:
return !Player.HasLadder;
default:
return true;
}
}///
/// Give the player a specific item
////// The Item to give to the player
public void GivePlayerItem(ItemSprite.ItemType type)
{
// Check by item type
switch (type)
{
case ItemSprite.ItemType.Bomb:
Player.BombCount++;
if (!Player.HasItemInSlot(PlayerState.BOMB_SLOT))
{
Player.SetItemInSlot(PlayerState.BOMB_SLOT, true);
}
SoundFactory.PlaySound(SoundFactory.SoundType.GetItem);
break;
case ItemSprite.ItemType.BonusBombs:
if (Player.BombCount <= (PlayerState.MAX_BOMB_COUNT – 4))
{
Player.BombCount += 4;
}
else
{
Player.BombCount = PlayerState.MAX_BOMB_COUNT;
}
if (!Player.HasItemInSlot(PlayerState.BOMB_SLOT))
{
Player.SetItemInSlot(PlayerState.BOMB_SLOT, true);
}
SoundFactory.PlaySound(SoundFactory.SoundType.GetItem);
break;
case ItemSprite.ItemType.Bow:
Player.HasBow = true;
Player.SetItemInSlot(PlayerState.BOW_SLOT, true);
SoundFactory.PlaySound(SoundFactory.SoundType.GetItem);
break;
case ItemSprite.ItemType.Rupee:
if (Player.RupeeCount < PlayerState.MAX_RUPEE_COUNT)
{
Player.RupeeCount++;
}
SoundFactory.PlaySound(SoundFactory.SoundType.GetRupee);
break;
case ItemSprite.ItemType.RedRupee:
if (Player.RupeeCount <= (PlayerState.MAX_RUPEE_COUNT – 5))
{
Player.RupeeCount += 5;
}
else
{
Player.RupeeCount = PlayerState.MAX_RUPEE_COUNT;
}
SoundFactory.PlaySound(SoundFactory.SoundType.GetRupee);
break;
case ItemSprite.ItemType.Heart:
if (Player.Health < Player.MaxHealth)
{
Player.Health++;
}
SoundFactory.PlaySound(SoundFactory.SoundType.GetHeart);
break;
case ItemSprite.ItemType.Key:
Player.KeyCount++;
SoundFactory.PlaySound(SoundFactory.SoundType.GetKey);
break;
case ItemSprite.ItemType.HeartContainer:
Player.MaxHealth++;
Player.Health = Player.MaxHealth;
SoundFactory.PlaySound(SoundFactory.SoundType.GetHeartContainer);
break;
case ItemSprite.ItemType.TriforcePiece:
Player.SetTriforcePiece(0, true);
SoundFactory.PlaySound(SoundFactory.SoundType.GetMapOrCompass);
OnTriforceCollected();
break;
case ItemSprite.ItemType.Fairy:
Player.Health = Player.MaxHealth;
SoundFactory.PlaySound(SoundFactory.SoundType.GetHeart);
break;
case ItemSprite.ItemType.Ladder:
Player.HasLadder = true;
SoundFactory.PlaySound(SoundFactory.SoundType.GetHeart);
break;
case ItemSprite.ItemType.Clock:
// Freeze all monsters
SoundFactory.PlaySound(SoundFactory.SoundType.GetHeart);
break;
case ItemSprite.ItemType.Candle:
Player.HasBlueCandle = true;
Player.SetItemInSlot(PlayerState.CANDLE_SLOT, true);
SoundFactory.PlaySound(SoundFactory.SoundType.GetItem);
break;
case ItemSprite.ItemType.BlueRing:
Player.HasBlueRing = true;
SoundFactory.PlaySound(SoundFactory.SoundType.GetItem);
break;
case ItemSprite.ItemType.Arrow:
if (Player.ArrowCount <= (PlayerState.MAX_ARROW_COUNT – 5))
{
Player.ArrowCount += 5;
}
else
{
Player.ArrowCount = PlayerState.MAX_ARROW_COUNT;
}
SoundFactory.PlaySound(SoundFactory.SoundType.GetItem);
break;
case ItemSprite.ItemType.BlueBoomerang:
Player.HasBlueBoomerang = true;
Player.SetItemInSlot(PlayerState.BOOMERANG_SLOT, true);
SoundFactory.PlaySound(SoundFactory.SoundType.GetItem);
break;
case ItemSprite.ItemType.MagicBoomerang:
Player.HasMagicBoomerang = true;
Player.HasBlueBoomerang = true;
Player.SetItemInSlot(PlayerState.BOOMERANG_SLOT, true);
SoundFactory.PlaySound(SoundFactory.SoundType.GetItem);
break;
case ItemSprite.ItemType.Sword:
Player.CurrentWeapon = PlayerState.Weapon.Sword;
SoundFactory.PlaySound(SoundFactory.SoundType.GetItem);
break;
case ItemSprite.ItemType.Raft:
Player.HasRaft = true;
SoundFactory.PlaySound(SoundFactory.SoundType.GetItem);
break;
default:
break;
}}
///
/// Reset the state (create a new player data object, etc)
///public void ResetState()
{
player = new PlayerState();
projectileManager = new ProjectileManager();
blockManager = new BlockManager();
collisionDetector = new CollisionDetector();
scoreKeeper = new ScoreKeeper();
particleManager = new ParticleManager();
}///
/// Reset the player’s state
////// Optional parameter to intialize the player data from another PlayerState
public void ResetPlayer(PlayerState newPlayer = null)
{
if (newPlayer == null)
{
player = new PlayerState();
}
else
{
player = (PlayerState)newPlayer.Clone();
}
}///
/// Reset the player’s state and set up a testing environment
///public void ResetPlayerForTesting()
{
player = new PlayerState();
player.SetupDebugState();
}#endregion
///
/// Private constructor to set up the initial game state
///private GameManager()
{
ResetState();
}
}
}# auks256/cse3902
/* Author — Scott-Michael Fried
* Contact — fried.uw.edu
* Created Date — 9.19.2012
* Last Modified Date — 10.24.2012
* Last Modified By — Scott-Michael Fried
*/using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using LegendOfZelda.Collisions;namespace LegendOfZelda
{
////// This class represents Link carrying a treasure. It acts as a wrapper to store the treasure with Link
////// The type of object that the treasure represents. Must be a sprite of some kind.
class LinkTreasure : ILink where T : AnimatedSprite, ICollidable
{
private ILink Link;
public T Treasure;///
/// Whether Link is holding treasure up or not.
///public bool HoldingTreasureUp { get; private set; }
///
/// Create a new link treasure. Link will hold up the treasure until the animation is over.
////// Link object to wrap.
/// Treasure that Link will be carrying.
public LinkTreasure(ILink link, T treasure)
{
HoldingTreasureUp = true;Link = link;
Treasure = treasure;
Treasure.Activate();
Treasure.X = Link.X;
Treasure.Y = Link.Y – 12;// Move Link back to facing up
if (Link.FacingDirection != ILink.Direction.North)
{
Link.ChangeDirection(ILink.Direction.North);
}// Freeze link in place when we get this treasure
GameContext.State.LinkIsFrozen = true;
}#region Link wrapper methods
public void Attack()
{
Link.Attack();
}public void ChangeDirection(ILink.Direction direction)
{
Link.ChangeDirection(direction);
}public void Draw(SpriteBatch spriteBatch)
{
if (!IsDead)
{
Link.Draw(spriteBatch);if (HoldingTreasureUp)
{
Treasure.Draw(spriteBatch);
}
}
}private bool firstUpdate = true;
private int timer = 150;
private bool linkDead = false;public void Update(GameTime gameTime)
{
if (firstUpdate)
{
linkDead = Link.IsDead;
firstUpdate = false;
}// Update wrapped Links
Link.Update(gameTime);if (HoldingTreasureUp)
{
timer -= gameTime.ElapsedGameTime.Milliseconds;if (timer <= 0)
{
HoldingTreasureUp = false;
GameContext.State.LinkIsFrozen = false;
}if (Link is LinkItemPickup)
{
Treasure.X = Link.X – 3;
Treasure.Y = Link.Y – 12;
}
else
{
Treasure.X = Link.X;
Treasure.Y = Link.Y – 12;
}Treasure.Update(gameTime);
}
}public void TakeDamage(int damage, ILink.Direction direction)
{
Link.TakeDamage(damage, direction);
}public void UseItem()
{
Link.UseItem();
}public int X
{
get { return Link.X; }
set { Link.X = value; }
}public int Y
{
get { return Link.Y; }
set { Link.Y = value; }
}public ILink.Direction FacingDirection
{
get { return Link.FacingDirection; }
}public ILink.State LinkState
{
get { return Link.LinkState; }
}public bool IsVisible
{
get { return Link.IsVisible; }
set { Link.IsVisible = value; }
}public bool IsDead
{
get { return linkDead; }
}public bool IsBeingDamaged
{
get { return Link.IsBeingDamaged; }
}///
/// Gets an integer representing the layer that this object should be drawn on, with higher values being drawn on top of lower values.
/// Objects with equivalent z-indices have an undefined render order relative to each other.
///public int ZIndex
{
get { return Link.ZIndex; }
}public Rectangle Bounds
{
get { return Link.Bounds; }
}public CollisionGroup CollisionGroup
{
get { return Link.CollisionGroup; }
}public Point Location
{
get { return Link.Location; }
}public Point Size
{
get { return Link.Size; }
}public int Width
{
get { return Link.Width; }
}public int Height
{
get { return Link.Height; }
}public void OnCollision(ICollidable obj)
{
if (HoldingTreasureUp) {
// If we’re holding the treasure up, give the treasure the collision if possible
Treasure.OnCollision(obj);
}// Give the collision to the decorated link if the treasure didn’t handle it
Link.OnCollision(obj);
}public void ResetState()
{
Link.ResetState();
}public void BecomeDamaged()
{
Link.BecomeDamaged();
}///
/// Move Link to the given position on the screen.
////// X-position to place Link at
/// Y-position to place Link at
public void MoveTo(int x, int y)
{
Link.MoveTo(x, y);
}///
/// Switch which item Link has selected
///public void CycleSelectedItem()
{
Link.CycleSelectedItem();
}///
/// Reset the item Link has selected
///public void ResetSelectedItem()
{
Link.ResetSelectedItem();
}///
/// Reset Links position
///public void ResetPosition()
{
Link.ResetPosition();
}///
/// Start animating Links death. Returns true if the Link is dead, false otherwise
///public bool Die()
{
return Link.Die();
}///
/// Get the center of the link
////// The Point where the Link’s center is.
public Point Center
{
get
{
return Link.Center;
}
}#endregion
}
}/* Author — Scott-Michael Fried
* Contact — fried.uw.edu
* Created Date — 9.19.2012
* Last Modified Date — 10.24.2012
* Last Modified By — Scott-Michael Fried
*/using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using LegendOfZelda.Collisions;namespace LegendOfZelda
{
////// A concrete Link decorator that represents how Link looks while picking up an item
////// The type of object that is collected. Must be a sprite of some kind.
class LinkItemPickup : ILink where T : AnimatedSprite, ICollidable
{
private ILink Link;
private bool firstUpdate;
private int pickupTimer;
private readonly int pickupTime = 1000;///
/// Link is picking something up
////// The ILink implementation for decoration
public LinkItemPickup(ILink link)
{
Link = link;// Freeze link in place
firstUpdate = true;
pickupTimer = pickupTime;
GameContext.State.LinkIsFrozen = true;
}#region Link wrapper methods
public void Attack()
{
Link.Attack();
}public void ChangeDirection(ILink.Direction direction)
{
Link.ChangeDirection(direction);
}public void Draw(SpriteBatch spriteBatch)
{
if (!IsDead)
{
Link.Draw(spriteBatch);
}
}public void Update(GameTime gameTime)
{
if (!IsDead)
{
Link.Update(gameTime);if (firstUpdate)
{
// If this is a new pickup, make sure Link is facing north
if (Link.FacingDirection != ILink.Direction.North)
{
Link.ChangeDirection(ILink.Direction.North);
}
firstUpdate = false;
}pickupTimer -= gameTime.ElapsedGameTime.Milliseconds;
if (pickupTimer <= 0)
{
GameContext.State.LinkIsFrozen = false;
}
}
}public void TakeDamage(int damage, ILink.Direction direction)
{
Link.TakeDamage(damage, direction);
}public void UseItem()
{
Link.UseItem();
}public int X
{
get { return Link.X; }
set { Link.X = value; }
}public int Y
{
get { return Link.Y; }
set { Link.Y = value; }
}public ILink.Direction FacingDirection
{
get { return Link.FacingDirection; }
}public ILink.State LinkState
{
get { return Link.LinkState; }
}public bool IsVisible
{
get { return Link.IsVisible; }
set { Link.IsVisible = value; }
}public bool IsDead
{
get { return Link.IsDead; }
}public bool IsBeingDamaged
{
get { return Link.IsBeingDamaged; }
}///
/// Gets an integer representing the layer that this object should be drawn on, with higher values being drawn on top of lower values.
/// Objects with equivalent z-indices have an undefined render order relative to each other.
///public int ZIndex
{
get { return Link.ZIndex; }
}public Rectangle Bounds
{
get { return Link.Bounds; }
}public CollisionGroup CollisionGroup
{
get { return Link.CollisionGroup; }
}public Point Location
{
get { return Link.Location; }
}public Point Size
{
get { return Link.Size; }
}public int Width
{
get { return Link.Width; }
}public int Height
{
get { return Link.Height; }
}public void OnCollision(ICollidable obj)
{
Link.OnCollision(obj);
}public void ResetState()
{
Link.ResetState();
}public void BecomeDamaged()
{
Link.BecomeDamaged();
}///
/// Move Link to the given position on the screen.
////// X-position to place Link at
/// Y-position to place Link at
public void MoveTo(int x, int y)
{
Link.MoveTo(x, y);
}///
/// Switch which item Link has selected
///public void CycleSelectedItem()
{
Link.CycleSelectedItem();
}///
/// Reset the item Link has selected
///public void ResetSelectedItem()
{
Link.ResetSelectedItem();
}///
/// Reset Links position
///public void ResetPosition()
{
Link.ResetPosition();
}///
/// Start animating Links death. Returns true if the Link is dead, false otherwise
//////
public bool Die()
{
return Link.Die();
}///
/// Get the center of the link
////// The Point where the Link’s center is.
public Point Center
{
get
{
return Link.Center;
}
}#endregion
}
}# auks256/cse3902
/* Author — Allen Antony Ukani
* Contact — auks256ATcs.washington.edu
* Created Date — 10.01.2012
* Last Modified Date — 10.18.2012
* Last Modified By — Allen Antony Ukani
*/using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using LegendOfZelda.Collisions;
using LegendOfZelda.Projectiles;
using LegendOfZelda.Items;namespace LegendOfZelda
{
class BasicLink : AnimatedSprite, ILink
{
public enum Direction : int { North = 0, South = 4, East = 8, West = 12 }
private ILink.Direction linkFacingDirection = ILink.Direction.South;public enum State : int { StillFacing = 0, Moving = 1, Sword = 2, ItemUse = 3 }
private ILink.State linkState = ILink.State.StillFacing;// Map for basic north, south, west and east movement
private static Dictionary directionToXYMap = new Dictionary()
{
{Direction.North, new Vector2(0,-1)},
{Direction.South, new Vector2(0,1)},
{Direction.East, new Vector2(1,0)},
{Direction.West, new Vector2(-1,0)}
};// Map for diagonal input movement – used if multiple directions are held
private static Dictionary<Tuple, Vector2> diagonalMap = new Dictionary<Tuple, Vector2>()
{
{new Tuple(Direction.North, Direction.East), new Vector2(1,-1)},
{new Tuple(Direction.North, Direction.West), new Vector2(-1,-1)},
{new Tuple(Direction.South, Direction.East), new Vector2(1,1)},
{new Tuple(Direction.South, Direction.West), new Vector2(-1,1)}
};// Store the spritesheet file for the current Link
private string spriteSheetName;// Rect for visualizing damage
private Color damageColor = Color.Red * 0.5f;#region Animation Variables
private Vector2 dir = Vector2.Zero;
private int[] animArray = null;private Dictionary<Tuple, int[]> animTable = null;
private const int ANIM_SPEED = 100;
private const int MOVE_SPEED = 1;
private const int DAMAGE_MOVE_SPEED = 2;private static Dictionary GetLinkAnimationTable()
{
Dictionary table = new Dictionary();// Still facing
table.Add(LinkAnims.NStill, new Rectangle(1, 11, 16, 16));
table.Add(LinkAnims.SStill, new Rectangle(1, 28, 16, 16));
table.Add(LinkAnims.EStill, new Rectangle(1, 77, 16, 16));
table.Add(LinkAnims.WStill, new Rectangle(1, 60, 16, 16));// Moving (two frames)
table.Add(LinkAnims.NMove1, new Rectangle(1, 11, 16, 16));
table.Add(LinkAnims.NMove2, new Rectangle(18, 11, 16, 16));
table.Add(LinkAnims.SMove1, new Rectangle(1, 28, 16, 16));
table.Add(LinkAnims.SMove2, new Rectangle(18, 28, 16, 16));
table.Add(LinkAnims.EMove1, new Rectangle(1, 77, 16, 16));
table.Add(LinkAnims.EMove2, new Rectangle(18, 77, 16, 16));
table.Add(LinkAnims.WMove1, new Rectangle(1, 60, 16, 16));
table.Add(LinkAnims.WMove2, new Rectangle(18, 60, 16, 16));// Sword (four frames)
table.Add(LinkAnims.NSword1, new Rectangle(1, 97, 16, 27));
table.Add(LinkAnims.NSword2, new Rectangle(18, 97, 16, 27));
table.Add(LinkAnims.NSword3, new Rectangle(35, 97, 16, 27));
table.Add(LinkAnims.NSword4, new Rectangle(52, 97, 16, 27));
table.Add(LinkAnims.SSword1, new Rectangle(1, 124, 16, 27));
table.Add(LinkAnims.SSword2, new Rectangle(18, 124, 16, 27));
table.Add(LinkAnims.SSword3, new Rectangle(35, 124, 16, 27));
table.Add(LinkAnims.SSword4, new Rectangle(52, 124, 16, 27));
table.Add(LinkAnims.ESword1, new Rectangle(1, 147, 27, 16));
table.Add(LinkAnims.ESword2, new Rectangle(35, 147, 27, 16));
table.Add(LinkAnims.ESword3, new Rectangle(69, 147, 27, 16));
table.Add(LinkAnims.ESword4, new Rectangle(103, 147, 27, 16));
table.Add(LinkAnims.WSword1, new Rectangle(1, 173, 27, 16));
table.Add(LinkAnims.WSword2, new Rectangle(35, 173, 27, 16));
table.Add(LinkAnims.WSword3, new Rectangle(69, 173, 27, 16));
table.Add(LinkAnims.WSword4, new Rectangle(103, 173, 27, 16));// Item Use (one frame)
table.Add(LinkAnims.NItem, new Rectangle(1, 196, 16, 16));
table.Add(LinkAnims.SItem, new Rectangle(18, 196, 16, 16));
table.Add(LinkAnims.EItem, new Rectangle(1, 214, 16, 16));
table.Add(LinkAnims.WItem, new Rectangle(18, 214, 16, 16));// Damage (one frame)
table.Add(LinkAnims.NDamage, new Rectangle(52, 196, 16, 16));
table.Add(LinkAnims.SDamage, new Rectangle(69, 196, 16, 16));
table.Add(LinkAnims.EDamage, new Rectangle(52, 214, 16, 16));
table.Add(LinkAnims.WDamage, new Rectangle(69, 214, 16, 16));return table;
}///
/// Link animation table
///protected enum LinkAnims
{
NStill, SStill, EStill, WStill,
NMove1, SMove1, EMove1, WMove1, NMove2, SMove2, EMove2, WMove2,
NSword1, SSword1, ESword1, WSword1, NSword2, SSword2, ESword2, WSword2,
NSword3, SSword3, ESword3, WSword3, NSword4, SSword4, ESword4, WSword4,
NItem, SItem, EItem, WItem,
NDamage, SDamage, EDamage, WDamage
}
#endregion// Position Management
private int x, y;// Internal state management
private bool isDying, isBeingDamaged;
private Rectangle damageBounds;
private int damageTimer, soundTimer;
private int damageDuration = 750;
private bool stillAttacking = false;
private bool usingItem = false;
private Direction damageDir;
private int frameTimer;
private const int swordDuration = 400; //200;
private const int itemDuration = 250;// Items
private int currentItemIndex = 0;// Cached PlayerState
private PlayerState player;///
/// Construct a new basic Link sprite
///public BasicLink() : base(„Link”)
{
ChangeAnimationTable(GetLinkAnimationTable());// Create the animation table map
animTable = new Dictionary<Tuple, int[]>();// Set up still animations
animTable.Add(new Tuple(Direction.North, State.StillFacing), new int[] { (int)LinkAnims.NStill });
animTable.Add(new Tuple(Direction.South, State.StillFacing), new int[] { (int)LinkAnims.SStill });
animTable.Add(new Tuple(Direction.East, State.StillFacing), new int[] { (int)LinkAnims.EStill });
animTable.Add(new Tuple(Direction.West, State.StillFacing), new int[] { (int)LinkAnims.WStill });// Set up moving animations
animTable.Add(new Tuple(Direction.North, State.Moving), new int[] { (int)LinkAnims.NMove1, (int)LinkAnims.NMove2 });
animTable.Add(new Tuple(Direction.South, State.Moving), new int[] { (int)LinkAnims.SMove1, (int)LinkAnims.SMove2 });
animTable.Add(new Tuple(Direction.East, State.Moving), new int[] { (int)LinkAnims.EMove1, (int)LinkAnims.EMove2 });
animTable.Add(new Tuple(Direction.West, State.Moving), new int[] { (int)LinkAnims.WMove1, (int)LinkAnims.WMove2 });// Set up sword animations
animTable.Add(new Tuple(Direction.North, State.Sword), new int[] { (int)LinkAnims.NSword1, (int)LinkAnims.NSword2, (int)LinkAnims.NSword3, (int)LinkAnims.NSword4 });
animTable.Add(new Tuple(Direction.South, State.Sword), new int[] { (int)LinkAnims.SSword1, (int)LinkAnims.SSword2, (int)LinkAnims.SSword3, (int)LinkAnims.SSword4 });
animTable.Add(new Tuple(Direction.East, State.Sword), new int[] { (int)LinkAnims.ESword1, (int)LinkAnims.ESword2, (int)LinkAnims.ESword3, (int)LinkAnims.ESword4 });
animTable.Add(new Tuple(Direction.West, State.Sword), new int[] { (int)LinkAnims.WSword1, (int)LinkAnims.WSword2, (int)LinkAnims.WSword3, (int)LinkAnims.WSword4 });// Set up item animations
animTable.Add(new Tuple(Direction.North, State.ItemUse), new int[] { (int)LinkAnims.NItem });
animTable.Add(new Tuple(Direction.South, State.ItemUse), new int[] { (int)LinkAnims.SItem });
animTable.Add(new Tuple(Direction.East, State.ItemUse), new int[] { (int)LinkAnims.EItem });
animTable.Add(new Tuple(Direction.West, State.ItemUse), new int[] { (int)LinkAnims.WItem });// Set up the first animation
animArray = animTable[new Tuple(Direction.South, State.StillFacing)];// Choose which sprite to load
DetermineSpriteType();// Cache player data
player = GameManager.Instance.Player;// Put Link in the center of the room
Reset();
}///
/// Determine which sprite type to draw for Link
///private void DetermineSpriteType()
{
if (GameManager.Instance.Player.HasBlueRing)
{
spriteSheetName = „BlueLink”;
}
else if (GameManager.Instance.Player.HasRedRing)
{
spriteSheetName = „RedLink”;
}
else
{
spriteSheetName = „Link”;
}
}#region ILink Implementation
////// Set the current facing direction of Link
////// The direction Link should face
public void ChangeDirection(ILink.Direction direction)
{
Direction newDirection = DirectionFromILinkDirection(direction);// Don’t allow any direction changes during attack
if (stillAttacking || usingItem) return;if (linkFacingDirection != direction)
{
// Change direction
linkFacingDirection = direction;// Update animations
animArray = animTable[new Tuple((Direction)((int)newDirection), (State)((int)linkState))];
AnimationIndex = 0;
}
}///
/// If Link is able to attack, perform an attack with his sword
///public void Attack()
{
if (stillAttacking || usingItem || isBeingDamaged || GameContext.State.LinkIsFrozen || isDying) return;// Check if Link has a sword
var playerState = GameManager.Instance.Player;
if (playerState.CurrentWeapon == PlayerState.Weapon.None) return;// Do the attack animation
linkState = ILink.State.Sword;
stillAttacking = true;
frameTimer = swordDuration;
AnimationIndex = 0;
animArray = animTable[new Tuple((Direction)((int)DirectionFromILinkDirection(linkFacingDirection)), (State)((int)linkState))];SoundFactory.PlaySound(SoundFactory.SoundType.LinkSword);
CreateSword();
}///
/// Stop Link’s Sword animation
///private void StopSwordAnimation()
{
linkState = ILink.State.StillFacing;
stillAttacking = false;
AnimationIndex = 0;
animArray = animTable[new Tuple((Direction)((int)DirectionFromILinkDirection(linkFacingDirection)), (State)((int)linkState))];
}///
/// If Link can use an item, use his currently selected item
///public void UseItem()
{
if (stillAttacking || usingItem || isBeingDamaged || GameContext.State.LinkIsFrozen || isDying) return;// Check if Link has an item selected & if he can use it
var playerState = GameManager.Instance.Player;// Don’t do anything if the player doesn’t have an item equipped
if (!playerState.HasItemInSlot(playerState.CurrentItemSlot))
{
return;
}// Handle specific item slots
if (playerState.CurrentItemSlot == PlayerState.BOOMERANG_SLOT)
{
if (playerState.HasBlueBoomerang) UseBoomerang();
}
else if (playerState.CurrentItemSlot == PlayerState.BOMB_SLOT)
{
if (playerState.BombCount > 0) UseBomb();
}
else if (playerState.CurrentItemSlot == PlayerState.BOW_SLOT)
{
if (playerState.HasBow && playerState.ArrowCount > 0) UseArrow();
}
else if (playerState.CurrentItemSlot == PlayerState.CANDLE_SLOT)
{
if (playerState.HasBlueCandle || playerState.HasRedCandle) UseCandle();
}
else if (playerState.CurrentItemSlot == PlayerState.WHISTLE_SLOT)
{
if (playerState.HasItemInSlot(PlayerState.WHISTLE_SLOT)) UseWhistle();
}
else
{
// ItemUse is only triggered for specific cases
return;
}// Do the attack animation
linkState = ILink.State.ItemUse;
usingItem = true;
frameTimer = itemDuration;
AnimationIndex = 0;
animArray = animTable[new Tuple((Direction)((int)DirectionFromILinkDirection(linkFacingDirection)), (State)((int)linkState))];
}private void UseWhistle()
{
// Disrupt all enemies in the current room
SoundFactory.PlaySound(SoundFactory.SoundType.WhistleSound);
}private void UseCandle()
{
SoundFactory.PlaySound(SoundFactory.SoundType.CandleFire);
CreateFireball();
}private void UseArrow()
{
if (GameManager.Instance.Player.ArrowCount <= 0)
{
return;
}GameManager.Instance.Player.ArrowCount–;
SoundFactory.PlaySound(SoundFactory.SoundType.ArrowShoot);
CreateArrow();
}private void UseBomb()
{
if (GameManager.Instance.Player.BombCount <= 0)
{
return;
}GameManager.Instance.Player.BombCount–;
SoundFactory.PlaySound(SoundFactory.SoundType.BombPlace);
CreateBomb();
}private void UseBoomerang()
{
SoundFactory.PlaySound(SoundFactory.SoundType.Boomerang);
CreateBoomerang();
}///
/// Stop Link’s Item animation
///private void StopItemAnimation()
{
linkState = ILink.State.StillFacing;
usingItem = false;
AnimationIndex = 0;
animArray = animTable[new Tuple((Direction)((int)DirectionFromILinkDirection(linkFacingDirection)), (State)((int)linkState))];
}///
/// Draws Link on the screen
////// SpriteBatch to be drawn with
public override void Draw(SpriteBatch spriteBatch)
{
if (IsVisible)
{
// Check whether we need to update the sprite type
DetermineSpriteType();// Determine location
Rectangle currentFrame = AnimationTable[animArray[AnimationIndex]];
int drawX = x;
int drawY = y;// Adjust for sword animations
if (stillAttacking)
{
if (linkFacingDirection == ILink.Direction.North)
{
// North sword animations place Link’s head at the same spot on the sheet
drawY -= 12;
}
else if (linkFacingDirection == ILink.Direction.East)
{
// East sword animations need to adjust x position
drawX -= 12;
}
}// Draw Link’s sprite
if (!isBeingDamaged)
{
spriteBatch.Draw(ResourceManager.GetInstance().GetTexture2D(spriteSheetName),
new Rectangle(drawX, drawY, currentFrame.Width * GameContext.Window.Scale, currentFrame.Height * GameContext.Window.Scale),
currentFrame, Color.White);/*// Debug drawing
Rectangle healthText = new Rectangle(drawX, drawY – 20, 12 * 3, 12);
spriteBatch.DrawString(ResourceManager.GetInstance().GetFont(„DebugFont”),
„HP: ” + GameManager.Instance.Player.Health,
new Vector2(drawX, drawY – 20), Color.White);*/
}
else
{
// Flash red when damaged
spriteBatch.Draw(ResourceManager.GetInstance().GetTexture2D(spriteSheetName),
new Rectangle(drawX, drawY, currentFrame.Width * GameContext.Window.Scale, currentFrame.Height * GameContext.Window.Scale),
currentFrame, damageColor);
}// Debug drawing
//spriteBatch.Draw(ResourceManager.GetInstance().GetTexture2D(„Pixel”), Bounds, Color.Green * 0.5f);
}
}///
/// Update’s Links state and animations
////// GameTime structure provided by XNA framework
public void Update(GameTime gameTime)
{
if (isDying)
{
// Check if Link has died
if (GameManager.Instance.Player.Health <= 0)
{
SoundFactory.PlaySound(SoundFactory.SoundType.LinkDie);// Wait 2s, then go to Game Over screen
GameContext.State.LinkIsFrozen = true;
GameContext.State.IsDying = true;
GameContext.State.LinkDeathToGameOver = true;isDying = false;
return;
}
}// Don't change Link's movement if he's attacking or using an item
if (!GameContext.State.LinkIsFrozen)
{
if (stillAttacking)
{
// Reduce the amount of time this animation is running
frameTimer -= gameTime.ElapsedGameTime.Milliseconds;
if (frameTimer <= 0) StopSwordAnimation();
}
else if (usingItem)
{
// Reduce the amount of time this animation is running
frameTimer -= gameTime.ElapsedGameTime.Milliseconds;
if (frameTimer <= 0) StopItemAnimation();
}
else if (!isBeingDamaged)
{
// Get the directions that the user is pressing
Vector2 moveDir = GetMovementKeysDirectionVector();// Check if Link is moving, or switch his state
if (moveDir != Vector2.Zero)
{
dir = moveDir; // Remember the direction Link was moving// Set Link's moving animation
if (linkState != ILink.State.Moving)
{
linkState = ILink.State.Moving;
animArray = animTable[new Tuple((Direction)((int)DirectionFromILinkDirection(linkFacingDirection)), (State)((int)linkState))];
AnimationIndex = 0;
}// Move Link by his speed * the time
int linkMove = MOVE_SPEED;
x += (int)(dir.X * MOVE_SPEED);
y += (int)(dir.Y * MOVE_SPEED);
}
else if (linkState != ILink.State.StillFacing)
{
// Set Link’s still animation
linkState = ILink.State.StillFacing;
animArray = animTable[new Tuple((Direction)((int)DirectionFromILinkDirection(linkFacingDirection)), (State)((int)linkState))];
AnimationIndex = 0;
}
}
else
{
// Tick the damage timer
damageTimer -= gameTime.ElapsedGameTime.Milliseconds;// Play the hurt sound again if it’s done
soundTimer -= gameTime.ElapsedGameTime.Milliseconds;
if (soundTimer <= 0)
{
SoundFactory.PlaySound(SoundFactory.SoundType.LinkHurt);
soundTimer = 200;
}// Check if Link is done being damaged
if (damageTimer <= 0)
{
isBeingDamaged = false;
//GameContext.State.LinkIsFrozen = false;
}
else
{
// Continue being damaged
Vector2 moveDir = directionToXYMap[(Direction)damageDir];// Continue moving Link in the damage direction
x += (int)(moveDir.X * DAMAGE_MOVE_SPEED);
y += (int)(moveDir.Y * DAMAGE_MOVE_SPEED);}
}
}// Update animation based on timer
UpdateAnimation(gameTime);// Check if Link is out of bounds in the room, and if so, reverse.
KeepLinkInBounds();
}///
/// Keeps Link inside the bounds of the room or transitions to new room if possible
///private void KeepLinkInBounds()
{
int offset = 48;
Rectangle roomBounds = GameContext.World.CurrentRoomTileSet.GetRoomBounds(GameContext.Window.RoomX, GameContext.Window.RoomY);// Block boundaries
Point blockSize = new Point(GameContext.Window.Scale * 16, GameContext.Window.Scale * 16);
Rectangle upperLeftBlock = new Rectangle(roomBounds.X, roomBounds.Y, blockSize.X, blockSize.Y);
Rectangle upperRightBlock = new Rectangle(roomBounds.X + roomBounds.Width – blockSize.X, roomBounds.Y, blockSize.X, blockSize.Y);
Rectangle lowerLeftBlock = new Rectangle(roomBounds.X, roomBounds.Y + roomBounds.Height – blockSize.Y, blockSize.X, blockSize.Y);
Rectangle lowerRightBlock = new Rectangle(roomBounds.X + roomBounds.Width – blockSize.X, roomBounds.Y + roomBounds.Height – blockSize.Y, blockSize.X, blockSize.Y);// Only transition from certain areas to avoid being caught in an infinite transition loop
if (!GameContext.State.TransitioningScreens)
{
// Don’t transition if holding a sword or item
if (!(stillAttacking || usingItem || isBeingDamaged || isDying))
{
Rectangle bounds = Bounds;
Room currentRoom = GameContext.World.CurrentWorldRoom;// Check for transitions to a new room
if (bounds.X <= roomBounds.X + offset && currentRoom.LeftDoorwayExists && !bounds.Intersects(upperLeftBlock) && !bounds.Intersects(lowerLeftBlock))
{
currentRoom.LeftDoorSpriteObj = GameContext.World.CurrentRoomTileSet.GetLeftDoorwaySprite();
GameContext.State.TransitioningScreens = true;
GameContext.State.TransitionDirection = GameContext.State.MovementDirection.West;
GameContext.State.DoorTransitionStarted = true;// Update the cache for the transition
Tuple roomCoordsWest = new Tuple(GameContext.World.CurrentRoomRow, GameContext.World.CurrentRoomCol – 1);
Tuple roomCoordsCurr = new Tuple(GameContext.World.CurrentRoomRow, GameContext.World.CurrentRoomCol);
if (!GameContext.State.transitionCache.ContainsKey(roomCoordsWest))
{
GameContext.State.transitionCache.Add(roomCoordsWest, new List<Tuple>());
}
if (!GameContext.State.transitionCache.ContainsKey(roomCoordsCurr))
{
GameContext.State.transitionCache.Add(roomCoordsCurr, new List<Tuple>());
}if (!GameContext.State.transitionCache[roomCoordsWest].Contains(roomCoordsCurr))
GameContext.State.transitionCache[roomCoordsWest].Add(roomCoordsCurr);
if (!GameContext.State.transitionCache[roomCoordsCurr].Contains(roomCoordsWest))
GameContext.State.transitionCache[roomCoordsCurr].Add(roomCoordsWest);SoundFactory.PlaySound(SoundFactory.SoundType.DoorSlam);
}
else if (bounds.Right >= roomBounds.X + roomBounds.Width – offset && currentRoom.RightDoorwayExists && !bounds.Intersects(upperRightBlock) && !bounds.Intersects(lowerRightBlock))
{
currentRoom.RightDoorSpriteObj = GameContext.World.CurrentRoomTileSet.GetRightDoorwaySprite();
GameContext.State.TransitioningScreens = true;
GameContext.State.TransitionDirection = GameContext.State.MovementDirection.East;
GameContext.State.DoorTransitionStarted = true;// Update the cache for the transition
Tuple roomCoordsEast = new Tuple(GameContext.World.CurrentRoomRow, GameContext.World.CurrentRoomCol + 1);
Tuple roomCoordsCurr = new Tuple(GameContext.World.CurrentRoomRow, GameContext.World.CurrentRoomCol);
if (!GameContext.State.transitionCache.ContainsKey(roomCoordsEast))
{
GameContext.State.transitionCache.Add(roomCoordsEast, new List<Tuple>());
}
if (!GameContext.State.transitionCache.ContainsKey(roomCoordsCurr))
{
GameContext.State.transitionCache.Add(roomCoordsCurr, new List<Tuple>());
}if (!GameContext.State.transitionCache[roomCoordsEast].Contains(roomCoordsCurr))
GameContext.State.transitionCache[roomCoordsEast].Add(roomCoordsCurr);
if (!GameContext.State.transitionCache[roomCoordsCurr].Contains(roomCoordsEast))
GameContext.State.transitionCache[roomCoordsCurr].Add(roomCoordsEast);SoundFactory.PlaySound(SoundFactory.SoundType.DoorSlam);
}
else if (bounds.Y <= roomBounds.Y + offset && currentRoom.TopDoorwayExists && !bounds.Intersects(upperLeftBlock) && !bounds.Intersects(upperRightBlock))
{
currentRoom.TopDoorSpriteObj = GameContext.World.CurrentRoomTileSet.GetTopDoorwaySprite();
GameContext.State.TransitioningScreens = true;
GameContext.State.TransitionDirection = GameContext.State.MovementDirection.North;
GameContext.State.DoorTransitionStarted = true;// Update the cache for the transition
Tuple roomCoordsNorth = new Tuple(GameContext.World.CurrentRoomRow – 1, GameContext.World.CurrentRoomCol);
Tuple roomCoordsCurr = new Tuple(GameContext.World.CurrentRoomRow, GameContext.World.CurrentRoomCol);
if (!GameContext.State.transitionCache.ContainsKey(roomCoordsNorth))
{
GameContext.State.transitionCache.Add(roomCoordsNorth, new List<Tuple>());
}
if (!GameContext.State.transitionCache.ContainsKey(roomCoordsCurr))
{
GameContext.State.transitionCache.Add(roomCoordsCurr, new List<Tuple>());
}if (!GameContext.State.transitionCache[roomCoordsNorth].Contains(roomCoordsCurr))
GameContext.State.transitionCache[roomCoordsNorth].Add(roomCoordsCurr);
if (!GameContext.State.transitionCache[roomCoordsCurr].Contains(roomCoordsNorth))
GameContext.State.transitionCache[roomCoordsCurr].Add(roomCoordsNorth);
SoundFactory.PlaySound(SoundFactory.SoundType.DoorSlam);
}
else if (bounds.Bottom >= roomBounds.Y + roomBounds.Height – offset && currentRoom.BottomDoorwayExists && !bounds.Intersects(lowerLeftBlock) && !bounds.Intersects(lowerRightBlock))
{
currentRoom.BottomDoorSpriteObj = GameContext.World.CurrentRoomTileSet.GetBottomDoorwaySprite();
GameContext.State.TransitioningScreens = true;
GameContext.State.TransitionDirection = GameContext.State.MovementDirection.South;
GameContext.State.DoorTransitionStarted = true;// Update the cache for the transition
Tuple roomCoordsSouth = new Tuple(GameContext.World.CurrentRoomRow + 1, GameContext.World.CurrentRoomCol);
Tuple roomCoordsCurr = new Tuple(GameContext.World.CurrentRoomRow, GameContext.World.CurrentRoomCol);
if (!GameContext.State.transitionCache.ContainsKey(roomCoordsSouth))
{
GameContext.State.transitionCache.Add(roomCoordsSouth, new List<Tuple>());
}
if (!GameContext.State.transitionCache.ContainsKey(roomCoordsCurr))
{
GameContext.State.transitionCache.Add(roomCoordsCurr, new List<Tuple>());
}if (!GameContext.State.transitionCache[roomCoordsSouth].Contains(roomCoordsCurr))
GameContext.State.transitionCache[roomCoordsSouth].Add(roomCoordsCurr);
if (!GameContext.State.transitionCache[roomCoordsCurr].Contains(roomCoordsSouth))
GameContext.State.transitionCache[roomCoordsCurr].Add(roomCoordsSouth);
SoundFactory.PlaySound(SoundFactory.SoundType.DoorSlam);
}
}
}// Separate checking to keep in bounds
if (!GameContext.State.TransitioningScreens)
{
// Check normal boundary restrictions
Rectangle bounds = Bounds;
if (bounds.X roomBounds.X + roomBounds.Width) x = roomBounds.X + roomBounds.Width – Width;
if (bounds.Y roomBounds.Y + roomBounds.Height) y = roomBounds.Y + roomBounds.Height – Height;
}
}///
/// Make Link take damage. If Link is already taking damage, the damage is ignored.
////// Amount of damage Link should take (reduces heart count)
/// The direction Link should be knocked back after being damaged
public void TakeDamage(int damage, ILink.Direction direction)
{
// Don’t apply damage if already taking damage
if (isBeingDamaged || isDying) return;// Update health state
if (damage > 0)
{
// Redo the player state
Player playerState = GameManager.Instance.Player;// Apply and cap health reduction
playerState.Health -= damage;// Become damaged
BecomeDamaged();// Remember which direction Link was hit from
damageDir = DirectionFromILinkDirection(direction);
}
}///
/// Begin link damaged animation without actually changing health
///public void BecomeDamaged()
{
if (isDying) return;// Set taking damage
isBeingDamaged = true;
stillAttacking = false;
usingItem = false;
linkState = ILink.State.StillFacing;// Set up damage animation
damageTimer = damageDuration;// Set up animation to flash
soundTimer = 0;
SoundFactory.PlaySound(SoundFactory.SoundType.LinkHurt);
}public ILink.Direction FacingDirection
{
get { return linkFacingDirection; }
}public ILink.State LinkState
{
get { return linkState; }
}public bool IsBeingDamaged
{
get { return isBeingDamaged; }
}public bool IsDead
{
get { return isDying; }
}public void MoveTo(int x, int y)
{
this.x = x;
this.y = y;
}///
/// Cycle which item Link has selected
///public void CycleSelectedItem()
{
if (isBeingDamaged || stillAttacking || usingItem || GameContext.State.LinkIsFrozen) return;// Move to the next item slot
var playerState = GameManager.Instance.Player;
playerState.CurrentItemSlot = (playerState.CurrentItemSlot + 1) % PlayerState.NUM_ITEM_SLOTS;// Make a selection sound
SoundFactory.PlaySound(SoundFactory.SoundType.MenuSelect);
}///
/// Reset which item Link has selected
///public void ResetSelectedItem()
{
GameManager.Instance.Player.CurrentItemSlot = 0;
}///
/// Reset Link’s position to the center of the screen
///public void ResetPosition()
{
x = GameContext.Window.CenterX – 8 * GameContext.Window.Scale;
y = GameContext.Window.CenterY – 8 * GameContext.Window.Scale;
}///
/// Reset’s Link to his default state
///public void ResetState()
{
Reset();
}///
/// Perform the death animation for Link and return if he is „dead”
////// True if Link died fully, false otherwise
public bool Die()
{
isDying = true;
return false;
}#endregion
#region Direction Helper Methods
///
/// Convert a LinkDirection from ILink to a Direction in BasicLink
////// Direction to convert from the ILink implementation
/// Direction to use in LinkBasic (internal enum)
private Direction DirectionFromILinkDirection(ILink.Direction direction)
{
switch (direction)
{
case ILink.Direction.East:
return Direction.East;
case ILink.Direction.North:
return Direction.North;
case ILink.Direction.South:
return Direction.South;
case ILink.Direction.West:
return Direction.West;
default:
return Direction.South; // Default to south
}
}///
/// Get a direction vector from the keyboard state.
////// A directional Vector2, already normalized, to represent where Link should move
private Vector2 GetMovementKeysDirectionVector()
{
// Default state – no movement
KeyboardState kstate = Keyboard.GetState();
Vector2 direction = Vector2.Zero;// Check North
if (kstate.IsKeyDown(Keys.W) || kstate.IsKeyDown(Keys.Up))
{
direction += Vector2.UnitY * -1;
if (linkFacingDirection != ILink.Direction.North)
{
linkFacingDirection = ILink.Direction.North;
animArray = animTable[new Tuple((Direction)((int)DirectionFromILinkDirection(linkFacingDirection)), (State)((int)linkState))];
AnimationIndex = 0;
}
}
// Check South
else if (kstate.IsKeyDown(Keys.S) || kstate.IsKeyDown(Keys.Down))
{
direction += Vector2.UnitY;
if (linkFacingDirection != ILink.Direction.South)
{
linkFacingDirection = ILink.Direction.South;
animArray = animTable[new Tuple((Direction)((int)DirectionFromILinkDirection(linkFacingDirection)), (State)((int)linkState))];
AnimationIndex = 0;
}
}// Check East
if (kstate.IsKeyDown(Keys.D) || kstate.IsKeyDown(Keys.Right))
{
direction += Vector2.UnitX;
if (direction.Y == 0 && linkFacingDirection != ILink.Direction.East)
{
linkFacingDirection = ILink.Direction.East;
animArray = animTable[new Tuple((Direction)((int)DirectionFromILinkDirection(linkFacingDirection)), (State)((int)linkState))];
AnimationIndex = 0;
}
}
// Check West
else if (kstate.IsKeyDown(Keys.A) || kstate.IsKeyDown(Keys.Left))
{
direction += Vector2.UnitX * -1;
if (direction.Y == 0 && linkFacingDirection != ILink.Direction.West)
{
linkFacingDirection = ILink.Direction.West;
animArray = animTable[new Tuple((Direction)((int)DirectionFromILinkDirection(linkFacingDirection)), (State)((int)linkState))];
AnimationIndex = 0;
}
}// Return a normalied vector
if (direction != Vector2.Zero)
{
direction.Normalize();
}return direction;
}#endregion
#region Animation Helper Methods
///
/// Update Link’s animation based on game timer
////// GameTime XNA class
private void UpdateAnimation(GameTime gameTime)
{
// Track animation timer
animTimer += gameTime.ElapsedGameTime.Milliseconds;// Update frame if it’s time
if (animTimer >= ANIM_SPEED)
{
animTimer = 0;if (animArray.Length < 2) return;
AnimationIndex = (AnimationIndex + 1) % animArray.Length;
}
}#endregion
#region Projectile Helper Methods
///
/// Create a new sword in the projectile manager
///private void CreateSword()
{
int weaponOffset = 12;
int x = this.X, y = this.Y;// Adjust position for the direction Link is facing
switch (linkFacingDirection)
{
case ILink.Direction.North:
y -= weaponOffset;
break;
case ILink.Direction.South:
y += weaponOffset;
break;
case ILink.Direction.East:
x += weaponOffset;
break;
case ILink.Direction.West:
x -= weaponOffset;
break;
}// Create the projectile in the ProjectileManager
IProjectile sword = ProjectileFactory.CreateLinkSword(x, y, linkFacingDirection);
GameManager.Instance.ProjectileManager.AddProjectile(sword);
}///
/// Create a new boomerang in the projectile manager
///private void CreateBoomerang()
{
int weaponOffset = 12;
int x = this.X, y = this.Y;// Adjust position for the direction Link is facing
switch (linkFacingDirection)
{
case ILink.Direction.North:
y -= weaponOffset;
break;
case ILink.Direction.South:
y += weaponOffset;
break;
case ILink.Direction.East:
x += weaponOffset;
break;
case ILink.Direction.West:
x -= weaponOffset;
break;
}// Create the projectile in the ProjectileManager
GameManager.Instance.ProjectileManager.AddProjectile(ProjectileFactory.CreateLinkBoomerang(x, y, linkFacingDirection));
}///
/// Create a new arrow in the projectile manager
///private void CreateArrow()
{
int weaponOffset = 12;
int x = this.X, y = this.Y;// Adjust position for the direction Link is facing
switch (linkFacingDirection)
{
case ILink.Direction.North:
y -= weaponOffset;
break;
case ILink.Direction.South:
y += weaponOffset;
break;
case ILink.Direction.East:
x += weaponOffset;
break;
case ILink.Direction.West:
x -= weaponOffset;
break;
}// Create the projectile in the ProjectileManager
GameManager.Instance.ProjectileManager.AddProjectile(ProjectileFactory.CreateLinkArrow(x, y, linkFacingDirection));
}///
/// Create a new fireball in the projectile manager
///private void CreateFireball()
{
int weaponOffset = 12;
int x = this.X, y = this.Y;// Adjust position for the direction Link is facing
switch (linkFacingDirection)
{
case ILink.Direction.North:
y -= weaponOffset;
break;
case ILink.Direction.South:
y += weaponOffset;
break;
case ILink.Direction.East:
x += weaponOffset;
break;
case ILink.Direction.West:
x -= weaponOffset;
break;
}// Create the projectile in the ProjectileManager
GameManager.Instance.ProjectileManager.AddProjectile(ProjectileFactory.CreateLinksFireball(x, y, linkFacingDirection));
}///
/// Create a new bomb in the projectile manager
///private void CreateBomb()
{
int weaponOffset = 12;
int x = this.X, y = this.Y;// Adjust position for the direction Link is facing
switch (linkFacingDirection)
{
case ILink.Direction.North:
y -= weaponOffset;
break;
case ILink.Direction.South:
y += weaponOffset;
break;
case ILink.Direction.East:
x += weaponOffset;
break;
case ILink.Direction.West:
x -= weaponOffset;
break;
}// Create the projectile in the ProjectileManager
GameManager.Instance.ProjectileManager.AddProjectile(ProjectileFactory.CreateLinkBomb(x, y));
}#endregion
#region ICollidable Interface
public override Rectangle Bounds
{
get
{
return new Rectangle(x + 4 * GameContext.Window.Scale, y + 4 * GameContext.Window.Scale,
8 * GameContext.Window.Scale, 10 * GameContext.Window.Scale);
}
}public override CollisionGroup CollisionGroup
{
get
{
return CollisionGroup.Link;
}
}public override Point Location
{
get
{
return new Point(x, y);
}
}public override Point Size
{
get
{
return new Point(Width, Height);
}
}public override int Width
{
get
{
return 16 * GameContext.Window.Scale;
}
}public override int Height
{
get
{
return 16 * GameContext.Window.Scale;
}
}public override void OnCollision(ICollidable obj)
{}
///
/// Get the X position of Link
///public int X
{
get
{
return this.x;
}
set
{
this.x = value;
}
}///
/// Get the Y position of Link
///public int Y
{
get
{
return this.y;
}
set
{
this.y = value;
}
}public override int ZIndex
{
get
{
return 0;
}
}public Point Center
{
get { return new Point(x + Width / 2, y + Height / 2); }
}#endregion
#region Helper Methods
///
/// Reset the position and state of Link
///private void Reset()
{
// Reset animation state
linkState = ILink.State.StillFacing;
linkFacingDirection = ILink.Direction.South;
stillAttacking = false;
usingItem = false;
isDying = false;
isBeingDamaged = false;
damageTimer = 0;
soundTimer = 0;
frameTimer = 0;// Reset position
x = GameContext.Window.CenterX – 8 * GameContext.Window.Scale;
y = GameContext.Window.CenterY – 10 * GameContext.Window.Scale;// Reset item slot
GameManager.Instance.Player.CurrentItemSlot = 0;// Set up first animation
animArray = animTable[new Tuple(Direction.South, State.StillFacing)];
AnimationIndex = 0;
animTimer = 0;
}///
/// Let Link become visible again
///public new bool IsVisible
{
get
{
return base.IsVisible;
}
set
{
base.IsVisible = value;
}
}#endregion
}
}# auks256/cse3902
/* Author — Allen Antony Ukani
* Contact — auks256ATcs.washington.edu
* Created Date — 9.19.2012
* Last Modified Date — 10.25.2012
* Last Modified By — Allen Antony Ukani
*/using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using LegendOfZelda.Collisions;namespace LegendOfZelda
{
////// Interface to represent Link. Can be used by Link himself as well as any decorator for Link.
///public interface ILink : ICollidable
{
////// An enumeration of possible directions Link could face
///enum Direction
{
North, South, East, West
}///
/// An enumeration of possible states Link could be in
///enum State
{
StillFacing, Moving, Sword, ItemUse
}///
/// Make Link attack (attemp to use his weapon), if possible
///void Attack();
///
/// Set the direction that Link should face
////// The direction Link should face
void ChangeDirection(Direction direction);///
/// Draw Link to the screen
////// SpriteBatch object for drawing
void Draw(SpriteBatch spriteBatch);///
/// Move Link to the given position on the screen.
////// X-position to place Link at
/// Y-position to place Link at
void MoveTo(int x, int y);///
/// Update Link’s logic (movement, animation, etc)
////// GameTime structure provided by XNA
void Update(GameTime gameTime);///
/// Make Link take damage
////// Amount of damage Link should take (reduces heart count)
/// The direction Link should be knocked back after being damaged
void TakeDamage(int damage, Direction direction);///
/// Make Link use the item that he has currently selected, if possible
///void UseItem();
///
/// Get the center of the link
////// The Point where the Link’s center is.
Point Center { get; }///
/// Get the X position of Link
///int X { get; set; }
///
/// Get the Y position of Link
///int Y { get; set; }
///
/// Get the direction Link is facing
///Direction FacingDirection { get; }
///
/// Get the state Link is in
///State LinkState { get; }
///
/// Get/set whether Link is visible or not
///bool IsVisible { get; set; }
///
/// Get whether link is dead or not
///bool IsDead { get; }
///
/// Get whether Link is being damaged or not
///bool IsBeingDamaged { get; }
///
/// Reset Link to his default state
///void ResetState();
///
/// Set Link to his damaged state. This is different from TakeDamage(), which actually reduces health.
///void BecomeDamaged();
///
/// Switch which item Link has selected
///void CycleSelectedItem();
///
/// Reset the item Link has selected
///void ResetSelectedItem();
///
/// Reset Links position
///void ResetPosition();
///
/// Start animating Links death. Returns true if the Link is dead, false otherwise
//////
bool Die();}
}/* Author — Allen Antony Ukani
* Contact — auks256ATcs.washington.edu
* Created Date — 9.29.2012
* Last Modified Date — 10.11.2012
* Last Modified By — Allen Antony Ukani
*/using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using LegendOfZelda.Particles;
using LegendOfZelda.Monsters;
using LegendOfZelda.Items;namespace LegendOfZelda
{
/**
* Creates visual particle effects (that have no collision) in the game.
*
* Similar to the ProjectileManager, except for effects that have no collision.
*/
class ParticleManager
{
private LinkedList particleList = new LinkedList();
private LinkedList newParticleList = new LinkedList();///
/// Create a new ParticleManager
///public ParticleManager()
{}
///
/// Add a new particle to the manager.
////// The particle to add
public void AddParticle(IParticle particle)
{
newParticleList.AddLast(particle);
}///
/// Update all particles in the manager.
////// GameTime structure from XNA
public void Update(GameTime gameTime)
{
// Add in the new particles at the beginning of this update loop
if (newParticleList.Count > 0)
{
foreach (var p in newParticleList)
{
particleList.AddLast(p);
}
newParticleList.Clear();
}// Go through all particles and update them, removing any expired particles
var node = particleList.First;
while (node != null)
{
// Cache the next pointer since we might change the list
var next = node.Next;
var particle = node.Value;if (particle.IsExpired)
{
// Remove the particle from the linked list
particleList.Remove(node);
}
else
{
// Update the particle
particle.Update(gameTime);
}// Move on to the next node
node = next;
}
}///
/// Draw all particles in the manager.
////// SpriteBatch to draw with
public void Draw(SpriteBatch spriteBatch)
{
// Draw all particles
foreach (var particle in particleList)
{
particle.Draw(spriteBatch);
}
}///
/// Clear out all particles in the manager.
///public void Clear()
{
// Clear both linked lists
particleList.Clear();
newParticleList.Clear();
}///
/// Create an explosion at the given point, with the given parameters.
////// X coordinate of the center of the explosion
/// Y coordinate of the center of the explosion
/// Number of particles to create (default: 75)
/// Lifetime of the explosion in milliseconds (default: 1500)
public void CreateExplosion(int x, int y, int numParticles = 40, int lifetime = 1500)
{
for (int i = 0; i < numParticles; i++)
{
// Create a particle at the center
var particle = new BaseBombParticle();
particle.X = x;
particle.Y = y;// Fire the particle at a random angle
double theta = MathHelper.ToRadians(Utility.RandomRange(0, 359));
double magnitude = Utility.RandomRange(1, 4);// Set a velocity
particle.VelocityX = (float)(Math.Cos(theta) * magnitude);
particle.VelocityY = (float)(Math.Sin(theta) * magnitude);// Set the lifetime
particle.LifetimeMilliseconds = (int)(lifetime * Utility.RandomRange(0.6f, 1.0f));// Add the particle
AddParticle(particle);
}
}///
/// Create a poof at the given point, with the given parameters
////// X coordinate of the center of the explosion
/// Y coordinate of the center of the explosion
/// Number of particles to create (default: 5)
/// Lifetime of the explosion in milliseconds (default: 400)
public void CreatePoof(int x, int y, int numParticles = 5, int lifetime = 400)
{
for (int i = 0; i < numParticles; i++)
{
// Create a particle at the center
var particle = new BaseParticle();
particle.X = x;
particle.Y = y;// Fire the particle at a random angle
double theta = MathHelper.ToRadians(Utility.RandomRange(0, 359));
double magnitude = Utility.RandomRange(0.5f, 1.5f);// Set a velocity
particle.VelocityX = (float)(Math.Cos(theta) * magnitude);
particle.VelocityY = (float)(Math.Sin(theta) * magnitude);// Set the lifetime
particle.LifetimeMilliseconds = (int)(lifetime * Utility.RandomRange(0.7f, 1.0f));// Add the particle
AddParticle(particle);
}
}///
/// Create an explosion for a particular monster
////// X coordinate of the center of the poof
/// Y coordinate of the center of the poof
/// EnemyAnimatedSprite enumeration for the monster that’s exploding
public void CreateMonsterExplosion(int x, int y, MonsterSprite.MonsterType type)
{
for (int i = 0; i < 6; i++)
{
// Create a particle at the center
var particle = new MonsterDeathParticle(type);
particle.X = x;
particle.Y = y;// Fire the particle at a random angle
double theta = MathHelper.ToRadians(Utility.RandomRange(0, 359));
double magnitude = Utility.RandomRange(1.0f, 2.5f);// Set a velocity
particle.VelocityX = (float)(Math.Cos(theta) * magnitude);
particle.VelocityY = (float)(Math.Sin(theta) * magnitude);// Set the lifetime
particle.LifetimeMilliseconds = (int)(400 * Utility.RandomRange(0.7f, 1.0f));// Add the particle
AddParticle(particle);
}
}///
/// Create a reward that’s picked up by Link
////// X coordinate of the Reward
/// Y coordinate of the Reward
/// ItemType enumeration for which reward appears
/// Description of the item that displays on-screen
public void CreateReward(int x, int y, ItemSprite.ItemType type, string description = „”)
{
RewardParticle reward = new RewardParticle(type, description);
reward.X = x;
reward.Y = y;
reward.LifetimeMilliseconds = 3000;
AddParticle(reward);
}
}
}# LegendOfZelda/LegendOfZelda/Control/BasicKeyboardController.cs
/* Author — Allen Antony Ukani
* Contact — auks256ATcs.washington.edu
* Created Date — 10.01.2012
* Last Modified Date — 10.19.2012
* Last Modified By — Allen Antony Ukani
*/using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Input;namespace LegendOfZelda
{
/**
* Accepts keyboard input to control the game.
* Pattern: Adapter (?)
*/
class BasicKeyboardController : IController
{
private KeyboardState oldState, currentState;
private string[] argsArray;private static BasicKeyboardController instance;
public static BasicKeyboardController GetInstance()
{
if (instance == null)
{
instance = new BasicKeyboardController();
}
return instance;
}private BasicKeyboardController()
{
oldState = Keyboard.GetState();
argsArray = new string[0];
}public void ProcessInput(GameTime gameTime, ICommandProcessor commandProcessor)
{
currentState = Keyboard.GetState();// Process a back key separately if transitioning screens
if (GameContext.State.TransitioningScreens)
{
// Determine if we should cancel the transition or not
if (CheckKeyPress(Keys.Escape))
{
commandProcessor.ProcessCommand(„global-back”, argsArray);
}
oldState = currentState;
return;
}// Only check keys based on what’s being displayed
switch (GameContext.State.CurrentScreen)
{
case GameContext.State.Screen.Title:
ProcessTitleScreenInput(commandProcessor);
break;
case GameContext.State.Screen.FileSelect:
ProcessFileSelectInput(commandProcessor);
break;
case GameContext.State.Screen.Game:
ProcessGameInput(commandProcessor);
break;
case GameContext.State.Screen.Inventory:
ProcessInventoryInput(commandProcessor);
break;
case GameContext.State.Screen.GameOver:
ProcessGameOverInput(commandProcessor);
break;
case GameContext.State.Screen.Win:
ProcessWinInput(commandProcessor);
break;
case GameContext.State.Screen.Credits:
ProcessCreditsInput(commandProcessor);
break;
default:
break;
}oldState = currentState;
}private void ProcessWinInput(ICommandProcessor commandProcessor)
{
if (CheckKeyPress(Keys.Escape) || CheckKeyPress(Keys.Enter))
{
commandProcessor.ProcessCommand(„global-back”, argsArray);
}
}private void ProcessCreditsInput(ICommandProcessor commandProcessor)
{
if (CheckKeyPress(Keys.Escape))
{
commandProcessor.ProcessCommand(„global-back”, argsArray);
}
else if (CheckKeyPress(Keys.Enter))
{
commandProcessor.ProcessCommand(„credits-select”, argsArray);
}
}private void ProcessGameOverInput(ICommandProcessor commandProcessor)
{
if (CheckKeyPress(Keys.Escape))
{
commandProcessor.ProcessCommand(„global-back”, argsArray);
}
else if (CheckKeyPress(Keys.Enter))
{
commandProcessor.ProcessCommand(„gameover-select”, argsArray);
}
}private void ProcessInventoryInput(ICommandProcessor commandProcessor)
{
if (CheckKeyPress(Keys.Escape))
{
commandProcessor.ProcessCommand(„global-back”, argsArray);
}
else if (CheckKeyPress(Keys.Tab))
{
commandProcessor.ProcessCommand(„inventory-close”, argsArray);
}
}private void ProcessGameInput(ICommandProcessor commandProcessor)
{
// Check for escaping to menu
if (CheckKeyPress(Keys.Escape))
{
commandProcessor.ProcessCommand(„global-back”, argsArray);
}
// Check for pausing and restarting the game
else if (CheckKeyPress(Keys.Enter))
{
commandProcessor.ProcessCommand(„game-pause”, argsArray);
}
// Check for pause from the inventory
else if (CheckKeyPress(Keys.Tab))
{
commandProcessor.ProcessCommand(„inventory-open”, argsArray);
}// Check for debug commands
if (CheckKeyPress(Keys.OemTilde))
{
commandProcessor.ProcessCommand(„debug-toggle”, argsArray);
}
if (CheckKeyPress(Keys.D1))
{
commandProcessor.ProcessCommand(„debug-mode1”, argsArray);
}
if (CheckKeyPress(Keys.D2))
{
commandProcessor.ProcessCommand(„debug-mode2”, argsArray);
}
if (CheckKeyPress(Keys.D3))
{
commandProcessor.ProcessCommand(„debug-mode3”, argsArray);
}
if (CheckKeyPress(Keys.D4))
{
commandProcessor.ProcessCommand(„debug-mode4”, argsArray);
}
if (CheckKeyPress(Keys.D5))
{
commandProcessor.ProcessCommand(„debug-mode5”, argsArray);
}
if (CheckKeyPress(Keys.D6))
{
commandProcessor.ProcessCommand(„debug-mode6”, argsArray);
}
if (CheckKeyPress(Keys.D7))
{
commandProcessor.ProcessCommand(„debug-mode7”, argsArray);
}
if (CheckKeyPress(Keys.D8))
{
commandProcessor.ProcessCommand(„debug-mode8”, argsArray);
}
if (CheckKeyPress(Keys.D9))
{
commandProcessor.ProcessCommand(„debug-mode9”, argsArray);
}
if (CheckKeyPress(Keys.D0))
{
commandProcessor.ProcessCommand(„debug-mode0”, argsArray);
}
if (CheckKeyPress(Keys.R))
{
commandProcessor.ProcessCommand(„debug-restart”, argsArray);
}
if (CheckKeyPress(Keys.L))
{
commandProcessor.ProcessCommand(„debug-clearCache”, argsArray);
}
if (CheckKeyPress(Keys.N))
{
commandProcessor.ProcessCommand(„debug-next-room”, argsArray);
}
if (CheckKeyPress(Keys.M))
{
commandProcessor.ProcessCommand(„debug-previous-room”, argsArray);
}
if (CheckKeyPress(Keys.J))
{
commandProcessor.ProcessCommand(„debug-jump-first-dungeon”, argsArray);
}
if (CheckKeyPress(Keys.K))
{
commandProcessor.ProcessCommand(„debug-jump-final-dungeon”, argsArray);
}// Let the player change their weapons
if (CheckKeyPress(Keys.Q))
{
commandProcessor.ProcessCommand(„game-link-cycle-item”, argsArray);
}// Move Link
if (GameContext.State.IsDying == false && !GameContext.State.LinkIsFrozen)
{
// Check attack command
if (CheckKeyPress(Keys.Z))
{
commandProcessor.ProcessCommand(„game-link-attack”, argsArray);
}// Check item use
if (CheckKeyPress(Keys.X) || CheckKeyPress(Keys.Space))
{
commandProcessor.ProcessCommand(„game-link-use-item”, argsArray);
}
}
}private void ProcessFileSelectInput(ICommandProcessor commandProcessor)
{
if (CheckKeyPress(Keys.Escape))
{
commandProcessor.ProcessCommand(„global-back”, argsArray);
}
else if (CheckKeyPress(Keys.Enter))
{
commandProcessor.ProcessCommand(„file-select”, argsArray);
}
else if (CheckKeyPress(Keys.Down) || CheckKeyPress(Keys.S))
{
// Move selection down
commandProcessor.ProcessCommand(„file-cursor-down”, argsArray);
}
else if (CheckKeyPress(Keys.Up) || CheckKeyPress(Keys.W))
{
// Move selection up
commandProcessor.ProcessCommand(„file-cursor-up”, argsArray);
}
}private void ProcessTitleScreenInput(ICommandProcessor commandProcessor)
{
if (CheckKeyPress(Keys.Escape))
{
commandProcessor.ProcessCommand(„global-back”, argsArray);
}
else if (CheckKeyPress(Keys.Enter))
{
commandProcessor.ProcessCommand(„title-select”, argsArray);
}
else if (CheckKeyPress(Keys.Down) || CheckKeyPress(Keys.S))
{
// Move selection down
commandProcessor.ProcessCommand(„title-cursor-down”, argsArray);
}
else if (CheckKeyPress(Keys.Up) || CheckKeyPress(Keys.W))
{
// Move selection up
commandProcessor.ProcessCommand(„title-cursor-up”, argsArray);
}
}private bool CheckKeyPress(Keys key)
{
return currentState.IsKeyDown(key) && !oldState.IsKeyDown(key);
}
}
}# auks256/cse3902
/* Author — Allen Antony Ukani, Dominic Doty
* Contact — auks256ATcs.washington.edu, ddoty21ATwashington.edu
* Created Date — 10.06.2012
* Last Modified Date — 10.14.2012
* Last Modified By — Dominic Doty
*/using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;namespace LegendOfZelda
{
public delegate void CommandExecutionHandler(string[] args);/**
* A processor that can execute commands. Manages a map of commands to the methods
* that execute those commands.
*
* Pattern: Command
*/
class CommandProcessor : ICommandProcessor
{
private Dictionary commandMap = new Dictionary();
private LinkedList commandHistory = new LinkedList(); // For debugging/macro purposespublic CommandProcessor()
{
}///
/// Register a command with its execution handler.
////// The command to register as a string
/// The handler that will process this command when its executed
public void RegisterCommand(string command, CommandExecutionHandler handler)
{
// Don’t register a command if it already exists
if (commandMap.ContainsKey(command))
{
return;
}// Register the command
commandMap.Add(command, handler);
}///
/// Process a given command along with the command arguments.
////// The command to run, as a string
/// The arguments to pass to the command, as a string array
public void ProcessCommand(string command, string[] args)
{
// Don’t process commands that aren’t registered
if (!commandMap.ContainsKey(command))
{
return;
}// Add the command to the history
if (commandHistory.Count > 100)
{
commandHistory.RemoveFirst();
}
commandHistory.AddLast(command);// Execute the command handler with the arguments
commandMap[command](args);
}///
/// Process a given command with no arguments.
////// The command to run, as a string
public void ProcessCommand(string command)
{
// Call the regular process method with empty args
ProcessCommand(command, new string[0]);
}///
/// Gets the command history for the processor.
////// A list of all the commands passed to the processor.
public IEnumerable GetCommandHistory()
{
return commandHistory;
}
}
}/* Author — Gary Stremlow
* Contact — [email protected]
* Created Date — 10.02.2012
* Last Modified Date — 10.15.2012
* Last Modified By — Gary Stremlow
*/using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using LegendOfZelda.Collisions;namespace LegendOfZelda
{
public class Block : ICollidable
{
private int x, y;
protected int width, height;
protected CollisionGroup collisionGroup;
protected bool isPassable;
protected bool isFalling;
protected bool isDoor;
protected Texture2D texture;
protected Rectangle sourceRectangle;
protected Color color;
protected Color deathColor;protected Room currentRoom;
///
/// Initialize a block to the given parameters.
////// X position of the block
/// Y position of the block
/// Width of the block
/// Height of the block
/// Whether the block can be passed through
/// The texture to use for the block
/// The part of the texture to use
public Block(int x, int y, int width, int height, bool isPassable, Texture2D texture, Rectangle sourceRectangle)
{
this.x = x;
this.y = y;
this.width = width;
this.height = height;
this.collisionGroup = isPassable ? CollisionGroup.PassableBlock : CollisionGroup.Block;
this.isPassable = isPassable;
this.isFalling = false;
this.isDoor = false;
this.texture = texture;
this.sourceRectangle = sourceRectangle;
this.color = Color.White;
this.deathColor = Color.White;
}///
/// Initialize a block to the given parameters.
////// X position of the block
/// Y position of the block
/// Width of the block
/// Height of the block
/// Whether the block can be passed through
/// The texture to use for the block
/// The part of the texture to use
/// Whether the block is a door
public Block(int x, int y, int width, int height, bool isPassable, Texture2D texture, Rectangle sourceRectangle, bool isDoor)
{
this.x = x;
this.y = y;
this.width = width;
this.height = height;
this.collisionGroup = isPassable ? CollisionGroup.PassableBlock : CollisionGroup.Block;
this.isPassable = isPassable;
this.isFalling = false;
this.isDoor = isDoor;
this.texture = texture;
this.sourceRectangle = sourceRectangle;
this.color = Color.White;
this.deathColor = Color.White;
}///
/// Initialize a block to the given parameters.
////// X position of the block
/// Y position of the block
/// Width of the block
/// Height of the block
/// Whether the block can be passed through
/// The texture to use for the block
/// The part of the texture to use
/// Color tint for the block
public Block(int x, int y, int width, int height, bool isPassable, Texture2D texture, Rectangle sourceRectangle, Color color)
{
this.x = x;
this.y = y;
this.width = width;
this.height = height;
this.collisionGroup = isPassable ? CollisionGroup.PassableBlock : CollisionGroup.Block;
this.isPassable = isPassable;
this.isFalling = false;
this.isDoor = false;
this.texture = texture;
this.sourceRectangle = sourceRectangle;
this.color = color;
this.deathColor = color;
}///
/// Create a new Block with the given location and passability
////// X position of the block
/// Y position of the block
/// Whether the block is passable or not
public Block(int x, int y, bool isPassable)
{
this.x = x;
this.y = y;
this.width = 16;
this.height = 16;
this.collisionGroup = isPassable ? CollisionGroup.PassableBlock : CollisionGroup.Block;
this.isPassable = isPassable;
this.isFalling = false;
this.isDoor = false;
}///
/// Draw the block on screen
////// SpriteBatch to draw to
public virtual void Draw(SpriteBatch spriteBatch)
{
// Base block for debugging to make sure there is something to draw
if (texture == null)
{
Texture2D pixel = ResourceManager.GetInstance().GetTexture2D(„Pixel”);
spriteBatch.Draw(pixel, new Rectangle(X, Y, Width, Height), Color.Magenta * 0.5f);
}
else if (isFalling)
{
spriteBatch.Draw(texture, new Rectangle(X, Y, Width, Height), sourceRectangle, deathColor);
}
else
{
spriteBatch.Draw(texture, new Rectangle(X, Y, Width, Height), sourceRectangle, color);
}
}///
/// Get the bounds of the Block
///public virtual Rectangle Bounds
{
get
{
return new Rectangle(X, Y, width, height);
}
}///
/// Gets a value indicating whether this block is passable.
//////
/// true if this instance is passable; otherwise, false.
///
public bool IsPassable
{
get { return isPassable; }
set {
isPassable = value;
collisionGroup = isPassable ? CollisionGroup.PassableBlock : CollisionGroup.Block;
}
}///
/// Get the collision group type of the Block.
/// (Link, Enemy, Block, Projectile, PassableBlock)
///public virtual CollisionGroup CollisionGroup
{
get
{
return collisionGroup;
}
}///
/// Get the location of the Block
///public virtual Point Location
{
get { return new Point(x, y); }
}///
/// Get the X position of the Block
///public int X
{
get { return x; }
set { x = value; }
}///
/// Get the Y position of the Block
///public int Y
{
get { return y; }
set { y = value; }
}///
/// Get the size of the Block as a Point
///public Point Size
{
get
{
return new Point(width, height);
}
}///
/// Get the width of the Block
///public virtual int Width
{
get
{
return width;
}
}///
/// Get the height of the Block
///public virtual int Height
{
get
{
return height;
}
}///
/// Whether the block is falling (for example, a push block that’s falling into a hole)
///public bool IsFalling
{
get { return isFalling; }
set { isFalling = value; }
}///
/// Gets a value indicating whether this block a door.
//////
/// true if this instance is door; otherwise, false.
///
public bool IsDoor
{
get { return isDoor; }
}///
/// Update a block
////// GameTime structure
public virtual void Update(GameTime gameTime)
{
// No update by default in a Block
}public virtual void OnCollision(ICollidable obj)
{
// Do nothing
}///
/// Gets an integer representing the layer that this object should be drawn on, with higher values being drawn on top of lower values.
/// Objects with equivalent z-indices have an undefined render order relative to each other.
///public virtual int ZIndex
{
get { return -1; }
}///
/// Gets the current room that the block is part of.
//////
/// The current room.
///
public Room CurrentRoom
{
get { return currentRoom; }
set { currentRoom = value; }
}
}
}# auks256/cse3902
/* Author — Allen Antony Ukani, Terence Leung
* Contact — auks256ATcs.washington.edu, terryATcs.washington.edu
* Created Date — 9.30.2012
* Last Modified Date — 10.17.2012
* Last Modified By — Allen Antony Ukani
*/using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using LegendOfZelda.Collisions;namespace LegendOfZelda
{
public class PushBlock : Block
{
// Map for cardinal movement
private static Dictionary directionToXYMap = new Dictionary()
{
{0, new Vector2(0,-1)}, // North
{1, new Vector2(0,1)}, // South
{2, new Vector2(1,0)}, // East
{3, new Vector2(-1,0)} // West
};private int moveDist;
private Vector2 direction;
private int moveSpeed;
private bool isMoving;
private bool isOnHole;
private const int deathSpeed = 1;
private float deathAlpha;///
/// Initialize a push block to the given parameters.
////// X position of the block.
/// Y position of the block
/// Width of the block
/// Height of the block
/// Whether the block is passable by Link
/// Texture to use for the block
/// Part of the texture to use
/// Tint of the block
public PushBlock(int x, int y, int width, int height, bool isPassable, Texture2D texture, Rectangle sourceRectangle, Color color) :
base(x, y, width, height, isPassable, texture, sourceRectangle, color)
{
this.collisionGroup = CollisionGroup.PushBlock;
moveSpeed = 2;
moveDist = 16 * GameContext.Window.Scale;
isMoving = false;
isOnHole = false;
deathAlpha = 1.0f;
deathColor = Color.White;
}///
/// Draw the push block on screen
////// SpriteBatch to draw to
public override void Draw(SpriteBatch spriteBatch)
{
// Draw the block
if (texture == null)
{
Texture2D pixel = ResourceManager.GetInstance().GetTexture2D(„Pixel”);
spriteBatch.Draw(pixel, new Rectangle(X, Y, Width, Height), Color.Green * 0.5f);
}
else if (isFalling)
{
spriteBatch.Draw(texture, new Rectangle(X, Y, Width, Height), sourceRectangle, new Color(deathColor.R, deathColor.G, deathColor.B, (byte)(255 * deathAlpha)));
}
else
{
spriteBatch.Draw(texture, new Rectangle(X, Y, Width, Height), sourceRectangle, color);
}
}///
/// Handle when the pushblock is pushed
////// Which object is colliding with the block
public override void OnCollision(ICollidable collision)
{
// If a LinkBlock is colliding with a Player && is NOT moving
if (collision.CollisionGroup == CollisionGroup.Link && !isMoving)
{
// Find out what direction the collision caused the block to move
HandleLinkPush(collision.Bounds, collision);
}// Check if we’re entering a hole
if (collision.CollisionGroup == CollisionGroup.Hole && isMoving)
{
isOnHole = true;
// Make the PushBlock fall in
SoundFactory.PlaySound(SoundFactory.SoundType.PushBlocked);
}
}///
/// Update the push block’s logic and location
////// GameTime structure from XNA framework
public override void Update(GameTime gameTime)
{
// Handle the block falling
if (isFalling)
{
Y += deathSpeed;
deathAlpha = Math.Max(0, deathAlpha – 0.01f);// If the block has lost alpha, remove it
if (deathAlpha <= 0)
{
isFalling = false;
}
}if (isMoving)
{
// Move block in direction
X += (int)(direction.X * moveSpeed);
Y += (int)(direction.Y * moveSpeed);
moveDist -= moveSpeed;if (moveDist <= 0)
{
isMoving = false;
if (isOnHole)
{
isFalling = true;
isPassable = true;
collisionGroup = CollisionGroup.PassableBlock;
}
}
}
}///
/// Handle logic when Link pushes the block
////// Link’s location
/// Link collision object
private void HandleLinkPush(Rectangle linkBounds, ICollidable link)
{
// Check if we can push
if (GameContext.State.LinkIsFrozen) return;// If Link’s center is above the block
if (linkBounds.Center.Y Bounds.Bottom)
{
direction = directionToXYMap[0]; // North
isMoving = true;
moveDist = 16 * GameContext.Window.Scale;
}
// If Link’s center is to the left of the block
else if (linkBounds.Center.X Bounds.Right)
{
direction = directionToXYMap[3]; // West
isMoving = true;
moveDist = 16 * GameContext.Window.Scale;
}// Make sure we’ve actually calculated a move
if (isMoving)
{
// Play sound
SoundFactory.PlaySound(SoundFactory.SoundType.PushBlock);// Check if Link is frozen for pushing the block
if (link is ILink)
{
GameContext.State.LinkIsFrozen = true;
GameManager.Instance.ActiveStopWatch = new SchedulableStopWatch(gameTime =>
{
GameContext.State.LinkIsFrozen = false;
}, 300);
}
}
}///
/// Gets a value indicating whether this block is moving.
//////
/// true if this block is moving; otherwise, false.
///
public bool IsMoving
{
get { return isMoving; }
}///
/// Gets an integer representing the layer that this object should be drawn on, with higher values being drawn on top of lower values.
/// Objects with equivalent z-indices have an undefined render order relative to each other.
///public override int ZIndex
{
get { return 0; }
}
}
}# auks256/cse3902
/* Author — Allen Antony Ukani
* Contact — auks256ATcs.washington.edu
* Created Date — 9.30.2012
* Last Modified Date — 10.10.2012
* Last Modified By — Allen Antony Ukani
*/using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;namespace LegendOfZelda
{
////// Keeps track of all the blocks in a room for the game, including collision detection.
///class BlockManager
{
private LinkedList blockList = new LinkedList();
private LinkedList newBlocksList = new LinkedList();///
/// Create the BlockManager
///public BlockManager()
{}
///
/// Add a block to the manager
////// Block to add
public void AddBlock(Block block)
{
newBlocksList.AddLast(block);
}///
/// Add a set of blocks to the manager
////// Blocks to add
public void AddBlocks(IEnumerable blocks)
{
foreach (Block block in blocks)
{
AddBlock(block);
}
}///
/// Update all blocks in the manager
////// GameTime structure from XNA
public void Update(GameTime gameTime)
{
// Add new blocks to the manager
if (newBlocksList.Count > 0)
{
foreach (var block in newBlocksList)
{
blockList.AddLast(block);
}
newBlocksList.Clear();
}// Update all blocks that need updating
foreach (var block in blockList)
{
block.Update(gameTime);
}
}///
/// Draw all blocks in the manager
////// SpriteBatch to draw with
public void Draw(SpriteBatch spriteBatch)
{
// Sort all blocks by Z-Index
var sortedBlocks = blockList.OrderBy(b => b.ZIndex);// Draw all blocks
foreach (var block in sortedBlocks)
{
block.Draw(spriteBatch);
}
}///
/// Get all the blocks in the manager (returns both new blocks and existing blocks)
////// List of all blocks
public IEnumerable GetBlocks()
{
foreach (var block in blockList)
{
yield return block;
}foreach (var block in newBlocksList)
{
yield return block;
}
}///
/// Clear out the manager’s list of blocks
///public void Clear()
{
blockList.Clear();
newBlocksList.Clear();
}///
/// Get a count of all the blocks in the manager
///public int Count
{
get
{
return blockList.Count + newBlocksList.Count;
}
}
}
}/* Author — Halle Luttrell
* Contact — [email protected]
* Created Date — 10.5.2012
* Last Modified Date — 10.12.2012
* Last Modified By — Allen Antony Ukani
*/using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using LegendOfZelda.Collisions;namespace LegendOfZelda
{
////// This class represents a door block that can be opened with keys
///class LockedDoor : Block
{
////// Create a locked door to block entry into another area of the dungeon
////// X position of the door
/// Y position of the door
/// Width of the door block
/// Height of the door block
/// Texture to use for the locked door
/// Source rectangle for the texture to draw the door
public LockedDoor(int x, int y, int width, int height, Texture2D texture, Rectangle sourceRect)
: base(x, y, width, height, false, texture, sourceRect, true)
{
// Add any logic for locked doors here
}///
/// Draw the door using the sprite sheet
////// SpriteBatch to use to draw the door
public override void Draw(SpriteBatch spriteBatch)
{
base.Draw(spriteBatch);
}///
/// Update the door appearance and state
////// GameTime object from XNA
public override void Update(GameTime gameTime)
{
base.Update(gameTime);
}///
/// Detect a collision with the locked door and handle it
////// The item that’s colliding with the door (usually a key)
public override void OnCollision(ICollidable obj)
{
// Check for Link colliding and having a key (to open the door)
if (obj.CollisionGroup == CollisionGroup.Link)
{
// Check if Link has a key to use
if (GameManager.Instance.Player.KeyCount > 0)
{
// Use a key to open the door
UnlockDoor();
}
}
}///
/// Unlock the door, removing it as an obstacle in the room.
///public void UnlockDoor()
{
// Door is now open
isPassable = true;
collisionGroup = CollisionGroup.PassableBlock;// Use up a key
GameManager.Instance.Player.KeyCount–;// Play a sound
SoundFactory.PlaySound(SoundFactory.SoundType.KeyDoor);// Remove the map
CurrentRoom.KeyDoorOpen(this);
}///
/// Gets an integer representing the layer that this object should be drawn on, with higher values being drawn on top of lower values.
/// Objects with equivalent z-indices have an undefined render order relative to each other.
///public override int ZIndex
{
get { return 1; }
}
}
}# auks256/cse3902
/* Original Author — Allen Antony Ukani
* Original Contact — auks256ATcs.washington.edu
* Created Date — 09.29.2012
* Last Modified Date — 10.28.2012
* Last Modified By — Allen Antony Ukani
*/using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using LegendOfZelda.Collisions;namespace LegendOfZelda.Projectiles
{
////// A fireball shot by an enemy
///public class Fireball : AnimatedSprite, IProjectile
{
private double moveSpeed = 1.7;
private int lifetime = 9000;
private int timeAlive = 0;
private ILink.Direction direction;// Original direction, in case we want to switch back
private ILink.Direction oldDirection;private Vector2 directionVector;
// Fixed movement for a specific angle
private float angle = -1;
private Vector2 fixedDirection = Vector2.Zero;private bool willExpireOnCollide = true; // If true, the fireball disappears when it hits
private int damage = 1;
///
/// Map for cardinal movement
///private static Dictionary directionToXYMap = new Dictionary()
{
{ILink.Direction.North, new Vector2(0,-1)},
{ILink.Direction.South, new Vector2(0,1)},
{ILink.Direction.East, new Vector2(1,0)},
{ILink.Direction.West, new Vector2(-1,0)}
};private enum FireballAnims
{
Frame1, Frame2, Frame3, Frame4
}private static Dictionary GetAnimationTable()
{
Dictionary table = new Dictionary();// Fireball animation
table.Add(FireballAnims.Frame1, new Rectangle(276, 3, 8, 10));
table.Add(FireballAnims.Frame2, new Rectangle(276, 19, 8, 10));
table.Add(FireballAnims.Frame3, new Rectangle(276, 35, 8, 10));
table.Add(FireballAnims.Frame4, new Rectangle(276, 51, 8, 10));return table;
}///
/// Create a new fireball traveling in a specific direction.
////// X position of fireball
/// Y position of fireball
/// Direction to travel in
public Fireball(int x, int y, ILink.Direction direction)
: base(„Projectiles”)
{
this.X = x;
this.Y = y;
this.direction = direction;
this.directionVector = directionToXYMap[direction];
this.oldDirection = direction;// Set up animations
ChangeAnimationTable(GetAnimationTable());
PlayAnimation(new int[] { (int)FireballAnims.Frame1, (int)FireballAnims.Frame2, (int)FireballAnims.Frame3, (int)FireballAnims.Frame4 }, 75);
RandomizeAnimationIndex();
}///
/// Create a new fireball traveling in a specific direction at a specific angle.
////// X position of fireball
/// Y position of fireball
/// Angle to travel in (radians)
public Fireball(int x, int y, float angle)
: base(„Projectiles”)
{
this.X = x;
this.Y = y;
this.angle = angle;
this.fixedDirection = new Vector2((float)Math.Cos(angle), (float)Math.Sin(angle));
this.fixedDirection.Normalize();
this.direction = ILink.Direction.East; // placeholder
this.directionVector = fixedDirection;
this.oldDirection = direction;// Set up animations
ChangeAnimationTable(GetAnimationTable());
PlayAnimation(new int[] { (int)FireballAnims.Frame1, (int)FireballAnims.Frame2, (int)FireballAnims.Frame3, (int)FireballAnims.Frame4 }, 75);
RandomizeAnimationIndex();
}///
/// Update the position and animation of the fireball.
////// GameTime structure from XNA
public override void Update(GameTime gameTime)
{
// Only update logic for fireballs on screen
if (!GameContext.State.TransitioningScreens)
{
// Update the location of the fireball
if (angle = lifetime)
{
IsActive = false;
}
}// Update animation as well
base.Update(gameTime);
}///
/// Draw the fireball
////// SpriteBatch to draw with
public override void Draw(SpriteBatch spriteBatch)
{
base.Draw(spriteBatch);
}///
/// Bounds of the projectile for collision detection
///public override Rectangle Bounds
{
get
{
return new Rectangle(X + 2 * GameContext.Window.Scale, Y + 2 * GameContext.Window.Scale,
4 * GameContext.Window.Scale, 4 * GameContext.Window.Scale);
}
}///
/// Collision group of the fireball
///public override CollisionGroup CollisionGroup
{
get
{
return CollisionGroup.EnemyProjectile;
}
}///
/// Check what to do when the fireball collides with a collidable object
////// The object the fireball hit
public override void OnCollision(ICollidable obj)
{
// See what the fireball hit
if (obj.CollisionGroup == CollisionGroup.Link && obj is ILink)
{
// Damage Link
ILink link = obj as ILink;
if (!link.IsBeingDamaged)
{
link.TakeDamage(damage, DetermineCollisionDirection(link.Bounds));
IsActive = false;
}
}
else if (obj.CollisionGroup == CollisionGroup.LinkProjectile || obj.CollisionGroup == CollisionGroup.Block)
{
// Expire on collision with blocks
IsActive = false;
}
else if (obj.CollisionGroup == CollisionGroup.PassableBlock)
{
// Don’t expire on collision with passable blocks
}
}///
/// Convert from the object hit’s bounds to a direction for the collision (north, south, east, west)
////// Bounds of the object hit by the fireball
/// Direction for the collision knockback to go in
private ILink.Direction DetermineCollisionDirection(Rectangle objBounds)
{
Rectangle bounds = Bounds;
var center1 = new Vector2(bounds.Center.X, bounds.Center.Y);
var center2 = new Vector2(objBounds.Center.X, objBounds.Center.Y);
var diff = center1 – center2;// Use the inverse of current direction, because that’s where we’re coming from
if (Math.Abs(diff.X) > Math.Abs(diff.Y))
{
// Left/Right
if (diff.X > 0) return ILink.Direction.East;
else if (diff.X 0) return ILink.Direction.South;
else if (diff.Y < 0) return ILink.Direction.North;
}return ILink.Direction.East; // default
}///
/// Get the current speed of the projectile
///public double Speed
{
get
{
return moveSpeed;
}
set
{
moveSpeed = value;
}
}///
/// Get the direction the projectile is moving in
///public ILink.Direction Direction
{
get
{
return direction;
}
set
{
// Don’t switch direction if we’re using a fixed angle
if (angle < 0)
{
direction = value;
directionVector = directionToXYMap[value];
}
}
}///
/// Get the location of the fireball
///public override Point Location
{
get
{
return new Point(X, Y);
}
}///
/// Get the size of the fireball
///public override Point Size
{
get
{
return new Point(Width, Height);
}
}///
/// Get or set the X position of the fireball
///public int X { get; set; }
///
/// Get or set the Y position of the fireball
///public int Y { get; set; }
///
/// Get the width of the fireball
///public override int Width
{
get
{
return 8 * GameContext.Window.Scale;
}
}///
/// Get the height of the fireball
///public override int Height
{
get
{
return 10 * GameContext.Window.Scale;
}
}///
/// Gets an integer representing the layer that this object should be drawn on, with higher values being drawn on top of lower values.
/// Objects with equivalent z-indices have an undefined render order relative to each other.
///public override int ZIndex
{
get { return 0; }
}}
}/* Original Author — Allen Antony Ukani
* Original Contact — auks256ATcs.washington.edu
* Created Date — 09.29.2012
* Last Modified Date — 10.17.2012
* Last Modified By — Allen Antony Ukani
*/using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using LegendOfZelda.Collisions;namespace LegendOfZelda.Projectiles
{
////// A boomerang projectile launched by Link.
///public class LinkBoomerang : AnimatedSprite, IProjectile
{
private const double maxMove = 1.5;
private const double moveAccel = 0.1;
private double currentMove;
private ILink.Direction direction;
private Vector2 directionVector;
private int distanceTraveled;// State checking
private bool returningToLink;
private bool hasDamagedSomething;private int damage = 1;
///
/// Map for cardinal movement
///private static Dictionary directionToXYMap = new Dictionary()
{
{ILink.Direction.North, new Vector2(0,-1)},
{ILink.Direction.South, new Vector2(0,1)},
{ILink.Direction.East, new Vector2(1,0)},
{ILink.Direction.West, new Vector2(-1,0)}
};private enum BoomerangAnims
{
North1, North2, North3, North4,
South1, South2, South3, South4,
East1, East2, East3, East4,
West1, West2, West3, West4
}private static Dictionary GetAnimationTable()
{
Dictionary table = new Dictionary();// North facing boomerang
table.Add(BoomerangAnims.North1, new Rectangle(95, 204, 8, 8));
table.Add(BoomerangAnims.North2, new Rectangle(87, 204, 8, 8));
table.Add(BoomerangAnims.North3, new Rectangle(79, 204, 8, 8));
table.Add(BoomerangAnims.North4, new Rectangle(71, 204, 8, 8));// East facing boomerang
table.Add(BoomerangAnims.East1, new Rectangle(95, 196, 8, 8));
table.Add(BoomerangAnims.East2, new Rectangle(87, 196, 8, 8));
table.Add(BoomerangAnims.East3, new Rectangle(79, 196, 8, 8));
table.Add(BoomerangAnims.East4, new Rectangle(71, 196, 8, 8));// South facing boomerang
table.Add(BoomerangAnims.South1, new Rectangle(95, 220, 8, 8));
table.Add(BoomerangAnims.South2, new Rectangle(87, 220, 8, 8));
table.Add(BoomerangAnims.South3, new Rectangle(79, 220, 8, 8));
table.Add(BoomerangAnims.South4, new Rectangle(71, 220, 8, 8));// West facing boomerang
table.Add(BoomerangAnims.West1, new Rectangle(95, 212, 8, 8));
table.Add(BoomerangAnims.West2, new Rectangle(87, 212, 8, 8));
table.Add(BoomerangAnims.West3, new Rectangle(79, 212, 8, 8));
table.Add(BoomerangAnims.West4, new Rectangle(71, 212, 8, 8));return table;
}///
/// Create a new Link boomerang traveling in a specific direction.
////// X position of boomerang
/// Y position of boomerang
/// Direction to travel in
public LinkBoomerang(int x, int y, ILink.Direction direction)
: base(„Projectiles”)
{
this.X = x;
this.Y = y;
this.direction = direction;
this.directionVector = directionToXYMap[direction];
this.returningToLink = false;
this.hasDamagedSomething = false;
this.currentMove = maxMove;
this.distanceTraveled = 0;// Set up animations
ChangeAnimationTable(GetAnimationTable());// Start spinning at frame 1 and use the right animation for the direction
AnimationIndex = 0;
SetDirectionAnimation(direction);
}///
/// Update the position and animation of the boomerang.
////// GameTime structure from XNA
public override void Update(GameTime gameTime)
{
if (!returningToLink)
{
// Check if it’s time to turn around
if (distanceTraveled >= 48 * GameContext.Window.Scale)
{
returningToLink = true;
currentMove = 0; // Reset speed
}
else
{
// Update the location of the Arrow
X += (int)(directionVector.X * currentMove * gameTime.ElapsedGameTime.Milliseconds / 16.0);
Y += (int)(directionVector.Y * currentMove * gameTime.ElapsedGameTime.Milliseconds / 16.0);
distanceTraveled += (int)(maxMove * gameTime.ElapsedGameTime.Milliseconds / 16.0);
}
}
else
{
// Seek out Link’s position
try
{
var link = GameManager.Instance.Link;
int linkCenterX = link.Bounds.Center.X;
int linkCenterY = link.Bounds.Center.Y;
int x = X, y = Y;// Calculate the distance to Link
double distance = Math.Sqrt(Math.Pow(X – linkCenterX, 2) + Math.Pow(Y – linkCenterY, 2));// Update the location of the boomerang
if (distance > 4)
{
// Get the unit vector from this location to Link’s
double dx = (linkCenterX – X) / distance;
double dy = (linkCenterY – Y) / distance;// Accelerate to max speed
currentMove += moveAccel * gameTime.ElapsedGameTime.Milliseconds / 16.0;
if (currentMove > maxMove) currentMove = maxMove;// Move towards the hero
x += (int)(dx * currentMove * gameTime.ElapsedGameTime.Milliseconds / 16.0);
y += (int)(dy * currentMove * gameTime.ElapsedGameTime.Milliseconds / 16.0);// Update game state
if (!GameContext.State.LinkIsFrozen && !link.IsDead && !link.IsBeingDamaged)
{
X = x;
Y = y;
}
}
else
{
// Close enough to be collected
IsActive = false;
}
}
catch (Exception)
{
// Just in case Link gets destroyed somehow, clean up this projectile too
IsActive = false;
}
}// Update animation as well
base.Update(gameTime);
}///
/// Draw the boomerang
////// SpriteBatch to draw with
public override void Draw(SpriteBatch spriteBatch)
{
base.Draw(spriteBatch);
}///
/// Bounds of the projectile for collision detection
///public override Rectangle Bounds
{
get
{
// Smaller hitbox on the boomerang
return new Rectangle(X + 2 * GameContext.Window.Scale, Y + 2 * GameContext.Window.Scale,
4 * GameContext.Window.Scale, 4 * GameContext.Window.Scale);
}
}///
/// Collision group of the boomerang
///public override CollisionGroup CollisionGroup
{
get
{
return CollisionGroup.LinkProjectile;
}
}///
/// Check what to do when the boomerang collides with a collidable object
////// The object the boomerang hit
public override void OnCollision(ICollidable obj)
{
// See what the boomerang hit
if (obj.CollisionGroup == CollisionGroup.Enemy)
{
// Move back towards Link
if (!returningToLink)
{
returningToLink = true;
currentMove = 0; // Reset speed
}// Track if boomerang has hit an enemy
hasDamagedSomething = true;
}
else if (obj.CollisionGroup == CollisionGroup.EnemyProjectile)
{
// Make the boomerang able to block projectiles if it hits them
hasDamagedSomething = true;
}
else if (obj.CollisionGroup == CollisionGroup.Block && !hasDamagedSomething)
{
// Bounce the boomerang back towards Link
returningToLink = true;
currentMove = 0; // Reset speed// Play a sound when it bounces
SoundFactory.PlaySound(SoundFactory.SoundType.BoomerangBounce);
}
else if (obj.CollisionGroup == CollisionGroup.Item)
{
// Collect the item
returningToLink = true;
currentMove = 0; // Reset speed
}
}///
/// Set the correct animation based on which direction the player is facing
////// Direction for the animation
private void SetDirectionAnimation(ILink.Direction direction)
{
switch (direction)
{
case ILink.Direction.North:
PlayAnimation(new int[] { (int)BoomerangAnims.North1, (int)BoomerangAnims.North2, (int)BoomerangAnims.North3, (int)BoomerangAnims.North4 }, 50);
break;
case ILink.Direction.South:
PlayAnimation(new int[] { (int)BoomerangAnims.South1, (int)BoomerangAnims.South2, (int)BoomerangAnims.South3, (int)BoomerangAnims.South4 }, 50);
break;
case ILink.Direction.East:
PlayAnimation(new int[] { (int)BoomerangAnims.East1, (int)BoomerangAnims.East2, (int)BoomerangAnims.East3, (int)BoomerangAnims.East4 }, 50);
break;
case ILink.Direction.West:
PlayAnimation(new int[] { (int)BoomerangAnims.West1, (int)BoomerangAnims.West2, (int)BoomerangAnims.West3, (int)BoomerangAnims.West4 }, 50);
break;
}
}///
/// Get the current speed of the projectile
///public double Speed
{
get
{
return maxMove;
}
set
{
// can’t change speed
}
}///
/// Get the direction the projectile is moving in
///public ILink.Direction Direction
{
get
{
return direction;
}
set
{
if (!returningToLink)
{
direction = value;
directionVector = directionToXYMap[value];
SetDirectionAnimation(direction);
}
}
}///
/// Get the location of the boomerang
///public override Point Location
{
get
{
return new Point(X, Y);
}
}///
/// Get the size of the boomerang
///public override Point Size
{
get
{
return new Point(Width, Height);
}
}///
/// Get or set the X position of the boomerang
///public int X { get; set; }
///
/// Get or set the Y position of the boomerang
///public int Y { get; set; }
///
/// Get the width of the boomerang
///public override int Width
{
get
{
return 8 * GameContext.Window.Scale;
}
}///
/// Get the height of the boomerang
///public override int Height
{
get
{
return 8 * GameContext.Window.Scale;
}
}///
/// Gets an integer representing the layer that this object should be drawn on, with higher values being drawn on top of lower values.
/// Objects with equivalent z-indices have an undefined render order relative to each other.
///public override int ZIndex
{
get { return 1; }
}}
}# auks256/cse3902
# LegendOfZelda/LegendOfZelda/Projectiles/EnemyBoomerang.cs
/* Original Author — Allen Antony Ukani
* Original Contact — auks256ATcs.washington.edu
* Created Date — 09.29.2012
* Last Modified Date — 10.17.2012
* Last Modified By — Allen Antony Ukani
*/using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using LegendOfZelda.Collisions;namespace LegendOfZelda.Projectiles
{
////// A boomerang projectile launched by an enemy
///public class EnemyBoomerang : AnimatedSprite, IProjectile
{
private const double maxMove = 1.5;
private const double moveAccel = 0.1;
private double currentMove;
private ILink.Direction direction;
private Vector2 directionVector;
private int distanceTraveled;// Movement and returning
private bool returningToSource;
private bool hasDamagedLink;// The enemy controller
private ICollidable source;private int damage = 1; // How much damage the boomerang does to link
///
/// Map for cardinal movement
///private static Dictionary directionToXYMap = new Dictionary()
{
{ILink.Direction.North, new Vector2(0,-1)},
{ILink.Direction.South, new Vector2(0,1)},
{ILink.Direction.East, new Vector2(1,0)},
{ILink.Direction.West, new Vector2(-1,0)}
};private enum BoomerangAnims
{
North1, North2, North3, North4,
South1, South2, South3, South4,
East1, East2, East3, East4,
West1, West2, West3, West4
}private static Dictionary GetAnimationTable()
{
Dictionary table = new Dictionary();// North facing boomerang
table.Add(BoomerangAnims.North1, new Rectangle(95, 204, 8, 8));
table.Add(BoomerangAnims.North2, new Rectangle(87, 204, 8, 8));
table.Add(BoomerangAnims.North3, new Rectangle(79, 204, 8, 8));
table.Add(BoomerangAnims.North4, new Rectangle(71, 204, 8, 8));// East facing boomerang
table.Add(BoomerangAnims.East1, new Rectangle(95, 196, 8, 8));
table.Add(BoomerangAnims.East2, new Rectangle(87, 196, 8, 8));
table.Add(BoomerangAnims.East3, new Rectangle(79, 196, 8, 8));
table.Add(BoomerangAnims.East4, new Rectangle(71, 196, 8, 8));// South facing boomerang
table.Add(BoomerangAnims.South1, new Rectangle(95, 220, 8, 8));
table.Add(BoomerangAnims.South2, new Rectangle(87, 220, 8, 8));
table.Add(BoomerangAnims.South3, new Rectangle(79, 220, 8, 8));
table.Add(BoomerangAnims.South4, new Rectangle(71, 220, 8, 8));// West facing boomerang
table.Add(BoomerangAnims.West1, new Rectangle(95, 212, 8, 8));
table.Add(BoomerangAnims.West2, new Rectangle(87, 212, 8, 8));
table.Add(BoomerangAnims.West3, new Rectangle(79, 212, 8, 8));
table.Add(BoomerangAnims.West4, new Rectangle(71, 212, 8, 8));return table;
}///
/// Create a new enemy boomerang traveling in a specific direction.
////// X position of boomerang
/// Y position of boomerang
/// Direction to travel in
/// Enemy that threw the boomerang
public EnemyBoomerang(int x, int y, ILink.Direction direction, ICollidable source)
: base(„Projectiles”)
{
this.X = x;
this.Y = y;
this.direction = direction;
this.directionVector = directionToXYMap[direction];
this.returningToSource = false;
this.hasDamagedLink = false;
this.currentMove = maxMove;
this.distanceTraveled = 0;
this.source = source;// Set up animations
ChangeAnimationTable(GetAnimationTable());// Start spinning at frame 1 and use the right animation for the direction
AnimationIndex = 0;
SetDirectionAnimation(direction);
}///
/// Update the position and animation of the boomerang.
////// GameTime structure from XNA
public override void Update(GameTime gameTime)
{
// Don’t update the movement if the source is gone
if (source != null)
{
if (!returningToSource)
{
// Check if it’s time to turn around
if (distanceTraveled >= 48 * GameContext.Window.Scale)
{
returningToSource = true;
currentMove = 0; // Reset speed
}
else
{
// Update the location of the Arrow
X += (int)(directionVector.X * currentMove * gameTime.ElapsedGameTime.Milliseconds / 16.0);
Y += (int)(directionVector.Y * currentMove * gameTime.ElapsedGameTime.Milliseconds / 16.0);
distanceTraveled += (int)(maxMove * gameTime.ElapsedGameTime.Milliseconds / 16.0);
}
}
else
{
// Return the boomerang
int sourceCenterX = source.Bounds.Center.X;
int sourceCenterY = source.Bounds.Center.Y;
int x = X, y = Y;// Calculate the distance to the source
double distance = Math.Sqrt(Math.Pow(X – sourceCenterX, 2) + Math.Pow(Y – sourceCenterY, 2));// Update the location of the boomerang
if (distance > 4)
{
// Get the unit vector from this location to the source
double dx = (sourceCenterX – X) / distance;
double dy = (sourceCenterY – Y) / distance;// Accelerate to max speed
currentMove += moveAccel * gameTime.ElapsedGameTime.Milliseconds / 16.0;
if (currentMove > maxMove) currentMove = maxMove;// Move towards the enemy
x += (int)(dx * currentMove * gameTime.ElapsedGameTime.Milliseconds / 16.0);
y += (int)(dy * currentMove * gameTime.ElapsedGameTime.Milliseconds / 16.0);X = x;
Y = y;
}
else
{
// Close enough to be considered collected
IsActive = false;
}
}
}
else
{
// Make the boomerang disappear if the source is gone
IsActive = false;
}// Update animation as well
base.Update(gameTime);
}///
/// Draw the boomerang
////// SpriteBatch to draw with
public override void Draw(SpriteBatch spriteBatch)
{
base.Draw(spriteBatch);
}///
/// Bounds of the projectile for collision detection
///public override Rectangle Bounds
{
get
{
// Smaller hitbox on the boomerang
return new Rectangle(X + 2 * GameContext.Window.Scale, Y + 2 * GameContext.Window.Scale,
4 * GameContext.Window.Scale, 4 * GameContext.Window.Scale);
}
}///
/// Collision group of the boomerang
///public override CollisionGroup CollisionGroup
{
get
{
return CollisionGroup.EnemyProjectile;
}
}///
/// Check what to do when the boomerang collides with a collidable object
////// The object the boomerang hit
public override void OnCollision(ICollidable obj)
{
// See what the boomerang hit
if (obj.CollisionGroup == CollisionGroup.Link)
{
// Boomerang hit Link, inflict damage
if (!hasDamagedLink && obj is ILink)
{
ILink link = obj as ILink;
link.TakeDamage(damage, Direction);
hasDamagedLink = true;
}// Move back towards the source
if (!returningToSource)
{
returningToSource = true;
currentMove = 0; // Reset speed
}
}
else if (obj.CollisionGroup == CollisionGroup.LinkProjectile)
{}
else if (obj.CollisionGroup == CollisionGroup.Block)
{
// Turn the boomerang around
returningToSource = true;
currentMove = 0; // Reset speed
}
else if (obj is ICollidable && obj == source)
{
// Collected by source
IsActive = false;
}
}///
/// Set the correct animation based on which direction the player is facing
////// Direction for the animation
private void SetDirectionAnimation(ILink.Direction direction)
{
switch (direction)
{
case ILink.Direction.North:
PlayAnimation(new int[] { (int)BoomerangAnims.North1, (int)BoomerangAnims.North2, (int)BoomerangAnims.North3, (int)BoomerangAnims.North4 }, 50);
break;
case ILink.Direction.South:
PlayAnimation(new int[] { (int)BoomerangAnims.South1, (int)BoomerangAnims.South2, (int)BoomerangAnims.South3, (int)BoomerangAnims.South4 }, 50);
break;
case ILink.Direction.East:
PlayAnimation(new int[] { (int)BoomerangAnims.East1, (int)BoomerangAnims.East2, (int)BoomerangAnims.East3, (int)BoomerangAnims.East4 }, 50);
break;
case ILink.Direction.West:
PlayAnimation(new int[] { (int)BoomerangAnims.West1, (int)BoomerangAnims.West2, (int)BoomerangAnims.West3, (int)BoomerangAnims.West4 }, 50);
break;
}
}///
/// Get the current speed of the projectile
///public double Speed
{
get
{
return maxMove;
}
set
{
// can’t change speed
}
}///
/// Get the direction the projectile is moving in
///public ILink.Direction Direction
{
get
{
return direction;
}
set
{
if (!returningToSource)
{
direction = value;
directionVector = directionToXYMap[value];
SetDirectionAnimation(direction);
}
}
}///
/// Get the location of the boomerang
///public override Point Location
{
get
{
return new Point(X, Y);
}
}///
/// Get the size of the boomerang
///public override Point Size
{
get
{
return new Point(Width, Height);
}
}///
/// Get or set the X position of the boomerang
///public int X { get; set; }
///
/// Get or set the Y position of the boomerang
///public int Y { get; set; }
///
/// Get the width of the boomerang
///public override int Width
{
get
{
return 8 * GameContext.Window.Scale;
}
}///
/// Get the height of the boomerang
///public override int Height
{
get
{
return 8 * GameContext.Window.Scale;
}
}///
/// Gets an integer representing the layer that this object should be drawn on, with higher values being drawn on top of lower values.
/// Objects with equivalent z-indices have an undefined render order relative to each other.
///public override int ZIndex
{
get { return 1; }
}
}
}/* Original Author — Allen Antony Ukani
* Original Contact — auks256ATcs.washington.edu
* Created Date — 09.29.2012
* Last Modified Date — 10.17.2012
* Last Modified By — Allen Antony Ukani
*/using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using LegendOfZelda.Collisions;namespace LegendOfZelda.Projectiles
{
////// Arrow projectile that can be shot by Link.
///public class LinkArrow : AnimatedSprite, IProjectile
{
private double moveSpeed = -2;
private ILink.Direction direction;
private Vector2 directionVector;
private int damage = 2;///
/// Map for cardinal movement
///private static Dictionary directionToXYMap = new Dictionary()
{
{ILink.Direction.North, new Vector2(0,-1)},
{ILink.Direction.South, new Vector2(0,1)},
{ILink.Direction.East, new Vector2(1,0)},
{ILink.Direction.West, new Vector2(-1,0)}
};private enum ArrowAnims
{
North, South, East, West
}private static Dictionary GetAnimationTable()
{
Dictionary table = new Dictionary();// North facing arrow
table.Add(ArrowAnims.North, new Rectangle(9, 188, 9, 17));// South facing arrow
table.Add(ArrowAnims.South, new Rectangle(9, 206, 9, 17));// East facing arrow
table.Add(ArrowAnims.East, new Rectangle(26, 188, 17, 9));// West facing arrow
table.Add(ArrowAnims.West, new Rectangle(26, 198, 17, 9));return table;
}///
/// Create a new LinkArrow traveling in a specific direction.
////// X position of arrow
/// Y position of arrow
/// Direction to travel in
public LinkArrow(int x, int y, ILink.Direction direction)
: base(„Projectiles”)
{
this.X = x;
this.Y = y;
this.direction = direction;
this.directionVector = directionToXYMap[direction];// Set up animations
ChangeAnimationTable(GetAnimationTable());// Select the animation frame for the right direction
switch (direction)
{
case ILink.Direction.North:
SetAnimation((int)ArrowAnims.North);
break;
case ILink.Direction.South:
SetAnimation((int)ArrowAnims.South);
break;
case ILink.Direction.East:
SetAnimation((int)ArrowAnims.East);
break;
case ILink.Direction.West:
SetAnimation((int)ArrowAnims.West);
break;
}
}///
/// Update the position and animation of the arrow.
////// GameTime structure from XNA
public override void Update(GameTime gameTime)
{
// Only update logic for arrows on screen
if (!GameContext.State.TransitioningScreens)
{
// Update the location of the Arrow
X += (int)(directionVector.X * moveSpeed * gameTime.ElapsedGameTime.Milliseconds / 16.0);
Y += (int)(directionVector.Y * moveSpeed * gameTime.ElapsedGameTime.Milliseconds / 16.0);
}// Check if arrow is onscreen and deactivate if no
if (!IsOnScreen())
{
IsActive = false;
}// Update animation as well
base.Update(gameTime);
}///
/// Draw the arrow
////// SpriteBatch to draw with
public override void Draw(SpriteBatch spriteBatch)
{
base.Draw(spriteBatch);
}///
/// Check if the projectile is on screen, with some padding around the edge
////// True if the projectile is still on screen, false otherwise
private bool IsOnScreen()
{
// Check that the object is actually located on screen, with some padding (100px)
Rectangle bounds = Bounds;
Rectangle roomBounds = GameContext.World.CurrentRoomTileSet.GetRoomBounds(GameContext.Window.RoomX, GameContext.Window.RoomY);
roomBounds.Inflate(100, 100);
return bounds.Intersects(roomBounds);
}///
/// Bounds of the projectile for collision detection
///public override Rectangle Bounds
{
get
{
return new Rectangle(X, Y, Width, Height);
}
}///
/// Collision group of the arrow
///public override CollisionGroup CollisionGroup
{
get
{
return CollisionGroup.LinkProjectile;
}
}///
/// Check what to do when the arrow collides with a collidable object
////// The object the arrow hit
public override void OnCollision(ICollidable obj)
{
// See what the arrow hit
if (obj.CollisionGroup == CollisionGroup.Enemy)
{
// Damage enemy (handled by enemy)
IsActive = false;
GameManager.Instance.ParticleManager.CreatePoof(Bounds.Center.X, Bounds.Center.Y);
}
else if (obj.CollisionGroup == CollisionGroup.Block)
{
// Hit a wall
IsActive = false;
GameManager.Instance.ParticleManager.CreatePoof(Bounds.Center.X, Bounds.Center.Y);
}
}///
/// Get the current speed of the projectile
///public double Speed
{
get
{
return moveSpeed;
}
set
{
moveSpeed = value;
}
}///
/// Get the direction the projectile is moving in
///public ILink.Direction Direction
{
get
{
return direction;
}
set
{
direction = value;
directionVector = directionToXYMap[value];// Update the animation to match the direction
switch (direction)
{
case ILink.Direction.North:
SetAnimation((int)ArrowAnims.North);
break;
case ILink.Direction.South:
SetAnimation((int)ArrowAnims.South);
break;
case ILink.Direction.East:
SetAnimation((int)ArrowAnims.East);
break;
case ILink.Direction.West:
SetAnimation((int)ArrowAnims.West);
break;
}
}
}///
/// Get the location of the arrow
///public override Point Location
{
get
{
return new Point(X, Y);
}
}///
/// Get the size of the arrow
///public override Point Size
{
get
{
if (direction == ILink.Direction.North || direction == ILink.Direction.South)
{
return new Point(9 * GameContext.Window.Scale, 17 * GameContext.Window.Scale);
}
else
{
return new Point(17 * GameContext.Window.Scale, 9 * GameContext.Window.Scale);
}
}
}///
/// Get or set the X position of the arrow
///public int X { get; set; }
///
/// Get or set the Y position of the arrow
///public int Y { get; set; }
///
/// Get the width of the arrow
///public override int Width
{
get
{
if (direction == ILink.Direction.North || direction == ILink.Direction.South)
{
return 9 * GameContext.Window.Scale;
}
else
{
return 17 * GameContext.Window.Scale;
}
}
}///
/// Get the height of the arrow
///public override int Height
{
get
{
if (direction == ILink.Direction.North || direction == ILink.Direction.South)
{
return 17 * GameContext.Window.Scale;
}
else
{
return 9 * GameContext.Window.Scale;
}
}
}///
/// Gets an integer representing the layer that this object should be drawn on, with higher values being drawn on top of lower values.
/// Objects with equivalent z-indices have an undefined render order relative to each other.
///public override int ZIndex
{
get { return 1; }
}}
}# auks256/cse3902
/* Original Author — Allen Antony Ukani
* Original Contact — auks256ATcs.washington.edu
* Created Date — 09.29.2012
* Last Modified Date — 10.17.2012
* Last Modified By — Allen Antony Ukani
*/using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using LegendOfZelda.Collisions;namespace LegendOfZelda.Projectiles
{
////// Implementation of a bomb, which blows up after a certain amount of time
///public class LinkBomb : AnimatedSprite, IProjectile
{
private int fuseDuration = 2000; // For how long does the bomb show a fuse
private int fuseRemaining;
private int blastDuration = 500; // For how long does explosion last
private int blastRemaining;
private bool exploded;
private int damage = 3; // Amount of damage an explosion deals
private int blastRadius = 24;private enum BombAnims
{
BombFuse, Explosion1, Explosion2, Explosion3
}private static Dictionary GetAnimationTable()
{
Dictionary table = new Dictionary();// Bomb with fuse animation
table.Add(BombAnims.BombFuse, new Rectangle(129, 185, 8, 14));// Explosion animations
table.Add(BombAnims.Explosion1, new Rectangle(164, 198, 16, 16));
table.Add(BombAnims.Explosion2, new Rectangle(187, 198, 16, 16));
table.Add(BombAnims.Explosion3, new Rectangle(210, 198, 16, 16));return table;
}///
/// Create a new bomb at the given position
////// X position of the bomb
/// Y position of the bomb
public LinkBomb(int x, int y)
: base(„Projectiles”)
{
this.X = x;
this.Y = y;
this.fuseRemaining = fuseDuration;
this.blastRemaining = blastDuration;
this.exploded = false;// Set up animations
ChangeAnimationTable(GetAnimationTable());
SetAnimation((int)BombAnims.BombFuse);
}///
/// Draw the bomb
////// SpriteBatch to draw with
public override void Draw(SpriteBatch spriteBatch)
{
base.Draw(spriteBatch);
}///
/// Update the bomb status
////// GameTime structure from XNA
public override void Update(GameTime gameTime)
{
// Check the bomb state
if (!exploded)
{
// Count down the fuse
fuseRemaining -= gameTime.ElapsedGameTime.Milliseconds;
if (fuseRemaining <= 0)
{
// Explode
Explode();
}
}
else
{
// Count down the explosion
blastRemaining -= gameTime.ElapsedGameTime.Milliseconds;
if (blastRemaining <= 0)
{
// Explosion is done
IsActive = false;
}
}// Update animation as well
base.Update(gameTime);
}///
/// Make the bomb explode
///private void Explode()
{
// Don’t allow multiple explosions
if (exploded) return;// See if link is in range of the explosion
Rectangle blastBox = new Rectangle(Bounds.X – blastRadius, Bounds.Y – blastRadius, Bounds.Width + blastRadius * 2, Bounds.Height + blastRadius * 2);
ILink link = GameManager.Instance.Link;
if (link.Bounds.Intersects(blastBox))
{
// Calculate the direction for damage knockback
Point linkCenter = new Point(link.Bounds.Center.X, link.Bounds.Center.Y);
Point center = new Point(Bounds.Center.X, Bounds.Center.Y);
Vector2 direction = new Vector2(linkCenter.X – center.X, linkCenter.Y – center.Y);
if (direction != Vector2.Zero) direction.Normalize();// Link was hit by the explosion
ILink.Direction knockbackDir;
if (Math.Abs(direction.X) > Math.Abs(direction.Y))
{
if (direction.X >= 0) knockbackDir = ILink.Direction.East;
else knockbackDir = ILink.Direction.West;
}
else
{
if (direction.Y >= 0) knockbackDir = ILink.Direction.South;
else knockbackDir = ILink.Direction.North;
}link.TakeDamage(damage, knockbackDir);
}// Set the bomb to the exploded state
exploded = true;
PlayAnimation(new int[] { (int)BombAnims.Explosion1, (int)BombAnims.Explosion2, (int)BombAnims.Explosion3 }, 150);SoundFactory.PlaySound(SoundFactory.SoundType.Bomb);
// Add some particles to the explosion, going out from the center of the bomb
GameManager.Instance.ParticleManager.CreateExplosion(Bounds.Center.X, Bounds.Center.Y);// Make a bigger hitbox for the bomb
X -= (16 * GameContext.Window.Scale) / 2;
Y -= (16 * GameContext.Window.Scale) / 2;
}///
/// Bounds of the projectile for collision detection
///public override Rectangle Bounds
{
get
{
if (!exploded)
{
return new Rectangle(X, Y, Width, Height);
}
else
{
// When the bomb is exploding, it has a bigger hitbox
return new Rectangle(X, Y, 16 * GameContext.Window.Scale, 16 * GameContext.Window.Scale);
}
}
}///
/// Collision group of the bomb
///public override CollisionGroup CollisionGroup
{
get
{
return (exploded) ? CollisionGroup.LinkProjectile : CollisionGroup.PassableBlock;
}
}///
/// Check what to do when the bomb collides with a collidable object
////// The object the bomb hit
public override void OnCollision(ICollidable obj)
{
// See what the bomb hit
if (obj.CollisionGroup == CollisionGroup.Enemy)
{
// Only checks for collision once the bomb explodes
// Damage enemy (handled by enemy)
}
}///
/// Get the current speed of the projectile
///public double Speed
{
get
{
return 0;
}
set
{
// do nothing
}
}///
/// Get the direction the projectile is moving in
///public ILink.Direction Direction
{
get
{
return ILink.Direction.North; // doesn’t matter
}
set
{
// do nothing
}
}///
/// Get the location of the bomb
///public override Point Location
{
get
{
return new Point(X, Y);
}
}///
/// Get the size of the bomb
///public override Point Size
{
get
{
if (!exploded)
{
return new Point(8 * GameContext.Window.Scale, 14 * GameContext.Window.Scale);
}
else
{
return new Point(16 * GameContext.Window.Scale, 16 * GameContext.Window.Scale);
}
}
}///
/// Get or set the X position of the bomb
///public int X { get; set; }
///
/// Get or set the Y position of the bomb
///public int Y { get; set; }
///
/// Get the width of the bomb
///public override int Width
{
get
{
if (!exploded)
{
return 8 * GameContext.Window.Scale;
}
else
{
return 16 * GameContext.Window.Scale;
}
}
}///
/// Get the height of the bomb
///public override int Height
{
get
{
if (!exploded)
{
return 14 * GameContext.Window.Scale;
}
else
{
return 16 * GameContext.Window.Scale;
}
}
}///
/// Gets an integer representing the layer that this object should be drawn on, with higher values being drawn on top of lower values.
/// Objects with equivalent z-indices have an undefined render order relative to each other.
///public override int ZIndex
{
get
{
if (exploded)
{
return 1;
}
else
{
return 0;
}
}
}}
}/* Original Author — Allen Antony Ukani
* Original Contact — auks256ATcs.washington.edu
* Created Date — 09.29.2012
* Last Modified Date — 10.17.2012
* Last Modified By — Allen Antony Ukani
*/using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using LegendOfZelda.Collisions;namespace LegendOfZelda.Projectiles
{
////// Sword projectile for Link’s sword attack
///public class LinkSword : AnimatedSprite, IProjectile
{
private float moveDistance = 1;
private ILink.Direction direction;
private Vector2 directionVector;
private int damage = 1;
private int currentSwordFrame = 0;
private int timer = 100;
private bool isExtended = false;
private bool beamActivated = false;
private int beamPos = 0;
private bool isShooting = false;
private bool canUseBeams;// Constants
private const int LINK_SWORD_OFFSET = 10;
private const int BEAM_SPEED = 4;
private const int BEAM_DAMAGE = 2;///
/// Map for cardinal movement
///private static Dictionary directionToXYMap = new Dictionary()
{
{ILink.Direction.North, new Vector2(0,-1)},
{ILink.Direction.South, new Vector2(0,1)},
{ILink.Direction.East, new Vector2(1,0)},
{ILink.Direction.West, new Vector2(-1,0)}
};private enum SwordAnims
{
North1, North2, North3, North4,
South1, South2, South3, South4,
East1, East2, East3, East4,
West1, West2, West3, West4,
NorthBeam, SouthBeam, EastBeam, WestBeam,
}private static Dictionary GetAnimationTable()
{
Dictionary table = new Dictionary();// North sword animation
table.Add(SwordAnims.North1, new Rectangle(1, 97, 16, 27));
table.Add(SwordAnims.North2, new Rectangle(18, 97, 16, 27));
table.Add(SwordAnims.North3, new Rectangle(35, 97, 16, 27));
table.Add(SwordAnims.North4, new Rectangle(52, 97, 16, 27));// East sword animation
table.Add(SwordAnims.East1, new Rectangle(1, 147, 27, 16));
table.Add(SwordAnims.East2, new Rectangle(35, 147, 27, 16));
table.Add(SwordAnims.East3, new Rectangle(69, 147, 27, 16));
table.Add(SwordAnims.East4, new Rectangle(103, 147, 27, 16));// South sword animation
table.Add(SwordAnims.South1, new Rectangle(1, 124, 16, 27));
table.Add(SwordAnims.South2, new Rectangle(18, 124, 16, 27));
table.Add(SwordAnims.South3, new Rectangle(35, 124, 16, 27));
table.Add(SwordAnims.South4, new Rectangle(52, 124, 16, 27));// West sword animation
table.Add(SwordAnims.West1, new Rectangle(1, 173, 27, 16));
table.Add(SwordAnims.West2, new Rectangle(35, 173, 27, 16));
table.Add(SwordAnims.West3, new Rectangle(69, 173, 27, 16));
table.Add(SwordAnims.West4, new Rectangle(103, 173, 27, 16));// Sword beam animations
table.Add(SwordAnims.NorthBeam, new Rectangle(42, 154, 8, 16));
table.Add(SwordAnims.SouthBeam, new Rectangle(26, 154, 8, 16));
table.Add(SwordAnims.EastBeam, new Rectangle(10, 172, 16, 8));
table.Add(SwordAnims.WestBeam, new Rectangle(10, 188, 16, 8));return table;
}///
/// Create a new LinkSword traveling in a specific direction.
////// X position of sword
/// Y position of sword
/// Direction to travel in
public LinkSword(int x, int y, ILink.Direction direction)
: base(„Link”)
{
this.X = x;
this.Y = y;
this.direction = direction;
this.directionVector = directionToXYMap[direction];// Set up the animation table
ChangeAnimationTable(GetAnimationTable());
SetAnimation(getSwordAnim(direction, 0));// Check health state
if (GameManager.Instance.Player.Health >= GameManager.Instance.Player.MaxHealth)
canUseBeams = true;
else
canUseBeams = false;
}///
/// Convert the current direction and frame into a sword animation
////// Direction of the sword
/// Frame of the animation
/// SwordAnims enumeration to put in the animation table
private int getSwordAnim(ILink.Direction direction, int frame)
{
switch (direction)
{
case ILink.Direction.North:
switch (frame)
{
case 0: return (int)SwordAnims.North1;
case 1: return (int)SwordAnims.North2;
case 2: return (int)SwordAnims.North3;
case 3: return (int)SwordAnims.North4;
default: return (int)SwordAnims.North1;
}
case ILink.Direction.South:
switch (frame)
{
case 0: return (int)SwordAnims.South1;
case 1: return (int)SwordAnims.South2;
case 2: return (int)SwordAnims.South3;
case 3: return (int)SwordAnims.South4;
default: return (int)SwordAnims.South1;
}
case ILink.Direction.East:
switch (frame)
{
case 0: return (int)SwordAnims.East1;
case 1: return (int)SwordAnims.East2;
case 2: return (int)SwordAnims.East3;
case 3: return (int)SwordAnims.East4;
default: return (int)SwordAnims.East1;
}
case ILink.Direction.West:
switch (frame)
{
case 0: return (int)SwordAnims.West1;
case 1: return (int)SwordAnims.West2;
case 2: return (int)SwordAnims.West3;
case 3: return (int)SwordAnims.West4;
default: return (int)SwordAnims.West1;
}
default: return 0;
}
}private SwordAnims getBeamAnim(ILink.Direction direction)
{
switch (direction)
{
case ILink.Direction.North: return SwordAnims.NorthBeam;
case ILink.Direction.South: return SwordAnims.SouthBeam;
case ILink.Direction.East: return SwordAnims.EastBeam;
case ILink.Direction.West: return SwordAnims.WestBeam;
default: return SwordAnims.NorthBeam;
}
}///
/// Update the position and animation of the sword.
////// GameTime structure from XNA
public override void Update(GameTime gameTime)
{
if (!isShooting)
{
// Update sword position
ILink link = GameManager.Instance.Link;
int offsetX = (int)(directionVector.X * LINK_SWORD_OFFSET * 5);
int offsetY = (int)(directionVector.Y * LINK_SWORD_OFFSET * 5);// Figure out where to place the sword
if (link.IsVisible)
{
X = link.X;
Y = link.Y;// Update the sword animation frame
currentSwordFrame = Math.Min(currentSwordFrame + 1, 3);
SetAnimation(getSwordAnim(direction, currentSwordFrame));// Check for shooting a beam
if (currentSwordFrame == 3)
{
// Can’t start a beam after the sword finishes extension
isExtended = true;
}if (currentSwordFrame == 2 && !isExtended && canUseBeams)
{
// Shoot the beam!
beamActivated = true;
beamPos = 0;
isShooting = true;
SoundFactory.PlaySound(SoundFactory.SoundType.SwordShot);
}
}
else
{
IsActive = false;
}
}
else
{
// A sword beam is being shot! Make it travel across the screen
// Update the sword animation frame
SetAnimation((int)getBeamAnim(direction));
X += (int)(directionVector.X * BEAM_SPEED * gameTime.ElapsedGameTime.Milliseconds / 16.0);
Y += (int)(directionVector.Y * BEAM_SPEED * gameTime.ElapsedGameTime.Milliseconds / 16.0);// Check if sword is on screen
if (!IsOnScreen())
{
IsActive = false;
}
}// Update animation as well
base.Update(gameTime);
}///
/// Check if the projectile is on screen, with some padding around the edge
////// True if the projectile is still on screen, false otherwise
private bool IsOnScreen()
{
// Check that the object is actually located on screen, with some padding (100px)
Rectangle bounds = Bounds;
Rectangle roomBounds = GameContext.World.CurrentRoomTileSet.GetRoomBounds(GameContext.Window.RoomX, GameContext.Window.RoomY);
roomBounds.Inflate(100, 100);
return bounds.Intersects(roomBounds);
}///
/// Draw the sword
////// SpriteBatch to draw with
public override void Draw(SpriteBatch spriteBatch)
{
if (isShooting)
{
// The sword is outside Link, draw it
base.Draw(spriteBatch);
}
}///
/// Bounds of the projectile for collision detection
///public override Rectangle Bounds
{
get
{
if (isShooting)
{
// Smaller hitbox on the beam
return new Rectangle(X + Width / 4, Y + Height / 4, Width / 2, Height / 2);
}
else
{
// Rectangular bounds for the sword
int width = 14 * GameContext.Window.Scale;
int height = 14 * GameContext.Window.Scale;
int offsetX = (int)(directionVector.X * LINK_SWORD_OFFSET);
int offsetY = (int)(directionVector.Y * LINK_SWORD_OFFSET);// Move it in the right direction, but only after a couple frames
if (currentSwordFrame >= 2)
{
X += offsetX;
Y += offsetY;// Return bounds relative to sword point
return new Rectangle(X + offsetX, Y + offsetY, width, height);
}
else
{
return Rectangle.Empty;
}
}
}
}///
/// Collision group of the sword
///public override CollisionGroup CollisionGroup
{
get
{
return CollisionGroup.LinkProjectile;
}
}///
/// Check what to do when the sword collides with a collidable object
////// The object the sword hit
public override void OnCollision(ICollidable obj)
{
// See what the sword hit
if (obj.CollisionGroup == CollisionGroup.Enemy)
{
if (isShooting)
{
// Damage enemy (handled by enemy)
IsActive = false;
GameManager.Instance.ParticleManager.CreatePoof(Bounds.Center.X, Bounds.Center.Y);
}
}
else if (obj.CollisionGroup == CollisionGroup.Block && isShooting)
{
// Hit a wall
IsActive = false;
GameManager.Instance.ParticleManager.CreatePoof(Bounds.Center.X, Bounds.Center.Y);
}
}///
/// Get the current speed of the projectile
///public double Speed
{
get
{
return 0; // Can’t change this
}
set
{
// do nothing
}
}///
/// Get the direction the projectile is moving in
///public ILink.Direction Direction
{
get
{
return direction;
}
set
{
if (!isShooting)
{
direction = value;
directionVector = directionToXYMap[value];
SetAnimation(getSwordAnim(direction, currentSwordFrame));
}
}
}///
/// Get the location of the sword
///public override Point Location
{
get
{
return new Point(X, Y);
}
}///
/// Get the size of the sword
///public override Point Size
{
get
{
if (isShooting)
{
// Beam sprite
switch (direction)
{
case ILink.Direction.North:
case ILink.Direction.South:
return new Point(8 * GameContext.Window.Scale, 16 * GameContext.Window.Scale);
case ILink.Direction.East:
case ILink.Direction.West:
return new Point(16 * GameContext.Window.Scale, 8 * GameContext.Window.Scale);
default:
return new Point(16 * GameContext.Window.Scale, 8 * GameContext.Window.Scale);
}
}
else
{
// Link’s sword animation
switch (direction)
{
case ILink.Direction.North:
case ILink.Direction.South:
return new Point(16 * GameContext.Window.Scale, 27 * GameContext.Window.Scale);
case ILink.Direction.East:
case ILink.Direction.West:
return new Point(27 * GameContext.Window.Scale, 16 * GameContext.Window.Scale);
default:
return new Point(27 * GameContext.Window.Scale, 16 * GameContext.Window.Scale);
}
}
}
}///
/// Get or set the X position of the sword
///public int X { get; set; }
///
/// Get or set the Y position of the sword
///public int Y { get; set; }
///
/// Get the width of the sword based on direction
///public override int Width
{
get
{
if (isShooting)
{
// Beam sprite
switch (direction)
{
case ILink.Direction.North:
case ILink.Direction.South:
return 8 * GameContext.Window.Scale;
case ILink.Direction.East:
case ILink.Direction.West:
return 16 * GameContext.Window.Scale;
default:
return 16 * GameContext.Window.Scale;
}
}
else
{
// Link’s sword animation
switch (direction)
{
case ILink.Direction.North:
case ILink.Direction.South:
return 16 * GameContext.Window.Scale;
case ILink.Direction.East:
case ILink.Direction.West:
returnKolejne rozdziały
Zapraszamy do dalszego czytania naszego leksykonu.
Wybierz kolejny rozdział z menu poniżej, aby otworzyć nową podstronę kompedium wiedzy i uzyskać szczegółowe informację o leku, substancji lub chorobie.