Tag Archives: C++

Should have seen that one coming

Well, as happens most times when I think I’ve got it all down, further investigation reveals quite the opposite. Long story short, my camera doesn’t work in all cases. Long story long, keep reading.

To determine the furthest distance between focus points (the 2d positional vectors that my camera must keep in view at all times) I was using std::max_element and std::min_element, like so:

where FocusPoints is a container of const references to 2d vectors, and Vec2Predicate is a function pointer for sorting the container by. This is where I made my fatal mistake.

How do you determine whether one point on a Cartesian grid is greater or lesser than another? As far as I know, you can’t. You can tell which is greater on an axis, but that’s it. My function Vec2Predicate compared two vectors on the x axis only. At first it seemed to work fine, but I ran into problems when the focus points were aligned with each-other on Y. As best as I can figure, min_element and max_element were returning the same element. Thus, the distance between the two points was always zero, and the camera never zoomed out. This resulted in actors getting awkwardly close to the edges and, in some cases, going off screen while the camera did nothing.

For obvious reasons, I’ve decided to do away with the entire system involving distance between points and instead use bounding circles. Here’s my plan for the new implementation:

Each frame, loop through the list of focus points
Find which Cartesian quadrant each point lies in
Test a point three meters towards each of the two nearest walls
If either point is off screen, break the loop and zoom out
If the loop finishes without any test points extending past the bounds of the screen, zoom the view in.

I’m really hoping it’ll work…I’ve spent far too much time on this facet of the engine and I’m longing to move onto something else.

Building an intelligent camera

My graph system is working nicely with multiple resolutions, but I realized while working on it that I’ve essentially locked myself into having every scene the same size. While not necessarily a problem, from a design standpoint it really isn’t conducive to the type of levels I want to implement. Of course, allowing scenes to exist that are larger than the size of the screen introduces several new problems, namely:

  • The camera needs to keep all actors in view at all times
  • Additional detail will be needed to surround the accessible area

That doesn’t seem too hard, right?

Hah!

Easy stuff first: The camera is going to need to center itself between all points I tell it to focus on. All I have to do is get the average value of all positions. Fortunately this actually happened exactly as I thought it would.

Now on to zooming. Essentially, I check distance between the two focus point furthest from each other. If it’s over a certain length, zoom out. If it’s under, zoom in. Stop zooming in once the view is a certain width, so it doesn’t zoom in to eternity.

Seems simple enough, right? That’s what happens when I write up a blog post after the fact. I really should start writing these while I’m in the thick of things…

Resolution independence

Planning posts are all well and good, but what happens when you end up going in an entirely different direction?

I ended up creating a new class, MN::Window, that inherits from sf::RenderWindow but adds some useful members to determine resolution and pixel scale ratio.

Now, when I’m constructing the pathing graph, each cell is WindowWidth/20 by WindowHeight/15. I still have a 20×15 grid and an array of Vector2fs, but they’re static to save on memory. I can also access grid locations from anywhere in the program, so all objects in the world will use graph indices for positional values from now on.

Previously I had been developing Meander to run in a window at 800×600. Besides the issue with hard-coded window dimensions, it also created the problem that resizing it larger (to, say, 1920×1080) stretched the images out from a 4:3 ratio to 16:9. And no, they’re not the same. To fix this, I started targeting a 16:9 resolution by default. But what happens when I want the display to be smaller? I added a few members to MN::Window that help me solve this problem.

To display correctly on a lower resolution, all the sprites on the screen need to be scaled by a factor of WindowDimensions/OriginalDimensions. For example, a transition from 1920×1080 to 1366×768 works out to this:

 

I’m no good at math. I may seem like it sometimes, but it’s all an act, I assure you. I don’t know if the scale ratio for any resolution of 16:9 will result in x === y. But just to be sure I’m going to leave both equations in.

This tells us that each sprite needs to display on the screen at 0.7 of its actual height and width. My sprite manager can take care of that each time the resolution changes.

Whew! Got that checked off the list. I made myself promise I wouldn’t play any video games until I’d finished. Time for a rest. :D

Fixing the graph – planning stage

Goal number the last on my roadmap reads: “Decoupling the navigation mesh from specific window sizes”. What on earth does that mean? I’m glad you asked.

Thus far I’ve been programming and debugging my program using a fixed-size window at 800 by 600 pixels. Unfortunately, when I wrote my Graph implementation I was all about magic numbers and not so much about planning for the future. Consider the following code snippet:

At some point I got it into my head to store exact locations in the graph. Now, there’s not anything necessarily wrong with this…as long as

  • I never need to change the window size or resolution
  • The view never changes

Obviously this is unacceptable, and really should have been fixed by now. I need a plan!

Currently the Graph class is made up of:

  • The Walkable list; a set of integers acting as boolean (0/1) variables (see here for why a vector is A Bad Thing)
  • The Node list; a set of Vector2s for positioning objects
  • The State list; a set of rectangles used to map mouse positions to nodes

Looking at this I realized that I really don’t need Nodes or States to be in there. After all, my pathfinder’s solver function only takes two numbers as arguments; the grid indices for the start and end of the path. At each step of the path, the pathfinder accesses the Node list with that step’s index and returns the position. I can easily strip this out and replace it with a simple function to convert a graph index to a Vector2. I’ll need a mesh to determine where on the screen the mouse clicks to signal the start of a pathfinding call, but I can most likely construct this on the fly.

No more delays. Time to get this done.

Debug streams

So far I’ve been handling console output using std::cout, as such:

This is all well and good, but I want certain things to only appear on the console in debug mode. For example, I may need to see pathfinding data while debugging a map, but the end-user won’t want to see all that. Using the Quake-style cvar system I’ve implemented I had started to add debug output like this:

This works, but it’s a lot of typing I wish I didn’t have to do. Ideally I’d be able to check for debug mode and print output on the same line. Which brings me to my results for the day:

Usage is exactly the same as std::cout:

…with the notable difference that it only runs if debug mode is on.

Anyone who wants to use this code is welcome to it under the license of your choice. I’d love to hear if you find it useful.

Meander engine teaser update

Everybody loves screenshots, right? Well, I do at least, and this is my blog. So here’s a screenshot of the GUI for my game engine. I’ll have a more technical/in-depth post after I get a video done, but I wanted to put this up right away.

Ladies and gentlemen, allow me to introduce… “Gooey”!

More later. :)