mirror of
https://github.com/photonstorm/phaser
synced 2024-12-20 18:14:13 +00:00
715 lines
36 KiB
Text
715 lines
36 KiB
Text
PART -1: intro/preamble
|
|
|
|
[3]**
|
|
-download the slides at: [++TODO: URL to slides.. metanet/tutorials/fitc05.zip?]
|
|
|
|
who am i
|
|
-one of two people who made N
|
|
-we've been using flash since v5 (i.e since actionscript was useful and easy to use)
|
|
|
|
<short demo of N, just watch a mainmenu replay>**
|
|
|
|
-promo blurb: "N is a platform/run-and-jump game which combines oldschool gameplay
|
|
with modern collision detection + physics simulation"
|
|
|
|
-we made N with flash prove that flash/actionscript could be used for "real video games"
|
|
|
|
|
|
[4]** -"the curse of sylvaniah" (by Strille/Luxregina) is another great game which also proves our point:
|
|
games made in flash can be "real video games"
|
|
|
|
|
|
[5]** -collision detection is a vast feild of research
|
|
-impossible to cover properly in an hour.
|
|
-i'll present specific methods well-suited for use in flash/actionscript
|
|
-some of the ideas we used in N, as well as some of the stuff we've learnt since making N
|
|
-there is a LOT of stuff to cover
|
|
|
|
-i'm going to try to introduce you to the ideas involved without a lot of technical detail
|
|
-understand the concepts, independent from the implementation of the concept
|
|
-there WILL be some code and formulas and stuff
|
|
-it's more important to understand the meaning behind the code and formulas.
|
|
|
|
-you can check out our online tutorials if you need to look at source.
|
|
|
|
-warning: i'm a programmer. these slides count as "programmer art".
|
|
|
|
-ask:
|
|
-how many people know what a vector is?
|
|
-how many people know what a dotproduct is?
|
|
|
|
|
|
[6]**
|
|
-to begin:
|
|
-this lecture is about collision detection
|
|
-implicitly, it's about game programming in flash
|
|
-game programming in flash feels a bit wrong.
|
|
-it certainly wasn't made for video games.
|
|
-there is a sense of "we're abusing this platform"
|
|
-but we're going to write games in flash anyway, so why not try to do it well.
|
|
-i'll start by trying to convince you about why collision detection matters
|
|
-then i'll discuss some solutions for dealing with collision detection
|
|
|
|
|
|
|
|
MOTIVATION:
|
|
|
|
-why does collision detection matter? is it only useful for ninja platformers?
|
|
[7]** -no. a lot of games would benefit from better collision detection/response
|
|
-everyone's favorite, the top-view racing game
|
|
-pool, pinball,
|
|
-basketball/sports (show McShitOut and/or scribball demo)
|
|
-platforming games
|
|
[8]** -most importantly: _new_ types of genre-defying games which you're going to invent next week
|
|
[9]** -having a good collision detection+response system enables a wide range of (otherwise inaccessible) gameplay possibilities.
|
|
|
|
|
|
[10]**
|
|
-HitTest:
|
|
-why do we need to learn about collision detection?
|
|
-doesn't flash already have built-in collision detection?
|
|
-yes, but it has two major weaknesses
|
|
1: only returns a yes/no answer
|
|
2: only works with axis-aligned rectangles
|
|
|
|
[11]** -what can you do with a yes/no answer?:
|
|
[12]** -destroy one/both objects
|
|
[13]** -move one/both objects to old position
|
|
[14]** -reverse direction of one/both objects
|
|
-or any combination of the above
|
|
|
|
[15]** -what can't you do with a yes/no answer?:
|
|
[16]** -friction and bounce
|
|
[17]** -sliding along obstacles
|
|
[18]** -rotating to orient to the ground
|
|
-etc.
|
|
|
|
[19]** -what can you do with axis-aligned rectangles?:
|
|
-anything! ..as long as it involves unrotated rectangles
|
|
|
|
[20]** -what can't you do with axis-aligned rectangles?:
|
|
-circles
|
|
-concave surfaces
|
|
-curved or angled surfaces
|
|
-rotating shapes
|
|
-etc.
|
|
|
|
[21]** -using hittest, if you need more than a yes/no answer about a collision, you can use "tricks":
|
|
-sample multiple points on an object
|
|
-from the multiple yes/no results, infer information about the collision direction, etc.
|
|
|
|
-if you work hard enough, you _might_ get it to work..
|
|
|
|
[22]** -it will be slower than it needs to be (due to the number of calls to hittest)
|
|
-it won't work 100% of the time (because you're relying on implied/approximated and not actual information)
|
|
-it just doesn't feel as solid as "the real thing"
|
|
|
|
|
|
[23]** -HitTest is awesome -- if you're living in the 80s
|
|
-lots of moving rectangles which explode when they touch each other
|
|
-if you want to actually respond to collisions in a meaningful way, HitTest isn't enough
|
|
-meaningful collision response requires meaningful information about the collision.
|
|
-better information, better response, better games, better "feel"
|
|
-ultimately, "real" (non-HitTest) collision detection enables "physics"
|
|
|
|
|
|
-physics?!
|
|
[24]** -in video games this year, "physics is the new graphics".. everyone wants more physics in their games.
|
|
-one common misconception is that "physics" means "slow and complex code". physics doesn't have to be complicated or slow.
|
|
|
|
<demo ragdoll>**
|
|
|
|
[25]** -"physics" is a much-abused term.
|
|
-most of the time it just means "things moving".
|
|
-if you've ever written "position += velocity" or "newpos = oldpos + velocity",
|
|
you've already been using "physics".
|
|
-what are you afraid of?
|
|
|
|
[26]** -the only math you need to know is some vector algebra/geometry which we'll cover
|
|
-no trig: trig is horrible
|
|
-it's very difficult to develop an intuition about it
|
|
-it's very hard to visualize when thinking about a problem
|
|
-vectors are your friends
|
|
-they can be used to replace trig in 99% of situations
|
|
-they are easy to visualize and develop intuitions about
|
|
|
|
[27]** -most importantly: flash vs. SNES
|
|
-way less graphical power, way more processing power
|
|
|
|
-flash can't compete with modern (or even classic) video games when it comes to graphical power
|
|
-consoles and PCs have dedicated graphics hardware; flash has only got the CPU
|
|
|
|
-flash CAN compete in terms of processing power and memory
|
|
-the SNES (which came out in 1991) had the same processor as an apple IIgs..
|
|
-even with the overhead of the flashplayer VM, flash outperforms the SNES in terms of both speed and complexity
|
|
-double-precision floating point, which lets us do a lot of things which simply weren't possible on an SNES
|
|
-because of the overhead of the flash VM, "expensive" ops like sqrt() aren't
|
|
really much more expensive than any other math op (+, -, etc.)
|
|
-this gives us flexibility to pursue different solutions (which might not be tractable on other platforms)
|
|
-flashplayer has built-in support for sophisticated structures like hashmaps (i.e "objects")
|
|
and dynamic memory management
|
|
-this makes it easier for us to explore complex ideas than possible on a SNES
|
|
|
|
[28]** -so: flash games have the ability to compete with modern (or classic) video games on the battlefield known as "gameplay"
|
|
-collision detection and physics are two great tools for developing novel gameplay
|
|
|
|
[29]** -some examples of games that are using collision detection and physics to create different types of gameplay
|
|
[30]**
|
|
[31]**
|
|
[32]**
|
|
|
|
-hopefully you're now motivated
|
|
|
|
|
|
[33]**
|
|
PART 0: collision response
|
|
|
|
-collision response is important to mention breifly because it provides the motivation for collision detection
|
|
-see our website for tutorials and links to more info
|
|
|
|
-collision response is _why_ you need a collision detection solution that's more informative than HitTest
|
|
-collision detection provides you with information describing a collision;
|
|
-if you don't _use_ this information in a meaningful way, CD is moot
|
|
|
|
[34]** -collision response "in a nutshell":
|
|
-there are many different ways to handle collision response
|
|
-they all of the need to know the same thing
|
|
|
|
[35]** -penetration direction, penetration amount
|
|
-pdir*pamt = penetration vector, projection vector, etc.
|
|
-i may use "penetration vector" and "projection vector" interchangeably
|
|
|
|
[36]** -one thing we want to do when notified of a collision is prevent the two colliding objects from continuing to collide
|
|
-a simple solution to this is "projection"
|
|
-given two colliding objects and their penetration vector
|
|
-translate (move) one object by the penetration vector
|
|
-OR: translate both objects by 1/2 the penetration vector
|
|
-etc.. playing with the ratios allows the simulation of objects with different relative mass
|
|
-i.e heavy objects aren't moved very much
|
|
|
|
[37]** -aside from preventing the objects from continuing to overlap, you can modify their properties based on the direction of the collision surface
|
|
-penetration vector describes the surface direction of the collision
|
|
-you can measure the velocity of objects parallel to and perpendicular to the surface
|
|
-we'll cover the math later, it's simple vector projection
|
|
[38]** -you break the object's velocity down into those two components
|
|
-scale each component seperately/differently, and recombine them to get the post-collision velocity
|
|
-this lets you simulate friction/bounce
|
|
|
|
-you can also let game logic make decisions based collision information
|
|
-rotating object graphics so that they align themselves to the ground
|
|
-inflicting damage for violent collisions
|
|
(the object's velocity perpendicular to the surface tells you how violent the collision was)
|
|
|
|
<demo: level 0-0, ninja skidding around and rotating to match the surface of things>**
|
|
<demo: level 0-0, ninja falling to death>**
|
|
|
|
|
|
|
|
|
|
[39]**
|
|
PART 1: narrow-phase collision detection, aka object-vs-object testing
|
|
|
|
[40]** -so, what we need to do when performing collision detection on a pair of shapes is:
|
|
(a) determine if the two shapes are colliding, and if so
|
|
(b) calculate the penetration vector which describes the collision
|
|
|
|
[41]** -actually.. that's only half of the collision detection problem.
|
|
-the other half is knowing which pairs of shapes to test in the first place
|
|
|
|
[42]** -these two parts of the collision detection process are often called "narrow" and "broad" phase collision detection
|
|
-broad = figuring out which pairs of objects we must test
|
|
-narrow = testing each pair
|
|
-sort of like sifting through something: start with a coarse filter to elliminate most things, then use a fine-grained filter on the remaining stuff
|
|
|
|
-we'll start with narrow-phase and then discuss broad-phase
|
|
|
|
-i'll try to answer questions breifly after each section
|
|
-i'd prefer to stick to specific questions (i.e if i'm not explaining something in detail)
|
|
-leave larger questions for Q&A at the end of the presentation
|
|
|
|
|
|
-there are several different approaches to object-vs-object tests; the one i'm going to describe is based on something called "the method of seperating axes" <todo: refer to ginoVDB and geomtools books>
|
|
-it's well-suited for flash
|
|
-fast (faster than any other method we've seen)
|
|
-simple (easy to understand, easy to code)
|
|
-flexible (easy to adapt to many different situations)
|
|
|
|
[43]**
|
|
-the method of seperating axes, in english
|
|
-there will be a lot of "axis" talk
|
|
-axis really just means "direction". any time you hear "axis", you can mentally substitute "direction".
|
|
-1 vector, many vertices
|
|
-1 axis, many axes
|
|
|
|
[44]** -the Method of Seperating Axes is based on the Seperating Axis Theorem:
|
|
-a mathmatical theorem about the properties of convex polygons
|
|
[45]** -thus, this method only works for convex shapes
|
|
-what is a convex shape? probably you've at least got an intuitive understanding of convexity.
|
|
there are many "practical" definitions:
|
|
-no internal angles <= 180deg
|
|
-a line connecting any two points inside the shape is contained within the shape
|
|
-only lefthand turns when walking CCW around the surface
|
|
-etc.
|
|
|
|
|
|
[46]** -Seperating Axis Theorem, part 1:
|
|
-if two convex polygons don't overlap, then there must be a direction along which they are "seperated"
|
|
-the converse is also true: if there is no direction which seperates two objects, the objects must be overlapping
|
|
-"seperated" means that, if we look at the world along that direction, there is a space between the two shapes
|
|
-the direction we look along is called an axis
|
|
-if the two objects are seperated, it's a seperating axis
|
|
-you could think of it as a line through the objects; it's offset in diagrams to make it less cluttered/confusing
|
|
<diagram: show seperated and overlapping cases>
|
|
|
|
|
|
[47]** -Seperating Axis Theorem, part 2:
|
|
-we don't have to test _all_ directions; if there is a seperating axis, then it must be perpendicular to an edge of one of the shapes
|
|
-so, instead of testing all possible directions to find a seperating axis,
|
|
we only test those directions which are perpendicular to the edges of our polygons
|
|
<diagram: as before, but point out/focus on normal directions>
|
|
|
|
-there's a proof for the SAT, but that's (thankfully) outside the scope of this lecture
|
|
-we didn't invent this method, we just noticed that other game programmers were using it
|
|
|
|
|
|
[48]** -the Method of Seperating Axes is a method of collision detection which is based on SAT:
|
|
-given two shapes, determine all the potentially seperating axes for those shapes
|
|
-i.e determine the directions which are perpendicular to each edges of each polygon
|
|
-test each potentially seperating axis until we find an axis along which the objects are seperated
|
|
-if we've tested all potentially seperating axes and found none that are seperating the objects,
|
|
the objects are colliding
|
|
|
|
-instead of a single, complicated 2D test (based on minimum distance or whatever), we perform a series of simple 1D tests
|
|
-each test is along a different direction, or "axis"
|
|
-each test boils down to a few lines of very simple (and fast) math
|
|
-we'll get to the math shortly
|
|
|
|
-the strength of this method is the "early out"
|
|
-we don't need to test every potentially seperating axis; as soon as we find an axis which seperates the two shapes,
|
|
we know (thanks to the SAT) they can't be colliding and we can skip the rest of the axes
|
|
-this means when two objects aren't colliding, we do less work than when they are
|
|
-in a typical game, any two objects picked at random are likely NOT colliding,
|
|
so optimising the not-colliding case makes sense and really speeds things up
|
|
|
|
|
|
|
|
[49]** -before we get into actual code, let's review some basic vector algebra/geometry
|
|
-basic vector math: nothing to be afraid of
|
|
|
|
[50]** -vectors (difference of two points)
|
|
|
|
[51]** -unit vectors/direction
|
|
-unit vectors: vectors whose length is 1
|
|
-very useful to use these to represent directions, INSTEAD of angles/radians/etc.
|
|
-they've got some useful properties which we'll see in a moment
|
|
-formula/code:
|
|
-basically, you divide x and y components by the length of the vector
|
|
-null (0-length) vectors don't work
|
|
-when you multiple a unit vector by a scalar X, the result is a vector which points in the same
|
|
direction as the unit vector, but which is X units long
|
|
-in this presentation, whenever you hear "axis" (and/or "direction"), this means normalized unit vector
|
|
-the process of taking a vector and scaling it until it's unit-length is called "normalization"
|
|
-the vector has been normalized
|
|
-NOT to be confused with the following
|
|
|
|
|
|
[52]** -normal vectors (NOT to be confused with normalized vectors! althouth.. normal vectors are often normalized..)
|
|
-perpendicular to a vector
|
|
-formula/code: it's so simple it's weird that the results are meaningful/useful
|
|
-each vector has two of these, LH and RH
|
|
|
|
[53]** -by convention, polygon edges are arranged in CCW order
|
|
-this means that each edge's RHnorm points "out" of the polygon edge
|
|
-these are of special importance to us: the RHnorms of each edge of a polygon _are_ the potentially seperating axes we must test
|
|
|
|
|
|
[54]** -dotproduct
|
|
-in highschool you may have learnt a definition of dotprod involving cosine:
|
|
-AdotB = |A|*|B|*cos(angle between A and B)
|
|
-this is irrelevant
|
|
-dotprod is a measure of the relative directions of two vectors
|
|
-formula/code: as with normal vectors, it's so simple it's weird that the results are meaningful/useful
|
|
-the important thing to note is that:
|
|
-when two vectors point in the same direction, their dp is at maximum value
|
|
-then they point in opposite directions, their dp is at minimum value
|
|
-when they're perpendicular to each other, their dp is 0
|
|
|
|
[55]** -if vector A is unit length and vector B isn't, the min/max values of their dp are -/+ the length of B
|
|
-the value of the dp is no longer just some value, it's now "meaningful":
|
|
-it's the _length_ of vector B when "measured along" the direction described by vector A
|
|
-"measured along, viewed along, the length of the image of B on A", etc.
|
|
-this is important for projection
|
|
|
|
|
|
[56]** -vector projection
|
|
-just one multiplication step added onto the end of a dotprod
|
|
-as we just learnt, when vector A is unit length, and vector B isn't,
|
|
AdotB gives you the length of the "image" of B, when measured along A
|
|
|
|
-we can make a vector of length AdotB, which is parallel to A
|
|
-just multiply A (unit vector) by AdotB
|
|
-that vector is called the projection of B onto A
|
|
-you can think of it as "B when viewed/measured along the line containing A"
|
|
-mapping 2D to 1D
|
|
|
|
[57]** -this is the core of our method: projecting shapes onto each potentially seperating axis
|
|
-if we only care about the length of the projected vector (i.e the dotproduct), we can use the dotproduct itself
|
|
-this is also what we use for friction/bounce
|
|
-as we saw earlier, you decompose object velocity into two perp. components
|
|
by projecting them onto the surface direction
|
|
|
|
|
|
[58]** -the method of seperating axes, revisited
|
|
-the if(overlap) step is "where all the action is"
|
|
|
|
[59]** -example: Box vs. Box
|
|
-figure out which axes we have to test
|
|
-aside: normally, testing two quadrilaterals would involve testing 8 potentially seperating axes
|
|
(4 from each quad)
|
|
-boxes are a special case which exploit the SAT's rules
|
|
-we need to test all directions which are perpendicular to the surface of each shape
|
|
-since, for each box, a single direction is perp. to two surfaces,
|
|
we can perform a single axis test for each pair of opposite box edges
|
|
-anyway:
|
|
-calculate the object-object delta vector (vector from center of one object ot center of the other)
|
|
-for each potentially seperating axis (show all 4 axes, then show each step below on a single axis):
|
|
-calculate the projected halfsize of each object (projected = when measured along the axis) (BLUE)
|
|
-calculate the projected length of the delta vector (projected = when measured along the axis) (GREEN)
|
|
-calculate the difference between the sum of the halfsizes, and the delta vector
|
|
-if negative, we've found a seperating axis and we can stop: the shapes don't overlap
|
|
-if positive, objects overlap along the axis, continue testing (RED)
|
|
[60]** -if, after testing each axis, we still haven't found a seperating axis, then the objects must be colliding
|
|
|
|
|
|
[61]** -what??!? i'm confused..
|
|
-why are we using this weird concept of "halfsize"?
|
|
-don't we still end up with only a yes/no answer? i thought this approach was supposed to give us more info
|
|
-..wait a minute.
|
|
-this might seem familiar.
|
|
|
|
[62]** -one very useful insight for understanding this approach is that it's a generalisation of circle-circle collision detection
|
|
(which everyone is probably familiar with)
|
|
|
|
[63]** -circle-circle <diagram each step>
|
|
-calculate the object-object delta vector
|
|
-for each potentially seperating axis (in this case, there's only one: the axis which passes through both circles' centers)
|
|
-calculate distance between circles
|
|
-SAT: calculate the projected size of the delta vector (in this case, this is == the length of the delta vector)
|
|
-calculate sum of radii
|
|
-SAT: calculate the projected halfsize of each object (in this case, this is == their radius)
|
|
-calculate the difference between the sum of halfsizes/radii and the delta vector
|
|
-if positive, objects overlap along the axis
|
|
|
|
[64]** -not only does this help us understand what's going on in our SAT test,
|
|
it also suggests how to get more than a yes/no answer from the results
|
|
-do whatever we do in the circle-circle case
|
|
|
|
-if the circles ARE overlapping
|
|
-the penetration direction is parallel to the axis
|
|
-the amount is equal to the difference we calculated (sum-of-radii minus size-of-delta)
|
|
|
|
[65]** -Box-vs-Box revisited
|
|
-it's the same process as with two circles, except that we have to test more than just a single potentially seperating axis
|
|
-each axis test is analogous to the circle-circle test, they just involve a bit more math, to project things onto the axis..
|
|
-in the circle case, the object halfwidths and delta vectors are parallel to the axis
|
|
-as we saw with dotprods, when you project a vector onto an axis that's parallel to the vector, you get the
|
|
original vector
|
|
-like multiplying any number by 1
|
|
-so, for circles, the values are basically "pre-projected" and we skip the projection math
|
|
-as soon as we find a seperating axis, we're done -- we know the objects don't overlap
|
|
|
|
[66]** -as with circles, if the objects ARE overlapping (i.e we tested all axes and none are seperating the two objects),
|
|
we can extract collision info "for free" from the per-axis calculations we made
|
|
-the axis with the smallest "difference" (sum-of-halfsizes minus size-of-delta) is the projection direction
|
|
-the size of the difference is the projection amount
|
|
-projection direction + projection amount = projection vector. tada!
|
|
|
|
|
|
[67]** -so, we can use this method to collide any two shapes together, provided that for each shape we can quickly determine:
|
|
a) which directions are perpendicular to the shape's surface
|
|
(i.e which axes are potentially seperating directions for that shape)
|
|
b) how to project the shape onto an axis, i.e
|
|
-the shape's center (when projected onto an axis)
|
|
-the shape's size/halfsize (when projected onto an axis)
|
|
|
|
|
|
[68]** -example: projecting a box onto an axis
|
|
-this is code for an arbitrarily rotated box (in the diagrams, we're just keeping the box still and moving the axis..)
|
|
-it's the same thing/relativity
|
|
-an important insight for box projection is:
|
|
the sum of the projections of the halfwidth vectors = projected halfwidth of box
|
|
<point to diagram of this>
|
|
|
|
[69]** -box representation:
|
|
-position (of box center)
|
|
-width/height (along object axes)
|
|
-unit vector (describing orientation of box; we use the convention that the orientation vector points along local x)
|
|
|
|
-see our tutorials for examples of how to project different shapes
|
|
-linesegs should be obvious
|
|
|
|
|
|
[70]** -step through Box-vs-Box code line-by-line, examining/explaining it
|
|
|
|
-point out that you COULD make the code more generic/general
|
|
-each shape has an array of unit vectors representing potential seperating axes
|
|
-each shape has a function "Project" which return the object's halfsize when projected onto a given axis
|
|
-however, if you want to it run as fast as possible, writing special code for each possible combination of objects is the best solution
|
|
|
|
|
|
[71]** -what we left out:
|
|
[66]** might help when explaining this
|
|
-tracking minimum penetration axis
|
|
-store all pen amounts and compare them at the end, or keep a "running minimum"
|
|
-which direction to project?
|
|
-projdir is parallel to the axis of minimum projection, but could point in two possible directions
|
|
-use the sign of the delta<dot>axis
|
|
|
|
|
|
[72]**-what about circles?
|
|
-we haven't mentioned circles or curved surfaces yet, but they're very useful as collision shapes
|
|
-the main difference between circles and polygons is the behaviour around corners (vertices)
|
|
-circles "roll" around corners: the collision direction changes smoothly
|
|
-polygons slide across them: the collision direction remains the same (surface normal)
|
|
<demo: use tutorialA demo: circle falling/sliding off the top of a square>**
|
|
<demo: as above, but use an AABB falling/sliding off the top of a square>**
|
|
|
|
-another way to look at this difference is that, unlike polygons,
|
|
there aren't a finite/discrete number of directions perpendicular to a circle's surface
|
|
-this is a problem, since our approach relies on knowing which directions might be potentially seperating directions
|
|
-but: since this SAT approach is a sort of generalization of circle-circle collision,
|
|
surely we can support circles without too much extra work
|
|
|
|
[73]** -we can
|
|
-instead of reiterating what's presented in our online tutorials, i'll just refer you to them
|
|
-the basic idea is that for a circle you perform the exact same tests as you would for a box, except you sometimes
|
|
perform a single additional test at the end
|
|
-to handle the case where the circle is colliding with a "corner" (vertex) of a shape instead of an edge (lineseg)
|
|
-you don't always have to perform this test
|
|
-there is a fast and simple way to determine if you have to perform this additional test
|
|
-you can use information from the axes you've already tested
|
|
-if the overlap along the box axes is less than the circle's radius, we know the circle is in a corner region
|
|
<demonstrate the above values/etc. with the diagram>
|
|
-if the circle's center is in the horiz/vertical regions, we only test the two box axes
|
|
-we can tell if the circle is in these regions by looking at the results of these 2 axis tests
|
|
-if the circle's NOT in these regions, we have to test it vs. the nearest box corner
|
|
-again, which corner to use is easy since part of the 2 axis tests was determining the box->circle delta vector
|
|
-this delta vector "points" at the box corner
|
|
|
|
[74]** -what about non-convex shapes?
|
|
-this is important, especially for world/level shapes
|
|
-just represent them as a union of convex shapes
|
|
-several (possibly overlapping) convex shapes
|
|
[75]** -tilebased games use the same idea: decompose the world into small chunks
|
|
[76]** -a different decomposition is: linesegs
|
|
-this is leading into the next section into broad-phase
|
|
|
|
|
|
|
|
[77]** -optimisations:
|
|
-the key is to precompute as much information as possible, so that you don't have to calculate it at runtime
|
|
-instead you just lookup your precomputed value
|
|
-almost every game subscribes to the rule: "the vast majority of things in the world are static"
|
|
-i.e the game code makes a distinction between (static) world/level geometry, and (dynamic) objects
|
|
-makings things static is a great optimisation because we can precompute almost everything about each static object
|
|
-triangles and more complex shapes are harder to project than a box
|
|
-more lines of code
|
|
-you _can_ still do it on the fly, it's just slower
|
|
-calculations for circles and boxes are very fast and simple; they make good candidates for dynamic objects
|
|
-more complex shapes can be used for static objects, since most of the calculations
|
|
(calculating surface normals aka axis directions, etc.) can be done beforehand instead of at runtime
|
|
|
|
|
|
|
|
|
|
[78]** QUESTIONS about Seperating Axis Thereom / Method of Seperating Axes
|
|
|
|
[++TODO: figure out how much time we can spend here, and note it down so that, when presenting, we don't get stuck here for too long]
|
|
|
|
|
|
|
|
|
|
[79]**
|
|
PART 2: broad-phase collision detection, aka spatial database
|
|
-switching gears...
|
|
|
|
[80]** -knowing how to test two objects for collision is only part of the solution to the CD problem
|
|
[81]** -if there are 10 objects in the world, we'd have to perform 10*10=100 tests
|
|
-it doesn't matter how fast your object-object test is if you're using it 100 times per frame
|
|
-for N objects, you have to use N^2 tests
|
|
|
|
[82]** -we want to be able to very quickly determine which pairs of objects we should test, i.e which pairs MIGHT be colliding
|
|
-how to figure out what might be colliding?
|
|
-all the methods i know of for broad-phase CD use the assumption:
|
|
if two objects are near each other, then they might be colliding
|
|
-quickly == approximately; we don't need to know for sure, that's the job of the narrow-phase
|
|
-once we know which pairs MIGHT be colliding, we can pass them to our narrow-phase collision system
|
|
to figure out if they actually _are_ colliding, and if so, how.
|
|
-so, we just need to find a way to quickly determine, given an object or a position in the world,
|
|
all of the other objects nearby
|
|
|
|
-this step is _very_ game specific
|
|
-there is no "magic bullet"
|
|
|
|
[83]** -for small numbers of objects (<=5), using HitTest on each possible pair is often "good enough"
|
|
-you're still doing N^2 tests, but you're not doing too many of them, and they're not too expensive
|
|
-it's fast, and it tells you what you need to know (that the objects might be colliding)
|
|
-if HitTest returns true, you know their bounding boxes are overlapping, and can investigate further using complex tests
|
|
-however, for the sake of argument, SAT code for AABBs (i.e rectangles) can be just as fast as Hittest
|
|
-the main cost is the overhead of a function call
|
|
|
|
|
|
[84]** -for larger numbers of objects, you need a more sophisticated way to find all the objects near a given point
|
|
-this problem has been solved in many different ways:
|
|
-grid: divide space into uniform boxes
|
|
[85]** -quadtree: recursively subdivide space into 4 equal regions
|
|
|
|
[86]** -they all amount to the same thing: partitioning space into discrete chunks, and building a database using those chunks
|
|
-the data in the database is the location of objects
|
|
-hence broad-phase collision systems are often called spatial databases
|
|
|
|
-the two most important operations on this database are:
|
|
a) neighborhood query (quickly determining which objects are near a given position)
|
|
b) updating an entry in the database (i.e moving an object)
|
|
-optimising (a) is very simple if you don't care about (b)
|
|
-games which must support large numbers of moving objects must optimise (b)
|
|
-it's hard to do both at once; this is why broad-phase is so game-specific
|
|
|
|
|
|
[87]** -grids are best for flash
|
|
-there are many different ways to use grids, but ALL of them are better suited for flash than non-grid-based methods
|
|
|
|
-why only grids?
|
|
|
|
-grids allow for constant-time neighborhood queries, and constant-time updating
|
|
-the constant cost is extremely low
|
|
-for a neighborhood query, you simply find the cell which contains your query point,
|
|
then look in the surrounding cells
|
|
-to update the position of an object in the grid, you just need to find the cells which the object touches,
|
|
which is fast and simple
|
|
-more on this later
|
|
|
|
-all other spatial database approaches are based on search-trees of some sort
|
|
-the quadtree i showed you LOOKED sort of like a grid, but the implementation looks
|
|
like a normal tree data structure
|
|
-each node has 4 children, etc.
|
|
-when you look something up from a tree, you have to descend to the leaves, performing tests at each level of the tree
|
|
-each test takes time
|
|
-grids only require one test, not one test per level of the heirarchy
|
|
-likewise, inserting something into a tree is more complex than with a grid
|
|
|
|
-if grids are so good, why don't other games use them?
|
|
-most 2D games _do_ use grids
|
|
-obviously, any tile-based game is using some sort of grid
|
|
-even doom used grid-based collision
|
|
|
|
[88]** -the problem with grids is that they take up a LOT of space, since the entire world must be covered in cells
|
|
-a 200x100-tile world means a grid with 20000 cells; if each cell needs 256bytes, that's 5MB
|
|
-in 3D, this only gets worse: 200x100x100 @ 256bytes = 500MB
|
|
-this is why trees are used; they require far less memory. instead of covering the entire world,
|
|
you only cover the non-empty parts of the world
|
|
-the tradeoff is that trees are slower and more complex to query and update
|
|
|
|
[89]** -in flash, in 2D, you can afford the extra memory needed by a grid, but you _can't_ afford the extra processing time required by trees
|
|
|
|
|
|
[90]** -all grid operations involve a couple math ops
|
|
-you can't get any faster than that
|
|
|
|
[91]** -using a grid for object-vs-object tests
|
|
-i'll just provide an outline of the process
|
|
-see our online tutorials for implementation details and source code
|
|
|
|
[92]** -a grid is just an abstract data structure; there are many differnet ways to actually use the structure.
|
|
-two popular ways are "regular" and "loose" grids
|
|
<explain the following in english while using diagram to illustrate>
|
|
|
|
-regular grid:
|
|
-every object knows which grid cell(s) it touches
|
|
-every grid cell knows which object(s) are touching it
|
|
<refer to diagram>
|
|
each blue cell must be tested for collision, and each blue cell must be updated when objects move
|
|
|
|
-loose grid:
|
|
-every object knows which grid cell contains it's center
|
|
-every cell knows which object(s) it contains
|
|
<refer to diagram>
|
|
each red cell must be tested for collision, and each blue cell must be updated when objects move
|
|
|
|
-regular vs. loose:
|
|
-less tests vs less time to update moving objects
|
|
-can handle any sized shape vs shapes must fit in a cell
|
|
|
|
|
|
|
|
[93]** -using a grid for object-vs-world
|
|
-as mentioned earlier, most games divide objects into "static" and "dynamic" groups
|
|
-you CAN simply use the grid to collide dynamic vs. static objects exactly as you
|
|
would for dynamic vs. dynamic objects (as we just saw)
|
|
-however, if you know that most of the game world will consist of static shapes,
|
|
you might want to create a special system for colliding these static shapes against dynamic objects
|
|
|
|
|
|
[94]** -there isn't time to explore all of the possible ways to use a grid for object-vs-world tests
|
|
-i'll breifly cover 2 approaches
|
|
-tilebased and geometry-based
|
|
|
|
-tilebased collision:
|
|
-each grid cell stores a tile shape
|
|
-each moving object collides against all other moving objects and tiles in it's neighborhood
|
|
-again, our online tutorials cover this topic very well (i'd rather not just repeat info that's already available)
|
|
-tilebased systems SEEM like a good choice (simple and fast)
|
|
-in practise they're quite hard to get good behaviour out of
|
|
-tilebased collision is usually rule-based instead of math-based;
|
|
rule-based works well for simple dynamic models, but when you start needing smooth
|
|
physics-based object movement, rule-based collision simply doesn't perform well
|
|
-you end up doing lots of extra work to get things behaving well
|
|
-doing lots of extra work defeates the purpose of using a tilebased world in the first place, which was speed and simplicity
|
|
|
|
-a different grid-based approach is geometry/lineseg based
|
|
-the world is made out of polygons
|
|
-convex or concave, it doesn't matter
|
|
-as a preprocess, before runtime, you decompose your polygons into their component linesegs
|
|
-insert each lineseg into a grid
|
|
-determining which cells to insert a lineseg into can be done in several ways
|
|
-since it's a preprocess it doesn't really matter how slow this code is
|
|
-you can simply try lineseg-vs-AABB test for all cells touching the lineseg's bounding box
|
|
-or you can use raycast code (which we'll touch on soon)
|
|
-at runtime, object-vs-world collision involves one or two object-vs-lineseg tests
|
|
-linesegs are the simplest and fastest shapes to collide against
|
|
-they have only a single potentially seperating axis
|
|
-performing several object-vs-lineseg tests is MUCH faster than performing
|
|
several object-vs-tileshape tests
|
|
-this system can support the exact same levels and shapes as a tilebased system
|
|
-but it's far simpler
|
|
-instead of having many different possible tile-shapes to collide against, you have just one shape: lineseg
|
|
-it's also a lot faster
|
|
-testing vs. linesegs is faster than vs. timeshapes
|
|
|
|
|
|
|
|
[95]** -another great advantage that grids have over other spatial databases is: raycasting is very easy
|
|
-rays are lines with one endpoint
|
|
-they're used to model fast-moving bullets in many games (doom, quake)
|
|
-they're also very useful for line-of-sight testing (AI uses these to determine what each enemy can "see")
|
|
|
|
[96]** -a very efficient and simple to understand raycasting algorithm is presented in this paper
|
|
-it's very simple, and very fast
|
|
-yet again, please see our online tutorials for implementation details
|
|
|
|
|
|
|
|
[97]**
|
|
PART 3: misc/conclusion
|
|
|
|
-summary:
|
|
-collision detection is a powerful tool for making fun games
|
|
-the MSA is a useful tool for narrow-phase collision detection
|
|
-a uniform grid is a useful tool for broad-phase collision detection
|
|
|
|
-QUESTIONS?
|
|
|
|
|
|
|
|
|
|
|