Skip to content

Commit

Permalink
Remove Entity and entity functions.
Browse files Browse the repository at this point in the history
Change the name of all Property items to Tree based names like Node, Leaf, Tree.

Make new tree traversal functions for inserting and removing from tree structures easily.

Remove the old Frame implementation from CurryDog.Physics2d.

Add Sprite datatype to CurryDog.Data and Shape datatype to go along with it.

Add documentation to CurryDog.Data to explain things better.

Change CurryDog module to fit new CurryDog.Data tree format, uncomment gameLoop and change quit to pull from tree structure game state.
  • Loading branch information
adorablepuppy committed May 29, 2011
1 parent be71237 commit ae19248
Show file tree
Hide file tree
Showing 3 changed files with 135 additions and 146 deletions.
246 changes: 118 additions & 128 deletions CurryDog.Data.lhs
Original file line number Diff line number Diff line change
@@ -1,142 +1,132 @@
This file will house most of the important data structures. Defined first are Graphical structures.
This file will house most of the important data structures.
Defined first are Graphical structures.

> module CurryDog.Data ( Vector, vectorX, vectorY, vectorZ, Color, colorRed, colorGreen, colorBlue, colorAlpha )
> module CurryDog.Data
> where

> import Data.Word ( Word8 )

A Vector is the main unit of 2d and 3d games. So here, we're defining a vector as either a 2d or 3d vector.
A Vector is the main unit of 2d and 3d games. So here, we're defining a
vector as either a 2d or 3d vector.

> data Vector = Vector2 Float Float
> | Vector3 Float Float Float
> data Vector = Vector2 { vX :: Float, vY :: Float }
> | Vector3 { vX :: Float, vY :: Float, vZ :: Float }
> deriving ( Show )

> vectorX :: Vector -> Float
> vectorX ( Vector2 x _ ) = x
> vectorX ( Vector3 x _ _ ) = x
Color is defined as ColorRGB, ColorRGBA

> vectorY :: Vector -> Float
> vectorY ( Vector2 _ y ) = y
> vectorY ( Vector3 _ y _ ) = y

> vectorZ :: Vector -> Float
> vectorZ ( Vector2 _ _ ) = error "Vector2 does not have a Z"
> vectorZ ( Vector3 _ _ z ) = z

Color is defined as ColorRGB, ColorRGBA, ColorBGR, ColorABGR

> data Color = ColorRGB Word8 Word8 Word8
> | ColorRGBA Word8 Word8 Word8 Word8
> | ColorBGR Word8 Word8 Word8
> | ColorABGR Word8 Word8 Word8 Word8
> data Color = ColorRGB { colorRed :: Word8, colorGreen :: Word8, colorBlue :: Word8 }
> | ColorRGBA { colorRed :: Word8, colorGreen :: Word8, colorBlue :: Word8, colorAlpha :: Word8 }
> deriving ( Show )

> colorRed :: Color -> Word8
> colorRed ( ColorRGB r _ _ ) = r
> colorRed ( ColorRGBA r _ _ _ ) = r
> colorRed ( ColorBGR _ _ r ) = r
> colorRed ( ColorABGR _ _ _ r ) = r

> colorGreen :: Color -> Word8
> colorGreen ( ColorRGB _ g _ ) = g
> colorGreen ( ColorRGBA _ g _ _ ) = g
> colorGreen ( ColorBGR _ g _ ) = g
> colorGreen ( ColorABGR _ _ g _ ) = g

> colorBlue :: Color -> Word8
> colorBlue ( ColorRGB _ _ b ) = b
> colorBlue ( ColorRGBA _ _ b _ ) = b
> colorBlue ( ColorBGR b _ _ ) = b
> colorBlue ( ColorABGR _ b _ _ ) = b

> colorAlpha :: Color -> Word8
> colorAlpha ( ColorRGB _ _ _ ) = 255
> colorAlpha ( ColorRGBA _ _ _ a ) = a
> colorAlpha ( ColorBGR _ _ _ ) = 255
> colorAlpha ( ColorABGR a _ _ _ ) = a

> data Pixel = Pixel Vector Color deriving ( Show )
> type Image = [Pixel]

A Property is a type of hashmap in which we can store useful name/value combinations. Take for instance:

example = Entity [ PropertyList "Character Sheet" [ StringProperty "Name" "Roger Dodger"
, IntegerProperty "Hit Points" 24
, PropertyList "Class/Level" [ IntegerProperty "Rogue" 1
, IntegerProperty "Fighter" 1
]
, PropertyList "ABILITY SCORES" [ IntegerProperty "STR" 14
, IntegerProperty "CON" 13
, IntegerProperty "DEX" 18
, IntegerProperty "INT" 10
, IntegerProperty "WIS" 9
, IntegerProperty "CHA" 16 ] ]
, VectorProperty "Location" (Vector2 0 0) ]

location_example = head $ entityNamedProperties "Location" example
ability_score_example = namedProperties "ABILITY SCORES" $ propertyList $ head (entityNamedProperties "Character Sheet" example)
Add birdtracks to see the examples in action. In this example, we have an Entity, example. It has a [Property].
The first value is a PropertyList, which nests a [Property]. In this nested [Property] we have a variety of data,
such as Name, Hit Points, Class/Level, and ABILITY SCORES. On the Entity [Property] level, we also have Location,
which specifies a Vector2.
> data Property = StringProperty String String
> | IntegerProperty String Integer
> | FloatProperty String Float
> | VectorProperty String Vector
> | NestedProperty String Property
> | PropertyList String [Property]
> deriving ( Show )
Getting a property's name is akin to getting a hashkey from a hashtable entry.
To extend storable types, simply add that type to the following 2 sections.
> propertyName :: Property -> String
> propertyName ( StringProperty name _ ) = name
> propertyName ( IntegerProperty name _ ) = name
> propertyName ( FloatProperty name _ ) = name
> propertyName ( VectorProperty name _ ) = name
> propertyName ( NestedProperty name _ ) = name
> propertyName ( PropertyList name _ ) = name
Each of the following get the value from a property and return that value in it's own format.
> propertyString :: Property -> String
> propertyString ( StringProperty _ value) = value
> propertyInteger :: Property -> Integer
> propertyInteger ( IntegerProperty _ value) = value
> propertyFloat :: Property -> Float
> propertyFloat ( FloatProperty _ value ) = value
> propertyVector :: Property -> Vector
> propertyVector ( VectorProperty _ value ) = value
> nestedProperty :: Property -> Property
> nestedProperty ( NestedProperty _ value ) = value
> propertyList :: Property -> [Property]
> propertyList ( PropertyList _ value) = value
Named property takes a string and a property list, then returns the property with that name.
It won't recurse multiple levels.
> namedProperties :: String -> [Property] -> [Property]
> namedProperties name properties = [ x | x <- properties, propertyName x == name ]
Think of an Entity as a sort of final root to all properties.
It isn't really anything particularly useful, but serves as a logical organization.
> data Entity = Entity [Property] deriving ( Show )
> getProperties :: Entity -> [Property]
> getProperties (Entity properties) = properties
Since setting the properties of an Entity gives you a new entity anyway,
it makes the most sense for setProperties to be a synonym for Entity.
> setProperties :: [Property] -> Entity
> setProperties = Entity
Shortcut function to access lowest level properties by name.
> entityNamedProperties :: String -> Entity -> [Property]
> entityNamedProperties name (Entity properties) = namedProperties name properties
> data Shape = Rectangle { rectangleX :: Float, rectangleY :: Float, rectangleWidth :: Float, rectangleHeight :: Float }
> | Circle { circleOriginX :: Float, circleOriginY :: Float, circleDiameter :: Float }

> data Sprite = CollisionSprite { spriteSheet :: Image, collisionSpriteClips :: [(Shape,[Shape])] }
> | PlainSprite { spriteSheet :: Image, spriteClips :: [Shape] }

A PropertyTree is an N-ary (n-way) data tree. All PropertyTree datatypes
take a String (let's call it a Key) and a Value. The Value datatype a
PropertyTree takes is dictated by name it's datatype. For example, an
IntegerLeaf takes an Integer as a value. A VectorLeaf will take a
Vector2 or Vector3. A NodeList will take a list of PropertyTrees as a
value.

example = NodeList "GameState" [ NodeList "Character Sheet" [ StringLeaf "Name" "Rodger Dodger"
, IntegerLeaf "Hit Points" 24
, NodeList "Class/Level" [ IntegerLeaf "Rogue" 1
, IntegerLeaf "Fighter" 1
]
, NodeList "ABILITY SCORES" [ IntegerLeaf "STR" 14
, IntegerLeaf "CON" 13
, IntegerLeaf "DEX" 18
, IntegerLeaf "INT" 10
, IntegerLeaf "WIS" 9
, IntegerLeaf "CHA" 16
] ]
, VectorLeaf "Location" ( Vector2 0 0 )
]

abilityscores = traversePropertyTree ["Character Sheet","ABILITY SCORES"] example

classlevels = traversePropertyTree ["Character Sheet", "Class/Level"] example

location = leafVector $ head $ namedProperties "Location" $ nodeList example
Add birdtracks to the above code to see it in action. In this example we
have a GameState NodeList which houses all the game state variables in
other PropertyTree's. In this nested NodeList we have a variety of data,
such as Name, Hit Points, Class/Level, and ABILITY SCORES. On the same
level as Character Sheet, we also have a Location, which is a VectorLeaf.
> data PropertyTree = BoolLeaf String Bool
> | StringLeaf String String
> | IntegerLeaf String Integer
> | FloatLeaf String Float
> | VectorLeaf String Vector
> | NodeLeaf String PropertyTree
> | NodeList String [PropertyTree]
> deriving ( Show )
Getting a tree's name is akin to getting a hashkey from a hashtable entry.
To extend storable types, simply add that type to the following 2 sections.
> leafName :: PropertyTree -> String
> leafName ( NodeList name _ ) = name
> leafName ( BoolLeaf name _ ) = name
> leafName ( StringLeaf name _ ) = name
> leafName ( IntegerLeaf name _ ) = name
> leafName ( FloatLeaf name _ ) = name
> leafName ( VectorLeaf name _ ) = name
> leafName ( NodeLeaf name _ ) = name
Each of the following get the value from a leaf and return that value in it's
own format.
> nodeList :: PropertyTree -> [PropertyTree]
> nodeList ( NodeList _ value ) = value
> leafBool :: PropertyTree -> Bool
> leafBool ( BoolLeaf _ value ) = value
> leafString :: PropertyTree -> String
> leafString ( StringLeaf _ value ) = value
> leafInteger :: PropertyTree -> Integer
> leafInteger ( IntegerLeaf _ value ) = value
> leafFloat :: PropertyTree -> Float
> leafFloat ( FloatLeaf _ value ) = value
> leafVector :: PropertyTree -> Vector
> leafVector ( VectorLeaf _ value ) = value
> leafNode :: PropertyTree -> PropertyTree
> leafNode ( NodeLeaf _ value ) = value
namedProperties takes a name and a PropertyTree list and returns a list of
all PropertyTree's that match name.
> namedProperties :: String -> [PropertyTree] -> [PropertyTree]
> namedProperties name properties = [ x | x <- properties, leafName x == name ]
> traversePropertyTree :: [String] -> PropertyTree -> [PropertyTree]
> traversePropertyTree nodePath ( NodeList a b )
> | null nodePath = b
> | null b = []
> | null (namedProperties (head nodePath) b) = []
> | otherwise = traversePropertyTree (drop 1 nodePath) (head (namedProperties (head nodePath) b))
> traversePropertyTree nodePath _ = []
> insertIntoNode :: [String] -> PropertyTree -> PropertyTree -> PropertyTree
> insertIntoNode nodePath newNode oldTree
> | null nodePath = NodeList (leafName oldTree)
> ( newNode : (filter (\ x -> leafName x /= leafName newNode )
> (traversePropertyTree nodePath oldTree)))
> | null $ traversePropertyTree nodePath oldTree = error "Node path doesn't exist"
> | otherwise = insertIntoNode ( init nodePath )
> ( NodeList ( last nodePath ) (newNode : ( filter (\ x -> leafName x /= leafName newNode ) ( traversePropertyTree nodePath oldTree ))))
> oldTree

> removeFromNode :: [String] -> String -> PropertyTree -> PropertyTree
> removeFromNode nodePath nodeName oldTree
> | null $ traversePropertyTree nodePath oldTree = error "Node path doesn't exist"
> | null nodePath = (NodeList (leafName oldTree) (filter (\ x -> leafName x /= nodeName ) (traversePropertyTree nodePath oldTree)))
> | otherwise = insertIntoNode (init nodePath) (NodeList (last nodePath) (filter (\ x -> leafName x /= nodeName ) (traversePropertyTree nodePath oldTree))) oldTree
13 changes: 5 additions & 8 deletions CurryDog.Physics2d.lhs
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,10 @@ This file will house all the 2D physics functions that don't fit into a general
> module CurryDog.Physics2d
> where

> import Graphics.UI.SDL as SDL
> import CurryDog.Data as CurryDog

> data Frame = Frame { surface :: SDL.Surface
> , boundingBoxes :: [(String,SDL.Rect)]
> }

> boundingBoxCollision :: SDL.Rect -> SDL.Rect -> Bool
> boundingBoxCollision (SDL.Rect x1 y1 w1 h1) (SDL.Rect x2 y2 w2 h2) = x1 <= (x2+ w2) && x2 <= (x1+w1)
> && y1 <= (y2+h2) && x2 <= (x1+h1)
> boundingShapeCollision :: Shape -> Shape -> Bool
> boundingShapeCollision ( Rectangle x1 y1 w1 h1 ) ( Rectangle x2 y2 w2 h2 ) = x1 <= ( x2 + w2 ) && x2 <= ( x1 + w1 )
> && y1 <= ( y2 + h2 ) && x2 <= ( x1 + h1 )
> boundingShapeCollision ( Circle cX1 cY1 d1 ) ( Circle cX2 cY2 d2 ) = False -- TODO
> boundingShapeCollision ( Circle cX1 cY1 d1 ) ( Rectangle x2 y2 w2 h2 ) = False -- TODO
22 changes: 12 additions & 10 deletions CurryDog.lhs
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,18 @@ TODO CurryDog.lhs:
> import CurryDog.Input as CurryDog
> import Graphics.UI.SDL as SDL

> runGame :: IO ()
> runGame = do SDL.init [SDL.InitEverything]
> SDL.setVideoMode 1280 720 32 [SWSurface]
> SDL.setCaption "Game" "Game"
> --gameLoop False []
> gameLoop NodeList "GameState" [ BoolLeaf "quit_game" False
> , NodeList "pressed_keys" []
> , StringLeaf "Caption" "Game"
> ]
> SDL.quit
> {-where
> gameLoop quitFired pressed_keys = SDL.waitEventBlocking >>= do
> let keys = (\ event -> event )
> if quitFired then
> return
> else
> gameLoop False keys
> return -}
> where
> gameLoop gamestate = SDL.waitEventBlocking >>= do keys <- checkKeys --This is broken.
> if (leafBool $ head $ namedProperties "quit_game" $ nodeList gamestate) then
> return
> else
> gameLoop gamestate
> return

0 comments on commit ae19248

Please sign in to comment.