Using netwire-4.0.7
As the question title says, I'm trying to create a wire that produces positions (moving the position with a certain velocity in each step), "bouncing" off other objects. The simplest example I could think of was moving within a box, like in some screen savers.
I wrote this function as an attempt to do just that (for one axis only):
import Control.Wire
bouncyWire :: Double -> Double -> Double -> Double -> Wire () IO a Double
bouncyWire startPosition startVelocity lowerBound upperBound = proc _ -> do
rec
v <- delay startVelocity -< if p < lowerBound || p > upperBound
then -v else v
p <- integral_ startPosition -< v
returnA -< p
(I actually use it with a different monad, but this code doesn't actually use it and it would overcomplicate the issue here).
Stepping it with a counterSession $ 1/60
however, I get a problem - instead of "bouncing" off the wall, it gets stuck there. I think what happens is that it keeps flipping the velocity v
over and over, but I'm not sure why. I think I might be using delay wrong or something.
As Richard Huxton explained, your wire is getting stuck behind the border. One solution is to check that you don't just reverse velocities, you always point them to the right direction. This way, the wire gets always from behind the border. Another solution is to change the position back inside the borders if it gets out. This way, the wire is never perceived to get behind (which is something you usually want to do in games). Combined together it could look like
I'm not very familiar with the arrow notation so I used
Category
andApplicative
notation (composition of wires using.
). For this task,object_
is particularly handy. It integrates the velocity and loops internally and all we need to do is to give it a modifying function and extract position from the output.