Friday, October 30, 2020

Weeklly Game Jam 173 - Secret Door

There is another weekly game jam that started today with a theme I can totally get behind, Secret Door. So, I'm doing a Rogue-like with secret doors. Hopefully I come up with some original game ideas over the next few days. 

I don't have a map rendering in MonoGame yet but I have a map being created. I just need to convert it to a tile map and all will be good. I should have that up and running tonight, tomorrow for sure. I will post a video tomorrow of my progress. If had something visual I would tonight.

Thursday, October 29, 2020

Second Collision Detection Tutorial Is Live

I have just published the second tutorial in my collision detection mini-series aimed at beginners. This tutorial covers doing collision detection with multiple bounding boxes and with bounding circles. You can find the tutorials on the MonoGame Tutorials page of the site. You can also use this direct link.

Wednesday, October 28, 2020

Beginner Collision Detect Tutorial

I have added a general tutorial on collision detection in MonoGame. It starts with the basics of testing for bounding box collision detection. It then moves to pixel based collision detection followed by collision detection of rotated objects. I will be doing another tutorial that covers alternate collision detection like multiple bounding boxes, bounding circles and a full explanation of per pixel collision detection on rotated animated sprites. You can find the link to the tutorial on the MonoGame Tutorials page of the site or you can use this direct link.

Tuesday, October 27, 2020

Per Pixel Collision Detection on Rotated and Scaled Sprites

This post about detecting collision between two rotated and/or scaled sprites where the sprites are part of a sprite sheet. I found lots of examples of detecting entire sprites but not so much for sprite sheets. This is an extension of my previous post about detecting if two sprites in sprite sheets collide.

For this to work you need to create a transformation matrix for each sprite. It is calculated by using the following formula: Matrix.CreateTranslation(new Vector3(-Origin, 0)) * Matrix.CreateScale(Scale) * Matrix.CreateRotationZ(Rotation) * Matrix.CreateTranslation(new Vector3(Position, 0)). Origin is calculated by (SourceRectangle.Width / 2, SourceRectangle.Height / 2).

The collision method takes six parameters: the source rectangle of sprite A, the transformation matrix of sprite A, the sprite sheet of sprite A, the source rectangle of sprite B, the transformation matrix of sprite B and the sprite sheet of sprite B. If a source rectangle is null the entire sprite sheet will be used.

It calls a second method that does the actual collision detection. It takes as parameters the source rectangle of sprite A, the transformation matrix of sprite A, the color data of sprite A, the source rectangle of sprite B, the transformation matrix of sprite B and the color data of sprite B.



/// <summary>
/// Checks if two sprites in a sprite sheet collide using per pixel collision detection
/// </summary>
/// <param name="sourceA">Nullable source rectangle of sprite A in the sprite sheet</param>
/// <param name="transformA">Transformation matrix for sprite A</param>
/// <param name="textureA">Texture for sprite sheet A</param>
/// <param name="transformB">Transformation matirx for sprite B</param>
/// <param name="sourceB">Nullable source rectangle of sprite B in the sprite sheet</param>
/// <param name="textureB">Texture for sprite sheet B</param>
/// <returns></returns>
public static bool SpriteSheetCollision(
    Rectangle? sourceA,
    Matrix transformA,
    Texture2D textureA,
    Rectangle? sourceB,
    Matrix transformB,
    Texture2D textureB)
{
    // If the sourceA is null use entire texture
    if (sourceA == null)
    {
        sourceA = new Rectangle(0, 0, textureA.Width, textureA.Height);
    }

    // Grab the texture data for checking if the pixels collide in the source rectangle
    Color[] textureDataA = new Color[sourceA.Value.Width * sourceA.Value.Height];
    textureA.GetData(0, sourceA, textureDataA, 0, textureDataA.Length);

    // If the sourceB is null use the entire texture as the source rectangle
    if (sourceB == null)
    {
        sourceB = new Rectangle(0, 0, textureB.Width, textureB.Height);
    }

    // Grab the texture data for checking if the pixels collide in the source rectangle
    Color[] textureDataB = new Color[sourceB.Value.Width * sourceB.Value.Height];
    textureB.GetData(0, sourceB, textureDataB, 0, textureDataB.Length);

    // Call the per pixel collision detection code
    return ColorDataCollides(sourceA.Value, transformA, textureDataA, sourceB.Value, transformB, textureDataB);
}

/// <summary>
/// Checks if two sprites collide using pixel perfect collision detection
/// where the sprites are rotated and/or scaled.
/// </summary>
/// <param name="sourceA">Source rectangle of sprite A in the sprite sheet</param>
/// <param name="transformA">The transformation matrix of sprite A</param>
/// <param name="textureDataA">The color data of sprite A</param>
/// <param name="sourceB">Source rectangle of sprite B in the sprite sheet</param>
/// <param name="transformB">The transformation matrix of sprite B</param>
/// <param name="textureDataB">The color data of sprite B</param>
/// <returns></returns>
private static bool ColorDataCollides(Rectangle sourceA, Matrix transformA, Color[] textureDataA, Rectangle sourceB, Matrix transformB, Color[] textureDataB)
{
    // Transformation of sprite A to sprite B
    Matrix mat1to2 = transformA * Matrix.Invert(transformB);

    // Loop over the source rectangle of sprite A
    for (int x1 = 0; x1 < sourceA.Width; x1++)
    {
        for (int y1 = 0; y1 < sourceA.Height; y1++)
        {
        
            // Calculate the position of the pixel in sprite A in sprite B
            Vector2 pos1 = new Vector2(x1, y1);
            Vector2 pos2 = Vector2.Transform(pos1, mat1to2);

            // Round to the nearest pixel
            int x2 = (int)Math.Round(pos2.X);
            int y2 = (int)Math.Round(pos2.Y);

            // Check to see if the pixel in sprite A is in the bounds of sprite B
            if ((x2 >= 0) && (x2 < sourceB.Width))
            {
                if ((y2 >= 0) && (y2 < sourceB.Height))
                {
                    // If the alpha channel of sprite A and sprite B is greater
                    // than zero we have a collision
                    if (textureDataA[x1 + y1 * sourceA.Width].A > 0)
                    {
                        if (textureDataB[x2 + y2 * sourceB.Width].A > 0)
                        {
                            return true;
                 }
                    }
                }
            }
        }
    }

    // No collision occurred
    return false;
}

The first method is similar to the previous method I posted the other day. It takes transformation matrices instead of destination rectangles. It uses the GetData method overload that takes a source rectangle. For starting position you need to use 0. If your texture has multiple levels you will want to repeat the testing for the different levels.

The second method does the actual collision detection. It calculates a matrix that is used to map the pixels in sprite A to the pixels in sprite B. That is done by multiplying the transformation matrix of sprite A by the inverse transformation of sprite B. I suggest reading up on matrix transformation if you're unclear about what is going on.

Next we loop over all of the pixels in sprite A and test if the collide with a pixel in sprite B. Inside the loops I create a vector for the current pixel in sprite A, or 1 in the code. I transform that vector next using the matrix we calculated earlier. I round the points to integers.

The next step is to check if the transformed pixel is inside the bounds of sprite B. If it is I compare the alpha channel of the two pixels. If their alpha channel are both greater than zero there is a collision and I return true. If a collision is not found I return false.

If you have questions leave a comment and I will answer them. I hope that you find the methods useful.

Monday, October 26, 2020

Space Raptor Tutorial 3 Is Live

 I have just posted tutorial. 3 in the Space Raptor tutorial series to the site. This tutorial adds in some backgrounds and frames per second counter. It also adds in a shield for the player that drains over time and regenerates slowly. I also add in a power up that gives the player three way shot for a limited time. You can find the tutorial on the MonoGame tutorial page of the site or you can download it from this direct link.

Per Pixel Sprite Sheet Collision Detection

 I've seen this question asked a few times but no public answers. How do you detect if two sprites in a sprite sheet collide using per pixel collision detection? The answer for entire sprites is available easily. I made two static methods that can be added to a project to check if two parts of a sprite sheet collide. Soon I will be posting code that handles rotated and scaled sprites as well.



public static bool SpriteSheetCollision(
    Rectangle destinationA, 
    Rectangle? sourceA, 
    Texture2D textureA,
    Rectangle destinationB,
    Rectangle? sourceB,
    Texture2D textureB)
{
    // If the sourceA is null use entire texture
    if (sourceA == null)
    {
        sourceA = new Rectangle(0, 0, textureA.Width, textureA.Height);
    }

    // Grab the texture data for checking if the pixels collide in the source rectangle
    Color[] textureDataA = new Color[sourceA.Value.Width * sourceA.Value.Height];
    textureA.GetData(0, sourceA, textureDataA, 0, textureDataA.Length);

    // If the sourceB is null use the entire texture as the source rectangle
    if (sourceB == null)
    {
        sourceB = new Rectangle(0, 0, textureB.Width, textureB.Height);
    }

    // Grab the texture data for checking if the pixels collide in the source rectangle
    Color[] textureDataB = new Color[sourceB.Value.Width * sourceB.Value.Height];
    textureB.GetData(0, sourceB, textureDataB, 0, textureDataB.Length);

    // Call the per pixel collision detection code
    return ColorDataCollides(destinationA, textureDataA, destinationB, textureDataB);
}

public static bool ColorDataCollides(Rectangle a, Color[] textureDataA, Rectangle b, Color[] textureDataB)
{
    // Find the bounds of the rectangle intersection
    int top = Math.Max(a.Top, b.Top);
    int bottom = Math.Min(a.Bottom, b.Bottom);
    int left = Math.Max(a.Left, b.Left);
    int right = Math.Min(a.Right, b.Right);

    // Check every point within the intersection bounds
    for (int y = top; y < bottom; y++)
    {
        for (int x = left; x < right; x++)
        {
            // Get the color of both pixels at this point
            Color colorA = textureDataA[(x - a.Left) +
                                    (y - a.Top) * a.Width];
            Color colorB = textureDataB[(x - b.Left) +
                                    (y - b.Top) * b.Width];

            // If both pixels are not completely transparent,
            if (colorA.A > 0 && colorB.A > 0)
            {
                // then an intersection has been found
                return true;
            }
        }
    }

    // No intersection found
    return false;
}

Sunday, October 25, 2020

Frames Per Second Counter

So, I'm going to try something new. I'm not happy with the way it is rendering 100% but it should copy/paste fine. Most probably have one by now but I thought I'd share my frames per second component outside of a tutorial on its own. It renders the FPS into the title bar of the window and the output log in Visual Studio. I recommend using the base constructor and adding it to the list of game components in the constructor using Components.Add(new FramesPerSecond(this)).

UPDATE: I fixed the issues I had with code.


using System;
using Microsoft.Xna.Framework;

namespace Psilibrary
{
    public sealed class FramesPerSecond : DrawableGameComponent
    {
        private float _fps;
        private float _updateInterval = 1.0f;
        private float _timeSinceLastUpdate = 0.0f;
        private float _frameCount = 0;

        public FramesPerSecond(Game game)
            : this(game, false, false, game.TargetElapsedTime)
        {
        }

        public FramesPerSecond(
            Game game, 
            bool synchWithVerticalRetrace, 
            bool isFixedTimeStep, 
            TimeSpan targetElapsedTime)
            : base(game)
        {
            GraphicsDeviceManager graphics = 
                (GraphicsDeviceManager)Game.Services.GetService(
                    typeof(IGraphicsDeviceManager));

            graphics.SynchronizeWithVerticalRetrace = synchWithVerticalRetrace;
            Game.IsFixedTimeStep = isFixedTimeStep;
            Game.TargetElapsedTime = targetElapsedTime;
        }

        public sealed override void Draw(GameTime gameTime)
        {
            float elapsed = (float)gameTime.ElapsedGameTime.TotalSeconds;
            _frameCount++;
            _timeSinceLastUpdate += elapsed;

            if (_timeSinceLastUpdate > _updateInterval)
            {
                _fps = _frameCount / _timeSinceLastUpdate;
                System.Diagnostics.Debug.WriteLine("FPS: " + _fps.ToString());
                Game.Window.Title = "FPS: " + ((int)_fps).ToString();
                _frameCount = 0;
                _timeSinceLastUpdate -= _updateInterval;
            }

            base.Draw(gameTime);
        }
    }
}

Space Raptor Tutorial 3 Status

I did some work on the next Space Raptor tutorial today. It covers adding in a shield for the player and a power up that gives the player a three way shot. It also adds a frames per second counter so you can gauge how well your game is performing. I'd recommend baselining it on an empty game so you know how hot your machine runs when it is unthrottled and what impact your code changes has on your games.

Saturday, October 24, 2020

Space Raptor Tutorial 2 Is Live

Sorry for not posting yesterday. I was not feeling well and didn't feel up to working on the computer. Today has been a better day though. I was able to work on programming and writing.

I have published the second tutorial in the Space Raptor mini-series to my site. This tutorial covers enemies firing bullets, explosions when the player or an enemy explode and pixel perfect collision detection between objects. You can find the tutorial on the MonoGame Tutorials page of the site or you can use this direct link.

Thursday, October 22, 2020

Space Raptor Tutorial One

 I have just published the first tutorial in my new MonoGame mini tutorial series Space Raptor. Space Raptor is a shoot 'em up or shmup that takes place in space. The object is to navigate through a sea of enemies and eventually defeat the final boss. This tutorial covers setting up the projects and adding in some basic components. It then moves to firing bullets and collision detection. You can find the tutorial on the MonoGame Tutorials page of my web site.

Wednesday, October 21, 2020

Shoot 'em Up (Shmup)

 I want to work on tutorials but I don't want these long involved tutorial series. I will still be working on the longer series but I want something shorter. For that reason I will be starting work on a Shoot 'em Up or Shmup. This will be a side scrolling game and will feature some more complex collision detection such as bounding circle, per pixel or pixel perfect collision detection. I will also be working on some other smaller games like platformers and probably a match three.

I'm planning out the next tutorial in Eyes of the Dragon. It will cover more work in the editor, saving the world from the editor and loading it back in again in the editor and the game.

Tuesday, October 20, 2020

Eyes of the Dragon Tutorial 6 is Live

I have published tutorial 6 in my Eyes of the Dragon tutorial series that is built using MonoGame. This tutorial starts building the game editor. The editor is unfortunately not cross platform and uses Windows Forms and DirectX. You can find the tutorial on the Eyes of the Dragon page of the site or you can use this direct link.

Sunday, October 18, 2020

Eyes of the Dragon Tutorial 6 Update

 I've made it about three quarters of the way through the next Eyes of the Dragon tutorial. As I've mentioned previously this tutorial focuses on creating a level editor for the game. I hope to wrap it up over the next few days. I've been busy with my app and it takes a lot of my attention.

Friday, October 16, 2020

Eyes of the Dragon Tutorial 6 Status and More

 I have started work on tutorial 6 in the Eyes of the Dragon tutorial series. This tutorial is about creating the editor for building worlds. It is unfortunately a Windows project instead of a cross platform solution because I use Win Forms. It is much easier to use the existing controls than trying to recreate them in MonoGame.

I've also been working on my app for Google Play and eventually the App Store. It is a mood tracker for people with bipolar disorder but more than that. It will also be a social media platform where they can connect with others with bipolar disorder.

I didn't work on my games much the past few days. I did do some work on Silver Prophet on my editor and in the editor. As I've said before, programming games is easy. Making the associated content that goes with them is what is hard. I'm looking at making a map that is 1000 tiles by 1000 tiles. That is hand painting a million tiles but more because my map has about five layers so that is up to five million tiles. That does not include all of the interior locations and dungeons. So, lots of work that is probably going to take years to complete. Even if I cut it in half I'm still looking at a million tiles.

Wednesday, October 14, 2020

Thanksgiving

Thanksgiving was nice, but smaller. There were half as many people as normal thanks to COVID-19. We did have the other half join virtually over zoom and my sister delivered their turkey dinners before hand. Yesterday was an off day. I just couldn't focus on anything. I puttered on my editor for Silver Prophet and did some level design. Nothing overly productive though. 

 I've started work on an app for Windows, Android and hopefully iOS eventually. It will be a free app, with ads, and is meant for people with bipolar, like me. It tracks their mood and sleep, which is very important. There are other apps that do this but I plan to offer a chat feature and a forum feature which other apps do not have.

Sunday, October 11, 2020

Drive Crash

 So, the drive in the laptop I spent the past few days working on died. I didn't lose much but I lost some tutorial work. Fortunately I have this laptop and all of my source code was stored on GitHub so the work that I've done is safe. Still, it sucks and I'll have to replace the drive. It is Thanksgiving here on Monday so I doubt I'll be doing any new tutorial work until Tuesday.

Saturday, October 10, 2020

Silver Prophet Battle Engine

Today I worked on Silver Prophet's battle engine. It's coming along nicely. I need to add attack animations yet but either side of the field can win or lose the battle. When a character is damaged the amount floats from the top of their head and fades to transparent. When they receive enough damage they go to a damaged state. Each character has a separate timer that controls when they can attack. When the play is ready their battle icon flashes and can be clicked. It opens up a context menu where they can choose from a basic attack, skill attack or use an item.




Friday, October 9, 2020

Laptop Transfer

I spent most of the data transferring from my main laptop to a different laptop. I had to reinstall most of the software, transfer data and set up the environments the way that I like. It's taking a bit to get used to the new keyboard after primarily using the other for so long. I do now have everything setup the way that I like and did do some work on Silver Prophet. I did a little graphic design as well, on the loading screen. It's not finished but I like it.



Thursday, October 8, 2020

Character Generator

 So, I'm working on Silver Prophet as my main project. It is going relatively well. I make progress every day and rarely get stuck for long. Right now the big problem is assets. I'm not a pixel artist by any means. I can do some basic graphic design but I don't have an aesthetic eye. Something has to be really bad for me to dislike it. I found a good site for RPG sprites that I thought I'd share. It builds more than just four directional movements. It has some basic actions as well. The sprites are free to use, even for commercial use, with attribution. Be sure to check them out.

http://gaurav.munjal.us/Universal-LPC-Spritesheet-Character-Generator/#?weapon=trident

Wednesday, October 7, 2020

Patreon

 I am now on Patreon for building Silver Prophet. I would appreciate your support in developing my game.https://www.patreon.com/synammon

Shadow Monster Tutorial 25 Is Live

I have just uploaded tutorial number 25 in the Shadow Monsters tutorial series that uses MonoGame. This tutorial covers how to capture shadow monsters. You can find the tutorial on the MonoGame tutorials page of the web site or you can use this direct link.

Tuesday, October 6, 2020

Shadow Monsters Tutorial 25 Update

 I've been working on tutorial 25 in the Shadow Monsters MonoGame tutorial series. I'm about two thirds through it. I will definitely finish it up tomorrow if not later today. As I've mentioned this tutorial covers healing shadow monsters and capturing new shadow monsters from random battles.

I'm in the process of creating a Patreon page to help fund my projects. On it I plan on offering premium tutorials as well as access to my latest build of Silver Prophet. I've been working on Silver Prophet and have been making some progress. I updated the combat engine so that you only fight for the player and NPCs that you've recruited fight for themselves. It is working great but I need to add in some animations for the battle.

Monday, October 5, 2020

Leaving Weekly Game Jam

 I am sadly leaving the weekly game jam. I was just plagued by problems with my editors and made no progress towards having my demo done by the deadline. I'm keeping the code though and plan to finish the game eventually. It will be a 2D platformer. I might even use it for a new tutorial series because there are some techniques that I haven't used in my other tutorial series.

Today I'm going to chill and putter around on various projects. I will likely spend some time writing as well. I'd like to post a new tutorial tomorrow.

Sunday, October 4, 2020

Weekly Game Jam Update

 I've made zero progress over the past day. I have my character on the map. She can jump but she warps to the ends of the map when she lands. I'm really discouraged by my lack of progress. I'm considering withdrawing from the jam and focus on my projects and tutorials. If I can't make any progress today I probably will withdraw.

Friday, October 2, 2020

Weekly Game Jam

 I found out about a weekly game jam and I'm taking place. The theme for the jam is treasure hunt, which I can totally get behind. I'm creating a platformer with a female elf as the protagonist. She is well, a treasure hunter, hunting for the famed Flame Sapphire. She will battle her way through enemies, over obstacles, solve puzzles and hopefully more if I have enough time. For that reason I will be putting tutorials on hold until the deadline next Thursday to focus on the game. I've made some good progress and have a game up, running, rendering the world and some basic animation up and running. I will be posting some video of my progress on here and on Twitter and Facebook.

Thursday, October 1, 2020

Silver Prophet

I updated My Projects Page with my old XNA project Silver Prophet that I converted to MonoGame. It is a fantasy role playing game set in a world filled with angels, demons and other fantastic monsters. The back story is that the Silver Prophet foretold of a hero that would appear in the town of Shadow Down in the hour of the world's greatest need.

I did some work on tutorial 25 in the Shadow Monster tutorial series. This tutorial covers capturing random shadow monsters. I should have it up tomorrow or Saturday.