A Game Collection Web Site

I wanted to create a project that showed that I can do full stack web development. I wanted to do something that was small enough to get done relatively quickly but complex enough to show that I did it myself and didn’t just follow a tutorial. I want it to be something that I can show potential employers as an example of the full stack web development that I am capable of. gcsite.crookedfingerguy.com is what I came up with.

I used C# ASP.Net Core 5.0 with Razor pages for the web development. For the database I used SQL initially for testing and then I switched to MariaDB on RDS on the Amazon cloud. I hosted the web application on AWS ECS Beanstalk. I deployed the software by using the amazon extension for Visual Studio 2019. I setup GitHub for version control. I used SendGrid to handle the account registration and password reset emails.

There was a lot of learning new technologies for me on this project. I really didn’t encounter any new programming concepts on this project. I was mostly going over the way ASP.Net (Model View Control) MVC system works. Learning how data moves between pages and the server was in this context was new to me.  Getting code first Entity Framework was something that I had never used before this project. I had always just made the tables on the database and used SQL Queries from the application before. Having the Entity Framework handle whole migration process was probably the most confusing aspect of the project for me. Because I had to learn a lot of syntax to get it to create a database that made sense for the project.

I learned to use the IGDB API to search for games to add to collections. Keeping the API key and database connection string secret on multiple systems with version control caused some problems for me but I sorted that out eventually. Otherwise, the IGDB API, which is owned by Twitch.tv, was not too difficult to get working with my web site.

I used the software I wrote about in my blog before to create the 3D models of the game boxes that I uploaded and displayed on the web site. It shows the game boxes in animated 3D on my phone browser even.

This is just a minimum viable program meant to be a proof-of-concept web application. The concept I am proving is that I can create and deploy a full stack web application by myself.

The main problem with the web site currently is that the caching from the IGDB API is stored on the beanstalk instance. That means the cache can get out of sync with the database if I republish the application for an update. It can also get out of sync if an additional instance is spun up due to web site being overloaded. To fix that I need to store the IGDB API cache and the uploaded 3D models on an AWS S3 bucket. Figuring out how to do that is on the list of things to learn how to do. Of course there is a large list of possible improvements that I could make to the site. I’m not sure if I will have time to get to any of those things anytime soon. I want to work on learning more JavaScript to make it more likely I will get a software development job.

A Classic Clone. Asteroids

In two streams I managed to make a simple clone of Asteroids. As has been my trend lately I used the DirectX wrapper for C# called SharpDX to handle the graphics.

I published the source code on my Github/CrookedFingerGuy with a stand alone .exe file.

One thing I did off stream to help me understand the whole rotating polygons situation was I made a toy program. That program helped me learn to draw functions and rotate vectors using SharpDX. I also related the unit circle and the the sine and cosine functions.

The interesting bit of cod e for this project was as follows:

            //unit vector on unit circle
            solidColorBrush.Color= new RawColor4(0.7529412f, 0.7529412f, 0.7529412f, 1.0f);           
            d2dRenderTarget.DrawLine(new Vector2(tx,ty),new Vector2(direction.X*magnitude+tx,direction.Y*magnitude+ty),solidColorBrush);
            d2dRenderTarget.DrawEllipse(new Ellipse(new RawVector2(tx,ty),magnitude,magnitude), solidColorBrush);

            //sine component of unit vector
            solidColorBrush.Color = new RawColor4(0.5019608f, 0.5019608f, 1f, 1.0f);            
            d2dRenderTarget.DrawLine(new Vector2(tx + direction.X * magnitude, ty),
                                     new Vector2(direction.X * magnitude + tx, direction.Y * magnitude + ty), solidColorBrush);

            //cosine component of unit vector
            solidColorBrush.Color= new RawColor4(0.1960784f, 0.8039216f, 0.2431373f, 1.0f);
            d2dRenderTarget.DrawLine(new Vector2(tx + direction.X * magnitude, ty), new Vector2(tx, ty), solidColorBrush);

            //red dot on unit circle
            solidColorBrush.Color= new RawColor4(1f, 0f, 0f, 1.0f);
            d2dRenderTarget.FillEllipse(new Ellipse(new RawVector2(direction.X * magnitude + tx,
                                         direction.Y * magnitude + ty), 3f, 3f), solidColorBrush);

            //sin graph
            sinXOffset = 50f;
            sinYOffset = 375;
            sinGraphWidth = magnitude*4;
            sinGraphHeight = sinGraphWidth / 2;
            solidColorBrush.Color = new RawColor4(0.7529412f, 0.7529412f, 0.7529412f, 1.0f);
            d2dRenderTarget.DrawLine(new Vector2(sinXOffset, sinYOffset),
                                      new Vector2(sinXOffset + sinGraphWidth, sinYOffset), solidColorBrush);
            d2dRenderTarget.DrawLine(new Vector2(sinXOffset + sinGraphWidth / 2, sinYOffset - sinGraphHeight / 2),
                                        new Vector2(sinXOffset + sinGraphWidth / 2, sinYOffset + sinGraphHeight / 2), solidColorBrush);

            PathGeometry shape = new PathGeometry(d2dFactory);
            GeometrySink sink = shape.Open();
            float y = (float)(sinGraphWidth / 4 * Math.Sin((float)-Math.PI));
            int x = 0;
            Vector2 vect = new Vector2(x + sinXOffset, y + sinYOffset);
            sink.BeginFigure(vect, FigureBegin.Hollow);

            for (x = 0; x < sinGraphWidth; x++)
            {
                vect.X = (float)(x + sinXOffset);
                vect.Y = (float)Math.Sin(Map((float)x, (float)0, (float)sinGraphWidth,
                         (float)-Math.PI, (float)Math.PI)) * sinGraphHeight / 2 + sinYOffset;
                sink.AddLine(vect);
            }
            sink.EndFigure(FigureEnd.Open);
            sink.Close();
            d2dRenderTarget.DrawGeometry(shape, solidColorBrush, 1f);

            //sine component of unit vector
            float sMapX = Map(rotation,-(float)(Math.PI),(float)(Math.PI),0, sinGraphWidth);
            float sMapY=Map(direction.Y,-1,1,-sinGraphHeight / 2, sinGraphHeight / 2);
            solidColorBrush.Color = new RawColor4(0.5019608f, 0.5019608f, 1f, 1.0f);
            d2dRenderTarget.DrawLine(new Vector2(sMapX+ sinXOffset, sinYOffset), 
                                        new Vector2(sMapX+ sinXOffset, sMapY + sinYOffset), solidColorBrush);


            //cosine graph
            cosXOffset = 50f;
            cosYOffset = 600;
            cosGraphWidth = magnitude*4;
            cosGraphHeight = cosGraphWidth/2;
            solidColorBrush.Color = new RawColor4(0.7529412f, 0.7529412f, 0.7529412f, 1.0f);
            d2dRenderTarget.DrawLine(new Vector2(cosXOffset,cosYOffset),
                                     new Vector2(cosXOffset+ cosGraphWidth, cosYOffset), solidColorBrush);
            d2dRenderTarget.DrawLine(new Vector2(cosXOffset+ cosGraphWidth/2, cosYOffset- cosGraphHeight/2), 
                                        new Vector2(cosXOffset + cosGraphWidth/2, cosYOffset+ cosGraphHeight/2), solidColorBrush);
            
            shape = new PathGeometry(d2dFactory);
            sink = shape.Open();
            y = (float)(cosGraphWidth / 4 * Math.Cos((float)-Math.PI));
            x = 0;
            vect = new Vector2(x+cosXOffset,y+cosYOffset);
            sink.BeginFigure(vect, FigureBegin.Hollow);

            for(x=0;x<cosGraphWidth;x++)
            {
                vect.X = (float)(x+cosXOffset);
                vect.Y = (float)Math.Cos(Map((float)x, (float)0, (float)cosGraphWidth, 
                         (float)-Math.PI, (float)Math.PI))*cosGraphHeight/2+cosYOffset;
                sink.AddLine(vect);
            }            
            sink.EndFigure(FigureEnd.Open);
            sink.Close();
            d2dRenderTarget.DrawGeometry(shape, solidColorBrush, 1f);
 
            //cosine component of unit vector
            float cMapX = Map(rotation, -(float)(Math.PI), (float)(Math.PI), 0, sinGraphWidth);
            float cMapY = Map(direction.X, -1, 1, -sinGraphHeight / 2, sinGraphHeight / 2);
            solidColorBrush.Color = new RawColor4(0.1960784f, 0.8039216f, 0.2431373f, 1.0f);
            d2dRenderTarget.DrawLine(new Vector2(cMapX + cosXOffset, cosYOffset),
                                        new Vector2(cMapX + cosXOffset, cMapY + cosYOffset), solidColorBrush);


            solidColorBrush.Color = Color.White;
            d2dRenderTarget.DrawText("Radians: "+rotation.ToString("0.00")+" Degrees: "+(rotation*180/Math.PI).ToString("0."),
                                TestTextFormat, TestTextArea, solidColorBrush);

            solidColorBrush.Color = new RawColor4(0.7529412f, 0.7529412f, 0.7529412f, 1.0f);
            asteroid.DrawAsteroid(d2dRenderTarget, d2dFactory, solidColorBrush);

There are many clones of 2048 but this one is mine

A year ago, I made 2048 in the console. I did it in less than 500 lines of code and I had made it with the game board drawing separate from the rest of the game with the intention of swapping out the display to a graphical one. A year later and that paid off because it was fairly simple to just drop in the game logic to my SharpDX template.

I did unfortunately separate out the generating of new pieces into its own class. This caused the code flow in an awkward way when the game resets, but it works. The code I wrote is about 2500 lines. Most of that is in the menu system that I started in my Matrix Falling Code project. I extended the functionality of the system to include text input and toggle controls.

I also created a way for menus to hand off to other menus. It was good practice in polymorphism. This was required to have sub menus and do things like get the played to enter their name to be saved in the high scores list. The project was a good example in the difference between a project that just does the bare minimum and one that is fully featured. I streamed about 16 hours of me working this on twitch and I probably spent another 4 off stream working on the project. I’m pleased with the result for 20 hours of effort.

I’ve published the code on my Github.

Here are a few of the menus in the game.

Timed To-Do List

Sometimes having a list of things isn’t enough planning. You need to assign a time to each task on your list too. Hey, why not have a program that can keep track of how much time you actually spent on those tasks so you can get an idea of how good your time estimates are. Well that’s what Timed Task List is for.

The program has many of the features you would expect. Save, load, add tasks, edit tasks, change the text size and font. There is a right-click context menu that allows you to delete tasks and reset the accrued time for the task.

I made the program in NET Core 3.1. The code is available on my GitHub.

I streamed a lot of the creation of this program on twitch.tv/crookedfingerguy. I made it to aid in streaming what my streams objectives for the day are and to track how well I stuck to the plan. This was also good programming practice. I haven’t made a windows forms desktop application for a while. I am pleased with the effort.

The Matrix Themed Motion Graphic

Trying to start programming regularly again so I started out simple by streaming the creation of a motion graphic using C# on twitch.tv. I have a few clone games in the works just copies of the old standbys like Tetris and Breakout. I created a template using the SharpDX wrapper for the DirectX API. It doesn’t do anything fancy like error checking or anything. The program crashes if you don’t have a DirectX compatible controller plugged in for example. What it does do is provide a simple non-flickering canvas in Windows. That’s it no game engine really at all.

Look I used a folder to organize my cs files!

I used this Matrix Falling Rain program to create a 2D motion graphic. I also over the course of about 10 hours streaming created a simple menu system for changing programs settings with a controller. I created the menu system that I hope to use in those simple game clones for things like the start menu and basic game settings. In this motion graphic program I used it to dynamically change the appearance of the motion graphic. You can change the number of falling symbol lines and their size. You can change the color, speed, and number of symbols in each falling line of symbols. I even added the ability to save settings or reset the settings to default.

I uploaded the code to my Github. You may have to fiddle with the NuGet packet manager to get all the references straightened out to compile it.

This is mostly some base programming to get used to streaming. Hopefully I will be getting a few more simple game clone programs finished and ready for people to take a look at soon.