Difference between revisions of "Tutorial:Sims 3 Custom Animations"
From SimsWiki
(→Figuring Stuff Out Beforehand) |
(→Setting Up Your Environment) |
||
Line 10: | Line 10: | ||
*Milkshape 3D | *Milkshape 3D | ||
== Figuring Stuff Out Beforehand == | == Figuring Stuff Out Beforehand == | ||
− | <h4>In any part of this tutorial, if you see something wrapped in curly braces {}, substitute it with one of the values below. For example, in my case, {YourNamespace} would change to "rothn" (without the quotes).</ | + | <h4>In any part of this tutorial, if you see something wrapped in curly braces {}, substitute it with one of the values below. For example, in my case, {YourNamespace} would change to "rothn" (without the quotes).</h3> |
YourNamespace - This is the namespace that your object's script will use. I generally use my forum username (rothn). | YourNamespace - This is the namespace that your object's script will use. I generally use my forum username (rothn). | ||
ObjectClass - This is the class that your object's script will use. There can't be multiple classes in the same namespace, so I generally choose a concise description of the object (e.g. AnimTutorial) | ObjectClass - This is the class that your object's script will use. There can't be multiple classes in the same namespace, so I generally choose a concise description of the object (e.g. AnimTutorial) |
Revision as of 04:20, 22 August 2010
Contents |
Introduction
This tutorial will cover the process of creating an object with a custom animation. This tutorial assumes that you have basic knowledge of object modding and cloning.
What You'll Need
- Smooth Jazz animation script editor
- S3PE
- S3OC
- Wes Howe's AnimTool
- adult_bodies_4_anim_2010_02_19.rar
- Microsoft® Visual C# Express Edition
- Milkshape 3D
Figuring Stuff Out Beforehand
In any part of this tutorial, if you see something wrapped in curly braces {}, substitute it with one of the values below. For example, in my case, {YourNamespace} would change to "rothn" (without the quotes).</h3>
YourNamespace - This is the namespace that your object's script will use. I generally use my forum username (rothn).
ObjectClass - This is the class that your object's script will use. There can't be multiple classes in the same namespace, so I generally choose a concise description of the object (e.g. AnimTutorial)
ObjectClassHash - This is the Fnv64 hash of your ObjectClass.
AnimName - This is the name of the specific animation that you will play (I used "a2o_test_x")
AnimNameHash - This is the Fnv64 hash of your AnimName.
SourceName - This is a name used for a group of animations (I used "a2o_test.ma")
Setting Up Your Environment
- Create a directory somewhere. You will use this in the development of the object.
- Choose an object to clone.
- Note that if you select an object which doesn't already make use of animations, you will have to do an extra step later in this tutorial.
- Put the package file of your new object in the aforementioned directory.
- Create a new CLR dll project in Visual C#.
- Make sure that the Sims 3 DLL's you're using are the most recent and from the same version of TS3.
- I will not go farther into this topic, as I assume that you are not new to making your own scripted objects.
- Create a new jazz script in Smooth Jazz.
- Open FullBuild0.package in "%ProgramFiles%\Electronic Arts\The Sims 3\GameData\Shared\Packages".
- Choose an animation (S3PE shows the tag CLIP for animations) to base your animation on.
- Right click on that animation, mouse over "Export", and click on "To File".
- Save the file in your object's directory.
- Extract "rigfile.txt" from "adult_bodies_4_anim_2010_02_19.rar" and put it in your object's directory.
- Extract all the contents of "AnimTool.rar" or "AnimTool-04a.rar" (whichever you downloaded), and put them in your object's directory.
Preparing Your Object
- Open the package file that you created in the previous section in S3PE.
- Select the OBJK resource and press "Edit OBJK".
- If it isn't checked, check the "Script" checkbox, and replace whatever existing text with "{YourNamespace}.{ObjectClass}" (e.g. "rothn.AnimTutorial")
- If the object you cloned is not animated (or if the boxes aren't checked), check the boxes labeled "Sacs", and "Animation".
- Create a new S3SA resource, where the instance is {ObjectClassHash}, the group is 0x00000000, and the name is descriptive of your object (e.g. AnimTutorial.dll).
- Enter your object's directory, right click on the animation that you exported from S3PE, and click rename.
- Change the file's name to "S3_6B20C4F3_00000000_{AnimNameHash}_{AnimName}%%+CLIP.animation".
Creating the C# Script
- Go to Visual C# and open up the project that you created in Setting Up Your Environment.
- If you know what you're doing, please look at the code sample below (which references a custom jazz script), and go to town. Otherwise, please scroll down to step 3.
public bool DoAnimation(InteractionInstance interaction, Sim Actor)
{
interaction.StandardEntry();
if (Actor.SimDescription.ChildOrAbove)
{
interaction.AcquireStateMachine("animtutorialjazz");
//interaction.UseAutoParameters(new TraitNames[] { TraitNames.Clumsy, TraitNames.HotHeaded, TraitNames.Unlucky });
interaction.SetActor("x", Actor);
//interaction.SetActor("object", this);
interaction.EnterSim("Enter");
interaction.AnimateSim("OurAnim");
interaction.AnimateSim("Exit");
}
interaction.StandardExit();
return true;
}
- If you don't know what you're doing, or you don't want to bother with writing your own script, paste this code into Visual C#.
using System;
using System.Collections.Generic;
using System.Text;
using Sims3.Gameplay;
using Sims3.Gameplay.Objects;
using Sims3.Gameplay.Objects.Seating;
using Sims3.Gameplay.Abstracts;
using Sims3.Gameplay.Interfaces;
using Sims3.Gameplay.Interactions;
using Sims3.Gameplay.Actors;
using Sims3.Gameplay.ActorSystems;
using Sims3.Gameplay.Autonomy;
using Sims3.SimIFace;
using Sims3.SimIFace.CustomContent;
using Sims3.UI;
using Sims3.Gameplay.ObjectComponents;
using Sims3.Metadata;
using Sims3.SimIFace.Enums;
using Sims3.Gameplay.Core;
using Sims3.Gameplay.Objects.CookingObjects;
namespace {YourNamespace}
{
public class {ObjectClass} : GameObject, IGameObject, IScriptObject, IScriptLogic, IHasScriptProxy, IObjectUI, IExportableContent
{
/*[Tunable, TunableComment("Range: Positive integers. Description: Maximum number of Sims that can wait in line.")]
private static int kMaximumNumberOfSimsInLine = 0x3;
[TunableComment("Range: Positive floats. Description: Amount of Sim minutes a Sim will wait in line before timing out and exiting."), Tunable]
public static float kTimeToWaitInLine = 15f;
public SimQueue Line = new SimQueue(SimQueue.WaitLocation.HangAroundNearObject, kMaximumNumberOfSimsInLine);*/
protected Sim mRevealingSim;
public override void OnStartup()
{
base.AddInteraction(DoAnimation.Singleton);
}
public bool DoAnimation(InteractionInstance interaction, Sim Actor)
{
/*if (!this.Line.WaitForTurn(interaction, SimQueue.WaitBehavior.Default, ~(ExitReason.MidRoutePushRequested | ExitReason.ObjectStateChanged | ExitReason.PlayIdle | ExitReason.MaxSkillPointsReached), kTimeToWaitInLine))
{
return false;
}
if (!Actor.RouteToSlotAndCheckInUse(this, Slots.Hash("Routing")))
{
return false;
}*/
interaction.StandardEntry();
if (Actor.SimDescription.ChildOrAbove)
{
interaction.AcquireStateMachine("animtutorialjazz");
//interaction.UseAutoParameters(new TraitNames[] { TraitNames.Clumsy, TraitNames.HotHeaded, TraitNames.Unlucky });
interaction.SetActor("x", Actor);
//interaction.SetActor("object", this);
interaction.EnterSim("Enter");
interaction.AnimateSim("OurAnim");
}
return true;
}
public bool FinishAnimation(InteractionInstance interaction, Sim Actor)
{
if (Actor.SimDescription.ChildOrAbove)
{
interaction.AnimateSim("Exit");
}
interaction.StandardExit();
return true;
}
public class DoAnimation : Interaction<Sim, {ObjectClass}>
{
// Fields
public static readonly InteractionDefinition Singleton = new Definition();
// Methods
protected override bool Run()
{
//base.BeginCommodityUpdates();
base.Target.DoAnimation(this, base.Actor);
base.Target.FinishAnimation(this, base.Actor);
//base.EndCommodityUpdates(true);
return true;
}
// Nested Types
private sealed class Definition : InteractionDefinition<Sim, {ObjectClass}, {ObjectClass}.DoAnimation>
{
// Methods
protected override string GetInteractionName(Sim actor, {ObjectClass} target, InteractionObjectPair iop)
{
return "Do Animation";
}
protected override bool Test(Sim a, {ObjectClass} target, bool isAutonomous, ref GreyedOutTooltipCallback greyedOutTooltipCallback)
{
return true;
}
}
[DoesntRequireTuning]
private sealed class ForceDefinition : InteractionDefinition<Sim, {ObjectClass}, {ObjectClass}.DoAnimation>
{
// Methods
protected override bool Test(Sim a, {ObjectClass} target, bool isAutonomous, ref GreyedOutTooltipCallback greyedOutTooltipCallback)
{
return true;
}
}
}
}
}
- Compile the dll, and put it in your object's folder.
- Switch to S3PE and select the S3SA resource that you created in Preparing Your Object.
Creating the Animation
- Open Wes Howe's AnimTool.
- Press the "Clip -> SMD" button.
- In the dialog box that comes up, select the .animation file that you renamed in Preparing Your Object.
- Now open up Milkshape 3D
- In Milkshape, import the SMD file that you just created with the AnimTool.
- Note that if you use bones that the animation you exported doesn't, then the animation will not display correctly ingame.
- When you are ready, export the animation from Milkshape 3D as a SMD file, taking care to use the same filename that you set in Preparing Your Object, but with the .smd extension rather than the .animation extension.
- Go back to Wes Howe's AnimTool.
- In the textbox labeled "Anim Name", type {AnimName}.
- In the textbox labeled "Source Name", type {SourceName}.
- Now, press SMD -> Clip.
- In the dialog box that comes up, select the .smd file that you exported in Milkshape 3D.
- Since the only difference between the filenames of the .smd file and the .animation file is the extension, the AnimTool will add a .bak00 extension to the original animation file, and your new .animation file will have the name of the original.
- Now, switch back to S3PE, and click "Resource" in the toolbar, mouse over "Import", and click "From file...".
- Select the .animation file and click OK in the dialog box that appears.
Creating the Jazz Script
- Close all instances of S3PE.
- In Smooth Jazz, click "Tools", and then "Options".
- Press "Add", navigate to your object's directory, and double click your object's package file.
- Press "OK".
- In the new jazz script that you created in Smooth Jazz in Setting Up Your Environment, enter the following code.
State Machine "animtutorialjazz"
{
Actor "x"
Assign Actor "{SourceName}"."x" as "x"
State "Enter"
{
Properties Public, Entry, Explicit
Transitions to "OurAnim"
}
State "OurAnim"
{
Transitions to "Exit"
Play "{AnimName}"
}
State "Exit"
{
Properties Public, Exit, Explicit
}
}
- Now, press "File", and click "Package All Into..."
- If there are any other state machines than "animtutorialjazz" that show up in the export dialog, uncheck the checkboxes next to them.
- Click "Export".
Finishing Up
- Please test your object, and PM me (rothn) at ModTheSims if you have any questions or if your object's animation will not play.
- Note that WesHowe does impose certain limits on the use of his AnimTool. If the Clip file that you try to copy is too big, his AnimTool won't take it. I know, I hate it too, please do PM Wes (also at MTS) so that he releases a version for those of us with top-of-the-line systems (and no frame limits).
- Note that if you select an object which doesn't already make use of animations, you will have to do an extra step later in this tutorial.
- Put the package file of your new object in the aforementioned directory.
- Make sure that the Sims 3 DLL's you're using are the most recent and from the same version of TS3.
- I will not go farther into this topic, as I assume that you are not new to making your own scripted objects.
- Choose an animation (S3PE shows the tag CLIP for animations) to base your animation on.
- Right click on that animation, mouse over "Export", and click on "To File".
- Save the file in your object's directory.
public bool DoAnimation(InteractionInstance interaction, Sim Actor) { interaction.StandardEntry(); if (Actor.SimDescription.ChildOrAbove) { interaction.AcquireStateMachine("animtutorialjazz"); //interaction.UseAutoParameters(new TraitNames[] { TraitNames.Clumsy, TraitNames.HotHeaded, TraitNames.Unlucky }); interaction.SetActor("x", Actor); //interaction.SetActor("object", this); interaction.EnterSim("Enter"); interaction.AnimateSim("OurAnim"); interaction.AnimateSim("Exit"); } interaction.StandardExit(); return true; }
using System; using System.Collections.Generic; using System.Text; using Sims3.Gameplay; using Sims3.Gameplay.Objects; using Sims3.Gameplay.Objects.Seating; using Sims3.Gameplay.Abstracts; using Sims3.Gameplay.Interfaces; using Sims3.Gameplay.Interactions; using Sims3.Gameplay.Actors; using Sims3.Gameplay.ActorSystems; using Sims3.Gameplay.Autonomy; using Sims3.SimIFace; using Sims3.SimIFace.CustomContent; using Sims3.UI; using Sims3.Gameplay.ObjectComponents; using Sims3.Metadata; using Sims3.SimIFace.Enums; using Sims3.Gameplay.Core; using Sims3.Gameplay.Objects.CookingObjects; namespace {YourNamespace} { public class {ObjectClass} : GameObject, IGameObject, IScriptObject, IScriptLogic, IHasScriptProxy, IObjectUI, IExportableContent { /*[Tunable, TunableComment("Range: Positive integers. Description: Maximum number of Sims that can wait in line.")] private static int kMaximumNumberOfSimsInLine = 0x3; [TunableComment("Range: Positive floats. Description: Amount of Sim minutes a Sim will wait in line before timing out and exiting."), Tunable] public static float kTimeToWaitInLine = 15f; public SimQueue Line = new SimQueue(SimQueue.WaitLocation.HangAroundNearObject, kMaximumNumberOfSimsInLine);*/ protected Sim mRevealingSim; public override void OnStartup() { base.AddInteraction(DoAnimation.Singleton); } public bool DoAnimation(InteractionInstance interaction, Sim Actor) { /*if (!this.Line.WaitForTurn(interaction, SimQueue.WaitBehavior.Default, ~(ExitReason.MidRoutePushRequested | ExitReason.ObjectStateChanged | ExitReason.PlayIdle | ExitReason.MaxSkillPointsReached), kTimeToWaitInLine)) { return false; } if (!Actor.RouteToSlotAndCheckInUse(this, Slots.Hash("Routing"))) { return false; }*/ interaction.StandardEntry(); if (Actor.SimDescription.ChildOrAbove) { interaction.AcquireStateMachine("animtutorialjazz"); //interaction.UseAutoParameters(new TraitNames[] { TraitNames.Clumsy, TraitNames.HotHeaded, TraitNames.Unlucky }); interaction.SetActor("x", Actor); //interaction.SetActor("object", this); interaction.EnterSim("Enter"); interaction.AnimateSim("OurAnim"); } return true; } public bool FinishAnimation(InteractionInstance interaction, Sim Actor) { if (Actor.SimDescription.ChildOrAbove) { interaction.AnimateSim("Exit"); } interaction.StandardExit(); return true; } public class DoAnimation : Interaction<Sim, {ObjectClass}> { // Fields public static readonly InteractionDefinition Singleton = new Definition(); // Methods protected override bool Run() { //base.BeginCommodityUpdates(); base.Target.DoAnimation(this, base.Actor); base.Target.FinishAnimation(this, base.Actor); //base.EndCommodityUpdates(true); return true; } // Nested Types private sealed class Definition : InteractionDefinition<Sim, {ObjectClass}, {ObjectClass}.DoAnimation> { // Methods protected override string GetInteractionName(Sim actor, {ObjectClass} target, InteractionObjectPair iop) { return "Do Animation"; } protected override bool Test(Sim a, {ObjectClass} target, bool isAutonomous, ref GreyedOutTooltipCallback greyedOutTooltipCallback) { return true; } } [DoesntRequireTuning] private sealed class ForceDefinition : InteractionDefinition<Sim, {ObjectClass}, {ObjectClass}.DoAnimation> { // Methods protected override bool Test(Sim a, {ObjectClass} target, bool isAutonomous, ref GreyedOutTooltipCallback greyedOutTooltipCallback) { return true; } } } } }
State Machine "animtutorialjazz" { Actor "x" Assign Actor "{SourceName}"."x" as "x" State "Enter" { Properties Public, Entry, Explicit Transitions to "OurAnim" } State "OurAnim" { Transitions to "Exit" Play "{AnimName}" } State "Exit" { Properties Public, Exit, Explicit } }