About object creation, updating, interactions, Unity

Member
Posts: 749
Joined: 2003.01
Post: #16
So osc you would not even make a function for shooting?

Personally i would make it a method for spaceship class, giving spaceship access to universe (hence bullets). Not super modular but lets me at least reuse the function easily.

Plus honestly

state->bullets[state->bulletCount].lifespan = BULLET_LIFESPAN;
state->bullets[state->bulletCount].x = state->ships[firingShip].x;
state->bullets[state->bulletCount].y = state->ships[firingShip].y;

does look fairly ugly Wink

©h€ck øut µy stuƒƒ åt ragdollsoft.com
New game in development Rubber Ninjas - Mac Games Downloads
Quote this message in a reply
Luminary
Posts: 5,143
Joined: 2002.04
Post: #17
Of course I'd make a function for it. I'd factor the code however made sense. It wouldn't be a method on the ship class though (there is no ship class!); it would be some sub-portion of update.

If you were to name the sub-structure that contains the bullet, you could write
Code:
state->bullets[state->bulletCount++] = shoot_bullet_from(&state->ships[firingShip]);
Quote this message in a reply
Member
Posts: 749
Joined: 2003.01
Post: #18
Hm yeah that's more elegant than passing state pointer to the function...

What if shooting a bullet created also a cloud of dust? (so you would need to return 2 objects from the shooting function), how would you handle that? Would you pass the state pointer to the functiom so you can directly change stuff in it?

©h€ck øut µy stuƒƒ åt ragdollsoft.com
New game in development Rubber Ninjas - Mac Games Downloads
Quote this message in a reply
Luminary
Posts: 5,143
Joined: 2002.04
Post: #19
Well, there are any number of options. I probably still wouldn't pass the whole state pointer in, but there probably is a point where I would.

As I said, I'm not very happy with the methods of actually updating the state that I've come up with.

I feel now we're getting bogged down in the details of the C, which isn't really (I think!) the point of this discussion. The architectures we're talking about here are applicable to any language.
Quote this message in a reply
Member
Posts: 749
Joined: 2003.01
Post: #20
I think that's a central point in the discussion.

One tries to be modular (minimizing the number of objects other objects (or functions) can access/depend on).

Like your first shooting function is nice and modular, only requires the spaceship in read only and returns a bullet object.

As interactions grow more complex you need to pass more and more stuff into functions (in read and write), up to the point where you might as well pass the whole state. There one has given up on modularity, but then again functions have become so game/situation specific that its very unlikely you're going to reuse it.

Personally i give up on modularity pretty soon. I end up passing state pointer to many functions/objects. Sometimes i realize i could reuse code by removing dependencies then i do it. But trying to minimize dependencies often gets back at you when you realize things are more interconnected than you thought and you need to access more stuff.

So yeah, i think minimizing dependecies is a good idea, in practice it often ends up being difficult.

©h€ck øut µy stuƒƒ åt ragdollsoft.com
New game in development Rubber Ninjas - Mac Games Downloads
Quote this message in a reply
Moderator
Posts: 3,571
Joined: 2003.06
Post: #21
Najdorf Wrote:Personally i give up on modularity pretty soon. I end up passing state pointer to many functions/objects.

Instead of passing state around, I just make it a global ID in my system.

Here's probably how I'd shoot:

Code:
void SpaceShipShoot(float x, float y, float velX, float velY)
{
    // this could be done any number of ways, so just pretend
    Array *shotsArray = retrieveArray(currStateGlobalID, spaceShipShotArrayID);

    // add a new shot to the shot array
    int i = arrayNewID(shotsArray);
    if (i == ARRAY_ID_INVALID)
    {
        // probably ran out of available slots in the array, so can't
        // shoot any more until some other shots time out first
        return;
    }

    // retrieve the new shot from the shots array
    Shot *spaceShipShot = arrayObjectForID(shotsArray, i);

    // init the shot
    spaceShipShot->x = x;
    spaceShipShot->y = y;
    spaceShipShot->velX = velX;
    spaceShipShot->velY = velY;
    spaceShipShot->rot = Rand1T() * 360.0f;
    spaceShipShot->timeAlive = 0.0;
    spaceShipShot->hit = NO;
}
Quote this message in a reply
Sage
Posts: 1,482
Joined: 2002.09
Post: #22
I was just playing around with inter-frame interpolation like two days ago. I've tried a couple different implementations before in the past as well, but have never been happy with them. Yet again my conclusion is that it's just not worth the extra effort. It's simply so much easier to just decouple the update frequency from the screen refresh rate and run the update at a high frequency (100 - 200hz). That gives you a fair amount of wiggle room to do time scaling effects and if you need more you can still interpolate fixed step update things like physics if you need to.

Part of the issue that I found that makes this difficult is (perhaps specific to Chipmunk) that using dead reckoning does not work whatsoever for drawing interpolation, and interpolating transformations becomes difficult when the object only exists at one of the boundaries. What do you do when the object is created or destroyed. (somebody else pointed this out too) Don't draw the object at all is simple enough for drawing, but I ran into a couple other annoying to deal with cases as well.

I've thought about the immutable gamestate approach as well. Mostly in terms of networking and time rewind effects like in the console Prince of Persia game. I've mostly rejected it as too much unnecessary work though. It seems like it would be easier to serialize a snapshot of the state than to save every state as an immutable object. I guess I'm thinking more like key/intra frames in video compression.

I instead like to try and make motion as procedural as possible. Like a bullet does not need to have a state update to make it move. It only needs to store the time, position, and velocity when it was created or last changed. Extrapolating it's position at any given time from that is easy. This can be applied to the motions of a lot of things, platforms, simple sprite movement behaviors, anything that follows a path, etc.

I also think that if I cared about making games so much as I did neat computer science ideas to apply to them I'd have created some really cool games by now. Rasp

Scott Lembcke - Howling Moon Software
Author of Chipmunk Physics - A fast and simple rigid body physics library in C.
Quote this message in a reply
Moderator
Posts: 3,571
Joined: 2003.06
Post: #23
Skorche Wrote:What do you do when the object is created or destroyed. (somebody else pointed this out too)
That was I. Totally in the same boat with you on that one.

My two main motivations for working out update interpolation are:
1) Precise frame rendering. In a Pong test I did recently while using Display Link, it provided absolute smooth animation Nirvana which I've been searching for since OS X came out. My Pong test is playable down to an update rate of 10 Hz, so I call it TenTickPong. It's *amazing*!
2) Client-side entity prediction for network multi-player. While it's not really something that I need at all, I'm interested in figuring it out because...

Skorche Wrote:I also think that if I cared about making games so much as I did neat computer science ideas to apply to them I'd have created some really cool games by now. Rasp

... I'm stuck in that too. Rasp

The server is only going to be sending out snapshots at somewhere between 20-30 Hz because that's about all you can reasonably get in network traffic, from what I've read, which is just way too much latency to be rendering from. So the client is going to have to be interpolating server snapshots, but also running its own simulation to have things snappy on the client side, which is called client-side prediction. The server is running the authoritative simulation though, and if the server snapshot turns out to be significantly different than the client's, then the client needs to back up and resynch to the server snapshot, which means it'll need to be interpolated to it, or else it'll be a major jarring experience to the player on the client machine. So, on top of this update interpolation, I'll need to figure out how to delta compress the updates to keep the snapshots small in size. ... for now though, just getting ultimately smooth animation against any update rate is what I'm shooting for.
Quote this message in a reply
Member
Posts: 446
Joined: 2002.09
Post: #24
Skorche Wrote:Part of the issue that I found that makes this difficult is (perhaps specific to Chipmunk) that using dead reckoning does not work whatsoever for drawing interpolation, and interpolating transformations becomes difficult when the object only exists at one of the boundaries. What do you do when the object is created or destroyed. (somebody else pointed this out too) Don't draw the object at all is simple enough for drawing, but I ran into a couple other annoying to deal with cases as well.

You know, I never considered this as a problem until you guys brought it up (though I still don't see the problem). If an object exists in the current frame, then it exists. As far as interpolation goes I just create a previous state for objects when they spawn that matches the initial state, and the interpolation code just works (but there's no interpolation). When I need graceful transitions from existing to not-existing I do one or two things: Stamp spawn/die times and adjust the graphics appropriately, or use temp entities (that run strictly in frame-time) as placeholders.

Skorche Wrote:I've thought about the immutable gamestate approach as well. Mostly in terms of networking and time rewind effects like in the console Prince of Persia game. I've mostly rejected it as too much unnecessary work though. It seems like it would be easier to serialize a snapshot of the state than to save every state as an immutable object. I guess I'm thinking more like key/intra frames in video compression.

That's what I'd do. You can usually get away with sampling frames at a lower rate (say 30Hz) and for forward-playing demos even just save the deltas from the previous snapshot.
Quote this message in a reply
Moderator
Posts: 3,571
Joined: 2003.06
Post: #25
I just realized this discussion is getting somewhat off-topic. We made need to split it.

Frank C. Wrote:When I need graceful transitions from existing to not-existing I do one or two things: Stamp spawn/die times and adjust the graphics appropriately, or use temp entities (that run strictly in frame-time) as placeholders.
That seems like a pretty good idea to use spawn/die times and note them in the entity.

A specific example of the problem: In my TenTickPong test I have the update rolling at 10 Hz. When the ball falls below the floor it is supposed to instantly move from below view (from out of view, which means it's dead) to being back on top of the paddle so it's ready to launch again. Using state interpolation it doesn't currently do that. What happens instead is that the ball appears to quickly move from below, and out of view, to on top of the paddle. This obviously happens because at state A it's below and state B it's on the paddle, and there are like six frames of drawing happening in between A and B. The question is: how do I stop that slewing effect from happening? That is, how do I stop the interpolator from interpolating between dead and the respawn position, but still draw the ball during those six frames?

Here we're transitioning from dead to alive but the object is still in the database because it's being reused, so the interpolator calculates it as if it moved, not died and respawned. Obviously one could remove it from the database and create a new ball for a new life, but this brings up yet another point: In my case, I reuse array slots, so what if a slot existed in A but was reused as a different object in B? My solution to that would be to give a unique ID to each object so the interpolator knows they're different. ... which would solve my ball issue too, now that I think about it, but it still wouldn't take care of the "how long do I keep drawing the dead ball during interpolation, and when do I start drawing the new ball?" problem... which is where your technique of marking spawn/die time should come in to save the day I think.
Quote this message in a reply
Member
Posts: 446
Joined: 2002.09
Post: #26
AnotherJake Wrote:The question is: how do I stop that slewing effect from happening? That is, how do I stop the interpolator from interpolating between dead and the respawn position, but still draw the ball during those six frames?
When spawning/reseting/warping an object you can just set the previous position to the (new) current position. Or alternately use a "no interpolate" flag that tells the interpolating code to skip interpolation for this frame then resets the flag.
Quote this message in a reply
Moderator
Posts: 3,571
Joined: 2003.06
Post: #27
Frank C. Wrote:When spawning/reseting/warping an object you can just set the previous position to the (new) current position. Or alternately use a "no interpolate" flag that tells the interpolating code to skip interpolation for this frame then resets the flag.

That's not a bad idea either. I was hung up on the idea that I wouldn't know that the object had died until frame B though, which was an oversight on my part because, duh, the entity would know that it respawned and can mark it as "noInterp" for that update, and the interpolator is looking at both frames, so in a sense, it gets to peek into the future. Easy.

To avoid bothering to calculate death/respawn times, the interpolator could just take the half-way point between A and B as when the instant transition occurs. That would get rid of the need for a unique ID for slot reuse. The trade-off would be that there would be a period of time in-between updates where the objects would not be interpolated, so they'd be motionless. I would guess that it'd probably not even be noticeable at rates of 20 Hz and upward, which should fit with network performance just fine.

Yeah, I think I might give that a try next. Thanks for the ideas Frank!
Quote this message in a reply
Post Reply 

Possibly Related Threads...
Thread: Author Replies: Views: Last Post
  updating to ios5 recorder doesn't work anymore sefiroths 3 3,786 Nov 21, 2011 03:56 AM
Last Post: sefiroths
  Updating Map Annotations - coordinates PHANTOMIAS 0 2,477 Dec 8, 2009 08:39 AM
Last Post: PHANTOMIAS
  Browser Based.. Updating turn times? guest_05 1 2,910 May 24, 2007 04:03 PM
Last Post: Tobs_
  Updating only parts of the screen Josh 1 2,978 Dec 18, 2002 02:38 AM
Last Post: kelvin