Welcome, Guest. Please login or register.
Did you miss your activation email?

Login with username, password and session length

 
Advanced search

877081 Posts in 32846 Topics- by 24286 Members - Latest Member: himowa

May 18, 2013, 01:29:45 PM
TIGSource ForumsDeveloperTechnical (Moderators: Glaiel-Gamer, ThemsAllTook)How do you program elasticity with homing? Like Avoision 2
Pages: [1]
Print
Author Topic: How do you program elasticity with homing? Like Avoision 2  (Read 869 times)
X3N
Level 6
*


View Profile Email
« on: April 13, 2011, 07:17:04 AM »

http://foon.co.uk/farcade/avoision2

The white ball follows your cursor steadily while close, quickly when far, and snaps if it's going away when there is distance.

How would you code this?
Logged

destiny is truth pre-op
SirEel
Level 0
**


View Profile
« Reply #1 on: April 13, 2011, 07:22:25 AM »

Use an acceleration model, where acceleration is set to a (capped) proportion of the distance (or more ideally, the square of the distance) between the two points... at a guess.
Logged
jotapeh
Level 10
*****



View Profile WWW Email
« Reply #2 on: April 13, 2011, 08:27:28 AM »

I got this behaviour by accident when coding a space sim. This mouse version is a little simpler I think. Essentially:

Code:
// psuedocode, assumes a well featured Vector2D class
int ARBITRARY_FIXED_DISTANCE = 30;
int MAX_ACCELERATION = 1;
int MAX_VELOCITY = 10;

function callThisEveryFrame() {
    Vector2D ballToMouse = (mouse.position-ball.position);

    if (ballToMouse.length > ARBITRARY_FIXED_DISTANCE && ballToMouse.dot(ball.velocity) < 0) {
        ballToMouse.length = MAX_ACCELERATION;
        ball.velocity += ballToMouse;
    }

    if (ball.velocity.length > MAX_VELOCITY)
        ball.velocity.length = MAX_VELOCITY;

    ball.position += ball.velocity;
}

Play with ARBITRARY_FIXED_DISTANCE and try swapping '&&' for '||' for differing behaviour. (edits: some derp coding mistakes fixed)
« Last Edit: April 13, 2011, 08:35:17 AM by jotapeh » Logged

jotapeh
Level 10
*****



View Profile WWW Email
« Reply #3 on: April 13, 2011, 08:42:31 AM »

Just for fun I went ahead and coded it up. This is pretty much the code above verbatim, but translated to AS3 and some of the variables tweaked.

http://www.wegetsignal.ca/elastomouse/
Logged

SirEel
Level 0
**


View Profile
« Reply #4 on: April 13, 2011, 09:56:28 AM »

Just for fun I went ahead and coded it up. This is pretty much the code above verbatim, but translated to AS3 and some of the variables tweaked.

http://www.wegetsignal.ca/elastomouse/

That behaves subtly but noticeably different to the OP's link, namely when the ball is moving fast and is close to the mouse.

As an after-thought to my earlier suggestion, if the ball has a component of its movement which is pointed away from the cursor, then that should be overdamped, though still by a proportion. I would write some code to demonstrate this, but I'm meant to be working on my dissertation...
Logged
X3N
Level 6
*


View Profile Email
« Reply #5 on: April 13, 2011, 12:42:21 PM »

Just for fun I went ahead and coded it up. This is pretty much the code above verbatim, but translated to AS3 and some of the variables tweaked.

http://www.wegetsignal.ca/elastomouse/

That behaves subtly but noticeably different to the OP's link, namely when the ball is moving fast and is close to the mouse.

As an after-thought to my earlier suggestion, if the ball has a component of its movement which is pointed away from the cursor, then that should be overdamped, though still by a proportion. I would write some code to demonstrate this, but I'm meant to be working on my dissertation...

Jotapeh, thanks for coding that. As SirEel pointed out, that's close - maybe if the ball is within a certain distance, it moves only towards the target?

SirEel, would you dampen the away from cursor movement only when close?

Jotapeh: There doesn't seem to be "sharp" elasticity in your example, as you are accelerating without checking the distance. If you tie a string to a tennis ball and run it one way, then jerk the string in the opposite direction, the ball changes courses very quickly, not at a default rate.

How does the .length flattener work? Can you post some pseudo code on how to cap a vector of X/Y to some max rate (eg X=side a in a triangle, Y=side b, max=C hypotenuse)? Tried a couple times and it didn't turn out quite right.
Logged

destiny is truth pre-op
SirEel
Level 0
**


View Profile
« Reply #6 on: April 13, 2011, 01:11:54 PM »

No, I'd add the additional dampening whenever it's moving more away than towards, as this is likely to happen only when the cursor has been moved quickly, making assumptions about where the cursor might be probably isn't a good idea...
Logged
jotapeh
Level 10
*****



View Profile WWW Email
« Reply #7 on: April 13, 2011, 06:16:36 PM »

Yeah, totally valid crits, I just wanted to give you a thought in the right direction.

As for length flatteners - essentially think of normalizing the vector (to a unit vector) and then scaling by the length you want. Shortform it might look like

Code:
function set length(n:Number):void {
    var l:number = Math.sqrt(this.x*this.x+this.y*this.y);
    if (!l)
        return;

    n /= l;
    this.x *= n;
    this.y *= n;
}
Logged

Nix
Level 10
*****



View Profile
« Reply #8 on: April 13, 2011, 06:46:04 PM »

Here you go http://www.kirupa.com/developer/actionscript/spring.htm
(there's a good chance Avoison 2 used this tutorial)
« Last Edit: April 14, 2011, 08:10:40 AM by Nix » Logged
X3N
Level 6
*


View Profile Email
« Reply #9 on: April 14, 2011, 05:49:06 AM »

Here you go http://www.kirupa.com/developer/actionscript/spring.htm
(there's a good chance Avoison 2 even this tutorial)

Helpful! Thanks.
Still seeing the circles curve around my mouse more than I want but I'll mess around with that formula.
Logged

destiny is truth pre-op
randomnine
Level 1
*


View Profile WWW
« Reply #10 on: April 14, 2011, 08:45:21 AM »

Yep, the main thing missing from that code earlier is friction. Add enough friction and the ball will settle down gradually once it arrives at the target, as in avoision2.

It's not very nice movement though. I think I'd do something like this... modifying the code from that tutorial:

Code:
predict = 0.2;

x = -(this._x + predict*xp) + centerx ;
y = -(this._y + predict*yp) + centery ;

This predicts where the ball's going to be in 0.2 seconds, then applies force towards the mouse cursor from there. If the ball's about to shoot past the mouse cursor, it'll begin slowing down in anticipation.

A combination of prediction and friction should make it much more stable. Don't give it too much prediction, though, or it'll lurch back and forth on the way to the cursor.

Here's another fix you can insert after the x= and y= lines and before the xp= and yp= lines:

Code:
tangentinertia = 0.7;

offlen = sqrt( x*x + y*y );
towardsp = (xp*x + yp*y)/offlen;
tangentp = (xp*y + yp*-x)/offlen;

tangentp *= tangentinertia;

xp = (towardsp*x + tangentp*y)/offlen;
yp = (towardsp*y + tangentp*-x)/offlen;

This will allow the ball to move freely towards and away from the cursor, but brake its sideways movement when it's trying to orbit.

(How it works: "offlen" is the length of the vector (x,y), so (x/offlen, y/offlen) is a unit length vector which points in the direction to the cursor. We then take the dot product of the ball's movement (xp, yp) with that vector (x/offlen, y/offlen), giving us the speed of the ball's movement towards the cursor (towardsp). We then rotate the vector 90 degrees, giving us (y/offlen, -x/offlen), and take the dotproduct of (xp, yp) with that to give the speed of the ball's movement around the cursor (tangentp).

We then apply friction to (tangentp) only and reverse the above process to convert (towardsp, tangentp) back to speeds along the X and Y axes.)
Logged

X3N
Level 6
*


View Profile Email
« Reply #11 on: November 24, 2011, 03:55:03 PM »

centerx/centery is the cursor, yeah?
And xp and yp are force? What is _x and _y?
Trying to hack this together in javascript
Logged

destiny is truth pre-op
randomnine
Level 1
*


View Profile WWW
« Reply #12 on: November 24, 2011, 05:10:49 PM »

In the tutorial Nix linked, which is what I was suggesting modifications to:

(centerx,centery) is the cursor position.
(_x,_y) is the ball position.
(x,y) is the vector from the ball to the mouse. It's used to calculate the force to apply to the ball.
(xp,yp) is the ball velocity (speed).

I stuck with those variable names for my changes.

They're horrible variable names, though! Smiley Here's the whole thing, including my changes, rewritten with more sensible variable names. The whole thing's untested though, so you might have to play around with the constant values before you get sensible behaviour.

Code:
// Variables provided every time the function's called:
// mousePosX, mousePosY

// Variables stored from frame to frame:
// ballPosX, ballPosY
// ballVelX, ballVelY

// Spring constant.
// Higher values will pull the ball towards the mouse faster.
springConstant = 0.1;

// Inertia.
// On a scale of 0 to 1.
// With low values, the ball will drag slowly like it's moving through treacle.
// With high values, the ball will happily bounce back and forth for a while.
inertia = 0.9;

// Prediction.
// Measured in seconds. Default: 0.
// How far ahead to predict the ball's movement, for the purposes of slowing it down.
// Low values will let the ball bounce back and forth past the mouse.
// High values will make the ball jitter and take a long time to reach the mouse.
predict = 0.2;

// Tangential inertia.
// On a scale of 0 to 1.
// Low values will force the ball to only move towards or away from the mouse.
// High values will allow the ball to sling around the mouse in circles.
tangentinertia = 0.7;

// Calculate a force from the ball's predicted position towards the mouse.
forceX = mousePosX - (ballPosX + predict*ballVelX);
forceY = mousePosY - (ballPosY + predict*ballVelY);

// This block is optional and the rest will work OK without it.
// You may as well get the rest working, then add this in after.
{
  // Split the ball's velocity into a "towards mouse" component and a "sideways" component.
  forceLength = sqrt( forceX*forceX + forceY*forceY );
  towardsComponent = (ballVelX*forceX + ballVelY*forceY)/forceLength;
  tangentComponent = (ballVelX*forceY - ballVelY*forceX)/forceLength;

  // Reduce the ball's sideways velocity.
  tangentComponent *= tangentinertia;

  // Convert the components back into X and Y.
  ballVelX = (towardsComponent*forceX + tangentComponent*forceY)/forceLength;
  ballVelY = (towardsComponent*forceY - tangentComponent*forceX)/forceLength;
}

ballVelX = ballVelX * inertia + forceX*springConstant;
ballVelY = ballVelY * inertia + forceY*springConstant;

ballPosX += ballVelX;
ballPosY += ballVelY;
Logged

Pages: [1]
Print
Jump to:  

Theme orange-lt created by panic