Maths Game.

 I am (occasionally) working on an action RPG game where every time you attack you have to answer a maths question. RPGs are cool and I used to play them a lot but now I am a social gamer and I don't appreciate the brain-drain.

I have accrued a large repository of spaghetti code with a few gems as I learn the ins and outs of game programming in C (https://github.com/BostonBrooks/Spaghetti_Graveyard.) . I chose C because it is what the electronic and computer engineers use and working as an ECE is a long term goal for me.

I am using the C binding for SFML because SDL doesn't easily incorporate 2D meshes, to be used for 2.5D curved ground surfaces.


A few demos below. Scritchyness is due to screen capture software.

 




 


All for now, Boston.

 

Update 17/02/2022

In the game, the terrain is represented as a 2 dimensional grid where each point has a third dimension (height). I have used bicubic interpolation (functions with x^3 and y^3 terms) to smooth the areas between points on the grid. I have then taken the derivatives in x and y to find the normal to the surface (a vector of length 1, perpendicular to the surface) at any point.

I used the dot product of the normal vector and a vector representing the incident sunlight to calculate how well the ground should be illuminated and used that in plotting the ground surface.

It doesn't work. Somewhere I've made a mistake :P the entire ground surface comes out black.

All for now, Boss.


Update 28/05/2022

I have got the code from the previous post working. There were a few places where I got the x and y coordinates confused and I had to modify the code that runs on the graphics card to scale the axes correctly. The resulting hill shading texture is pretty speckled and has little patches where the bicubic interpolation overshoots the data points causing shadows where there shouldn't be shadows.

I had this same problem with my original code that I am in the process of rewriting because I've learned more about writing good code. I may achieve better results if I use a different form of interpolation. This would be pretty easy if I just re-calculate some values in two four-by-four matrices used to calculate the bicubic coefficients. These little glitches in the way hill shading is calculated don't effect the rest of the game so this is a low-priority.

Here is an image of the graphics of the game so far:

 

All for now, Boss.

 

Update 17/06/2022

Here is a screenshot of my second most recent built:


 

As you can see, elevations and hill shading are drawn correctly. The red spheres are drawn to the screen correctly based on their location in 3d coordinates. Four of the spheres are drawn on the left corners of the terrain squares being drawn to the screen, the other is drawn at the 3d coordinate that should be at the center of the viewport. The texture of the ground surface is oriented correctly.


Here is a screenshot of my most recent build:


The different layers are being drawn to the screen correctly.

Instead of mapping the texture directly to the ground surface, I have set the ground surface to be green, then drawn a sprite of the given texture to the ground surface. As you can see, the result is flipped around the j axis for all the layers of the ground surface except for hill shading.

I have no idea why, Boss


Update 24/09/2022

 I fixed the above bug by making everything "flipped" and then flipping it back.

I have changed the way I interpolate height values between points on the height map for the purposes of hill shading.



The left shows hill shading using bi-cubic interpolation. The right shows interpolation using a Lanczos convolution kernel and interpolation of derivative using a Gaussian derivative convolution kernel. The result is much smoother hill shading, but the new approach takes a LONG time to generate the hill shading for the entire sandbox. I'm thinking about pre-loading the convolution kernel rather than calculating it's value over and over again for every single pixel.

All for now, Boston.


Update 01/10/2022

I've been re-writing my entire code-base to properly use headers and source files. In the past I had just one source file and the bulk of my code was in header files. I have more or less implemented all of the features I had implemented with my previous spaghetti code.

 


 

All for now, Boss


Update 26/12/2022

I added a frame-rate calculator to my game; how can I put this politely? When I screen-shotted it, it was sitting at 20fps, at the moment it's sitting at 7fps and I'm not even doing much graphically. My plan was to go ahead and draw far more objects to the screen and implement other features like AI for creatures in the game, and have the game run at 60fps.

This graph shows the time taken to draw one frame to the screen over 66 frames. About half of the time it takes about 2ms to draw one frame, which is good. The other half of the time it takes about 26ms to draw to the screen, which equates to 38fps. This isn't game-over because if I can figure out how to make it always take 2ms to draw a frame I'm in the clear.

PS. I was able to get a high frame-rate by making a test program that only shows the frame-rate and has a tiny resolution, but a low frame-rate running the same program with a high resolution, so it wasn't a problem with my code. I installed the latest proprietary drivers and now everything is fine.


 All for now, Boston.

 

Update 05/01/2023


I have updated by code to store objects to be drawn to the screen in a pool (to save time allocating space for new objects. Objects further from the screen should be drawn before objects closer to the screen, and I've made a hack that does this most of the time. It'll take a bit more work to make this always the case.

Just as fan service I've created a visual demo of my project thus far and it's starting to look a bit like a game. Frame-rate should be higher since this is a simple demo but life, uh, finds a way. The video is pretty low-frame-rate but that is a problem with the recording software.




All for now, Boston

Update 05/01/2023

I've created new class called bbAIControl, which represents an entity in my game such as a player or a monster.



I've created a type of AI fox that moves around and keeps the window centered on itself and an AI jellyfish that tries to follow the fox.


Update 16/01/2023

Ive coded up a repelling force between objects on the screen and objects that move around. This local avoidance leads to nice swarming behavior from the jellyfish. It's a bit glitchy, but i'm moving in the right direction.


All for now,

Boston.


Update 11/5/2023

Ive gone through line by line and changed my code to store the information about how to load animations in a spreadsheet (csv file) rather than a plain text file. The first problem I had was a bunch of tailing commas on each row. I used the following code to trim any characters from a line of text that go beyond the useful data:

 fscanf(Media, "%*[^\n]\n");

I also had trouble since LibreOffice Calc sometimes exports with string delimiters and sometimes doesn't. I just have to muck around and make sure the data is exported correctly every time I edit media.csv

The way the jellyfish move in the previous update is a bit glitchy, sometimes they get thrown away from the swarm instead of moving smoothly. I've been putting some thought into implementing potential fields for local avoidance, but I myself have been a bit avoidant :P

All for now,

Boston

Update 17/5/2023

I've coded up the potential field for unit path-finding / local avoidance. Units avoid bumping into other units, other units are represented as hills on a 3d surface. The slope of the surface represents the direction the unit wants to travel. Units just have to figure out how to travel down hill.


 

Units could travel downhill by knowing the slope at each point. This will take a lot of effort to code up and I would consider it premature optimization. I have coded up the Nelder - Mead algorithm but I haven't debugged it yet.

Nelder - Mead in 2d works by starting with a triangle of vertices, and then successively finding a better replacements for the worst vertex.

All for now,

Boss

Update 25/4/2023

I've implemented potential field local avoidance in the game. The result is less glitchy than going by velocity = sum of forces (flow fields). With the previous method, units in a group would tend to shoot away from the group stochastic-ally. With the potential fields method, things go a bit more smoothly, but the game runs slow on my fairly robust work station.

Here is a video I cobbled together comparing the two:

 
 
All for now,
 
Boston

Update 11/6/2023

After some hair pulling I decided to switch the focus of my effort.

I've implemented a shell / command prompt so that players can interact simultaneously through text and mouse clicks. This has been a nice afternoon project.


 

 Code is at:

 https://github.com/BostonBrooks/Spaghetti_Graveyard/tree/a79f3205ee6657fc32495d626504428230447e17/prompt_2023-06011

 Update 16/6/2023

I've just completed a massive refactor! Ive changed most of the names of all of the object-like structures, functions, globals and even files to make things look more proffessional. My program with all of the includes and an empty main function compiles and prints "hello world"

This was a big task, but now I have to re-write my main function which is a big old rat's nest!

I added this tortoise to make it easier to see where the latest compilation attempt starts:



All for now,

Boston

Update 30/10/2023

I've put in a flourish of work lately and was able to produce a somewhat playable demo. I was using graphics that I borrowed from Diablo 2, but then I decided to not release it and removed the stolen files from my project.

"Drawable" Objects in the game exist on a grid, with 8 grid points per pixel. What if the object wants to move only 1 grid point? It can only move north, south, east or west! This may be the cause of glithynes with my work on potential field and flow field avoidance (I'm currently implementing flow fields). I will experiment with this soon, but I'm about to go on holiday. 


All for now.

Boss

PS: I've purchased a programming suite called Clion and it has made my life much easier as a programmer, and I've been doing frequent pushes to github.

PPS:

There is game called 0AD, and the game graphics are under a free license. I plan to use these assets in my own game. I'm not a fan of limited polygon 3d art. That's why my game is based off 2d graphics, but I am no 2d graphics maestro so thems the breaks!


Update 8/11/2023:

I've just gotten back from a one week holiday.

I was thinking of adding a fog effect with a depth buffer so further objects are more obscured by fog than nearer objects. Then I thought of swirling fog, then falling snowflakes, then falling cherry blossoms, then filling my game with watercolour art of cherry blossom trees and willows.

I think I will rush out a minimum playable demo, then focus on graphics.

PS. I had been using graphics from Diablo 2. These have been expunged. I've recorded a quick demo to show where its at.


Boss

Update 19/12/2023

I've taken a few shortcuts but now my game is (barely) playable. I've decided to work on graphics instead of fixing my shortcuts. As such I need graphical assets to add to the game. At the same time I'd like to learn what professionally written code looks like before I rewrite my game.

There is a game called 0 A.D. which "is a free, open-source, historical Real Time Strategy (RTS) game currently under development by Wildfire Games, a global group of volunteer game developers."

I plan to use the free resources made by the team for my game but they use 3d graphics and I am using 2d graphics. I've set myself the task of modifying their software to convert 3d graphics into 2d graphics. In doing so I will open up the resources for a generation of game developers and gain the skills I need to produce my own software.

This image shows that it is possible to render 3d assets as 2d images:


This image is a mock-up of the kind of tool that I would like to build:


I have been attempting to do Object Oriented Programming in C. I can achieve polymorphism by storing virtual functions in vtables, and unions can be used to store different data for different types of objects within the same class. I only need a few basic classes of objects to do what I need. I don't feel the need to have any kind of inheritance between classes.

All of the large projects I've looked into volunteering my time to in return for training are written in C++. C++ is nice and I see why it is preferred...

Reading code written in C++ is not easy for me, with the need to trace inheritance between classes and track dependencies. It makes sense if the game engine provides some base classes to be built upon by the developer, without the need to modify the game engine. My project is small enough that I can just monkey around and make changes to the code wherever I please.

On a different subject, I don't even know if my program structure is sound.

The main loop looks like this:

  • Parse input
  • "Player" object reads input and sets the goals for an "AIController" that represents the player character.
  • "AIController" objects collect data about "Drawable" objects on the map and place "Message" objects in a queue
  • "Message" objects are read from the queue and these change the state of "Drawable" objects.
  • "Drawable" objects are drawn to the screen
     

That's my offload for today,

Boss 

Update 21/12/2023:

My game is (barely) playable.

Here is a video of me playing it:

I added a button to toggle between 2d and 3d view in the Actor Viewer, which is a part of Atlas, the 0 A.D. map editor.

Here is a video of me using it:



All for now,

Boston

Update 28/01/2024:

I've been stuck on a bug in my code for creating a hash table for a long time. My hash function was having integer overflow (which was expected) but since I was using signed integers it was returning negative values (which was problematic)

It's such a relief when things just work.

Boston 

PS I can't wait to have fast internet again so I can go back to coding in 0.A.D

Update 26/03/2024

Ive put in-game code, related to the 2.5D viewport, on hold and started coding up a 2d UI somewhat like xwidgets.

Have implemented pools, dictionaries, trees (set theory), and nice wrapper functions for vtables.

Some of the code I wrote for testing has become deprecated and its all due for a big clean up.

I have able to implement inheritance between types of struct:

The first element of struct A is struct B and the first element of struct B is struct C. As such, a pointer to a struct A can be cast as a struct B, can be cast as a struct C. Voila, inheritance.

0AD code is progressing slowly.

Boss.

Update 21/04/2024

My 0A.D. code is ready to publish XD

I've been working on implementing a 2d widget based user interface. It's a lot of work threading together communication between widgets to implement functionality. I have implemented some reusable code for object pools, data trees, dictionaries and vtables.

I have been storing references to different objects all as indices in each pool. This makes the data easy to load/store/reallocate, as opposed to using memory address pointers. I know that in some languages this is the only way of storing references, but I'm worried about all of the look-ups and pointer arithmetic slowing down my code. Much of this pointer arithmetic could be saved by the compiler if it can inline functions and keep track of intermediate values, but my code is spread over many "translation units" so this might not work. I'm tempted to turn all of my libraries into header-only, so then the compiler can "see" all of these intermediate values shared across the code-base.

So tempted in fact, I'm going to try it now.

Boston.

PS. Including all my .c files in main.c worked. The word I was searching for is Link Time Optimization. I'm going to keep doing what I'm doing and hope the build system can keep track of intermediate values across multiple function calls.

Comments

Popular posts from this blog

Diablo II Hell Bovine Figurines

Original Art