|
||||||||||||||||||
Add Forum to Favorites | Send Topic To a Friend | View Forum FAQ | Track this topic |
Last Thread Next Thread ![]() |
| 2D Beat-em-up. |
|
![]() Briskon Member since: 5/11/2003 From: Ireland |
||||
|
|
||||
| I'm looking to develop a side scrolling 2D beat-em-up ala Streets of Rage, Final Fight. There are a few things I'm a bit unsure about. 1. I was wondering how the collision detection works when you have a third axis (x,y,z)? 2. When a character punches (or kicks) do you make the bounding box bigger to check for a collision?, or is he already surrounded by an enlarged bounding box to cater for punching and kicking? If so, are the collisions in these types of beat-em-ups detected using color scans? 3. Also does anyone know any good sites that give details on how to render the sprites against the background when using 3 axes? Can anyone give me some advice? Thanks. |
||||
|
||||
![]() Programmer_Prime Member since: 12/25/2002 |
||||
|
|
||||
| 1. Adding depth just means you have to check a bounding volume instead of a bounding rectangle 2. You can have one bounding box for the fighters body and another for his fist/foot during the attack. You can also use 'pixel perfect' col det; the idea you have a 0/1 mask of the bits in the bitmaps and compare them to see if they overlap. I don't know how well that would work in simulated 3d. 3. No, but its pretty simple depending on what viewpoint your using just adjust the y component. Check here for more details: www.gamedev.net/reference/ |
||||
|
||||
![]() Briskon Member since: 5/11/2003 From: Ireland |
||||
|
|
||||
| Hmm... some things to think about there........... I see what you're saying about seperate bounding boxes during the attacks. Would you mind elaborating on the bounding volume concept? Thanks. |
||||
|
||||
![]() Big Sassy Member since: 7/3/2000 From: Rockville, MD, United States |
||||
|
|
||||
| I was working on a 2D beat-em-up a little while ago, but I put the project on the back burner. I wanted to bulk up my knowledge in a lot of different things (math, programming, etc). I'll probably get around to it again. I still have a small demo of the engine here. It's not the latest version I made unfortunately. I had support for all the basic stuff except collision detection (object, defining zones, enemy starting positions, etc), but this one just has scrolling and the fighting system. [edited by - Big Sassy on June 10, 2003 12:30:38 PM] |
||||
|
||||
![]() Funkymunky Member since: 7/29/1999 From: Exton, PA, United States |
||||
|
|
||||
| Wow! I was actually playing symphony of the night and randomly browsing the forums. Who else should I see but Alucard! Can you send me those sprites, or at least tell me how to open the ecs file? bkd126@psu.edu |
||||
|
||||
![]() marcus12024 Member since: 3/11/2003 From: Canada |
||||
|
|
||||
| Here's my thought for the time being... I assume that you know how to do collision in 2-D... In doing this type of game all characters and objects that are to be painted to the screen will need some attribute that determines where they are in 2.5-D space. You could probably get away with an x value for horizontal position, and a y value for the "back/forth" position. Render all objects with the "farthest back" positions first, then the closer ones, etc. Now, in checking for collisions, you only need to check characters and objects that are roughly in the same y position. If they aren't, then they cannot collide. Made sense to me, anyway! What do you think? |
||||
|
||||
![]() Big Sassy Member since: 7/3/2000 From: Rockville, MD, United States |
||||
|
|
||||
quote:Thanks |
||||
|
||||
![]() GroZZleR Member since: 1/26/2002 From: Whitby, Canada |
||||
|
|
||||
| Wow thats pretty nice =) If its a dead project you should release the source, I'm sure a lot of people could learn something from it. (I know I could!). Just an idea =P |
||||
|
||||
![]() Big Sassy Member since: 7/3/2000 From: Rockville, MD, United States |
||||
|
|
||||
quote:Thanks |
||||
|
||||
![]() Big Sassy Member since: 7/3/2000 From: Rockville, MD, United States |
||||
|
|
||||
| I just realized that I accidentally hijacked your thread. Sorry about that. I'll try and make it up to you by answering your question. Let me start by apologizing for the image quality. I didn't want this thread to take an hour to load :) Anyway, here's my theory on how to do it. I would use two collision passes. The first one would be to decide whether the two different object are at the same "depth". The second pass would be to decide whether the two objects collided or not using a standard collision detection. First I'll explain how I'd implement the first pass, and then I'll explain how I'd do the second. Let's just say that we have two different characters in the game, one being the "hero" and the other being the "villain". Assuming you arrange the bitmap so that each frame of a sprite is in a cell, each character's sprite looks like this. The sprite on the left is the "hero" and the sprite on the right is the "villain". Note the shadows that each sprite has. This is important in any 2D game that is trying to show depth in anyway. Let's throw them into the game...well, a mockup of a game anyway. ![]() Here's an example of no collision taking place. You can tell just by looking at it. The shadows aren't even close to each other, which means they aren't at the same depth. Unfortunately, your program doesn't have the ability to look at the screen and make the same judement. You'll have to tell it that they aren't even close. This is where the first collision test comes in. The test will use the shadow as a reference point to where the character is on the screen, in terms of depth. We'll keep track of the y position on the screen for the top and bottom of the shadow. Here's a visual representation of the y values we are tracking. I've zoomed in to make it a little easier to see. ![]() The image on the left is with the characters, and the one on the right takes the characters out and shows the y values we are tracking for each character's "depth". The "hero"'s y values are in red and the "villains"'s y values are in green. To determine whether the two characters are at the same depth (or close enough to collide), we just need to check if one of their y values falls in between the other character's y values. For example, if we're checking if the "hero" collided with the "villain", we'd check whether each of it's y values fall in between the "villains"'s y values. The code would look something like this: // checks whether hero collided with villain bool testDepthCollision(int heroY1, int heroY2, int villainY1, int villainY2) { // check if the first y value of the hero is in between both // of the villain's y values if( heroY1 >= villainY1 && heroY1 <= villainY2) return true; // check if the second y value of the hero is in between both // of the villain's y values if( heroY2 >= villainY1 && heroY2 <= villainY2) return true; // if neither of the hero's y values were in between both of // the villain's y values then no collision happened return false; } Now if we ran that on the current position of the "hero" and "villain" it would look like this: 283 > 241 ? True 283 < 251 ? False So the first if statement would fail (remember that BOTH have to be true for it to succeed). What about the second? 293 > 241 ? True 293 < 251 ? False That one fails too, which could only mean one thing...no collision! Now you're program can figure out whether two characters on the screen are at the same depth. Let's look at an example where they do collide. ![]() Here's an example of a collision taking place. You can see that the shadows are overlapping each other. The question now is whether our algorithm will see that? Let's find out. ![]() Let's run our algorithm against the data. 240 > 245 ? False 240 < 255 ? True Well, looks like the first if statement didn't find anything. It's all up to the second one now. 250 > 245 ? True 250 < 255 ? True Success! Looks like the algorithm works! It successfully saw that the two characters are indeed at the same depth. And if they are at the same depth, you can treat the rest of the collision like a 2D side scroller. When you think about it, everything is at the same depth in a standard 2D side scroller. Anyway, I hope I was clear. If you have any further questions, don't hesitate to ask HERE. I'd rather not answer through e-mail. Thanks. PS - To all those who are saying, "What is he doing? Doesn't he know it's more efficient to check when a collision has NOT occured?", yes I'm well aware of that. It's just easier to visualize what's happening when you check whether the two characters are inside each other, rather then outside. If you see any other optimizations, see anything wrong with the algorithm, or just want to make a comment please feel free. [Edited by - Big Sassy on April 25, 2007 11:30:15 PM] |
||||
|
||||
![]() Briskon Member since: 5/11/2003 From: Ireland |
||||
|
|
||||
| Thanks a million, that was a great little tutorial! I have another question though (it seems, the more you know, the more you don't know): What do you mean by it being easier to check for a collsion not occurring? |
||||
|
||||
![]() Big Sassy Member since: 7/3/2000 From: Rockville, MD, United States |
||||
|
|
||||
<SPAN CLASS=smallfont>quote:Well, it goes like this. Instead of finding out whether each of the hero's y values fall in between the villain's y values, you check if they fall outside of them. Let's look at the non-collision example again: ![]() This time we will make the program check whether each y value does not fall in between the villains's y values. We can do this in half as many steps because of two things. The first is that the y value of the top of the a shadow will always be less than the botton of the same shadow. And the second is that the y value of the bottom of a shadow will always be greater than the top of the same shadow. So what good does that do us? Well, if the top of the hero's shadow is below the villain's shadow, then you know that the bottom of the shadow is below the villain's shadow as well. Which means you don't have to check if the bottom of the shadow is less. Which means that is one less step to process. Which is good :). Likewise, if the bottom of the hero's shadow is above the villain's shadow, then the top of the hero's shadow is above it as well. Once again you take out a step. To put it another way, we are testing two things: 1. Is the hero above the villain? 2. Is the hero below the villain? This is what the code would look like: // checks whether hero collided with villain bool testDepthCollision(int heroY1, int heroY2, int villainY1, int villainY2) { // check if the hero is below the villain if( heroY1 > villainY2) return false; // check if the hero is above the villain if( heroY2 < villainY1) return false; // if the hero isn't above or below the villain, then he // must be at the same depth, which means a depth collision // occured. return true; } Going back to our no-collision example, if you test the values with this algorithm it will go like this: 283 > 251 ? True (He's below him) So the algorithm has already determined that the hero is above the villain, which means that they aren't at the same depth. It's already done after one comparison, whereas the old one took 4! That's a nice increase in speed :). Now let's look at the collision example. ![]() If we run the algorithm on this it will go like this: 240 > 255 ? false (he's not below him...) 250 < 245 ? false (...and he's not above him) This time the algorithm determined that the hero is not below or above the villain, which means that they must be at the same depth. So after 2 comparisons we've found that a collision has occured, whereas the old one took 4 comparisons. So in the worst case scenario, this algorithm is twice as fast as the old algorithm. You gotta love that :) I'd like to futher elaborate on why you should check for depth collision. The only difference between a 2D beat-em-up and a regular 2D side scoller is that a beat-em-up has depth. If you take away the depth, then you can treat it just like a regular 2D side scroller. This is why we check for depth collision first. After you know they are at the same depth, you can treat everything else like a regular 2D side scroller (which is much easier). Anyway, once you got them at the same depth you should now check for a regular collision. Just because they are at the same depth, doesn't mean that they are colliding. Now you can use that same algorithm to test whether each character's bounding box intersect, which means that they are colliding. Now the algorithm tests for 4 things: 1. Is the hero above the villain? 2. Is the hero below the villain? 3. Is the hero to the left of the villain? 4. Is the hero to the right of the villain? So on top of checking if the bottom of the hero is above the top of the villain, and the top of the hero is below the bottom of the villain, we'll now test whether the left of the hero is to the right of the right side of the villain, and the right of the hero is to the left of the left side of the villain. I hope that doesn't sound too complicated. You're basically just adding two more tests to the previous algorithm. The code would look like this: // checks whether hero collided with villain bool testNormalCollision(int heroX1, int heroX2, int heroY1, int heroY2, int villainX1, int villainX2, int villainY1, int villainY2) { // check if the hero is below the villain if( heroY1 > villainY2 ) return false; // check if the hero is above the villain if( heroY2 < villainY1 ) return false; // check if the hero is to the left of the villain if( heroX2 < villainX1 ) return false; // check if the hero is to the right of the villain if( heroX1 > villainX2 ) return false; // if the hero isn't above or below the villain, or to // the left or right of the villain, then he must be inside // the villain, which means that a collision occured. return true; } And that's all there is to it. If there's anything you don't understand, please say so and I'll try and elaborate more. As for your other two questions: <SPAN CLASS=smallfont>quote: A2. Yes, you should make the bounding box go out to as far as his attack goes. A3. Nope, but what I did was keep all the graphical elements in a linked list sorted by their bottom y values. Then when I drew all the graphical elements, I started from the top of the list and worked my way down. This may not be the most efficient (and it really is a pain in the ass to keep it sorted), but it works. Anyway, I'm going to be late for my appointment at a winery. If you have any more questions, feel free to ask. [Edited by - Big Sassy on April 25, 2007 11:30:12 PM] |
||||
|
||||
![]() Impossible Member since: 11/1/2000 |
||||
|
|
||||
| You should make a game with those dudes. You already have all the collision code and a good deal of artwork. I think it would be pretty sweet. |
||||
|
||||
![]() Funkymunky Member since: 7/29/1999 From: Exton, PA, United States |
||||
|
|
||||
| Yeah but you'll need a female character. Give her D cups |
||||
|
||||
![]() Big Sassy Member since: 7/3/2000 From: Rockville, MD, United States |
||||
|
|
||||
| hahahahaha. Maybe I'll whip up a quick and crappy demo just for the hell of it. I'll have to think about it. |
||||
|
||||
![]() Briskon Member since: 5/11/2003 From: Ireland |
||||
|
|
||||
| I have another question.................. When your character picks up an object like a baseball bat, beer bottle, chainsaw, etc....... Should you have a different set of animations for the whole charater ie: Character unarmed Character with baseball bat Character with knife or should you have a one set of animations for the character and overdub the weapons with seperate masked images. I don't know if I'm making myself clear here. Anyway, if anyone could give me a few pointers it'd be much appreciated. I don't want to draw up a whole load of animations and find out I didn't need to. Thanks |
||||
|
||||
![]() Pike65 Member since: 3/11/2003 From: United Kingdom |
||||
|
|
||||
| How about a combination of both? Have an unarmed strike, a swing and a stab - then you could fit all of your weapons into one of those two categories and then 'overdub' (I'll use your term - I can't think of a better one ; ) It'd save you a shitload of memory when you'll probably end up reusing the same base image to draw the animations anyway. May as well do it at runtime. You'd still have to animate each individual weapon, though. [EDIT : I'd have gotten away with it too if it wasn't for those meddling typos . . .] [edited by - Pike65 on June 13, 2003 8:39:17 AM] |
||||
|
||||
![]() Big Sassy Member since: 7/3/2000 From: Rockville, MD, United States |
||||
|
|
||||
quote:What he said. Oh and this... quote:was pretty funny. Gotta love scooby doo references |
||||
|
||||
All times are ET (US)![]() |
Last Thread Next Thread ![]() |
|