Jump to content
  • Advertisement

Horscht

Member
  • Content Count

    27
  • Joined

  • Last visited

Everything posted by Horscht

  1. 2 few years have passed since I last tried to make my own game and like always I had to give up because I encountered an unsolvable problem. And here I go again, hitting the same brickwall with no solution in sight. My question is: How exactly do I design all my classes so that coupling is minimal when they need to talk to one another somehow. Let's look at one prime example: The player exists inside a "world", an environment, where other entities also reside, enemies, obstacles, chests, whatever. Now the question is, who is responsible for moving the player? The player class itself in something like Player::Update()? But then how does it know if it hit an obstacle or walks on an ice-tile or got pushed back by a boulder that hit him? For that it would somehow need to talk to the world class, or the boulder class would need to talk to the player and tell it "hey I hit you please move back 3 tiles"? Last time I tried to create a game I had huuuuuge "pass down" chains where class D was instantiated inside C but class D needed class F so I also needed to pass an instance of that into C, which didn't need it itself and since it was created inside class B, class B also needed that instance of class F. So I passed that instance along like 10 levels deep in each constructor... Not confusing at all, right? Or maybe should the "world"/level class somehow coordinate everything, move everything, since it knows where everything is, but then how does it know the objects movement logic? How does separation of concerns fall into this, since optimally, every class should only have 1 responsibility. So what should each one do? I don't even know how to describe it properly, hopefully you can understand what I mean. Can someone give me a graph of how everything should be "connected"? Which class should "own"/instantiate what, should the player be instantiated by/inside the world class, or from outside and then passed in? But then in what part of the code should he get instantiated, the main loop? I tried looking for open source projects so I can see how they did it but all of them are wayyyyy too big and I don't even know in which of the 50000 files I need to start looking. Does anyone maybe know a very simple open source game with a similar structure that I can study? (Platformer, or something like zelda, something with a world/obstalces/player etc).
  2. I think for that I misused my MainForm as a giant "Service Locator" ;D With tons of properties for getting a reference to anything and a static "GetInstance" so from anywhere I could just type MainForm.GetInstance().ActiveTool to, for instance, get or change the active tool from anywhere... It kind of worked but there was basically almost no encapsulation whatsoever.
  3. Well my cycle is something like this: Get the desire to make a game, start a new project and program for a few weeks, hit a brickwall, get a feeling that I'm doing it all wrong, ask on some forum, still can't figure it out, give up, pause for 2 years and then it starts all over ;P I've mostly programmed small stuff, where I don't need a big complex system working together. (Chrome extensions, an addon for world of warcraft, a level editor (in C# .Net) for my last attempt at making a game). The only thing I never understood is how to seperate everything out logically to not have one monolithic class and then wire it back together. A level class that loads a level from file, player class that takes care of moving, shooting etc, enemy class with some AI... Somehow I always end up with the same structure everytime where everything needs a reference to everything else where I might as well put EVERYTHING in Singleton classes...
  4. Thanks for all that learning material, I'll look into it over the next few days, but I think before I'll try to make my own ECS from scratch I'll start by just using an existing, well designed and tested one to get a feel for how it all fits together.
  5. The Caves of Qud video was informative but the other one waaaaay too complicated, especially since it involves template metaprogramming which is super hardcore hard and I have no experience at all with that.
  6. I tried making something with Unity to get an understanding of how an entity component system works, but to me it looks a lot like spaghetti-wiring everything together "Oh how will this object talk to the environment? Whatever just put a reference to it in there, done!" It's so much easier when you can just drag + drop one object from the editor onto a script to give it a reference to it. What would be the equivalent of this in code? Instantiating everything in the "main scope" and then passing it along like "objA->child->child->childThatNeedsObjB->referenceToObjB = &objB"? Well thanks for the videos I'm going to watch them now Somehow I always have a feeling I'm missing something completely obvious/fundamental.
  7. When I started programming one of the biggest mysteries to me was how to provide access to things like SoundPlayer, Renderer, ErrorLog, StateMachine etc to very deeply "nested" objects, like the player. Let's say I create my StateMachine in main(), inside the constructor of StateMachine I initialize it's member: GameState, which in turn initializes it's member Level which in turn initializes it's member Player. Player wants to play a sound when he jumps, so he would need to call soundPlayer.playSound(SOUND_JUMP). But Player doesn't have a reference to a SoundPlayer object. He also wants to draw himself at the center of the screen, so he needs a reference to a Renderer and the Window, to get it's dimensions. What do? After a lot of inconclusive articles (or failure to understand them), I decided to just use a static global class, since I wanted to generate results as fast as possible and I kinda got stuck with it. Actually, I used a mixture of dependency injection through constructors, dependecy injection through methods and global variables... Here is an example (not actual code): class Player {     private:         SoundPlayer& _soundPlayer;         Sprite _sprite;     public:     Player(SoundPlayer& soundPlayer) :_soundPlayer(soundPlayer) {} // Dependency injection, storing the reference inside the object     void Render()     {         Renderer* renderer = Renderer::GetInstance(); // Global static horrible singleton!         renderer->Render(_sprite);     }     void Shoot(ParticleSpawner& particleSpawner) // Dependency injection through function argument, not stored     {         particleSpawner.Spawn(PARTICLE_BULLET);     } }; What I really don't like, are the static GetInstance() function calls everywhere. It just isn't clear that this class depends on the other, it just hides somewhere inside of a random method. At least in the constructor it's clear, you can't even create an instance if you don't pass it's dependency in. Inside the methods parameters it's already a little more awkward, because you're happy you could create an instance of the object, but then it suddenly needs an instance of another class.   The worst part is when I have a deep "component hierarchy" or whatever it's called. I read the term "call-tree" before and think it fits quite well. Player needs a reference to an instance of SoundPlayer, otherwise it can't be created, so it's owner ALSO needs that reference to pass it in, but it itself DOESN'T need it, except for creating the player, so it also puts it into its constructor as a required parameter, so now THIS class ALSO needs a reference to SoundPlayer, even though it has no intention of ever using it, but one of its components needs it, to in turn construct one of its components, which in turn needs it to construct one of its components, which in turn... feels kind of wrong to me :|   I got so tired of typing it all out that My state machine just has a #define to pass it all in. Kind of like this: class StateMachine {     private:         Renderer& _renderer;         SoundPlayer& _soundPlayer;         ErrorLog& _errorLog;         FileSystem& _fileSystem;         NetworkSystem& _networkSystem;         InputDevice& _inputDevice;         BreadMakingSystem& _breadMakingSystem;         SystemsManager& _systemsManager;         // ...         State* _gameState;     public:         StateMachine(Renderer& renderer, SoundPlayer& soundPlayer, ErrorLog& errorLog, FileSystem& fileSystem, NetworkSystem& networkSystem, InputDevice& inputDevice, BreadMakingSystem& breadMakingSystem, SystemsManager& systemsManager):             _renderer(renderer),             _soundPlayer(soundPlayer),             _errorLog(errorLog),             _fileSystem(fileSystem),             _networkSystem(networkSystem),             _inputDevice(inputDevice),             _breadMakingSystem(breadMakingSystem),             _systemsManager(systemsManager)         {         }         enum StateType         {             STATE_GAME,             STATE_INTRO,             STATE_TITLE,             STATE_OPTIONS         };         void SwitchState(StateType state)         { #define STUFF_TO_PASS renderer, soundPlayer, errorLog, fileSystem, networkSystem, inputDevice, breadMakingSystem, systemsManager             switch (state)             {                 case STATE_GAME:                     _state = new GameState(STUFF_TO_PASS);                     break;                 case STATE_INTRO:                     _state = new IntroState(STUFF_TO_PASS);                     break;                 case STATE_TITLE:                     _state = new TitleState(STUFF_TO_PASS);                     break;                 case STATE_OPTIONS:                     _state = new OptionsState(STUFF_TO_PASS);                     break;             }         } }; And inside of the GameStates constructor, again a #define to keep passing it on to it's children.   I was asking myself what the best way to do all of this would be, while refactoring Renderer::GetInstance() out and instead rewriting 100 constructors to accept a reference to Renderer instead. I just thought "What the hell am I doing? Is this really better?!"   Before I go and rewrite everything I want to make sure I do it correctly this time. This is something that really irritates me about programming, there never seems to be a definitive correct way and I'm only satisfied with perfection, even though I'm nowhere good enough to even achieve anything close to it :P Should I just leave it like this or is there a better way?
  8. So I should call ServiceLocator::GetRenderer() every update/render, instead of storing it once in the constructor? Isn't that kind of inefficient? But other than that it sounds interesting, but also like a lot of extra work and complexity. Implementing NullSound, NullRender etc, and designing the system around being able to run in a "null" state. I can imagine it becoming kind of complicated when functions return something, like a null version of TextureCache::LoadTexture(), it would have to return a NullTexture, or some kind of default texture... hmm...   Whatever, I think I will probably give ServiceLocator a try. I have to rewrite the whole render code anyway, since I did not think ahead. @haegarr: How would I go about checking the state of Player inside of PlayerController? Provide accessors for every member, like GetPosition() etc, or declare PlayerController a friend class, or something else? Should I also seperate logic for sound playing etc into something like PlayerSoundController, or put it all into one PlayerController? Some kind of messaging system sounds like it would make things easier, but I'm not sure if I can come up with a good one. I coded in different scripting languages for different games (like coding Addons for World of Warcraft) and there it was always soooo easy Register for an event, through a global variable and then just pass a function to play a sound, like event.Register(PLAYER_TAKE_DAMAGE, playMySound). Boom, done! I really need to learn more about decoupling and abstraction... that's one of my weaknesses, everything in my code is so "direct".
  9. I agree and I have a hard time thinking outside the box. My current approach is to have all the logic related to the player inside one class: Player. In Player::Update() I check if the jump button has been pressed, using a reference to InputDevice that got passed into the constructor and saved as a member, then play the sound the same way, but instead with a SoundPlayer. If I had more things for whoknowswhat I would also put it there I don't really know how to really do it from "outside" since I would have to expose a million different things like position, velocity, state etc (which would be the hardest since the Player class itself uses kind of a state machine pattern instead of a variable).   Reminds me of this one: http://gameprogrammingpatterns.com/service-locator.html But I don't really see how it is much different from a static singleton. It just goes through one more class to actually fetch the service. The only upside I see is, it can dynamically return different derived classes. (Like the NullSound example).   Let's make sure we are talking about the same things here, could you explain what exactly you mean by layers and levels, up and down? The way I see it is, a layer is a scope, like the function body of main() or the scope of a class like GameState. Up is main() and down is something like statemanager.gamestate.level.player, right? So if the Player wants to be drawn, it should not interact with the Renderer but instead the Renderer should "collect" all Renderables "below" it, or the class that owns Renderer should feed the renderer the Sprites/Renderables? So something like: void GameState::Render() { _renderer.Render(_level.GetPlayer().GetSprite()); _renderer.Render(_level.GetEnemy().GetSprite()); _renderer.Render(_level.GetPickup().GetSprite()); } Of course that would need to be made more general, maybe through an Interface with a recursive function like GetAllRenderables() or whatever :) I don't know it's just an idea. The way I do it is kind of the opposite, I call stateManager.Render() which calls gameState.Render() which calls level.Render() which calls player.Render() which then gets a pointer to the DirectX device directly and does all its drawing directly in low level code hahaha :) But once I wanted different graphic-layers, for UI and debug output, it became clear that this is not a very good way to do it.
  10. I have been struggling with collision resolution forever. I always wanted to create a platforming game but never managed to get past the collision resolution part. Usually I would start programming a game, and after a while when it comes to collisions, I just sit there for days and weeks, fiddle around with the code and NOTHING works, absolutely nothing. I work less and less on it because it's just nothing except pure frustration and then I kind of let it die. A few months or years later I start trying again, hit the brickwall again and the same thing goes on forever... I even procrastinated like crazy until I decided to make this post but I don't even know where to start and how I should even formulate my questions. Sometimes I just have a feeling I may be just too stupid for game development and I will never understand it. My brain just doesn't come up with any solutions anymore. Most of the time I just sit there, looking at the code and after 30 minutes of thinking and not coming up with anything new I just go do something else, this repeats forever, so here I am asking you!   I have read almost every article that I could find on google, a lot of sites links to the same old stuff that doesn't even really explain anything, or just doesn't fit my game. I'm still trying to create some kind of megaman clone, or maybe like shovel knight or mario. Simple 2D collisions without fancy physics. Just 2D box shapes, no rotations, no polygons or circles or whatever. There are articles that don't cover tunneling, others only try to solve 1 body vs 1 body collisions, others have weird behaviour like jittering on the floor, falling of the edge of a platform, because there is only one "collision point" on the bottom of the player, or when there are 2 points on the right and left foot, fall through blocks if they are narrower than the two points. Player can't be smaller than n x m, can't be faster than x pixels per seconds etc... There doesn't seem to be anything out there that fits my idea of a good collision system. But there HAS to be a solution because there are TONS of good games out there that don't seem to have all those restrictions. All I want is a consistent collision resolution system for axis aligned bounding boxes without tunneling, pixel perfect movement, no jittering, or any strange behaviour, because I want the game to be difficult, and when the player suddenly falls through the floor and has to start all over again just because the collision system encountered a rare condition in which it fails, it's going to be extremely annoying and frustrating, especially when it could happen again anytime. Same goes for suddenly getting pushed through walls, that would make the game too easy ;)   A lot of those articels also don't cover how a "collision system" should be designed in general or how entities/objects/whatever can check and react to collisions, or check their surroundings (like if they are touching the floor or whatever). I want to have a system where I can easily react to At first when I started I put all of my code in the Player class, had a reference to a class called World, which basically was just a collection of Tiles, with functions to ask something like: class Player { //... private: World& _world; //... public: Player(World& world):_world(world){} //... } void Player::Update(float dt) { if(_world.GetTileAt(x,y).IsSolid()) // Do something if(_world.GetTilesInRect(this->GetBoundingBox()).count() == 0) velocity.y += gravity * dt; // Or whatever, just an example position += velocity * dt; } But then I realized this is going to result in a lot of duplicate code when I want to have the same collision resolution for enemies or pushable boxes or whatever.   So I generalized it, In hopes to be able to just have to implement a function like "HandleCollision(...)" in whatever class I would like to be a part of "the World".   So here are the classes that I have: Body - Holds information like position, velocity, size, and has a function GetCollisionInfo(Body* other) which returns a struct of data describing when and how this body is going to collide with the other body, by comparing position, size, velocity etc... CollisionHandler - An Interface that specifies the function HandleCollision(Body* other, CollisionInfo colInfo) Player - Implements CollisionHandler, holds a reference to it's Body created using World::CreateBody(), then sets body->SetCollisionHandler(this) World - Keeps a list of all bodies and provides a function CreateBody() which inserts a new body into a vector or whatever and returns a pointer to it.   In my gameloop, world.update() gets called, which then loops over all bodies, asks each body to get a collision info of it and the other body, puts all colliding bodies in a list, orders it by timeOfImpact and then calls body->HandleCollision(other, colInfo) on the first object ("other" is whichever the body collides with first) which delegates the call to player->HandleCollision or whatever has been set as the collisionHandler. And there I do checks like these: // Gets called by World::Update() bool PlayerWalking::HandleCollision(CollisionInfo colInfo, Body* other) { Vector2D newVel = player.body->GetVelocity(); Vector2D pos = player.body->GetPosition(); RECT obsRect = other->GetBoundingBox(); switch (colInfo.impactSide) { case CollisionInfo::Side::LEFT: newVel.x = 0.0f; player.body->SetPosition(obsRect.left - player.GetBoundingBox().GetWidth(), pos.y); break; case CollisionInfo::Side::TOP: newVel.y = 0.0f; player.body->SetPosition(pos.x, obsRect.top - player.GetBoundingBox().GetHeight()); break; case CollisionInfo::Side::RIGHT: newVel.x = 0.0f; player.body->SetPosition(obsRect.right, pos.y); break; case CollisionInfo::Side::BOTTOM: /*newVel.y = 0.0f; player.body->SetPosition(pos.x, obsRect.bottom);*/ break; } player.body->SetVelocity(newVel); return true; } So this then modifies the velocites or position and at last, the world class increments the position by velocity * timestep, or whatever. This way I can change how the timestepping works in one place: World::Update(float dt) instead of the objects like player/enemy etc. So you're probably wondering why I'm even complaining, right? Because it just doesn't work like I want it to and I have a feeling no matter how much I fiddle with the code I will never figure out how to do this correctly. With this method, what happens in the following scenario? The first collision that will get handled is the one with the right block. It cancels out the y velocity, then comes another iteration of checking the velocity against other bodies and since we are now only moving straight left, we move OVER the gap instead of into it. This is what should have happened (all happening in one frame, animation just for clarification): So this is what I DONT want! NO SLIDING over gaps! Of course I could solve this by NOT initiating a NEW iteration of collision checks and instead continue with the one that would happen next. Instead of checking again, I say I already know we would collide with the left block, so we handle that and place the block at the right side of it. (Forgot to make a picture for this case, just imagine the "player" a little more to the left, so its left side is aligned at the right side of the left blue rectangle) Now for this case you COULD say, well thats ok, the player will just start falling down the hole the next frame, right? Sure, but what if there is no gap? Just 2 blocks next to each other (ground)? Yep, the goold old "player gets stuck when walking over tiles" problem because he gets blocked by the left one..... *sigh* So all I can do is shuffle the code around, do it in a different order and jump from one problem to another one, without ever being able to eliminate ALL of them at once.   These are the two solutuons that I came up with and none of them work: // Handle all of the collisions one after another, this one places the block on the right side and stops floor-movement for (auto it = toiOrderedList.begin(); it != toiOrderedList.end(); it++) { bodyA->HandleCollision(it->second, it->first); } // And this one only handles the first collision, then starts another iteration of checks with the new velocities, // this one makes the player be able to move over gaps/holes and prevents being able to move into a space in a wall, // because the body just slides past it. if (!toiOrderedList.empty()) { bodyA->HandleCollision(toiOrderedList[0].second, toiOrderedList[0].first); } The only thing I can think of is splitting this movement up into 3 different velocity vectors. The first one until it hits the right block, then "slide" it to the left until it hits the edge, then create another vector that moves it left+down again, once the first block doesn't block downward movement anymore. But that seems insanely complicated, and I am 100% certain this will NOT work or create 5 new problems and I'm just going to waste my time... Another thing this brings up is, how should it look like if I wanted to check if one body is "touching" another body, or "at the edge" or something?   What does a GOOD collision system design look like? Should the player modify the position/velocity of it's body directly or return some kind of "desired" correction, which then gets evaluated by the "physics system"? Should It all have some kind of generalized behaviour that it just sets up at the beginning? body->SetBehaviour(FALL_ONTO_FROM_ABOVE, SLIDE_ALONG) or something like that instead of having a HandleCollision() which modifies position etc itself?   Btw the reason I'm not using Box2D is, first of all, I want to understand this stuff and be able to do it myself and second of all it just doesn't work very well with pixel-precise movement. Jittering on the floor, having to parse my level and create ghost vertices everywhere two bodies are side by side etc... I tried It and it was ugly. Why should I use a physics library and then program workarounds for the "physics"-part anyway, then why use physics simulation in the first place? Shovel Knight uses it apparently, that's why I tried it.
  11. But what if the solution is inside the box, it's just too small or too obvious to see it? Like when your looking for your glasses but you have them on already :) Then stepping out of the box would be a mistake ;) That's another problem I often have, not knowing if I'm moving in the right direction. Should I keep going, am I close to a solution? Or am I heading into a dead end and should rather turn around, look for another way? My current approach seems to be kind of working and my gut tells me I just need to fine-tune it somehow, it's likely just some minor mistake that messes everything up. Like an "off by one" error. (i.e. > instead of >=). Found one just yesterday, after a long time of not noticing it at all. A big problem is that I currently have no real idea how to catch bugs that happen in real time, like when my game is running at 60 fps and from one frame to the other, suddenly the player falls through the floor. I can't go back in time and look at all the possible states the player was in, and I can't set a breakpoint if I don't know when, why or where in the code it happens. If I set a breakpoint before collision resolution happens, it will break EVERYtime, even when the resolution works correctly. Displaying the coordinates etc on the screen is also useless because it changes way too fast. Maybe I need to implement some way to only move one timestep per keypress or a giant array of past states of everything, I don't know.   I have read a few articles explaining algorithms like GJK, SAT, minkowski sum/diff in the past but somehow I find it hard to get a good intuition for it and putting it together into a working system. But I don't think I will need any of those more advanced algorithms anyway in a "simple" project like mine, I will never have any polygons or rotated rectangles, just plain old AABBs. Simple arithmetic on position, size and velocity should be enough, like braindigitalis suggested, or am I wrong? It's just a matter of correct order of operations, update first, then check for collisions, or check before moving, solve collsion A first then B or other way around, if solved, start a new iteration of collision checks or keep going etc...   Well, I will keep trying, I guess it's just a matter of trial and error. By the way, thanks for all your input, everyone :)
  12. @Randy Gaul Thanks, I'll take a look at the slides. Yeah that's a video of what my "game" actually looks like :) (I wish I could call it a game but I dont seem to be able to advance past the collision part...) It may look like a lot is going wrong because of floats, but I don't think it actually is. Through all my debugging I never found the floats to be a problem. At least not anymore, one change that fixed most bugs was changing the representation of my rectangle class to x,y for the top left corner and width and height instead of x2,y2 for the bottom right corner. Maybe I'm wrong and am just missing some sneaky cases. But I think the main reason why its not working is because of the order the collisions get resolved in. Especially when I have to skip some collisions for special tiles/obstacles, like ladders.   I already had some kind of tile based system but then I realized I wanted freely moving platforms etc, so I rewrote everything. Another reason why I wanted to rewrite it is because I thought tile based would be too restrictive and I might as well go with the "real" thing.     @CC Ricers Hmm I think I tried something like that and a few things didn't work out, thats why I switched to calculating the "time of impact" instead of penetration amount checking. One of the things was the same thing that's being adressed in the article: Wrong resolutions. But I'm not sure If I tried it with the correct ordering. Maybe I could try swapping the techniques around and do it with the least penetration amount technique again.   I'm kind of sick of fiddling around with it. For two years I am stuck with this problem now and I'm making next to no progress... soooooo frustrating argh... But of course I didn't work 2 years non-stop on it. Otherwise I would already have gone insane Have been procrastinating a lot because I have absolutely no idea what to do anymore and I'm kind of lazy and demotivated.
  13. Oh my god, my system is so extremely poorly designed... I have absolutely no idea how to do it right. Right now I'm wondering how to transition into the "falling" state of the player. Before I just checked if the velocity of the body is positive, if yes, change state to "falling". But after realizing I cannot stand still on a ladder, because gravity is still pulling me down I had to rewrite the code a little bit. Before, I added gravity to the players body in player::update(), AFTER doing the specific PlayerState::update() (like standing, walking, sliding etc). This way, vel.y was always 0 inside of the substates, because collision resolution happened before. But this way I cannot set vel.y to zero in "climbing" state, because right after that, gravity would be applied. So I changed the order, now gravity gets applied FIRST, then PlayerClimbing::update() runs, which sets it back to zero. But now in PlayerWalking::update() vel.y will ALWAYS be positive, because gravity got already applied, and therefore it transitions immediately into the falling state. I have no idea what the correct order would be in a good system. So instead I now have to actually check if the players body is "touching" any collidable bodies from above. What a mess... Just look at this: void PlayerWalking::update() { //... RectEx footRect = player.GetBoundingBox(); footRect.ResizeSides(0, -footRect.GetHeight()-1, 0, 0); footRect.MoveBy(0, 1.0f); auto tiles = player.level.GetTilesInRect(footRect);         // I could also ask the world instead, and get generic bodies back instead of the actual tiles/platforms etc.         // but then I would have to convert them to Tile* or something first. bool onFloor = false; for each (auto tile in tiles) { if (tile.second->IsSolid()) { onFloor = true; } } if (!onFloor) player.ChangeState(player.states.falling); //... } Is there a better way of keeping track when bodies come in conact and lose it again? Thinking of it more like callbacks/events "OnContactBegin(...)" and "OnContactEnd(...)" instead of non-stop polling/checking.   I also have huge problems correlating bodies to their actual owners. For instance if I check inside PlayerWalking::resolveCollision() against the body, how do I know what it actually is? Is it a platform? An enemy? A bullet? All I have is a pointer to a body. For now I did it kind of like the Box2D library where every body has a "void* userData" that can be assigned anything. So for now everytime I create a body I save a pointer to its owner in there. But casting it back and checking then becomes a mess. Should I give the body class a "GetType" function, which returns a value of an enum? Something like: enum BodyOwnerType {     TYPE_PLAYER,     TYPE_PLATFORM,     TYPE_GIANT_ROBOT_ENEMY,     TYPE_SMALL_ROBOT_ENEMY,     //... }; player.body->SetType(TYPE_PLAYER); // so later I can do huge chunks of checking in PlayerWalking::resolveCollsion like this: //... // inside PlayerWalking::ReactToCollsion(Body* body, CollsionInfo info) if (body->GetType() == TYPE_GIANT_ROBOT_ENEMY) { GiantRobotEnemy* enemy = reinterpret_cast<GiantRobotEnemy*>(body->GetUserData()); player.takeDamage(enemy.GetDamage()); } else if (body->GetType() == TYPE_PLATFORM) { Platform* platform = reinterpret_cast<Platform*>(body->GetUserData()); if (platform.IsSolid()) vel.y = 0; } //... Are there any good tutorials on how to actually design a GOOD "system" or whatever its called? Software engineering for 2d platforming games? I just don't think I can come up with something good on my own. My own design feels like a way too complicated rube goldberg machine that does something that should be relatively simple, way too complicated and indirectly. Or is it not possible to do it any better? Should I stick with this or try to make it better?
  14. @Randy Gaul: That's definitely what it feels like I'm doing: trying to do something that's almost impossibly difficult. Maybe I'll just have to design levels with big enough gaps and forget about falling into "1 tile" big gaps. I'm still using tile based layout, but I'm not doing collisions in a grid or something because I want moving platforms and enemies and the player will move freely anyways, so why not just make everything be free of the restrictions that a tile based system would put in place.   @jHaskell: Yes I tried it, but I don't like it. It just doesn't really work well if you want pixel precise movement and if there are many "tiles" beside each other, walking over them causes the player to hop over the "seams" between them. So in order to prevent that I would have to basically either add ghost vertices on every side for every body, or create some kind of chain shapes, or somehow merge multiple bodies whose sides are colinear into one big body. And that would really only work if they are the same type, with the same behaviour. So if one was some kind of ice-tile and the other maybe rubber, I would not really be able to make them into one body. Except if I make some kind of "split-body" type, which then defines regions inside of it, and check if the collision happened on the left half of it, it would react like ice, and if it happened on the right, like rubber. Those are just ugly workarounds/hacks. Box2D really is more of a physics simulation library for more dynamic movements where pixel precision doesn't really matter.   This is from the official Box2D FAQ: And #2 is what I want :) I don't want the character to sometimes stop 1 pixel in front of a wall, other times 2, or 0. I want consistent behaviour. No jittering. Otherwise it just feels "cheap".     Right now after kind of randomly changing the code, I seem to be able to fall into gaps, but sometimes I just walk through walls, especially when objects are involved that should be not be collidable and just return false in HandleCollision(), returning false should mean "ignore this collision"... Heres a little demo what it looks like: (the white things are supposed to be ladders, pass through, except when standing on the last rung of the ladder on top, like a platform).
  15. @JeffCarp: Wow, thanks, nice find. Checked out a few videos today, but since I didn't watch all the previous videos it's kind of hard to just jump in and understand whats going on. I'll try to watch more in the coming days. The video for Day 50 seems to be what has the most relevant information for my problem. At the end of it it kind of seems to work, but who knows, I'm sure I'll find a problem with it ;) I am never satisfied... One problem that I already see is that hes doing it all in one place, so the player kind of is the collison system and handler at the same time? Maybe he seperates it and makes a more generalized collision system in a future episode, I don't know, I need to check out more of his videos.   @Glass_Knife: Yep probably read it in the past, just skimmed over it right now because I don't need it, but thanks. I'm already pretty happy with my collision detection code, detecting is not the problem, the only problem is, now that I know what collides with what, when and how, what do I do to prevent the collision and set the objects to their correct location and correct their velocities? And where should I do it? How should the "World" or collision system, that does all the moving and checking, interact with classes that actually "own" the bodies? I think I want the behaviour defined inside of the different entities/objects like player, enemy, bullet etc. But how can they both work together? As explained in my original post, currently every body has a CollisionHandler assigned to it and when system detects a collision it calls the bodies CollisionHandler to pretty much tell the player or whatever "Hey you're going to collide, change your position and velocity yourself however you want to react to it". I'm not sure if it's a good idea to manipulate the pos/vel directly, would it be better to just return some kind of "desired position/velocity change" struct and have the world take care of actually updating the values? One of my main problems right now is that solving ONE collision works perfectly but as soon as there are more than one collisions per timeframe, it doesn't work like I want it to. Here is one example. The player is on the ground and starts walking left, his velocity is slightly downward because of gravity. If I change the velocity after the first collision, It won't "slide into" the gap, because the Y velocity is now zero. He would end up on the other side of the gap instead of falling into the deathhole ;) The excpected behaviour would be that he gets stuck on the edge and starts falling down next frame: But THIS method has as a side effect that he will get stuck when walking: So the problem is kind of with the ordering when handling multiple collisions in the same timestep and the needed correction of position and velocity. I actually had a tile based system before, where in this case I could just easily check if there is an adjacent solid tile, if so, don't count the X collision. But now I have a tile-free system where objects can be anywhere and any size and thats where this simple check doesn't work anymore. Somehow I need to check for two cases basically, one: the gap is smaller than the player, then ignore the X collision and walk over it or two: the gap is big enough for the player to slide/fall into. But I need to do these checks only if the Y coordinates are exactly the same, otherwise he SHOULD always get stuck, if there is a little bump. I'm thinking of maybe a ton of raycasting and conditional checking... Is there a better way?     Edit: A bit of info of how I detect collisions. I basically just extend bounding box A by its velocity (swept), then do a check which other bodies intersect with that rect, those are the POSSIBLE collisions. Then I divide the velocity by the distance to get the "time of impact": toi < 0 collision happened before this frame. 0 < toi < 1 collision happening sometime this timestep (0.5 would mean halfway through movement) 1 < toi collision will happen in a future timestep I get that for every axis, then I move the rect by velocity * toiX or toiY respectively and a little more to actually move it INTO the other rect and then check if it is intersecting. If both are colliding, which toi is smaller (x or y) determines where the collision happens first. So I can figure out for instance, that 33% (toiX = 0.33) into the movement, bodyA collides into bodyB from the right side, since vel.x is negative (moving left).
  16. Horscht

    2D Collision Reponses

    The problem with that approach is that it doesn't really take into account on which axis the collision happened first, meaning the player can be pushed out of a platform sideways instead of landing on top, depending if you check the X or Y axis first. You probably won't notice it most of the time, except when you move diagonally onto a corner. A way to fix this is to calculate the overlap first, then divide that by the objects velocity to find out which axis collided first, and then push it out in that direction. float timeOfImpactX = std::numeric_limits<float>::infinity(); float timeOfImpactY = std::numeric_limits<float>::infinity(); if(dynamicBody.velocity.x != 0.0f) timeOfImpactX = GetRECTOverlapX(staticBodyRect, dynamicBodyRect) / dynamicBody.velocity.x; if(dynamicBody.velocity.y != 0.0f) timeOfImpactY = GetRECTOverlapY(staticBodyRect, dynamicBodyRect) / dynamicBody.velocity.y; if(timeOfImpactX < timeOfImpactY) {     // Solve X first } else {     // Solve Y } Something like that. I'm not sure myself if this is the best way but it's something to think about when your collision resolution feels weird when trying to land on the edge of a platform/tile.  
  17. Horscht

    C++ Ball Bouncing

    Well, you also need to reverse the velocity of the balls once they hit the walls so that they move in the opposite direction in the next frame. if(BallRect[1].x < 0 || BallRect[1].x + BallRect[1].w > 800) { BallRect[1].x -= X_Vel[1]; X_Vel[1] *= -1; // This will 'reverse' the direction the ball is going, if you want them to slow down every time they hit a wall you can change the -1 to -0.95 or less } And for the other ones too of course.
  18. For my game I did it like this (i did mine in C++ but the concept should be the same): You have two rectangles: a viewport, that's the area that's supposed to be visible, basically the whole area of the window/screen, and the boundaries of your level. The center of the viewport is the spot the camera is "looking at". So if you set the cameras centerpoint to the players centerpoint in every frame, it will follow the player. All you need to do is keep the viewport in the boundaries of the level and then when drawing the player draw him at his current position minus the distance of the viewports left side to the left side of your level boundary. Like in the attached picture xOffset = cameraCenter.x - (viewportWidth / 2) - bounds.left; yOffset = cameraCenter.y - (viewportHeight / 2) - bounds.top Something like that. I'm not sure if this is 100% correct but it should get you started.  
  19. Horscht

    search container

    If passendeAirports is a container, passendeAirports.begin() will just return a pointer to the first element I think. So it wouldn't make sense to make a string out of a pointer to an Airport. Or maybe I just don't know everything that strings are capable of :P Do you want to return a string like this: "Airport1, Airport2, Airport3"? If so I would say use a stringstream: stringstream ss; for (auto it = foundAirports.begin(); it != foundAirports.end(); it++) {     auto airport = (*it);     ss << airport->GetName();     if(airport != foundAirports.back())         ss << ", "; } return ss.str(); For your asAirport and deepCopy I would suggest using dynamic_cast and the copy constructor instead and not return something with new, because you will have to call delete on it, the problem is that this wouldn't be obvious, you might forget to call delete because you don't see any "new" in your code where you use this method. Try it like this instead for copying: // Copy constructor Airport(const Airport& copyFrom): id(copyFrom.id), name(copyFrom.name), lat(copyFrom.lat), lon(copyFrom.lon), elevation_ft(copyFrom.elevation_ft) { } // Somewhere else in the code Airport newAirport(otherAirport); // Or Airport* newAirport = new Airport(otherAirport); If you don't provide a copy constructor the compiler will generate one for you automatically, but I'm not sure how exactly it does the copying, maybe just like my example, so you wouldn't need to write your own unless you have pointers in your class. You don't really want two objects pointing to the same thing. You would need to create a copy for your copy. Well, you can look up copy constructors yourself, if this interests you :) As for the dynamic_cast, that would look like this: Waypoint* waypoint = new Waypoint(); Airport* airport = dynamic_cast<Airport*>(waypoint); // You can't convert a base class to a derived, so this will fail, meaning airport will be 0 or nullptr. Waypoint* waypoint = new Airport("London"); Airport* airport = dynamic_cast<Airport*>(waypoint); // This will work because the object waypoint points to is indeed an Airport. So airport will be a valid pointer. I hope I'm not explaining everything wrong here, I'm not an expert either sorry :) But I think it should be correct... hopefully.
  20. I don't think the floats are a problem, because they will get casted implicitly to ints when needed and you will get a compiler warning about that so it doesn't go unnoticed, unless you turned those warnings off. So the actual values that are used in the calculations can only be off by 1. One thing that i found out the hard way by looking for a bug for 2 days is and may be helpful to you: Floats get rounded down when positive and rounded "up" to a higher value when negative. So 4.56f will become 4.0f and -4.56f will become -4.0f. But as long as you are not doing pixel-perfect collision detection that shouldn't be a problem. ( I did :) )   Anyways, here are a few things you can try to find your bug: 1. Make sure your collision detection works. To make absolutely sure I would write a small program that draws two rects, where one can be moved with the mouse or keyboard and then use check_collision_rect() to see if it works in every single possible constellation. You could set the color of the rects accordingly, red if they intersect, green if no. If that works perfectly then the bug is clearly somewhere else. 2. See if the tile you are colliding with is indeed solid or maybe you just forgot to set that attribute? Run your game and set a breakpoint at that section of code when your player should be colliding and step through the code and look at the variables. Is the type really 2 when it should be? 3. It could even be LEVEL_WIDTH that's causing problems, who knows :P If it's wrong your loop will wrap incorrectly and your player would never collide. Again use your debugger and while stepping through look at every variable possible if it has the value you would expect.   Learn to use the debugger and you will find bugs like this MUCH faster and easier. Remember you can set a breakpoint even while your program is running. Oh any btw I think the bounding boxes should not be: rightA = A.x + A.w; but rightA = A.x + A.w - 1; Why? Let's say you have a rect that starts at 0,0 and is 10 pixels wide: The width is 10, so rightA would be 0 + 10 = 10, is that correct? No :) The rightmost pixel really is 9 -> 0,1,2,3,4,5,6,7,8,9, that's 10 pixels wide.
  21. Horscht

    search container

    Sounds like a job for regular expressions. Maybe theres a better way already implemented in the map but this seems to work: #include <iostream> #include <map> #include <vector> #include <regex> #include <sstream> using namespace std; class Airport { private: string _name; public: Airport(string name):_name(name) { } string GetName() { return _name; } }; map<string, Airport*> airports; std::vector<Airport*> getAirports(string searchTerm) { std::vector<Airport*> matchingAirports; for (auto it = airports.begin(); it != airports.end(); it++) { auto mapEntry = (*it); stringstream ss; ss << ".*" << searchTerm << ".*"; regex regEx(ss.str().c_str(), regex_constants::icase); if(regex_match(mapEntry.first, regEx)) { matchingAirports.push_back(mapEntry.second); } } return matchingAirports; } int main() { Airport one("London Heathrow"); Airport two("Tokyo International"); Airport three("Los Angeles International"); airports.insert(make_pair(one.GetName(), &one)); airports.insert(make_pair(two.GetName(), &two)); airports.insert(make_pair(three.GetName(), &three)); string searchTerm; while(true) { cout << "Please enter a name to look for, 'exit' to quit: " << endl; getline(cin, searchTerm); if(searchTerm.find("exit") != -1) { break; } auto foundAirports = getAirports(searchTerm); cout << foundAirports.size() << " airports found: " << endl; for (auto it = foundAirports.begin(); it != foundAirports.end(); it++) { auto airport = (*it); cout << " - " << airport->GetName() << "\n"; } } system("pause"); } If you search for "dOn HeatHR" it will find London Heathrow. Of course you can change how exactly you want it to match at this line: ss << ".*" << searchTerm << ".*"; Here's a good reference for regular expressions: http://msdn.microsoft.com/en-us/library/az24scfc.aspx Hope this helps :)
  22. I had a similiar problem with my platformer game and the way I solved it was by calculating how far the two object overlap and then divide that by the velocity, to determine which side was hit first and then push the player out on that side. void ResolveCollisions() { Vector2D penetration = GetPenetrationAmount(playerBoundingBox, tileBoundingBox); float tx = 100000.0f; // Time of impact, 0 = now, really big number = never float ty = 100000.0f; // Calculate time of impact, the smaller happened first if(velocity.x != 0) tx = abs(penetration.x / velocity.x); // Don't divide by zero or everything explodes :) if(velocity.y != 0) ty = abs(penetration.y / velocity.y); // Check in which direction we collide first and resolve collision on that axis if(tx < ty) { PushOutOfCollisionX(penetration.x); } else { PushOutOfCollisionY(penetration.y); } } Vector2D GetPenetrationAmount(RECT r1, RECT r2) {     Vector2D p;     int l2r = r1.right - r2.left;     int r2l = r1.left - r2.right;     int t2b = r1.bottom - r2.top;     int b2t = r1.top - r2.bottom;     if(abs(l2r) <= abs(r2l))     {         p.x = l2r + 1;     }     else     {         p.x = r2l - 1;     }     if(abs(t2b) <= abs(b2t))     {         p.y = t2b + 1;     }     else     {         p.y = b2t - 1;     }     return p; } Something like that. I hope this helps you somehow, good luck :)
  23. My current super primitive amateurish system works like this: I have a GameState class which just calls update() and render() on all child objects like the player, level, later enemies and so on. then there is a Player class and a Level class which in turn has a list of LevelSections, this is the class that holds the tiles, renders the tiles, provides methods to access the tiles like GetTileAt(x,y). The Level class provides the same methods and redirects it to the section the player is currently in. Tile coordinates start at 0,0 for every section and each section has it's own x,y start position, so when the player is at the last tile of the current section i should be able to iterate through all sections and check if there is a section which has the coordinates of the next tile, right? Player is at tile 30,20, 31,20 doesn't exist so i iterate through the list of all sections and see if there is one which has the start coordinates 31,xxx and then initiate the mysterious "scrollover-mechanism". Does this sound like a plan?...   My player currently gets a pointer to the level like this: // GameState.cpp GameState::GameState() { level = new Level(); player = new Player(level); } So now player has access to level and can call it's GetTileAt(x,y) method for colission detection and so on. Just by the way, what if the level also needs access to the player? At the time the level gets instanciated the player doesn't exist yet... In the Level class I do everything using a pointer to the current section. Like so: // Level.cpp Tile* Level::GetTile(int x, int y) { return currentSection->GetTile(TL_FOREGROUND, x, y); } void Level::Render() { currentSection->Render(); } And so on... This works fine if I wanted to stay in one section forever and never be able to go to the next one, but that's not really what I want As soon as the player reaches the end of one section, player control should be suspended and the screen should scroll over to the next section, but the player also has to move and play walking animations or not depending on if he is in the air or ground or whatever.   How do I do that? Where should the code go that moves the "camera"? Currently it's in GameState::Render() like this: void GameState::Render() { RECT pBB = player->GetBoundingBox(); Vector2D pMid; pMid.x = (float)(pBB.left + (pBB.right - pBB.left) / 2); pMid.y = (float)(pBB.top + (pBB.bottom - pBB.top) / 2); int levelWidth = level->GetWidth(); int levelHeight = level->GetHeight(); int minPlayerXOffset = (int)(pMid.x - g_window_width/2); int maxPlayerXOffset = (levelWidth - g_window_width); if(minPlayerXOffset < 0) minPlayerXOffset = 0; if(minPlayerXOffset > maxPlayerXOffset) minPlayerXOffset = maxPlayerXOffset; level->Render(minPlayerXOffset); player->render(minPlayerXOffset, dt); } How do the classes need to interact to make this work? Should the GameState check if the player is on the edge and if so, call player->SuspendControl() and move the player every frame over to the next section until the transition is complete? But that sounds like it should be in the player class itself. Or maybe the player should have a different state, but I don't know how to implement that, with lot's of switch cases? If elses scattered throughout the update() and render() methods? A different update() and render() for every state()? What would be a good way to do that? I thought maybe with a function pointer that gets passed a different method like this: // Player.cpp Player::Player() { _update = &Player::StateDefaultUpdate; _render = &Player::StateDefaultRender; } void Player::Update(float dt) { (this->*_update)(dt); } But how should I organize this? Put it all in the same file or in different ones? I have absolutely NO IDEA... I wish there was more information on the internet on how to program more complex games than tic tac toe or a jump'n'run that only has one screen and fit in one file. All the open source games I looked at are a THOUSAND times more complicated than what is taught in books and tutorials StateManagers, ScreenManagers, BlablaHandler, MovementComponent, blablabla... none of this is explained anywhere. It's like it's expected of me to come up with these myself. But for me that's like coming up with something like calculus from scratch on my own... I have so much I don't know I don't even know where to start or what questions to ask hahahhaa.... Hopefuly some of you will understand what I am trying to do and can give me some tips on how to do it. Here's a video of the game I'm trying to copy if you don't already know it: Book recommendations for getting into more sophisticated game programming or whatever also highly appreciated. I attached my current sourcecode for the involved classes if you wanna take a look at the actual code. It's ugly but I wanna get it working first before I clean it up. No need for nice and good to read code that doesn't work [attachment=17248:Code.zip]
  24. Awesome, that's exactly what I'm trying to do too, you even made your code available on github, big thanks for that! I also found another one a while ago (https://github.com/Tesserex/C--MegaMan-Engine) but both are a little over my head How do I progress from simple games to something like this? This is on a whole different level than what is taught anywhere. The thing I'm having the most trouble with and I think is the most important thing is the software engineering part. Code design, structuring, architecture, whatever it's called. Hopefully I can learn something from reading your code, but I never know where to start and how it all works together when there are already 100 files.   I thought that my "Transition Regions" would just be the edge of the map, or maybe the last column/row of the tile array that doesn't get drawn or something like that. If I then want to stop the player from going back I could just make those tiles solid in the next room. But I still don't know how to do the actual scrolling. Which class should check where the player is and when to initiate the transition? The GameState? The Level? The Player? I guess all the classes do their scrolling in their own way, but how do the classes know when the transition is over and gameplay should resume?    
  25. Hi,   i've been trying to create a very simple 2D platformer game over the last few weeks. I'm basically trying to make a megaman clone. That's it. No fancy physics or anything, just regular rectangle vs rectangle collision, non-rotated. The problem is, i can't get the collision handling to work... i have rewritten the code a billion times and even though it should work, it doesn't and the player is just falling through the floor or not being able to walk on the floor, getting stuck in the floor, being teleported along tiles, being able to stand on walls and so on... For me this is something i ABSOLUTELY cannot wrap my head around While looking for a solution i found 1000 pages describing how to detect collision and then just leaving it at that, as if that was the hard part... I have found only a few pages that actually show some method on how it's supposed to be done, i tried implementing this one: http://go.colorize.net/xna/2d_collision_response_xna/ But i can't get it to work... I also tried 100 different ways on my own:   1. Moving the player first, check if he's colliding, if so, move him out on the axis with smallest overlap, then check again and do the same for the other axis. Didn't work, i don't know why. 2. Moving the player first, check if he's colliding, if so, place him beside/on top of the block. Didn't work, i don't know why. 3. Check if player would collide in the next frame, given current position and velocity, if so, place him beside/on top of the block. Didn't work, and again, i can't figure out WHY... And a few more that i already forgot, they are all kinda similiar except for one thing they have in common: THEY DON'T WORK Another thing that happens with most of the techniques is, the player bounces on top of the tiles because i have to place him 1 pixel above the tile, or else he gets stuck inside. That means he will fall 1 pixel per frame and constanly bounce just a tiny bit. Looks very unprofessional and to me means the method is very poorly executed.   This is the most complicated thing i have ever come across and i need some help to understand what the best way to implementing something like a 2D Platformer like Megaman or Mario or whatever is. I seriously doubt that i will ever in my life intuitively understand how it's supposed to work. Moving player out of 1 tile on just 1 axis works, as soon as the other axis comes into play or more tiles, everything breaks and nothing works like it should.   Anyone out there who has real experience with this matter? I'm not asking for how it theoretically should work, i know that, but when i try to write the code for it, it just DOESN'T work Only moving the player when he's not colliding is ugly, because he will just float above the tiles or stop beside a wall with a gap inbetween. The only thing left is brute force, move player pixel by pixel until he collides with something, but that's not very efficient and extremely bad code in my opinion, there has to be a better, more sophisticated way   Here's just one example of what i tried (left out the code for the other axis): COLLISION_INFO ResolveCollisions(RECT* rect, std::vector<RECT>* obstacles, int dirX, int dirY) { COLLISION_INFO ci = {0,0}; int pushX = GetMinOverlapX(rect, obstacles); int pushY = GetMinOverlapY(rect, obstacles); if(abs(pushX) < abs(pushY)) // resolve smallest overlap first { ci.pushDirectionX = ResolveCollisionOnXAxis(rect, pushX, dirX); pushY = GetMinOverlapY(rect, obstacles); if(abs(pushY) > 0) // if other axis still overlapping { ci.pushDirectionY = ResolveCollisionOnYAxis(rect, pushY, dirY); } } else { ci.pushDirectionY = ResolveCollisionOnYAxis(rect, pushY, dirY); pushX = GetMinOverlapX(rect, obstacles); if(abs(pushX) > 0) // if other axis still overlapping { pushX = GetMinOverlapX(rect, obstacles); ci.pushDirectionX = ResolveCollisionOnXAxis(rect, pushX, dirX); } } return ci; } int ResolveCollisionOnXAxis(RECT* rect, int pushX, int dirX) { if((dirX > 0 && pushX < 0) || (dirX < 0 && pushX > 0)) // don't push in the same direction as player is moving, or else bugs occur { if(pushX > 0) { rect->left += pushX+1; // 1 more to get out of the tile return 1; } if(pushX < 0) { rect->left += pushX-1; return -1; } } return 0; } int GetMinOverlapX(RECT* rect, std::vector<RECT>* obstacles) { int minPushX = INT_MAX; for(auto obstacle = obstacles->begin(); obstacle != obstacles->end(); obstacle++) { int dx1 = rect->left - obstacle->right; int dx2 = rect->right - obstacle->left; int thisPushX = 0; if(abs(dx1) < abs(dx2)) { // push player to the right thisPushX = -dx1; } else { // push player to the left thisPushX = -dx2; } if(abs(thisPushX) < abs(minPushX)) minPushX = thisPushX; } if(minPushX == INT_MAX) return 0; // if for whatever reason the vector was empty dont move else return minPushX; }
  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!