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(); } }