{- $Id: SimpleGun.as,v 1.2 2003/11/10 21:28:58 antony Exp $ ****************************************************************************** * I N V A D E R S * * * * Module: SimpleGun * * Purpose: A simple gun as a signal function * * Author: Antony Courtney * * * * Copyright (c) Yale University, 2003 * * * ****************************************************************************** -} module SimpleGun ( simpleGunObject -- :: Object ) where import qualified Random import AFRP import AFRPUtilities import AFRPGeometry import PhysicalDimensions import WorldGeometry import Parser import Object ------------------------------------------------------------------------------ -- Gun ------------------------------------------------------------------------------ data SimpleGunState = SimpleGunState { sgsPos :: Position2, sgsVel :: Velocity2, sgsFired :: Event () } type SimpleGun = SF GameInput SimpleGunState simpleGun :: Position2 -> SimpleGun simpleGun (Point2 x0 y0) = proc gi -> do -- Desired position: (Point2 xd _) <- ptrPos -< gi rec -- Controller. -- Desired acceleration: let ad = 10 * (xd - x) - 5 * v -- basic physics: v <- integral -< clampAcc v ad x <- (x0+) ^<< integral -< v fire <- lbp -< gi returnA -< SimpleGunState { sgsPos = (Point2 x y0), sgsVel = (vector2 v 0), sgsFired = fire } ------------------------------------------------------------------------------ -- Support ------------------------------------------------------------------------------ -- Compute actual acceleration from -- desired acceleration by setting -- hard limits on acceleration and velocity: clampAcc v ad = let a = symLimit gunAccMax ad in if (-gunSpeedMax) <= v && v <= gunSpeedMax || v < (-gunSpeedMax) && a > 0 || v > gunSpeedMax && a < 0 then a else 0 limit ll ul x = if x < ll then ll else if x > ul then ul else x symLimit l = let absl = abs l in limit (-absl) absl -- We really aught to test this, but we'll just settle for type checking -- for now, since we know the gun works... simpleGunObject :: Object simpleGunObject = undefined -- Since this file doesn't import ObjectBehavior, I'm going to place a -- couple of versions of the code for ObjectBehavior.gun here. These -- correspond exactly with what is presented in the paper; they are -- copied here just to ensure we don't make any obvious mistakes -- that could be caught by parsing / typechecking. -- *sigh*. So much for typechecking...we have to comment this out anyway, -- because oosGun is undefined. {- gun :: Position2 -> Object gun (Point2 x0 y0) = proc objIn -> do let gi = oiGameInput objIn -- Desired position: (Point2 xd _) <- ptrPos -< gi rec -- Controller. -- Desired acceleration: let ad = 10 * (xd - x) - 5 * v -- basic physics: v <- integral -< clampAcc v ad x <- (x0+) ^<< integral -< v fire <- lbp -< gi returnA -< ObjOutput { ooObsObjState = oosGun (Point2 x y0) (vector2 v 0), ooKillReq = noEvent, ooSpawnReq = fire `tag` [missile (Point2 x (y0 + (gunHeight/2))) (vector2 v missileInitialSpeed)] } -} -- Ammunition magazine. Reloaded up to maximal -- capacity at constant rate. -- n ... Maximal and initial number of missiles. -- f .......... Reload rate. -- input ...... Trigger. -- output ..... Tuple: -- #1: Current number of missiles in magazine. -- #2: Missile fired event. magazine :: Int -> Frequency -> SF (Event ()) (Int, Event ()) magazine n f = proc trigger -> do reload <- repeatedly (1/f) () -< () (level,canFire) <- accumHold (n,True) -< (trigger `tag` dec) `lMerge` (reload `tag` inc) returnA -< (level, trigger `gate` canFire) where inc :: (Int,Bool) -> (Int, Bool) inc (l,_) | l < n = (l + 1, l > 0) | otherwise = (l, True) dec :: (Int,Bool) -> (Int, Bool) dec (l,_) | l > 0 = (l - 1, True) | otherwise = (l, False) -- Of course, this would be much better if we used the real impulse stuff: -- No bogus iPre, for instance. missile :: Position2 -> Velocity2 -> Object missile p0 v0 = proc oi -> do rec -- Basic physics vp <- iPre v0 -< v ffi <- forceField -< (p, vp) v <- (v0 ^+^) ^<< impulseIntegral -< (gravity, ffi) p <- (p0 .+^) ^<< integral -< v die <- after missileLifeSpan () -< () returnA -< ObjOutput { ooObsObjState = oosMissile p v, ooKillReq = oiHit oi `lMerge` die, ooSpawnReq = noEvent } ------------------------------------------------------------------------------ -- Force fields acting on objects ------------------------------------------------------------------------------ -- Object are subject to gravity and a strange repellent forcefield that -- drives objects away from the edges, effectively creating a corridor. -- The strange field is inversely proportional to the cube of the distance -- from either edge. It is thought that the field is a remnant of a defence -- system put in place by the mythical and technologically advanced -- "Predecessors" eons ago. {- field :: Position2 -> Acceleration2 field (Point2 x _) = vector2 (leftAcc - rightAcc) 0 ^+^ gravity where leftAcc = min (if x > worldXMin then k / (x - worldXMin)^3 else maxAcc) maxAcc rightAcc = min (if x < worldXMax then k / (worldXMax - x)^3 else maxAcc) maxAcc k = 10000000 maxAcc = 10000 -} -- New attempt. Force fields act like invisible walls. -- The fact that this is a stateful *signal* function (Fields having state? -- Come on ...), can be attributed to the fact that we are cheating in the -- first place by abstracting events of short duration to instantaneous -- events. "field" being a stateful signal functio is part of the price -- one have to pay for that to make this work in practice. forceField :: SF (Position2, Velocity2) (Event Acceleration2) forceField = proc (p, v) -> do lfi <- edge -< point2X p < worldXMin && vector2X v < 0 rfi <- edge -< point2X p > worldXMax && vector2X v > 0 returnA -< (mergeBy (^+^) (lfi `tag` (vector2 (-2 * vector2X v) 0)) (rfi `tag` (vector2 (-2 * vector2X v) 0))) gravity = vector2 0 (-20)