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
import Prelude hiding ((.), id)
import Control.Category
import Control.Wire
import Control.Wire.Wire
import Control.Wire.Prefab.Move
bouncyWire :: (Monad m)
=> Double -> Double -> Double -> Double -> Wire () m a Double
bouncyWire startPosition startVelocity lowerBound upperBound =
objPosition <$> object_ update (ObjectState startPosition startVelocity)
. constant (Accelerate 0, ())
where
update _ s@(ObjectState pos vel)
| (pos > upperBound) = ObjectState (2*upperBound - pos) (- abs vel)
| (pos < lowerBound) = ObjectState (2*lowerBound - pos) (abs vel)
| otherwise = s
I'm not very familiar with the arrow notation so I used Category
and Applicative
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.