Side Scrolling Game Challenge : Explosive Balls

posted in A Hobbyist Tale
Published April 20, 2019
Advertisement

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 :D Okay that's week one.   

design_worms.thumb.jpg.26bac4262b5e9f603dfd5d05bed0848b.jpg

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

sideChallenge_scr01.jpg.0aee02f32a66f08d37aca593653b72ab.jpg

Let's do this thing...still pumped.

 

Part two continues here.

 

2 likes 11 comments

Comments

Rutin

Best of luck with your entry. :) 

April 08, 2019 04:03 PM
NubDevice

oh, no no no no no....I make my own luck. Thanks dude.

April 08, 2019 04:05 PM
Rutin
10 minutes ago, GoliathForge said:

oh, no no no no no....I make my own luck. Thanks dude.

I don't even believe in luck, but I do wish it a lot! :D We're in 2019, just name it and claim it!

April 08, 2019 04:16 PM
NubDevice

word up :D 

April 08, 2019 04:17 PM
lawnjelly

Good idea using your software renderer with it!! :D Hopefully I can do this too in a later challenge. Designing on a napkin oh yes, this is the stuff.

April 08, 2019 04:18 PM
NubDevice

Getin' pretty pumped here... lol. ;)

April 08, 2019 04:48 PM
NubDevice

okay cool...so today was a nice sit to get some physics going on. I do a neat little psudo per pixel / flood fill accumulation thing to generate reflection on collision. More on that later perhaps... 

It was more play than work when we started blowing stuff up :D

 

April 10, 2019 07:17 AM
Rutin

Nice!

April 10, 2019 07:25 AM
NubDevice

l^^^ lol...this one's a 'gimme :D we got him surrounded now...hehe...

still somewhat jittery little buggers that take a long time to settle down (if at all) :) I'll go look for that low end threshold eventually to make the stable enough call. Feels pretty good. Using this pixel plotter thing really makes you aware of every pixel you're blinking. In a way makes me feel like I'm working with a shader program instead of application code (in a small way) I don't know, that's probably weird. Anyway, really diggin' it. Okay...a little cleanup, some size tweaks to fit the game design concept and start toward moving to the lose game event with what I have before getting on with user events and feedback behavior. 

edit: ended up swapping out for something fake but interesting (to me) Can't explode unless you feed it a huge time step. Thinking about fixing my step and maybe some extra tweens, like pronto.

April 10, 2019 07:50 AM
lawnjelly

Wow looks like you've got the perfect environment for doing a worms game! Accessing the pixels like that reminds me of the old days before GPUs. :) 

April 10, 2019 09:30 AM
NubDevice

The initial source grab was demonstrating a worms environment so triple points for that observation. Got the blog caught up, going back to work.

April 15, 2019 08:02 PM
You must log in to join the conversation.
Don't have a GameDev.net account? Sign up!
Profile
Author
Advertisement
Advertisement