This week: Animation, Movement, Float Truncation and Entity Spawns
I spent a good week and a bit finishing Dark Souls 3. I have no regrets.Not that I spent the entire time playing the game, even I get burnt out on Dark Souls if I'm spending 4 consecutive hours getting Rekt by a boss (Dancer). This does, of course, mean that progress was slowed for the past two weeks, but not entirely halted. So without further interruptions…Sprites, Animation and Movement
The 'big feature' I tackled over the past two weeks was getting the player onto the screen and moving in the same way the GM version had it. End Result (Click for full size):Looks a bit jerky in GIF form, but I can assure that it feels exactly as it should (I should get into the habit of recording WEBMs instead, they retain most information including the full framerate).The movement code was more or less directly ported from the Game Maker project, then polished up to make better use of the C++ language; things like x/y pairs (force_x, force_y) have been paired into t_point structs to clean things up a bit, for instance, and the motion calculation has been pushed off into a few general purpose motion calculation functions that are now part of the broad engine instead of exclusive to the player.One annoying little bug I created was that, at first, walking wasn't working and only the dash would work… but if a key was held at the end of the dash, the player would continue walking as normal.This happened at some point after midnight last Thursday, so I only discovered the cause of the bug in the morning.Basically, Truncation. Consider this piece of code:C++
// Float Truncation Example
float floatyNumber = 2.9F;
int intyNumber = (int)floatyNumber;
Sprites and Animation
Getting player motion to work was one problem that needed solving, but having a still frame floating around the screen wasn't very amusing. I spent a bit of time making a decent animated Sprite module for the engine. It supports a few basic features I'm likely to use: > Sprite flipping (Vertical and Horizontal) > Reverse animation and automatic Stop on Begin/End of animation > Callbacks for animation stop/end > Sprite blending (Coloration and Transparency)I haven't got much of a fancy system for actually putting these on the screen; I'm basically using a backbuffer for everything, rendering to that, then swapping it out to the active framebuffer as needed. I'm wanting to get the framebuffer update onto a separate thread to untie game ticks from render ticks, but that's for "later" in the project. My current tasks involve basic game features, and I want to reach parity with my GM project by month's end.At this point, I can pretty much render everything as it appears in the GM version. Later I might add some shader effects for a few things like Magic and particles.Entity Spawns
This is one of those major engine features I tend to forget until it's too late; then I end up getting stuck trying to shoehorn something into the engine that deals with whatever level format I'm using.In this case, I'm using Ogmo to edit my levels; Ogmo allows for a specified Entity layer, with custom named Entities (And icons for them to help with editing). These get stored in the resulting XML like so:xml
<DebugPlayerStart id="0" x="144" y="80" />
c++
// Entity Manager Registration Function
void registerSpawn(std::string name, std::function<Entity* ()> spawner);
// In initialization function for spawns:
EntityManager::registerSpawn("DebugPlayerStart", []() {
return new ENTPlayer();
});
// In level spawn code:
Entity* ent = entity_manager.spawn(node.name);
if(ent) {
ent->setPosition(node.x, node.y);
}
Hehe, gotta be careful not to get carried away with low level stuff.
It makes more sense anyways to store entity-positions in floats rather than ints, if the rest of your game is floaty. Then doing the casting at the end when you actually need ints for drawing, alt. just flooring them, after culling and whatnot. Casting to ints seemingly randomly in the code could get messy. It's also pretty expensive to convert float to int in volumes. In one case in one of my older engines, I speeded up the physics significantly by changing tile/triangle storage from short to float, because every time needed the a triangle for collision or such, that resulted in 9 short ->float conversions, I kept it in shorts to begin with as an untested cache optimization, that proved to just slow things down and make things ugly. Shorts could probably be made to work faster, and simd and stuff, but you know, "premature optimization…" and so on. Nice website. I look forward to the next post.Heh, the low level stuff is a bit of a problem sometimes. So fun to tinker with.
I'm staying focused though, sticking to my todo list on my Gitlab setup; I'm basically spending a couple of hours each Monday going over the list, working out what gameplay feature I need to implement next, create a milestone for that, then add 'issues' to it; if there's anything that requires a low-level feature or something, I do it as quickly and cleanly as possible… with the exception of things like the tile renderer above, but that's a case of design-phase optimization; the fewer bottlenecks the better.Ah, don't take my comment the wrong way. I often think people are too quick on the gun when repeating Knuth's words (POITROAE). One should have a plan for performance when designing a system, especially when making a c++ game.
Also, on stack overflow, it's fucking annoying to have to scroll trough 10 comments of "POITROAE, u newb, i'll have you know i graduated mit…," before reaching an answer to the actual question (even if the original asker was indeed POing). Nah, that doesn't happen often lately tbh. Guess they are downvoted.Heh, don't worry, I didn't take it the wrong way. I usually just follow the concept of "Optimization by Design". Generally speaking, you receive higher gains from a system that's designed to be fast over optimizing an existing system.
On the other hand, if you've made something and you can see a definitive area in your code that you know you can improve… branch, checkout, try it out, test it, and use it if you find it works better.The advantage to doing this is that you're not only speeding up your game/app/whatever, you're streamlining your development process (Next time you encounter this type of code you'll end up jumping straight to the optimized solution without requiring the intermediate steps).Nice site. Not sure how I feel about all the slide-down panels on every page load (and also your games page images are 404ing) but otherwise it looks good. Also I didn't know .space was a GTLD.
Ogmo looks pretty cool; did not know about that. Definitely something to look into.Yeah, I wasn't much liking that either. It's basically a hodgepodge of Blogger templates I pulled bits and pieces from to make a semi-coherent whole, and a lot of those templates are just messy.
Culprit for the slide was a bunch of jQuery slideUp/Down calls. Just hunted them down and removed them from the template.I was also surprised by .space. It was going pretty cheap as well, $10 renewals (Or somewhere around there, could have been $8, had a lot of choices). Like you and flashback mentioned in the other comment thread, a VPS seems like a good deal better than shared hosting. I'm probably going to give it a shot sometime later this month, make a mini blog/portfolio site in Node.js.EDIT: Grabbed the $5 plan, really easy to set everything up. Set up my keys and everything. Even dug up a promo-code I'd gotten from some newsletter or other from last month, got $10 credit… so basically 2 months of free use for the single droplet I've activated.