JOSEPH SIEREJKO
GAME DEVELOPER : PROGRAMMER : DESIGNER
| roles | Lead Programmer • 2D Artist • UI |
| software | MonoGame • Unity Engine • Adobe Photoshop • Visual Studio |
| languages | C# • Visual C# |
| team size |
Vector2 HorizontalCollisionTest(Vector2 movement)
{
if (movement.X == 0) //No need to test collision on X Axis
return movement;
Rectangle moveTestCollider = BoxCollider;
//Get the path of next movement by offsetting the collider
moveTestCollider.Offset((int)movement.X, 0);
Vector2 topPixel, bottomPixel;
if (movement.X < 0)
{
topPixel = new Vector2(moveTestCollider.Left, moveTestCollider.Top + 1); //Gets top left corner of movement
bottomPixel = new Vector2(moveTestCollider.Left, moveTestCollider.Bottom - 1); //Gets bottom left corner of movement
}
else
{
topPixel = new Vector2(moveTestCollider.Right, moveTestCollider.Top + 1); //Gets top right corner of movement
bottomPixel = new Vector2(moveTestCollider.Right, moveTestCollider.Bottom - 1); //Gets bottom right corner of movement
}
//Covers the 2 tiles, taking the possibility that player is jumping or falling (Y position)
Vector2 topCell = TileMap.GetCellByPixel(topPixel);
Vector2 bottomCell = TileMap.GetCellByPixel(bottomPixel);
//Tests Cells for collision
if (TileMap.IsColliding(topCell) || TileMap.IsColliding(bottomCell))
{
movement.X = 0; //Disable movement on X
velocity.X = 0; //Cancel velocity for current frame
}
return movement;
}
static public Rectangle CellWorldCollider(int cellX, int cellY)
{
Tile tile = GetTileAtCell(cellX, cellY);
if(tile != null)
return new Rectangle(
(cellX * TileWidth) + tile.boundX,
(cellY * TileHeight) + tile.boundY,
tile.boundWidth, tile.boundHeight);
return new Rectangle(0,0,0,0);
}
//Collider ScreenSpace Rectangle for tile
static public Rectangle CellScreenCollider(int cellX, int cellY) =>
Camera.WorldToScreen(CellWorldCollider(cellX, cellY));
//Given the pieces of a coordinate, return whether the Cell has active collision
static public bool IsColliding(int cellX, int cellY)
{
Tile tile = GetTileAtCell(cellX, cellY);
if (tile == null)
return false;
else
return tile.CollisionEnabled;
}
static public bool IsCollidingByPixel(Vector2 pixelLocation) =>
IsColliding(
GetCellByPixelX((int)pixelLocation.X),
GetCellByPixelY((int)pixelLocation.Y));
static public bool IsColliding(Vector2 cell) => IsColliding((int)cell.X, (int)cell.Y);
#region Selection
public static Slot GetSlot(int index) => Slots[index];
//Takes current index and moves it by a specified amount
static void TranslateToActiveSlot(int amount)
{
SlotIndex += amount;
CurrentSelectedSlot = GetSlot(SlotIndex);
moveCurrentTime = 0f;
}
//Direcly Set the Current Slot
static void SetActiveSlot(int index)
{
SlotIndex = index;
CurrentSelectedSlot = GetSlot(SlotIndex);
moveCurrentTime = 0f;
}
public static void HandleSlotSelection(GameTime gameTime)
{
KeyboardState kState = Keyboard.GetState();
//Timer - allows holding key down without moving every frame
moveCurrentTime += (float)gameTime.ElapsedGameTime.TotalSeconds;
if (moveCurrentTime < moveSelectionTimer) return;
if (kState.IsKeyDown(Keys.Up) & SlotIndex - ColCount >= 0)
{
TranslateToActiveSlot(-ColCount); //Move up a row
}
else if (kState.IsKeyDown(Keys.Down) & (SlotIndex + ColCount < Slots.Count))
{
TranslateToActiveSlot(ColCount); //Move down a row
}
else if (kState.IsKeyDown(Keys.Left) & SlotIndex > 0)
{
TranslateToActiveSlot(-1); //Move Left
}
else if (kState.IsKeyDown(Keys.Right) & (SlotIndex + 1 < Slots.Count))
{
TranslateToActiveSlot(1); //Move Right
}
}
#endregion
#region Add, Remove, and Manage Items
public static void AddItem(Item item)
{
if (IsFull) return;
//First loop checks for item by ID in reduced list
foreach(Slot slot in OccupiedSlots)
if (slot.CurrentItem.ID == item.ID)
{
slot.PushItem(item);
return;
}
//Second Loop finds an unoccupied slot
foreach (Slot slot in Slots)
if (!slot.IsOccupied)
{
EmptySlots--;
slot.PushItem(item);
return;
}
}
public static Item DropSelectedItem() => CurrentSelectedSlot.PopItem();
//Push all stacks in slots to front of list
public static void Reorganize()
{
for(int i = 0; i < Slots.Count - 1;)
{
//Current slot is empty and next slot has stack, push stack back one index
//Keep pushing Slots back until they all Slots are pushed to front of list
if (!Slots[i].IsOccupied & Slots[i + 1].IsOccupied)
{
SwapSlotItems(i, i+1);
//Avoid out of range
if(i > 0) i--;
continue;
}
i++;
}
}
//A/B Swap Function
public static void SwapSlotItems(int a, int b)
{
//Temp stack reference
Stack<Item> items = Slots[a].Items;
Slots[a].Items = Slots[b].Items;
Slots[b].Items = items;
ChangeSprite(a);
ChangeSprite(b);
}
#endregion
#region Add and Remove Items
//Throws set number of stacks out
internal void RemoveItems(int quantity)
{
for(int i = 0; i < quantity; i++) PopItem();
}
//Get an item from Item Stack
internal Item PopItem()
{
if (!IsOccupied) //If stack is empty before popping, return nothing
return null;
Item pop = items.Pop(); //Get the next item in stack
if (!IsOccupied) //If stack is empty after popping an item
{
ChangeSprite(); //Change UISprite back to default empty slot
InventoryManager.EmptySlots++; //Give a Slot back to inventory
}
UpdateText();
return pop;
}
//Add an item into item stack
internal void PushItem(Item item)
{
ChangeSprite(item.UIFrameX, item.UIFrameY); //If slot is empty, set to item's UI Sprite
items.Push(item); //Add item to slot
UpdateText();
}
#endregion
#region Font Handling
internal void UpdateText()
{
if (Count <= 1)
uiCount.Text = "";
else
uiCount.Text = Count.ToString();
}
#endregion
/// <summary>
/// Get individual slot X position in Screen Space
/// </summary>
/// <param name="col">col of slot in array</param>
/// <param name="screenSpaceAnchorX">X position of slot as percent (0.0 - 1.0)</param>
/// <returns>X Position in Screen space as pixels</returns>
public static int GetSlotPositionX(int col, float screenSpaceAnchorX = 0f)
{
int screenSpaceX = (int)(Camera.ViewPortWidth * screenSpaceAnchorX);
int offset = col * SlotWidth - (ColCount * SlotWidth) / 2;
return screenSpaceX + offset;
}
/// <summary>
/// Set slot position relative to another UI Element or Screen Space position
/// </summary>
/// <param name="col">col of slot in array</param>
/// <param name="relativeTo">Offset relative to another Screen space position</param>
/// <returns>X Position in Screen space as pixels</returns>
public static int GetSlotRelativePositionX(int col, int relativeTo) =>
GetSlotPositionX(col) + relativeTo;
/// <summary>
/// Set slot position relative to another Screen Space position, with margins between cols
/// </summary>
/// <param name="col">col of slot in array</param>
/// <param name="relativeTo">Offset relative to another Screen space position</param>
/// <param name="spaceBetweenCols">Offset relative to another Screen space position</param>
/// <returns>X Position in Screen space as pixels</returns>
public static int GetSlotRelativePositionX(int col, int relativeTo, int spaceBetweenCols)
{
int relativeSlotPositionX = GetSlotRelativePositionX(col, relativeTo);
int spacing = (spaceBetweenCols * (col % ColCount)) - spaceBetweenCols;
return relativeSlotPositionX + spacing;
}
/// <summary>
/// Get individual Slot Y position in Screen Space
/// </summary>
/// param name="row">Row of slot in array</param>
/// <param name="screenSpaceAnchorY">Y position of slot as percent (0.0 - 1.0)</param>
/// <returns>Slot Y Position in Screen space as pixels</returns>
public static int GetSlotPositionY(int row, float screenSpaceAnchorY = 0f)
{
int screenSpaceY = (int)(Camera.ViewPortHeight * screenSpaceAnchorY);
int offset = row * SlotHeight - (RowCount * SlotHeight) / 2;
return screenSpaceY + offset;
}
/// <summary>
/// Get Slot Y Position relative to another Screen Space Position
/// </summary>
/// <param name="row">Row of Slot in array</param>
/// <param name="relativeTo">Offset relative to another Screen Space Position</param>
/// <returns>X Position in Screen space as pixels</returns>
public static int GetSlotRelativePositionY(int row, int relativeTo) => GetSlotPositionY(row) + relativeTo;
/// <summary>
/// Get Slot Y Position relative to another Screen Space Position, with space between Rows
/// </summary>
/// <param name="row">col of slot in array</param>
/// <param name="relativeTo">Offset relative to another Screen space position</param>
/// <param name="spaceBetweenRows">Offset relative to another Screen space position</param>
/// <returns>X Position in Screen space as pixels</returns>
public static int GetSlotRelativePositionY(int row, int relativeTo, int spaceBetweenRows)
{
int relativeSlotPositionY = GetSlotRelativePositionY(row, relativeTo);
int spacing = (spaceBetweenRows * (row % RowCount)) - spaceBetweenRows;
return relativeSlotPositionY + spacing;
}
//Assign slot positions based on anchor points
public static void SetSlotPosition(int col, int row,
float screenSpaceAnchorX = 0f, float screenSpaceAnchorY = 0f)
{
Slot currentSlot = GetSlot(row * ColCount + col); //Get slot out of list
int x = GetSlotPositionX(col, screenSpaceAnchorX);
int y = GetSlotPositionY(row, screenSpaceAnchorY);
currentSlot.SetPosition(x, y);
}
//Assign Slot Position using anchor point (center position)
public static void SetSlotRelativePosition(int col, int row,
int relativeX, int relativeY)
{
Slot currentSlot = GetSlot(row * ColCount + col); //Get slot out of list
int x = GetSlotRelativePositionX(col, relativeX);
int y = GetSlotRelativePositionY(row, relativeY);
currentSlot.SetPosition(x, y);
}
//Assign Slot Position relative to a Screen Space Position
public static void SetSlotRelativePosition(int col, int row,
int relativeX, int relativeY, int spaceBetweenCols, int spaceBetweenRows)
{
Slot currentSlot = GetSlot(row * ColCount + col); //Get slot out of list
int x = GetSlotRelativePositionX(col, relativeX, spaceBetweenCols);
int y = GetSlotRelativePositionY(row, relativeY, spaceBetweenRows);
currentSlot.SetPosition(x, y);
}
public static void SetInventoryLayout(int rows, int cols,
float screenSpaceAnchorX, float screenSpaceAnchorY)
{
SetSlotGrid(rows, cols);
for(int i = 0; i < Slots.Count; i++)
{
int row = i / cols,
col = i % cols;
SetSlotPosition(col, row, screenSpaceAnchorX, screenSpaceAnchorY);
}
}
public static void SetInventoryLayout(int rows, int cols,
int relativeX, int relativeY, int spaceBetweenCols = 0, int spaceBetweenRows= 0)
{
SetSlotGrid(rows, cols);
for (int i = 0; i < Slots.Count; i++)
{
int row = i / cols,
col = i % cols;
SetSlotRelativePosition(col, row, relativeX, relativeY, spaceBetweenCols, spaceBetweenRows);
}
}
internal void AddSpriteSheet(string fileName, int animationFrames)
{
if (!listSpriteSheet.Items.Contains(fileName)) //Sprite is not loaded in already
{
string filePath = Application.StartupPath + @"\Content\Textures\" + fileName;
Bitmap newSpriteSheet = new Bitmap(filePath);
int spriteSheetIndex = spriteSheets.Count; //SpriteSheet number
spriteSheets.Add(newSpriteSheet);
spriteFrames.Add(animationFrames); //If SpriteSheet is an animated strip
listSpriteSheet.Items.Add(fileName); //Add SpriteSheet to List
Settings.AddSpriteSheet(fileName, animationFrames); //Add SpriteSheet for Saving in User Settings
}
}
void LoadImageList()
{
imgListTiles.Images.Clear();
listTiles.Items.Clear();
Bitmap loadedSpriteSheet = spriteSheets[CurrentSpriteSheet];
int tileCount = 0;
for (int i = 0; i < (loadedSpriteSheet.Width / TileMap.TileWidth) / spriteFrames[CurrentSpriteSheet]; i++)
for (int j = 0; j < loadedSpriteSheet.Height / TileMap.TileHeight; j++)
{
//Cut a tile out of larger bitmap
Bitmap newBitmap = loadedSpriteSheet.Clone(
new System.Drawing.Rectangle(
i * TileMap.TileWidth, j * TileMap.TileHeight,
TileMap.TileWidth, TileMap.TileHeight), System.Drawing.Imaging.PixelFormat.DontCare);
imgListTiles.Images.Add(newBitmap); //Add to list of images
string itemName = "";
if (tileCount == 0)
itemName = "Empty";
//Add a new listview item
listTiles.Items.Add(new ListViewItem(itemName, tileCount++));
}
}
#region Save And Load User Settings
public void SaveSettings()
{
BinaryFormatter formatter = new BinaryFormatter();
FileStream fileStream = new FileStream(Application.StartupPath + @"\Settings\Settings.txt", FileMode.OpenOrCreate);
formatter.Serialize(fileStream, Settings);
fileStream.Close();
}
public void LoadSettings()
{
if (File.Exists(Application.StartupPath + @"\Settings\Settings.txt"))
{
BinaryFormatter formatter = new BinaryFormatter();
FileStream fileStream = new FileStream(Application.StartupPath + @"\Settings\Settings.txt", FileMode.Open);
Settings = (Settings)formatter.Deserialize(fileStream);
RestoreEditorSettings(); //Add loaded settings to Editor Window Form
fileStream.Close();
}
else
AddSpriteSheet("TerrainSpriteSheet.png", 1); //If load fails/ no file located in folder, reinitialize with default sprite sheet
}
void RestoreEditorSettings()
{
//Add all the saved user code values to combo box
for (int i = 0; i < Settings.cboCodeValues.Count; i++)
cboCodeValues.Items.Add(Settings.cboCodeValues[i]);
itemCodeValues.AddRange(Settings.gameCodeValues); //Make all code values available to TileEngine
//Add all loaded sprite sheets
for (int i = 0; i < Settings.spriteSheets.Count; i++)
AddSpriteSheet(Settings.spriteSheets[i], Settings.spriteSheetFrames[i]);
}
public void RestoreTileMapSettings()
{
if (Settings.spriteSheets.Count > 0)
for (int i = 0; i < Settings.spriteSheets.Count; i++)
TileMap.AddSpriteSheet(Settings.spriteSheets[i].Replace(".png", ""));
else
TileMap.AddSpriteSheet("TerrainSpriteSheet");
}
#endregion
void browseButton_Click(object sender, EventArgs e)
{
using (openFileDialog)
{
openFileDialog.InitialDirectory = "c:\\"; //Starting directory
//Acceptable File Types
openFileDialog.Filter = "Image Files (*.png, *.jpg) | *.jpg; *.png | All Files (*.*) | *.*";
openFileDialog.FilterIndex = 2;
openFileDialog.RestoreDirectory = true;
if(openFileDialog.ShowDialog() == DialogResult.OK)
{
//Assign found image to file
File = Image.FromFile(openFileDialog.FileName);
//Display in textBox
filePath = openFileDialog.FileName;
directoryPath = Path.GetDirectoryName(filePath);
Stream fileStream = openFileDialog.OpenFile();
using(StreamReader reader = new StreamReader(fileStream))
{
fileContent = reader.ReadToEnd();
}
}
}
txtBoxFilePath.Text = openFileDialog.SafeFileName;
}
private void btnImport_Click(object sender, EventArgs e)
{
if(File != null && openFileDialog != null)
File.Save(Application.StartupPath + "\\Content\\Textures\\" + openFileDialog.SafeFileName);
editor.AddSpriteSheet(txtBoxFilePath.Text, (int)cboAnimationFrames.SelectedItem);
}
//Set a new Tile to cell at index
public static void SetTileAtCell(int tileX, int tileY, Tile tile)
{
if (IsInMapBounds(tileX, tileY))
mapCells[tileX, tileY] = tile;
}
//Overload --- Updates the Current Tile at index
static public void SetTileAtCell(int x, int y, int layer, int tileIndex,
int spriteSheetIndex, string animationKey = "", string animationMode = "", float frameTimer = 0.0f)
{
if (!IsInMapBounds(x, y)) return;
Tile tile = mapCells[x, y];
tile.ClearAnimation(layer); //Remove any animations on layer
tile.LayerTiles[layer] = tileIndex;
tile.LayerSpriteSheetIndices[layer] = spriteSheetIndex;
tile.AnimationKey[layer] = animationKey; //Tagging for animation
tile.AnimationPlayMode[layer] = animationMode; //How animation plays back
tile.FrameTimer = frameTimer; //Frame speed
}
//Set collision for a tile by map location
static public void SetTileCollider(int x, int y, int boundX, int boundY, int width, int height)
{
if (IsInMapBounds(x, y))
SetTileCollider(ref mapCells[x, y], boundX, boundY, width, height);
}
//Set collision directly to Tile
static public void SetTileCollider(ref Tile tile, int boundX, int boundY, int width, int height)
{
tile.boundX = boundX;
tile.boundY = boundY;
tile.boundWidth = width;
tile.boundHeight = height;
}
//***********************************************//
#region Saving and Loading
//Serialize map to binary for saving
public static void Save(FileStream fileStream)
{
//Resets all animations to frame zero when saving!
foreach (Tile tile in mapCells)
for (int i = 0; i < tile.LayerTiles.Length; i++)
if (tile.LayersCurrentSprite[i].Count > 0)
{
tile.LayerTiles[i] = tile.LayersCurrentSprite[i][0];
}
BinaryFormatter formatter = new BinaryFormatter();
formatter.Serialize(fileStream, mapCells);
fileStream.Close();
}
//Deserialize map for loading
public static bool Load(FileStream fileStream)
{
try
{
BinaryFormatter formatter = new BinaryFormatter();
mapCells = (Tile[,])formatter.Deserialize(fileStream);
fileStream.Close();
Console.WriteLine(fileStream.ToString());
return true;
}
catch
{
Console.WriteLine("No Map found for stream: " + fileStream.ToString());
fileStream.Close();
return false;
}
}
#endregion
//***********************************************//
//***********************************************//
#region Tile Sheet Methods
public static void AddSpriteSheet(string fileName)
{
if (!tileSheets.Contains(Content.Load<Texture2D>(@"Textures\" + fileName)))
tileSheets.Add(Content.Load<Texture2D>(@"Textures\" + fileName));
}
//Number of Tiles in a Row of the tileSheet
public static int TilesPerCol(int spriteSheetIndex) =>
tileSheets[spriteSheetIndex].Height / TileHeight;
//Get a tile from the tilesheet based on the index
public static Rectangle TileSourceRectangle(int tileIndex, int spriteSheetIndex)
{
//Uses 2D-to-1D conversion to get a tile from the tileSheet
return new Rectangle(
(tileIndex / TilesPerCol(spriteSheetIndex)) * TileWidth,
(tileIndex % TilesPerCol(spriteSheetIndex)) * TileHeight,
TileWidth, TileHeight);
}
//Gets the items Sprite Sheet Location
public static Rectangle ItemSourceRectangle(Item item)
{
return new Rectangle(
item.FrameX * TileWidth, item.FrameY * TileHeight,
item.FrameWidth, item.FrameHeight);
}
#endregion
//***********************************************//
void LoadImageList()
{
imgListTiles.Images.Clear();
listTiles.Items.Clear();
Bitmap loadedSpriteSheet = spriteSheets[CurrentSpriteSheet];
int tileCount = 0;
for (int i = 0; i < (loadedSpriteSheet.Width / TileMap.TileWidth) / spriteFrames[CurrentSpriteSheet]; i++)
for (int j = 0; j <= loadedSpriteSheet.Height / TileMap.TileHeight; j++)
{
//Cut a tile out of larger bitmap
Bitmap newBitmap = loadedSpriteSheet.Clone(
new System.Drawing.Rectangle(
i * TileMap.TileWidth, j * TileMap.TileHeight,
TileMap.TileWidth, TileMap.TileHeight), System.Drawing.Imaging.PixelFormat.DontCare);
imgListTiles.Images.Add(newBitmap); //Add to list of images
string itemName = "";
if (tileCount == 0)
itemName = "Empty";
//Add a new listview item
listTiles.Items.Add(new ListViewItem(itemName, tileCount++));
}
}

internal int FrameCount => texture.Width / frameWidth;
//Get current frame of animation
internal Rectangle FrameRectangle =>
new Rectangle(
CurrentFrame * frameWidth, 0,
frameWidth, frameHeight);
#region Constructor
public Animation(Texture2D texture, int frameWidth, string
name)
{
this.texture = texture;
this.frameWidth = frameWidth;
this.frameHeight = texture.Height;
this.name = name;
}
#endregion
#region Methods
internal void BeginPlay()
{
CurrentFrame = 0;
isPlaying = true;
}
//Called when isPlaying
internal void Play(GameTime gameTime)
{
frameTick += (float)gameTime.ElapsedGameTime.TotalSeconds;
if (frameTick < frameDelay) return;
frameTick = 0f;
CurrentFrame++;
//End of animation
if (CurrentFrame >= FrameCount)
{
if(loopingAnimation)
CurrentFrame = 0; //Reset Animation
else
{
CurrentFrame = FrameCount - 1; //End of Animation
isPlaying = false; //Stop playing animation
}
}
}
#endregion
//Checks Current Animation Status and Updates if Required
void UpdateAnimation(GameTime gameTime)
{
if (animations.ContainsKey(currentAnimation)) //Check in LookUpTable for anim
//Check if animation status is finished
if (!animations[currentAnimation].IsPlaying)
{
//Get next animation if applicable
PlayAnimation(animations[currentAnimation].NextAnimation);
}
else
animations[currentAnimation].Play(gameTime); //Continue playing Animation
}
//Checks if animation exists in Lookup Table and Plays if found
internal void PlayAnimation(string name)
{
if (name != null && animations.ContainsKey(name))
{
currentAnimation = name;
animations[name].BeginPlay();
}
}