Closed DivFord closed 9 years ago
I've just finished implementing bounding boxes, so you hopefully won't need to do anything extra there. The numbers I used were just made up, so feel free to change them (they're in PropList.hpp).
Otherwise, yeah, this seems like it would be really nice.
I did wonder whether we could use the existing Position class, but call it something like Object. We could then base all entities that appear on the screen upon this class via inheritance. If we gave a collision radius to this object, then for each Object instance, we pass the list of Objects to some member function, update say, then each object would adjust it's position to account for the Objects nearby.
Something like:
// Init object list. E.g. std::vector<std::unique_ptr<Object> > objects = get_objects
for (auto& object_ptr : objects)
object_ptr->update(objects)
for (auto& object_ptr : objects)
Window::instance().draw(object_ptr, sprite);
How would that handle collision aspects other than position? Bullet impacts, for example.
Well everything drawn to the screen would be an instance of Object of one of it's child classes, so Bullet would just inherit Object.
Ok, that seems better. It's going to mean a major rework to pretty much all the source files though. How should we coordinate this?
Hmm. I like the idea, but I'd say it should be separate to Position. This way, it's position and dimensions can be Position instances, so both can move and change easily.
Just nominate someone, and everyone else keep away from the code. That seems to be the simplest way.
I suppose I was considering it from the point of view that position only makes sense in the context of entities that actually have a position, and Position seems to encode more information than simply the coordinates of something, as it has velocity and acceleration as well.
That's for if the object wants to move. This can also be use to scale the object's dimensions (if that's ever necessary) as dim is also a position.
I think we should get rid of position, and instead have GameEntity (containing the position and bounds) with DynamicGameEntity deriving from that (adding velocity and acceleration). Then block can derive from game entity, while prop, player and projectile derive from DynamicGameEntity.
I'm going to work on art for a while, so one of you two can handle this.
Would the Sprite then be part of GameEntity? It'd need to know the pos and dim, which is what GameEntity is going to contain.
Position has many of the same properties as what you describe, and is a good starting point, I just think it makes more sense to refer to it as an object, then use inheritance to subclass it.
Here's a brief sketch of a possible class layout:
class Object // or GameEntity or some such
{
public:
Object(const Vector& pos, const Vector& vel);
virtual ~Object() { }
virtual void update(/* Some list of objects */) { }
virtual void destroy(); // Here we can destroy ourself and any objects we have as children
void setVelocity(const Vector& vel);
void setAcceleration(const Vector& acc);
private:
Vector position_;
Vector velocity_;
Vector acceleration_;
float collisionRadius_;
int index_;
std::vector<Object*> children_; // Used to ensure children are destroyed, maybe?
};
I think if we could somehow set things so that you could pass each object into a draw function, which would look up the index of the object and fetch the sprite, then that way you can achieve better encapsulation of the graphics code.
Agreed.
@Fyll : Sprite needs to know the pos, which we can presumably just pass as a vector, but it makes sense for sprite dimensions to be independent from gameplay dimension, so I don't think it needs to link to Matt's Object class.
I think it's really important that the only thing that can change GameEntity's position is its own update method. This way you simply have an entity that reacts to the objects around it with either a change in velocity or acceleration, then the position is updated automatically.
Actually it's going to be important to create a seperate move function that is called after update. If the position is changed by update, then when the next object in the list looks through to find it's neighbours, it'll encounter objects that have moved within the update step.
The trouble with that is that the sprites are all on different sheets.
It may work if you have two indices, one the texture index, and the other the yIndex for things like props.
Also, I've tweaked Position a bit so gravity is separate to the normal acceleration, and acceleration also decays. From this, jumping and running and so on are done by supplying an acceleration rather than a velocity. It leads to smoother movement I feel, so we should probably keep something similar here.
@DivFord : Fair enough. The object dimensions are basically the topLeft and bottomRight positions at the moment.
My comment may not have shown up, but I set jumping back to a velocity change. Otherwise it feels like a rocket taking off.
@mspraggs : But wasn't part of the reason for doing this so that things could push one another? If they can't move each other, how will they accomplish this?
They can move one another, they just have to do it by applying acceleration.
One of the comments someone made during the final round of playing was that the jumping was too jarring. That's what made me think of changing it to an acceleration.
How about this? When you create an object, you know it's type and so forth. What you then do is to get it's index, and register that unique index with some sprite, so that way the graphics code just needs the index to look up the sprite.
@DivFord or indeed velocity
GFX_POOL does that with the textures already.
Yes, but the point is that the actual code to call SDL to render the sprite to the screen is separated from the class that encodes the behaviour of the objects in the game. That way things are encapsulated better and it's easier to maintain.
EDIT: Then you're literally just passing an integer and a set of coordinates to the graphics system.
Sprite contains the texture ID and performs the call to SDL. Position handles the manipulation and behaviour of the object in game. I don't see how what you're suggesting is different to this (in this respect).
So, in Unity they have two of force modes, one that applies instant force, another that applies continuous force. Is it worth encapsulating velocity and acceleration, and instead accessing them through Force() and Impulse() ?
I think Sprite is fine as is, except referencing position.
It has to reference position, as it otherwise doesn't know where to draw the sprite.
Forces would be the ideal way to do it (you're talking to two physicists :P), they just seemed like too much hassle during the Game Jam.
That's what I'm saying, the sprite doesn't need all the velocity and acceleration aspects, all it needs is a position vector, not the position class. All sprite position should be is x and y.
@Fyll Ah I see what you're saying now. Yes, Position and Sprite do contain the sort of thing I was suggesting. However, what we currently have is a system where classes own instances of Sprite and Position. What I'm suggesting is to have Player, say, be a subclass of Position/Entity/Object, without a Sprite member variable. This way the Player instance has zero knowledge of what's going on with the graphics, which frees us from thinking about this when writing the game mechanics.
The other issue is that the graphical coordinates and game coordinates are currently one and the same. Whilst this isn't a big deal as we're working in 2D, it would be nice to be able to pass the game coordinates to the graphics engine, which would transform them into graphical coordinates before plotting them.
Are they the same? I thought gameplay was in screenspace but graphics was in pixels.
So, Game would contain an array of Sprites, and each Object would contain it's Sprite's index, the Game draws all of the Sprites itself, thus removing the Sprites from Object? That makes sense, but seems to be a roundabout way of doing things.
What about cases where the Sprite needs to be moved manually (like with the gate. It's not animated, it just switches its frame when you stop standing underneath it)?
I'm not sure I understand the bit about the graphics engine though.
@DivFord : They're both screenspace. EDIT: The only things in pixels are the initial window size, and the images as they're loaded up.
If we have the sprite index, can we use that to call an animation function on the sprite?
What do you mean, an animation function?
Say, the sprite class has SetFrame(), AnimPlay(), AnimPause(), stuff like that.
Sorry, I perhaps I got confused about the coordinates.
Ok, how about this: there's also a base view class. Something that handles the drawing of an object to the screen. The base could just be drawing a sprite to at the given coordinates. Then you subclass it when you need additional functionality, such as an animation for change of state. The Game class would then link each object to it's respective view in some way.
So I suppose Sprite is akin to what I'm talking about at the moment, but it could potentially be subclassed to handle multiple sprites and the animation between them. EDIT: As David's just suggested :-P
So, ideally we would have sprite subclasses for player, blocks, and props, right? They all animate (or not) in slightly different ways.
I still don't see what the point of this is. Sprite already handles animation (not very elegantly mind, but that can be tidied up). I'm not sure how the various things you're proposing are any better.
The Object idea I can understand and get behind.
@DivFord : Do they?
Yeah, Tilesets use an x coordinate based on tiling (and when I implement internal corners, I'm going to need that to affect y coordinate as well). Props have y coordinates based on prop, and x coordinates based on frame. Player (and presumably other units if we ever add them - we may want to avoid a naming conflict there) has different animation cycles at different y coords, and different frames at each x coord.
I think it would give us some flexibility if we later wanted to add behaviour to certain objects over others, but then needed to reflect this in the graphics. Say we subclass Object into Gate. Gate could have a boolean open. Sprite could then be subclassed into GateSprite, which would monitor the variation in Gate.open, and act accordingly.
At the moment, they each handle their own sprite manipulation, which I can understand goes against the splitting of graphics and gameplay, but I don't really see how it's too much of a problem.
On that note actually, the Position class only updates the movement now, so I don't see why it needs to be removed.
But an open gate is just a solid prop to the closed gate's non-solid prop. There already is a boolean handling that.
@mspraggs To be honest, that's just the lack of encapsulation the other way round, so there's no real benefit. I would rather gameplay call anim functions than graphics query gameplay.
Perhaps I'm overcomplicating things, I'm not sure. I'm just trying to think of a design pattern we can settle on so the code is well organised. I'll do some reading.
Actually, if we're going to be doing some big changes to the underlying system, does someone want to back it up on here (or whatever) in case something goes wrong?
Good point. Matt, can you make a branch?
I can do, yes. Branching only makes sense though if you want to keep updating the existing branch while you're working on the new branch. Are we planning on doing that? Otherwise I could tag the current commit as say version 0.0-1 or something, so it'd be easy to find if we want to revert.
Yes, that second option would be better.
Great, I'll do that :-)
Can everyone confirm we're all committed and pushed, before I do this.
I have a new tile set, but I haven't implemented it. I'll do that once all this changing is done.
I'm all pushed.
I'm planning to re-do collisions.
Thoughts?