This is of yet a place holder blog entry which I intend to edit as I progress. This go around I'll be using the software pixel plotter I mentioned in a previous blog entry. At this time of writing, all I have is my napkin design concept, which I think I really have something here.... you know...the whole no weapons thing...We let that simmer for a week. Hop over to the forums for some inspiration. Will my game idea cut it? Shouldn't matter. But it does you know it. So whats' happening, a partial automatic background simulation running pretty smooth and reliable. I'm testing with some debug visuals, all good. My bodies go stable, perfect..,,whoops it somewhat quickly starts to sink slowly. Slowly, at a speed that appears to be on purpose. Umm...little bug. I go find it, and stop...wait...that's actually pretty cool. I have it trigger when it completely buries itself. So, slap a feature label on it instead. Sha-bang. Now we're talking Okay that's week one.
And...we're back.
Week two and maybe a few. I got distracted, but didn't ignore. My little pixel got tucked in every night and thought about during the day. So, I've always thought this challenge game thing should be played slightly different. Everyone goes off to do one of their next best things, or show off this or that. In the end it's great. But what about the middle...right? <-- Here's my go at it for today. The following listing is my collision code. I'm using this goofy thing that might be worth a share.
Right out of the gate, don't laugh. trying to write a little game here. Thanks, actually this is one of the 'why do you do it' things right here. Those times when math dances that dance and it's so nice to looks at. If this is one of those times, we'll see But right now the simplistic approach at its finest and I think per pixel. Check it out, I'll walk though real quick like. physicsObjs is a std::list of an abstract class. Then inheritance gives me other objects but all in the same list. So we walk it and early out if it's not active. Here we go...now expert I am not, but I want to do something cool. I choose a lite physics sim and first up is that downward force. All right, equals mc what? Telling you... truth. didn't even bother to look. I don't care. This is my game, we're doing it how I want...it's going to be banging...What's that value 9.8 something, size should effect this thing and we'll chop it into a time slice. Nice, let's build our first force direction do-dad. Umm, I appear to be short on some overloads with the framework I choose. No problem, long hand it, mix it with some outside influence and put it in a next desired holding spot. Clamp it for good measure.
Now that we know how fast we want to get there, we calculate where that might put us and hold on to that. So what this is, is a circle against 2D pixel terrain. Terrain is stored on a grid larger than the screen size so we have some indexing math to contend with. I start off with a check against the grid height of the memory terrain so I don't flow into memory that's not mine and I'm scanning down. I want to look at all the pixels in the lower hemisphere of my search grid. So I build that rectangle and walk it bottom up. I assume that against terrain, my objects only care about bouncing and a bounce will never be directly above. Hence only test the bottom half. Object-object collision is a separate pass. What is important to me also is where is this bounce going to take me. So here's what I do. From the bottom center I go horizontal negative per pixel, on hit, I record the vector offsets. No big boy math. If it's terrain, take that raw offset and add it to the reflection accumulator. Found one, okay stop. move up a pixel and go again until another hit or just pass through. Repeat on the positive side. Now we have this ugly 2d vector, so I normalize and then scale it by the magnitude of what we were. Squeeze it with a cheep decay and off we go.
// update physics ---------------------------------------------
for (auto &obj : physicsObjs)
{
if (obj->bDead) continue;
// apply force ....................................
float gravity = 9.81f * obj->mass * fElapsedTime;
vec2 force = { 0.f, 0.f }; // todo : mass / size maybe / etc.. obj->acc
obj->nextVel.x += force.x;
obj->nextVel.y += (gravity)+force.y;
// clamp velocity .................................
if (obj->nextVel.x > 10.f) obj->nextVel.x = 10.f;
if (obj->nextVel.x < -10.f) obj->nextVel.x = -10.f;
if (obj->nextVel.y > 10.f) obj->nextVel.y = 10.f;
if (obj->nextVel.y < -10.f) obj->nextVel.y = -10.f;
// calculate desired position
obj->nextPos = obj->pos + obj->nextVel;
// potential positions established and next desired state set (free form)
obj->bHitThisFrame = false; // reset for next run (hmmm...not sure i want or need)
// check against terrain (sudo raycast)
vec2 reactionAccumulator = { 0.f, 0.f }; // sum all positive hit vectors
int numHits = 0;
if ((obj->nextPos.y + obj->radius) < terrain.nMapHeight)
{
// assuming a positive downward velocity (only test lower hemisphere)
int xL = int(obj->nextPos.x - obj->radius); // left index
int xC = int(xL + obj->radius); // ---- center vertical ----
int xR = int(xC + obj->radius); // right index
int yT = int(obj->nextPos.y); // slice center top
int yB = int(yT + obj->radius); // bottom index
float objR2 = obj->radius * obj->radius; // radius squared
for (int i = yB; i > yT; i--)
{ // scanline search for terrain (bottom up)
int scanlineIndex = i * terrain.nMapWidth;
for (int j = xC; j > xL; j--)
{ // scan center to left- break on first hit
if (terrain.map[scanlineIndex + j] == 1)
{
vec2 v = obj->pos - vec2(float(j), float(i));
if ((v.x * v.x) + (v.y * v.y) < objR2)
{
reactionAccumulator += v;
numHits++;
break;
}
}
}
for (int j = xC; j < xR; j++)
{ // scan right to center - break on first hit
if (terrain.map[scanlineIndex + j] == 1)
{
vec2 v = obj->pos - vec2(float(j), float(i));
if ((v.x * v.x) + (v.y * v.y) < objR2)
{
reactionAccumulator += v;
numHits++;
break;
}
}
}
}
if (numHits > 0)
{
vec2 unitReaction = reactionAccumulator.norm();
obj->vel = unitReaction * obj->nextVel.mag();
obj->nextVel = obj->vel * 0.94f; // decay
if (numHits >= ((yB - yT - 1) * 2))
PostQuitMessage(0);
numHits = 0;
}
obj->pos = obj->nextPos; //todo : get closet to contact point
// object position wrap terrain screen
if (obj->pos.x > terrain.nMapWidth) obj->pos.x -= terrain.nMapWidth;
if (obj->pos.x < 0) obj->pos.x += terrain.nMapWidth;
}
else {
obj->bDead = true;
}
}
Okay, that was fun. Last night I shoe horned in my game state manager, adapted it to draw in this fashion with the base menu switch I use to start out with and it should be mostly game play stuff this week... I'm excited to pull out one of my real old sprite sets for this player charcter.
"I'll be back"
And a week old screenshot
Let's do this thing...still pumped.
Part two continues here.
Best of luck with your entry.