• Announcements

    • khawk

      Download the Game Design and Indie Game Marketing Freebook   07/19/17

      GameDev.net and CRC Press have teamed up to bring a free ebook of content curated from top titles published by CRC Press. The freebook, Practices of Game Design & Indie Game Marketing, includes chapters from The Art of Game Design: A Book of Lenses, A Practical Guide to Indie Game Marketing, and An Architectural Approach to Level Design. The GameDev.net FreeBook is relevant to game designers, developers, and those interested in learning more about the challenges in game development. We know game development can be a tough discipline and business, so we picked several chapters from CRC Press titles that we thought would be of interest to you, the GameDev.net audience, in your journey to design, develop, and market your next game. The free ebook is available through CRC Press by clicking here. The Curated Books The Art of Game Design: A Book of Lenses, Second Edition, by Jesse Schell Presents 100+ sets of questions, or different lenses, for viewing a game’s design, encompassing diverse fields such as psychology, architecture, music, film, software engineering, theme park design, mathematics, anthropology, and more. Written by one of the world's top game designers, this book describes the deepest and most fundamental principles of game design, demonstrating how tactics used in board, card, and athletic games also work in video games. It provides practical instruction on creating world-class games that will be played again and again. View it here. A Practical Guide to Indie Game Marketing, by Joel Dreskin Marketing is an essential but too frequently overlooked or minimized component of the release plan for indie games. A Practical Guide to Indie Game Marketing provides you with the tools needed to build visibility and sell your indie games. With special focus on those developers with small budgets and limited staff and resources, this book is packed with tangible recommendations and techniques that you can put to use immediately. As a seasoned professional of the indie game arena, author Joel Dreskin gives you insight into practical, real-world experiences of marketing numerous successful games and also provides stories of the failures. View it here. An Architectural Approach to Level Design This is one of the first books to integrate architectural and spatial design theory with the field of level design. The book presents architectural techniques and theories for level designers to use in their own work. It connects architecture and level design in different ways that address the practical elements of how designers construct space and the experiential elements of how and why humans interact with this space. Throughout the text, readers learn skills for spatial layout, evoking emotion through gamespaces, and creating better levels through architectural theory. View it here. Learn more and download the ebook by clicking here. Did you know? GameDev.net and CRC Press also recently teamed up to bring GDNet+ Members up to a 20% discount on all CRC Press books. Learn more about this and other benefits here.

xytor

Members
  • Content count

    218
  • Joined

  • Last visited

Community Reputation

136 Neutral

About xytor

  • Rank
    Member
  1. By 'finite' do you mean they are line segments?
  2. I set the realDeltaT to 1.0/60 but that didn't help with the balls ghosting through the bottom bound. The number of physics iterations had to be set to at least 5 to get it stable (especially with balls of a small radius). I think the place where I go wrong is my "continuous collision" scheme. I extend the velocity of the ball by a ball radius, and then see if that line collides with the bounds. In that case, I use the intersection point as the other "ball" for your collision spring formula. This seems to result in wrong behavior...
  3. I slowed it down, reduced the framerate and had a look... it seems that the force due to gravity is 981 kg*pixels/second^2 downwards, but the opposing force has a magnitude of about 100. As I reduce the deltaT, this effect seems to get better. On the other hand, as I increase the number of iterations to the hundreds (thereby decreasing the deltaT by a significant amount), the bounce force is getting much larger! Is there a missing deltaT term somewhere, or does the spring equation not take acceleration into account? [CODE] private function update(e:Event) { if (mouseDown) { mouseIsDown(); } realDeltaT = Number(getTimer()) - prevTime; prevTime = getTimer(); realDeltaT /= 15000.0; //Time slowed to for more stability var numIterations:int = 1; //# of physics loops in one graphics loop for more stability deltaT = realDeltaT / Number(numIterations); for (var i:int = 0; i < numIterations; ++i) { updateForcesOnBalls(); updateVelocityAndPositionOnBalls(); } drawAllBalls(); } private function updateForcesOnBalls() { for each (var ball:MovieClip in balls) { assignWithVector(ball["prevForce"], ball["force"]); assignWithElements(ball["force"], 0, 9.81 * pixelsInMeter); //collide with bounds for (var i = 0; i < bounds.length; i += 2) { var scaledVel:Vector3D = copy(ball["vel"]); scaledVel.scaleBy(deltaT); var augmentedVel:Vector3D = copy(ball["vel"]); augmentedVel.normalize(); augmentedVel.scaleBy(ballRadius); augmentedVel = scaledVel.add(augmentedVel); var wallVec:Vector3D = bounds[i + 1].subtract(bounds[i]); var intersection:Vector3D = lineSegmentIntersection(bounds[i], wallVec, ball["pos"], augmentedVel); if (intersection != null || lineSegmentCircleIntersection(bounds[i],wallVec,ball["pos"],ballRadius)) { if (intersection == null) { intersection = closestPointBetweenLineSegmentAndCircle(bounds[i], wallVec, ball["pos"], ballRadius); } var normalizedDistance:Vector3D = intersection.subtract(ball["pos"]); var overlapAmount:Number = Math.abs(normalizedDistance.length-ballRadius); normalizedDistance.normalize(); var velocityDifference:Vector3D = copy(ball["vel"]); velocityDifference.scaleBy( -1.0); var velocityAlongDistance:Number = normalizedDistance.dotProduct(velocityDifference); normalizedDistance.scaleBy( -(((wallCollisionSpringConstant / (deltaT * deltaT)) * overlapAmount) + (wallCollisionDampeningConstant / deltaT) * velocityAlongDistance) / (inverseBallMass + 0)); ball["force"] = ball["force"].add(normalizedDistance); } } //collide with other balls for each (var other:MovieClip in balls) { if (other == ball) { continue; } //same formula as with the wall collision above overlapAmount = circleIntersectsCircle(ball["pos"], ballRadius, other["pos"], ballRadius); if (overlapAmount >= 0) { normalizedDistance = other["pos"].subtract(ball["pos"]); normalizedDistance.normalize(); velocityDifference = other["vel"].subtract(ball["vel"]); velocityAlongDistance = normalizedDistance.dotProduct(velocityDifference); normalizedDistance.scaleBy( -(((collisionSpringConstant / (deltaT * deltaT)) * overlapAmount) + (collisionDampeningConstant / deltaT) * velocityAlongDistance) / (inverseBallMass + inverseBallMass)); ball["force"] = ball["force"].add(normalizedDistance); } } } } private function updateVelocityAndPositionOnBalls() { for each (var ball:MovieClip in balls) { var futurePos:Vector3D = new Vector3D(); futurePos.x = ball["pos"].x + ball["vel"].x * deltaT + (0.5 * ball["prevForce"].x * inverseBallMass * (deltaT * deltaT)); futurePos.y = ball["pos"].y + ball["vel"].y * deltaT + (0.5 * ball["prevForce"].y * inverseBallMass * (deltaT * deltaT)); var futureVel:Vector3D = new Vector3D(); futureVel.x = ball["vel"].x + (0.5 * (ball["prevForce"].x + ball["force"].x) * deltaT); futureVel.y = ball["vel"].y + (0.5 * (ball["prevForce"].y + ball["force"].y) * deltaT); assignWithVector(ball["pos"], futurePos); assignWithVector(ball["vel"], futureVel); } } [/CODE]
  4. Sure, here is my main update code. Notice that I must slow time and have many physics iterations in order to get the collision springs to work... [CODE] private function update(e:Event) { if (mouseDown) { mouseIsDown(); } realDeltaT = Number(getTimer()) - prevTime; prevTime = getTimer(); realDeltaT /= 2000.0; //Time slowed to 0.5x for more stability var numIterations:int = 8; //8 physics loops in one graphics loop for more stability deltaT = realDeltaT / Number(numIterations); for (var i:int = 0; i < numIterations; ++i) { updateForcesOnBalls(); updateVelocityAndPositionOnBalls(); } drawAllBalls(); } private function updateForcesOnBalls() { for each (var ball:MovieClip in balls) { assignWithVector(ball["prevForce"], ball["force"]); assignWithElements(ball["force"], 0, 9.81 * pixelsInMeter); //collide with bounds for (var i = 0; i < bounds.length; i += 2) { var scaledVel:Vector3D = copy(ball["vel"]); scaledVel.scaleBy(deltaT); var augmentedVel:Vector3D = copy(ball["vel"]); augmentedVel.normalize(); augmentedVel.scaleBy(ballRadius); augmentedVel = scaledVel.add(augmentedVel); var wallVec:Vector3D = bounds[i + 1].subtract(bounds[i]); var intersection:Vector3D = lineSegmentIntersection(bounds[i], wallVec, ball["pos"], augmentedVel); if (intersection != null || lineSegmentCircleIntersection(bounds[i],wallVec,ball["pos"],ballRadius)) { var normal:Vector3D = wallVec; normal = new Vector3D(normal.y, -normal.x); normal.normalize(); normal.scaleBy(scaledVel.length * (ballBounciness / (deltaT*deltaT))); ball["force"] = ball["force"].add(normal); //project velocity onto the wall ball["vel"] = projectVectorOntoAnother(ball["vel"], bounds[i + 1].subtract(bounds[i]) ); //calculate force of friction var frictionForce:Vector3D = copy(ball["vel"]); frictionForce.scaleBy( -1.0); frictionForce.normalize(); frictionForce.scaleBy(wallFrictionCoefficient * normal.length); ball["force"] = ball["force"].add(frictionForce); } } //collide with other balls for each (var other:MovieClip in balls) { if (other == ball) { continue; } var overlapAmount:Number = circleIntersectsCircle(ball["pos"], ballRadius, other["pos"], ballRadius); if (overlapAmount >= 0) { var normalizedDistance:Vector3D = other["pos"].subtract(ball["pos"]); normalizedDistance.normalize(); var velocityDifference:Vector3D = other["vel"].subtract(ball["vel"]); var velocityAlongDistance:Number = normalizedDistance.dotProduct(velocityDifference); normalizedDistance.scaleBy( -(((collisionSpringConstant / (deltaT * deltaT)) * overlapAmount) + (collisionDampeningConstant / deltaT) * velocityAlongDistance) / (inverseBallMass + inverseBallMass)); ball["force"] = ball["force"].add(normalizedDistance); } } } } private function updateVelocityAndPositionOnBalls() { for each (var ball:MovieClip in balls) { var futurePos:Vector3D = new Vector3D(); futurePos.x = ball["pos"].x + ball["vel"].x * deltaT + (0.5 * ball["prevForce"].x * inverseBallMass * (deltaT * deltaT)); futurePos.y = ball["pos"].y + ball["vel"].y * deltaT + (0.5 * ball["prevForce"].y * inverseBallMass * (deltaT * deltaT)); var futureVel:Vector3D = new Vector3D(); futureVel.x = ball["vel"].x + (0.5 * (ball["prevForce"].x + ball["force"].x) * deltaT); futureVel.y = ball["vel"].y + (0.5 * (ball["prevForce"].y + ball["force"].y) * deltaT); assignWithVector(ball["pos"], futurePos); assignWithVector(ball["vel"], futureVel); } } [/CODE]
  5. Yes, I'm using the velocity verlet integration method which has the same accuracy as regular verlet. I also request that you edit your formula to use proper parenthases... it's very confusing with standard PEMDAS order of operations! The only problem I see with using the spring method to determine collision (with walls or otherwise) is if the ball is going fast enough to teleport through the wall/ball. I still haven't figured out a cheap/easy way to do continuous collision with your spring-based approach. Sure I could increase iterations (thereby decreasing the timestep), but that's really expensive. Also, I can't seem to keep the balls contained... Eventually they sag through the bottom wall!
  6. After trying out your formula, it seems that this is the process: 1) get overlap amount between two balls, call it x 2) get distance vector between two balls, call it dist 3) normalize said distance vector 4) get the difference in velocity vector, call it velDiff 5) calculate the dot product; dist * velDiff, call it v 6) calculate the force magnitude, call it M: ( -( (k/dt^2) * x + (d/dt) * v ) ) / ( inverseM1 + inverseM2) 7) force = dist * M; Works really well with relatively large inverse masses and small spring/dampening constants... Also works better with 5x slowed time and 5 physics iterations per frame [img]http://public.gamedev.net//public/style_emoticons/default/biggrin.png[/img]
  7. Thanks again, now I understand how to use this formula. However, I'm not sure of why the ' [left]velocity along normalized distance vector' is being used. As far as I remember, Hooke's law only needs a distance...[/left] [left]Also, is the order of operations in your formula correct? The term [b]k / dt^2 * x [/b]could be [b]([/b][b]k / dt^2) * x[/b]?[/left]
  8. Thanks, h4tt3n. I have a few questions about your method: What exactly is the x term? An intersection could have multiple points, so I'm not sure what you mean. Also, can you explain more about the velocity along normalized distance vector? Also, I wonder if this method can be applied to collision with bounding walls. Currently I'm using a custom method where the ball's position plus velocity is made into a line segment and intersected with the wall, and a force in the direction of the wall's normal is applied. However this makes the balls either bounce endlessly or eventually ghost through the wall. Thanks again!
  9. [quote name='bzroom' timestamp='1327389457' post='4905708'] There's nothing wrong with using a fixed time step (1/30s for example). Euler is very unstable without a fixed timestep. My guess is that you dont need the + term in those equations. dX/dt would be everything just up until the +'s. vel = (newpos - oldPos) / dt; I've never used verlet. Also, you should make a vector class, with operators. This way you wont have to keep doing component wise math everywhere, leading to mistakes. [/quote] The [left]+'s term is more accurate. Think about it, position isn't just x' = x + v', it's also not x' = x + v' + a'... In reality, there are infinite terms that need to be integrated (velocity, acceleration, jerk, ...) to get an accurate position. That's why my velocity calculation has the extra acceleration term. It's an extra integration step for more accuracy.[/left] [left]The problem seems to go away when I multiply deltaT back in:[/left] [color=#282828][font=helvetica, arial, verdana, tahoma, sans-serif][size=4][left]ball["vel"] = deltaT * (((ball["pos"] - ball["prevPos"]) / deltaT) + (0.5 * ball["force"] * inverseBallMass * deltaT)); [/left][/size][/font][/color] [color=#282828][font=helvetica, arial, verdana, tahoma, sans-serif][size=4][left]That gives the correct length velocity. I'm guessing that without the extra deltaT, I was getting velocity in meters per second, but I really want to get the velocity in meters per timestep.[/left][/size][/font][/color] [quote name='h4tt3n' timestamp='1327398960' post='4905742'] @Wildbunny. Yes, stability is impressive, but in my opinion it comes with too high a cost. As Xytor also mentions, there's no conservation of momentum due to the forced coefficient of restitution value of zero. @Xytor. Use force based damped springs for all contacts, it will remove all jitter and is stable with hundreds and hundreds of balls interacting. cheers, Mike [/quote] Force based damped springs for contacts? That sounds interesting, can I have more info or a whitepaper please?
  10. Obstacle avoidance can be achieved with steering behaviors. [url="http://www.red3d.com/cwr/steer/"]http://www.red3d.com/cwr/steer/[/url]
  11. Gah, it's still unstable... considering using some other method other than naive frame-based euler integration (my time step is currently implicitly a frame -- always 1/30th of a second). It seems all the time I'm putting into this to make it a "quick" "hacked together" sim could be better spent just making a real physics engine -.- Edit: Ok, trying out verlet... things seem to be working relatively well, except my derived velocity vector is inaccurate. It's the correct direction but way bigger. What am I doing wrong here? ball["vel"].x = ((ball["pos"].x - ball["prevPos"].x) / deltaT) + (0.5 * ball["force"].x * inverseBallMass * deltaT); ball["vel"].y = ((ball["pos"].y - ball["prevPos"].y) / deltaT) + (0.5 * ball["force"].y * inverseBallMass * deltaT);
  12. Hmm... Trying to adapt this method to my simple simulation has been troublesome. I don't have impulses or masses... Just force, velocity and position. Don't suppose there's any stable way of making it work? Or do I have to have a full-blown physics engine?
  13. [quote name='bzroom' timestamp='1327210727' post='4905038'] try this: [url="http://www.wildbunny.co.uk/blog/2011/03/25/speculative-contacts-an-continuous-collision-engine-approach-part-1/"]http://www.wildbunny...pproach-part-1/[/url] [/quote] That method is impressive! Thank you! My only concern is dealing with the conservation of velocity(momentum) and bouncing.
  14. [quote name='fastcall22' timestamp='1327218145' post='4905050'] Not everyone working with 2D space has a 3D math library readily available. Hplus' approach makes the most sense (with an thorough explanation even!) and avoids 6 multiplications, 3 subtractions, and storage overhead for z component and the extra vector. [/quote] It's super cheap and easy to make your own cross product function that takes one 2d vector, assumes the z is 0 and crosses it with (0,0,1). Here, let me give you the exact formula: Given a 2d vector (a,b), the normal is (x,y): x = b y = -a So basically, flip a and b, and negate the y. Two assignments and one negation. Can't be cheaper!
  15. Much easier way: 1) Find the direction of the line by subtracting one point from the other 2) Convert the direction into a 3D vector, leave z as 0. 3) do a cross product with (0,0,1) 4) normalize the result Voila, you have the normal to the line!