by date
TorqueX Newbie Diary #6
TorqueX Newbie Diary #6
| Name: | David Everhart | |
|---|---|---|
| Date Posted: | Jan 28, 2008 | |
| Rating: | Not Rated | |
| Public: | YES | |
| Comments: | YES | |
| RSS Feed: | or Subscribe with . | |
| Profile Page: | View profile page for David Everhart |
Blog post
Quite a bit has been done on Arillian since the last update. The main advances have been:
1) Introduction of another animation
2) Revamp of the project setup
3) Revamp of the animation system
4) Animation change based on mouse
Introduction of another animation
In order to test out animation transition, and the action that causes it, I needed another animation. I already had one for a human male in an idle mode with no weapons facing south. I went to my trusty poser 7 and used the same mode, but this time, rendered it southwest. One thing to note, I do not include shadows, since I will be implementing shadows runtime based on light sources.
Revamp of the project setup
I restructured my project by moving out the peices to logical projects. I now have the following projects in my solution:
1) DataAccess - Persistence layer, provides access to a persistance engine (in my case, Sql Server 2005 Express)
2) AnimationManagement - This project handles all the animation creation and management
3) Common - Anything that is common to all the projects, or needs to be access globally.
4) ArillianGameEngine - This project handles all the core Arillian classes, such as Player, ItemManager, etc
5) Game - The basic project that the startertemplates use, it is still used as the starting point
Revamp of the animation system
I was unhappy with the file naming system I had originally used. Although Diablo II used a similar format for naming, it felt hackish to me. I went ahead and implemented a data model in sql server 2005 express to persist the animation information, as well as all game related information (such as login , accounts, saved games, configuration, etc). This allowed me to run stored procedures (that take around 5- 10 milliseconds) to grab animation layer information. Since my AnimationLayers have IDs now, My file system now has folders related to the ID.
Fo example, The root folder to the animationlayers is constant (C:\Projects\Arillian\Game\data\Images\AnimationLayers). Inside that folder are folders called 1, 2, 3, 4, etc. They correspond to the AnimationLayerID. Inside those folders are the frames for that animation layer. If you recall, an AnimationLayer is just one layer for an animation configuration. The animation configuration for any player is always 4 animation layers (head, torso, lefthand, righthand).
My Player object has one animated sprite, which I was hoping to just swap in and out the animation datas. Unfortunately, I do not think TorqueX was really designed for that. So I implemented a solution around it. I still have the animated sprite definition in my Player object, but now I copyto() a new animated sprite, attach the animation, and then run it from there. I maintain the object id of the current sprite in the TorqueObjectDatabase, so I can unregister it, and then register the new one, and set the current id. Here is my Player.UpdateAnimation() function so far:
When the code runs, this is how long it takes to compress 60 frames (4 animation layers * 15 frames each), draw a shadow on each cell of the final image (I do this runtime, as opposed to baking it in the image), render it to T2DAnimationData, and then attach it to the newly copied animated sprite:
UpdateAnimation::Start Time is 3:01:17 AM
UpdateAnimation::End Time is 3:01:17 AM
UpdateAnimation::Time to run is 234.375
Now, when I run this, I cache the animation layer in a Dictionary<int,Image>. The int is the animation layer id, and the image is the animation layer image. When the animation is cached, it will use the image from there, instead of rerendering the 15 frames. Here is a cached pull:
UpdateAnimation::Start Time is 3:01:19 AM
UpdateAnimation::End Time is 3:01:19 AM
UpdateAnimation::Time to run is 78.125
There is no noticeable lag in animation switching. Bear in mind, the time to run is in milliseconds. I am happy with the speed of it, but do not know yet how it will perform when a lot of things are moving on the screen. The below code is the check to see if it is cached, and if is not, to cache it.
Animation change based on mouse click position
I first wanted to use a button to test my animation change, but realized I would have to figure out the new 1.5 GUI setup. Instead , I decided to implement the mouse functionality. I have some guidelines on what I want the mouse to do in regards to the player. They are:
1) If the Shift button is held down, mouse clicking anywhere on the screen will have the player face that direction
2) If the shift button is not held down, and they are within a distance of 50, then perform the walk animation and move the player in that direction
3) If the shift button is not held down, and they are over a distance of 50, then perform the run animation and move the player in that direction
I implemented ITickOBject on my custom player class, and in the process tick, handle the mouse. I have not integrated the distance or shift peices yet, but have implemented the change direction based on angle of mouse click or drag.Code is below:
This allows me to capture even mouse drag events, so you can literally mousedrag a circle around the player, and it will only fire if the angle is between certain ranges. You can also click, and it will do a check as well (Thanks to John Kanalkis for the idea, and Josh Thomas for the screen to world conversion function.).
Summary
Here are two screenshots of the south idle and southwest idle animations:
Facing South:

Facing SouthWest:

Its been a long and fun road so far, a lot more to go. With Poser 7, I am finally feeling comfortable in it, and can whip out renderings pretty easy. I am still learning the animation aspects of it though. The world is comng along, thanks to WorldCreator 2.5 as well. My next steps are to render out the 8 direction for the idle, walking, and running animations. I also want to get it so that you can move the player around like in Diablo. I am close to it now, the mechanics are there, I just need to flush it out. With the inclusion of a database, I now have a persistence layer I am very familiar with, so that should speed things up as well. Until the next update!
1) Introduction of another animation
2) Revamp of the project setup
3) Revamp of the animation system
4) Animation change based on mouse
Introduction of another animation
In order to test out animation transition, and the action that causes it, I needed another animation. I already had one for a human male in an idle mode with no weapons facing south. I went to my trusty poser 7 and used the same mode, but this time, rendered it southwest. One thing to note, I do not include shadows, since I will be implementing shadows runtime based on light sources.
Revamp of the project setup
I restructured my project by moving out the peices to logical projects. I now have the following projects in my solution:
1) DataAccess - Persistence layer, provides access to a persistance engine (in my case, Sql Server 2005 Express)
2) AnimationManagement - This project handles all the animation creation and management
3) Common - Anything that is common to all the projects, or needs to be access globally.
4) ArillianGameEngine - This project handles all the core Arillian classes, such as Player, ItemManager, etc
5) Game - The basic project that the startertemplates use, it is still used as the starting point
Revamp of the animation system
I was unhappy with the file naming system I had originally used. Although Diablo II used a similar format for naming, it felt hackish to me. I went ahead and implemented a data model in sql server 2005 express to persist the animation information, as well as all game related information (such as login , accounts, saved games, configuration, etc). This allowed me to run stored procedures (that take around 5- 10 milliseconds) to grab animation layer information. Since my AnimationLayers have IDs now, My file system now has folders related to the ID.
Fo example, The root folder to the animationlayers is constant (C:\Projects\Arillian\Game\data\Images\AnimationLayers). Inside that folder are folders called 1, 2, 3, 4, etc. They correspond to the AnimationLayerID. Inside those folders are the frames for that animation layer. If you recall, an AnimationLayer is just one layer for an animation configuration. The animation configuration for any player is always 4 animation layers (head, torso, lefthand, righthand).
My Player object has one animated sprite, which I was hoping to just swap in and out the animation datas. Unfortunately, I do not think TorqueX was really designed for that. So I implemented a solution around it. I still have the animated sprite definition in my Player object, but now I copyto() a new animated sprite, attach the animation, and then run it from there. I maintain the object id of the current sprite in the TorqueObjectDatabase, so I can unregister it, and then register the new one, and set the current id. Here is my Player.UpdateAnimation() function so far:
public void UpdateAnimation()
{
DateTime startTime = DateTime.Now;
Console.WriteLine("UpdateAnimation::Start Time is " + startTime.ToLongTimeString());
// Get the Current Camera
T2DSceneCamera currentCamera = (T2DSceneCamera)TorqueObjectDatabase.Instance.FindObject("Camera");
// Get the AnimationConfiguration
AnimationConfiguration configuration = GetAnimationConfiguration();
// Make sure we have 4, if we dont, then the AnimationConfiguration is not valid
if (configuration.AnimationLayers.Count == 4)
{
// Get the T2dAnimationData
T2DAnimationData animationData = AnimationManager.Instance.CreateT2DAnimationData(configuration, ImageFormat.Png);
// Check to see if the current sprice has an ID, default is -1
if (currentSpriteId > -1)
{
// Unmount the Camera
currentCamera.Dismount();
// Unregister it
TorqueObjectDatabase.Instance.Unregister(TorqueObjectDatabase.Instance.FindObject((uint)currentSpriteId));
}
// Create a new copy based off our _sprite definition
T2DAnimatedSprite spriteCopy = new T2DAnimatedSprite();
_sprite.CopyTo(spriteCopy);
// Set the new animation data
spriteCopy.AnimationData = animationData;
// Setup our Sprite
TorqueObjectDatabase.Instance.Register(spriteCopy);
currentSpriteId = Convert.ToInt32(spriteCopy.ObjectId);
currentCamera.Mount(spriteCopy, "", true);
// Play the new animation
spriteCopy.PlayAnimation();
}
DateTime endTime = DateTime.Now;
Console.WriteLine("UpdateAnimation::End Time is " + endTime.ToLongTimeString());
TimeSpan timeToRun = endTime.Subtract(startTime);
Console.WriteLine("UpdateAnimation::Time to run is " + timeToRun.TotalMilliseconds.ToString());
}
When the code runs, this is how long it takes to compress 60 frames (4 animation layers * 15 frames each), draw a shadow on each cell of the final image (I do this runtime, as opposed to baking it in the image), render it to T2DAnimationData, and then attach it to the newly copied animated sprite:
UpdateAnimation::Start Time is 3:01:17 AM
UpdateAnimation::End Time is 3:01:17 AM
UpdateAnimation::Time to run is 234.375
Now, when I run this, I cache the animation layer in a Dictionary<int,Image>. The int is the animation layer id, and the image is the animation layer image. When the animation is cached, it will use the image from there, instead of rerendering the 15 frames. Here is a cached pull:
UpdateAnimation::Start Time is 3:01:19 AM
UpdateAnimation::End Time is 3:01:19 AM
UpdateAnimation::Time to run is 78.125
There is no noticeable lag in animation switching. Bear in mind, the time to run is in milliseconds. I am happy with the speed of it, but do not know yet how it will perform when a lot of things are moving on the screen. The below code is the check to see if it is cached, and if is not, to cache it.
Image imageToMerge;
if (AnimationManager.Instance.AnimationLayerImages.ContainsKey(newAnimationLayer.ID))
{
// Load from cache
AnimationManager.Instance.AnimationLayerImages.TryGetValue(newAnimationLayer.ID, out imageToMerge);
}
else
{
// Load from file
imageToMerge = CreateAnimationImageStrip(newAnimationLayer);
// Store it for future use if it isnt already cached
AnimationManager.Instance.AnimationLayerImages.Add(newAnimationLayer.ID, imageToMerge);
}
Animation change based on mouse click position
I first wanted to use a button to test my animation change, but realized I would have to figure out the new 1.5 GUI setup. Instead , I decided to implement the mouse functionality. I have some guidelines on what I want the mouse to do in regards to the player. They are:
1) If the Shift button is held down, mouse clicking anywhere on the screen will have the player face that direction
2) If the shift button is not held down, and they are within a distance of 50, then perform the walk animation and move the player in that direction
3) If the shift button is not held down, and they are over a distance of 50, then perform the run animation and move the player in that direction
I implemented ITickOBject on my custom player class, and in the process tick, handle the mouse. I have not integrated the distance or shift peices yet, but have implemented the change direction based on angle of mouse click or drag.Code is below:
public void ProcessTick(Move move, float dt)
{
// Get the current Mouse State
MouseState state = Mouse.GetState();
if (state.LeftButton == ButtonState.Pressed) // Means button was pressed
{
// Get the Mouse coordinates
Vector2 mouseCoordinates = Utility.ConvertScreenToWorld(new Vector2((float)state.X, (float)state.Y), Configuration.Instance.ScreenResolution);
// Figure out what the angle is in relation to the player
float angle = T2DVectorUtil.AngleFromTarget(mouseCoordinates, Player.Instance.Sprite.Position);
// Convert it to an enumeration we can use
Enumeration.Direction newDirection = Utility.ConvertAngleToDirection(angle);
// Check to see if we need to do anything
if (newDirection != Player.Instance.Direction)
{
//Console.WriteLine(newDirection.ToString());
float distance = Vector2.Distance(mouseCoordinates, Player.Instance.Sprite.Position);
Player.Instance.Direction = newDirection ;
Player.Instance.UpdateAnimation();
}
}
}
This allows me to capture even mouse drag events, so you can literally mousedrag a circle around the player, and it will only fire if the angle is between certain ranges. You can also click, and it will do a check as well (Thanks to John Kanalkis for the idea, and Josh Thomas for the screen to world conversion function.).
Summary
Here are two screenshots of the south idle and southwest idle animations:
Facing South:

Facing SouthWest:

Its been a long and fun road so far, a lot more to go. With Poser 7, I am finally feeling comfortable in it, and can whip out renderings pretty easy. I am still learning the animation aspects of it though. The world is comng along, thanks to WorldCreator 2.5 as well. My next steps are to render out the 8 direction for the idle, walking, and running animations. I also want to get it so that you can move the player around like in Diablo. I am close to it now, the mechanics are there, I just need to flush it out. With the inclusion of a database, I now have a persistence layer I am very familiar with, so that should speed things up as well. Until the next update!
Recent Blog Posts
| List: | 09/03/08 - TorqueX 3D Hiding Meshes Part 2 07/09/08 - TorqueX - First Stab at Hiding Mesh Resource 06/22/08 - Journey Into 3D 01/28/08 - TorqueX Newbie Diary #6 01/07/08 - TorqueX Newbie Diary #5 12/12/07 - TorqueX Newbie Diary #4 12/07/07 - TorqueX Newbie Diary #3 12/01/07 - TorqueX Newbie Diary #2 |
|---|
Submit your own resources!| Oliver Rendelmann - DerR (Jan 28, 2008 at 16:27 GMT) |
| David Everhart (Jan 28, 2008 at 17:06 GMT) |
| John Kanalakis (Jan 29, 2008 at 05:51 GMT) |
John K.
| David Everhart (Jan 29, 2008 at 06:43 GMT) |
| John Kanalakis (Jan 30, 2008 at 05:18 GMT) |
John K.
| David Everhart (Jan 30, 2008 at 16:11 GMT) |
You must be a member and be logged in to either append comments or rate this resource.


Not Rated


