User:Josh Oosterman/Design Study
Line 36: | Line 36: | ||
[[Image:Josh-uml1.png]] | [[Image:Josh-uml1.png]] | ||
− | === | + | === Explanation === |
The above UML diagram looks large, but the system is very simple and it should be easy to find your way around. | The above UML diagram looks large, but the system is very simple and it should be easy to find your way around. | ||
Line 44: | Line 44: | ||
At the top left is the ''IDrawable'' interface. This defines just one method, but is used throughout the design. The Draw method takes a reference to a Graphics context. | At the top left is the ''IDrawable'' interface. This defines just one method, but is used throughout the design. The Draw method takes a reference to a Graphics context. | ||
− | At the top left we can see the ''Scene'' class. The scene class is just that - a scene in an animation. The application lets you use only one scene object, but it is not a singleton as it is feasible multiple scenes could be supported in the future. The ''Scene'' class consists of a background, and a collection of ''AnimatedObjects''. The ''Background'' of a scene could be a ''SimpleBackground'', optionally decorated with effect using the ''LightningBackground'' or ''RainBackground'' classes. ''RainDrop'' is a lightweight class used by the ''RainBackground'' decorator. The background classes can be seen in the top center of the diagram. The ordering of ''AnimatedObjects''in a | + | At the top left we can see the ''Scene'' class. The scene class is just that - a scene in an animation. The application lets you use only one scene object, but it is not a singleton as it is feasible multiple scenes could be supported in the future. The ''Scene'' class consists of a background, and a collection of ''AnimatedObjects''. The ''Background'' of a scene could be a ''SimpleBackground'', optionally decorated with effect using the ''LightningBackground'' or ''RainBackground'' classes. ''RainDrop'' is a lightweight class used by the ''RainBackground'' decorator. The background classes can be seen in the top center of the diagram. The ordering of ''AnimatedObjects'' in a ''Scene'' is not important, but .NET 2.0 does not include a Set class so a ''List<AnimatedObject>'' was used instead. |
The inheritance tree of ''AnimatedObject'' constitutes the left third of the UML diagram. The two subclasses of ''AnimatedObject'' are ''Prop'' and ''Figure''. A ''Prop'' represents a single solid object, such as a soccer ball (as seen in the screenshot above). Props have only a ''Sprite'' and a position. The ''Figure'' subclass is more complex, and is used to represent posable composite objects such as humans or animals. ''Figure'' is further explained below. ''AnimatedObject'' also uses a ''Handle'' object, accessible through its ''MainHandle'' property. The syntax "+ MainHandle { get; }" on the UML diagram represents a .NET property, equivalent to a getter method. | The inheritance tree of ''AnimatedObject'' constitutes the left third of the UML diagram. The two subclasses of ''AnimatedObject'' are ''Prop'' and ''Figure''. A ''Prop'' represents a single solid object, such as a soccer ball (as seen in the screenshot above). Props have only a ''Sprite'' and a position. The ''Figure'' subclass is more complex, and is used to represent posable composite objects such as humans or animals. ''Figure'' is further explained below. ''AnimatedObject'' also uses a ''Handle'' object, accessible through its ''MainHandle'' property. The syntax "+ MainHandle { get; }" on the UML diagram represents a .NET property, equivalent to a getter method. | ||
− | A ''Handle'' is used to position or pose an ''AnimatedObject''. The MainHandle handle is used to position the ''AnimatedObject'' within the scene. The ''Figure'' | + | A ''Handle'' is used to position or pose an ''AnimatedObject''. Handles are drawn as red or blue squares, as seen in the screenshot above. The ''MainHandle'' handle is used to position the ''AnimatedObject'' within the scene. The ''Figure'' class has a further collection of handles, which can be used to move arms and legs, for example. The ''Handle'' class defines a delegate type and event called ''MoveCallback'' that is called when a handle is moved. The ''AnimatedObject'' can subscribe to this event and react when the handle is moved. |
+ | Although it is not implemented at the moment, eventually the ''AnimatedObject''s would store several instances of their state, one for each key frame in the animation. A state could be calculated for each frame by interpolating between these key frames. When this is implemented, the state of an ''AnimatedObject'' would be stored as the set of positions of it's handles. The memento pattern would probably be used to do this. | ||
+ | Now we look at the ''Figure'' class. The subclasses ''Man'' and ''Snake'' do not need much explanation. They currently only define a new constructor, which creates the limbs and joints in their body. The ''Figure'' class does have a strategy reference to an instance of ''LimbAnimationStrategy'', which is used to calculate limb positions and angles from a handle position. This follows the strategy pattern. ''NaiveLimbStrategy'' and ''InverseKinematicStrategy'' are the current options. | ||
+ | |||
+ | The ''Figure'' has a root ''BodyPart''. The ''BodyPart'' class is abstract and has two concrete implementations. An ''Extremity'' is one of these, which has a ''Sprite'', and is used for the hands, feet and heads of figures. A ''Limb'' is more complex as it can have children (for example, when modelling the human body the lower arm could be seen as a child of the upper arm, and the hand (an extremity) can be seen as a child of the lower arm). A ''Limb'' has a length, and a ''Pen'' which are used to render it (in a stick figure fashion). Importantly, it has a collection of connector ''Joint'' objects. The ''Joint'' objects are used to define the children of a ''Limb''. The ''Limb'' class has a ''To'' property, which is the child ''BodyPart'', and an ''Angle'' property, which is the angle at that joint (between the parent and child object). | ||
Finally, the ''Sprite'' class can be seen near the top right of the diagram. A ''Sprite'' is a static image that can be used in the animation. Internally, it just wraps a .NET ''Bitmap'' object, but the interface does not depend on this. Sprites can be created by either loading an image file, or creating an empty image of a specified size and colour. The benefit of the Sprite class is to provide resource sharing, using the Flyweight design pattern. | Finally, the ''Sprite'' class can be seen near the top right of the diagram. A ''Sprite'' is a static image that can be used in the animation. Internally, it just wraps a .NET ''Bitmap'' object, but the interface does not depend on this. Sprites can be created by either loading an image file, or creating an empty image of a specified size and colour. The benefit of the Sprite class is to provide resource sharing, using the Flyweight design pattern. |
Revision as of 09:54, 1 August 2010
Contents |
The Problem
I wanted to create a tool to animate scenes, and humanoid characters.
Eventually I want be able to create complex animations which can be loaded into a 2d game.
This would take too long for a 427 assessment, so I've simplified the problem to having an interactive stickmen tool. The extensibility of the design of the system is critical so I can extend it in the future.
The system was fully designed and implemented for COSC427, and was not based on previous work.
A screenshot of the current version is shown below.
System Goals
Within my 427 Project
- Customisable backgrounds
- Posable figures (Such as Stickmen)
- Props
- Extensible - so I can add the below features eventually
Outside the scope of this project, but to be added in the future:
- Interpolation between Keyframes
- Advanced Inverse Kinematics & Constraints on Joints
- Export angles & positions as animation file to be used in games
Code
The system was implemeted in C# and can be obtained here. To build and run is trivial -- Open Stickman.sln in Visual Studio and build. You'll need Windows and VS2008 or later.
System Design
The image below is a simplified UML class diagram of nearly all of the classes in the system.
Explanation
The above UML diagram looks large, but the system is very simple and it should be easy to find your way around.
The far right classes MainForm and Program are for the .NET generated GUI for the application. This is not an important part of the OO design and is mostly ignored in the design study. Similarly, the Point and Vector classes next to it are geometry utility classes I have written, which will also be ignored in this study.
At the top left is the IDrawable interface. This defines just one method, but is used throughout the design. The Draw method takes a reference to a Graphics context.
At the top left we can see the Scene class. The scene class is just that - a scene in an animation. The application lets you use only one scene object, but it is not a singleton as it is feasible multiple scenes could be supported in the future. The Scene class consists of a background, and a collection of AnimatedObjects. The Background of a scene could be a SimpleBackground, optionally decorated with effect using the LightningBackground or RainBackground classes. RainDrop is a lightweight class used by the RainBackground decorator. The background classes can be seen in the top center of the diagram. The ordering of AnimatedObjects in a Scene is not important, but .NET 2.0 does not include a Set class so a List<AnimatedObject> was used instead.
The inheritance tree of AnimatedObject constitutes the left third of the UML diagram. The two subclasses of AnimatedObject are Prop and Figure. A Prop represents a single solid object, such as a soccer ball (as seen in the screenshot above). Props have only a Sprite and a position. The Figure subclass is more complex, and is used to represent posable composite objects such as humans or animals. Figure is further explained below. AnimatedObject also uses a Handle object, accessible through its MainHandle property. The syntax "+ MainHandle { get; }" on the UML diagram represents a .NET property, equivalent to a getter method.
A Handle is used to position or pose an AnimatedObject. Handles are drawn as red or blue squares, as seen in the screenshot above. The MainHandle handle is used to position the AnimatedObject within the scene. The Figure class has a further collection of handles, which can be used to move arms and legs, for example. The Handle class defines a delegate type and event called MoveCallback that is called when a handle is moved. The AnimatedObject can subscribe to this event and react when the handle is moved.
Although it is not implemented at the moment, eventually the AnimatedObjects would store several instances of their state, one for each key frame in the animation. A state could be calculated for each frame by interpolating between these key frames. When this is implemented, the state of an AnimatedObject would be stored as the set of positions of it's handles. The memento pattern would probably be used to do this.
Now we look at the Figure class. The subclasses Man and Snake do not need much explanation. They currently only define a new constructor, which creates the limbs and joints in their body. The Figure class does have a strategy reference to an instance of LimbAnimationStrategy, which is used to calculate limb positions and angles from a handle position. This follows the strategy pattern. NaiveLimbStrategy and InverseKinematicStrategy are the current options.
The Figure has a root BodyPart. The BodyPart class is abstract and has two concrete implementations. An Extremity is one of these, which has a Sprite, and is used for the hands, feet and heads of figures. A Limb is more complex as it can have children (for example, when modelling the human body the lower arm could be seen as a child of the upper arm, and the hand (an extremity) can be seen as a child of the lower arm). A Limb has a length, and a Pen which are used to render it (in a stick figure fashion). Importantly, it has a collection of connector Joint objects. The Joint objects are used to define the children of a Limb. The Limb class has a To property, which is the child BodyPart, and an Angle property, which is the angle at that joint (between the parent and child object).
Finally, the Sprite class can be seen near the top right of the diagram. A Sprite is a static image that can be used in the animation. Internally, it just wraps a .NET Bitmap object, but the interface does not depend on this. Sprites can be created by either loading an image file, or creating an empty image of a specified size and colour. The benefit of the Sprite class is to provide resource sharing, using the Flyweight design pattern.
Interfaces, Inheritance and Encapsulation
IDrawable ToDo
AnimatedObject heirachy ToDo
Design Patterns
- Strategy pattern (LimbAnimationStrategy) ToDo
- Observer (Handle) ToDo
- Flyweight (Sprite) ToDo
- Decorator (Background) ToDo
Maxims Followed
ToDo
Object Encapsulation ToDo
Maxims Violated
MVC etc ToDo