-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
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
1 parent
be71237
commit ae19248
Showing
3 changed files
with
135 additions
and
146 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters