3

I have the following types:

data Bomb = TimedBomb   { bPos :: Point, bPower :: Float, detTime :: Float }

data Enviro = Enviro { bombs :: [Bomb], stuff :: [Picture]}

When the TimedBomb timer reaches 0, I need it to explode, damage any enemies within it's blast radius (controlled by bPower), and persist for a few seconds to add to the chance that it will cause damage. To do that, I was thinking of creating another object representing an explosion, then check to see if any enemies are within its bounds. The problem is, I can't think of the best set-up to hold explosions that are taking place. I'm using Haskell's Gloss library, so the entirety of what's being drawn needs to be contained within a single "world" object. What I've thought of:

  1. I could make an explosion a type of Bomb, hold it in bombs in the environment, and map over bombs when I want to check for collisions. That seems like the simplest route, but it would involve possibly doing checks on non-explosion-Bombs, which is inefficient. An explosion isn't really a bomb either; its the end result, so the types don't make intuitive sense.

  2. I could make explosions a separate type, then add another field to Enviro called explosions of type [Explosion]. That makes more sense, but adds another field to Enviro, which already tends to be a cluttered type.

  3. I could be thinking of the whole set-up wrong, and there's a third, more sensical way to go about this.

Any thoughts here would be appreciated

  • 1
    Why do you need to store explosions? Don't they have immediate effect and then go away immediately? – raptortech97 Nov 7 '14 at 16:54
  • @raptortech97 I want them to persist for several seconds. I'll clarify that, thanks. – Carcigenicate Nov 7 '14 at 17:22
  • Nevermind. I just realized that I can add a second timer to the bomb that starts when the first one ends, and controls how long the explosion stays active. – Carcigenicate Nov 7 '14 at 17:34
  • 4
    @Carcigenicate Wouldn't adding a second timer violate point number 1 though? If you're going to go that route anyway then I would suggest doing something like data Bomb = CountingDown {...} | Exploding {...} to make the phases explicit. – paul Nov 7 '14 at 18:26
  • FYI, this should have been moved to CodeReview.SE – recursion.ninja Nov 10 '14 at 18:13
5

The key to clarity is separation

You should separate the Bomb's constant data from it's mutable state:

data Bomb
  = Bomb 
  { bPos    :: Point
  , bPower  :: Float
  , bState  :: BombState
  }
  deriving (Eq,Read,Show)

data BombState
  = Armed       { detTime :: Float }
  | Discharging { expTime :: Float }
  deriving (Eq,Read,Show)

data Enviro
  = Enviro
  { bombs :: [Bomb]
  , stuff :: [Picture]
  }
  deriving (Eq,Read,Show)

isDischarging (Discharging _) = True
isDischarging  _              = False

exploding :: Enviro -> [Bomb]
exploding = filter (isDischarging . bState) . bombs

This would allow you to add more states later such as Disarmed and Inert

data BombState
  = Armed       { detTime :: Float }
  | Discharging { expTime :: Float }
  | Disarmed    ( remTime :: Float }
  | Inert
  • Excellent, that is clearer. The only thing I'd have to change is where the position is held, as I'm using collision. – Carcigenicate Nov 8 '14 at 17:31

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.