tkofh / coily

Spring Physics Utilities
MIT License
2 stars 0 forks source link

Flipped value/target movement #1

Open Gregoor opened 1 year ago

Gregoor commented 1 year ago

Hi, thanks for the lib! Exactly what I was looking for wrt API, though my use cases diverges a bit, which is why I am wondering if I should fork or whether you'd look at a PR. Here's the gist:

With the currrent value/target dichotomy, where one can only set the target, each step moves the value closer to the target, according to the spring's physics. But I am also looking for the opposite case, where a movement should happen opposite to the spring direction, dampened by its force.

I am also thinking that for this model the naming is a bit off, it would be more like anchor, value & target, where anchor would be what target is now and target would be optional, only needed when a movement opposite to anchor is desired.

I'll work on a fork now, but happy to PR, if desired.

tkofh commented 1 year ago

Hey Gregoor, this is a really neat idea! Would you be able to elaborate a bit on the functionality you're imagining? Reading your description here, I can think of two directions to take:

  1. Emulating a tween When creating a spring, perhaps in addition to a target, the user can specify an initial (or anchor or start). The value will immediately move towards the target from the initial/anchor/start.

  2. Emulating a Physical spring Right now, the "spring" collapses to be infinitely small. A real spring does not do this, it has a start and end point that cannot be the same point. The spring has a natural resting distance between the start and end points. When the value is set to less than that resting distance, the spring pushes away. When the value is set further, the spring pulls back.

I will say both of these types of behaviors are accomplishable with the current API, so perhaps I'm misunderstanding your ask. Or, perhaps we can make the API clearer and make one of these a first-class concept in the library.

Gregoor commented 1 year ago

Thanks for the swift response, and good point, a concrete example might make my use case clearer:

I want to loop a spring value from its anchor a to a value t, and back. So in pseudo code it'd be sth like

spring.anchor = A
onLoop(delta => {
  spring.simulate(delta)

  if (spring.isAtAnchor()) {
    spring.target = t
  } else if (spring.isAtTarget()) {
    spring.target = a
  }
})

and when the spring is simulating movement towards t, away from the anchor (the behavior I don't know how to accomplish with this lib yet), I'd expect velocity to decrease, the further it moves away from the anchor (the opposite of the current behavior, i.e. moving towards the anchor).

Maybe this is already accomplishable and I'm missing it? Maybe I could set the arrival behavior to bounce and that'd do the trick (I'd need to abs() the value then for my example, but that should be fine)? I guess I'll try that route next time I'm on it.

tkofh commented 1 year ago

I think the easiest way to accomplish what you're talking about here is to maintain two targets and two configurations outside of the spring, and swap them out based on the state of the spring:

const bouncy: SpringConfig = {
  mass: 3,
  tension: 500,
  friction: 25,
};
const smooth: SpringConfig = {
  mass: 0.75,
  tension: 300,
  friction: 45,
};

const anchor = 0;
const target = 200;

const spring = createSpring(target, smooth);

createTicker().add((_, delta) => {
  spring.simulate(delta);

  if (spring.state === 'resting') {
    if (spring.target === target) {
      spring.target = anchor;
      spring.config = smooth;
    } else {
      spring.target = target;
      spring.config = bouncy;
    }
  }
});

Here's a working example: https://stackblitz.com/edit/spring-target-and-anchor?file=index.ts

Does this capture what you're looking to accomplish?

Gregoor commented 1 year ago

Thanks for the example! Where it still seems off, for my use case, is that it goes fast at first, and then slows down as it gets closer to the target (as spring relaxes), in both directions.

I'm starting to think I might not have enough of a springy motion in mind, sorry for loading it here then. I suppose what I'm looking to accomplish is more like a jumping motion where there is

Maybe that just does not map well to springs, and I should just go full-physics?

Anyway, thanks a lot for thinking this through with me, I really appreciate you taking some time for me rando on the internet. And ofc feel free to close this issue, I think I'm moving out-of-scope.

tkofh commented 1 year ago

I think I'm understanding you better now, you basically want to simulate throwing a ball in the air and letting gravity bring the ball back down to the ground.

I think something that would help is a setVelocity() method on the springs, along with maybe a constantAcceleration option for the gravity bit.

Both of those should be relatively easy to implement. Even if you do end up implementing the physics here yourself, I think they would be valuable additions to the library so I'll get working on those. Would love your feedback if it would suit your needs in any event.