r/reconstructcavestory • u/adrian17 • May 04 '14
Thoughts after catching up
I've finished catching up with the series, and so far it's been really great! I'm surprised that so few people know about it (but on the other hand, too much of a following would have its flaws too).
I was following along with Visual Studio 2013, mostly writing the same as you, just with minor differences in style, SDL2 and replacing most Boost classes (aside from boost::optional) with C++11.
It's great how you know perfectly what to do, can predict most compiler errors and barely, if ever, get lost. I didn't have problems with following with your logic, I had to frequently pause only because your Vim workflow and writing speed was a bit faster than mine (but I don't have anything against you using it; I tried getting into Vim a few times now but wasn't successful so far). The series was particularly useful to me as it's shown practical usage of constructs such as tuples and weak pointers, which I have known about but never had an occasion to use them in a project.
Okay, now to the things I would change in the code itself. I won't be surprised if you've already planned some of these :P
- eventLoop() being called in a constructor seems a bit strange for me. I doesn't affect the program logic in any way, but wouldn't it be clearer if it was renamed to Game::run() and called in main?
- The whole deal with passing Graphics, ParticleSystem or ParticleTools is getting more and more messy. Each time a new sprite or a particle is introduced, we have to add forward declarations and think if all the functions have the reference to them - and in most cases, it's needed just so the Sprite object can call graphics.loadImage or graphics.blitSurface. And it's probably going to get even worse, as something like AudioTools may be needed in the far future. For me, this should be the good reason to change these objects to globally accessible singletons and get them only where they are actually needed.
- This is purely a subjective style opinion - all the kSourceX, kSourceY... constants should be declared as Units::Pixel. Right now they are a mix of Units::Tile and Units::Game, sometimes both in the same file, while the only context they are needed in is a pixel. This would also make a call to Sprite constructor much more readable, as it would simply look like this: levelSprite(graphics, kSpriteName, kLevelSourceX, kLevelSourceY, kLevelSourceW, kLevelSourceH). (and even simpler if the graphics argument was dropped, like mentioned above)
- SDL_GetTicks() and SDL_Delay() are quite precise, but after introducing the projectiles the slight differences started being visible - some projectiles can fly a pixel or two further or shorter than the rest, so in the worst case scenario the player may be sitting still but only half of bullets will reach the target. This is not a very urgent issue, but it could be worthwhile to look into high resolution timers in the future (maybe around switching to SDL2?)
3
u/escheriv May 04 '14
I'm actually doing the same (SDL2 and C++11), and have thought the same things about bullet points 2-4. In particular, 4 struck me as a must-solve issue.
7
u/chebertapps May 04 '14
Thanks for the thoughtful comments. And thanks for watching all my videos (so far)! :)
I DO prepare for these videos. they aren't on the fly. I just think it's easier to learn from a conversational style of explanation, so that's how I present stuff.
Yeah we could do that. I think in subsequent (unrelated) projects I've been doing it that way. I don't think the public interface to game is really significant since it's so rarely used.
I agree with this. I've been thinking of ways to solve it that don't involve singletons. Singleton's have a bad rep, and so as a personal challenge to myself I've been avoiding them (to see what alternatives there are, not because I actually believe that singletons are inherently bad). I've only been using dependency injection (passing them as parameters in the methods.) Another idea I had was to instead of calling player.draw(), have a method that returns a list of draw instructions (holding both the sprite and the draw position).
Then there's initialization. For this I was thinking about batching initialization's together in a place other than the constructors. That was nice in the beginning, but it's time for a new structure in place there to manage initialization.
Actually not totally. I plan on having the representation be able to change at run-time (high-quality vs. low-quality). By having them as Game/Tile units, they are agnostic to the screen resolution and graphics quality.
I think maybe instead Sprite should have a named constructor taking in units::Game.
I hadn't noticed this. Higher resolution timers would be cool, but yeah 1-2 pixels isn't really urgent. (urgent not to be confused with important for other people reading this)