A King Arthur's Gold mod that provides the tools to more easily create 3D mods. Easy3D currently focuses on models and animations but also contains various utility classes and functions.
- Usage
- Examples
- Classes
- Interfaces
- Functions
- Easing
- Maths
- Utility Animations
- Frequently Asked Questions
- Put the Easy3D folder in your
Mods
folder. - Add
Easy3D
to a new line inmods.cfg
above any mod that will use it. - Add
Easy3DHooks.as
to thescripts
list in your rules.cfg
file above any scripts that will reference Easy3D. - Add
#include "Easy3D.as"
to the top of any scripts that require it.
Tip: Refer to the examples provided in the Examples section below if the final two steps are unclear.
Update ExampleMod/Default/Rules.cfg
to enable/disable each example script. Only one example script should be active at once.
Script: ExampleMod/Examples/01-Model.as
Demonstrates rendering a basic model.
Script: ExampleMod/Examples/02-CompositeModel.as
Demonstrates composing a complex model.
Script: ExampleMod/Examples/03-Animation.as
Demonstrates animating a basic model.
Script: ExampleMod/Examples/04-CompositeAnimation.as
Demonstrates creating a composite animation and using utility animations to reduce the complexity of individual animations.
Script: ExampleMod/Examples/05-Choreographer.as
Demonstrates animating a basic model using a choreographer.
Animates a specific model using a provided animation.
A camera that can be positioned and rotated which represents the client's view.
Organizes one or more animations into states to choreograph complex animations.
A wrapper class for float[]
matrices that provides methods for the vanilla Matrix::
functions and operator overloads (=
, *
, *=
) for intuitive matrix multiplication.
A model that is composed of several models in a tree-like structure, with child models translated, rotated, and scaled relative to their parent model.
A 3D model that has an .obj model, a texture, and can be translated, rotated, and scaled.
A representation of spatial orientations and rotations in three-dimensional space.
Tip: Quaternions do not suffer from gimbal lock as Euler angles do which allows for straightforward interpolation between any two angles.
Read more: Quaternions and spatial rotation
Vec2f but with three dimensions.
Represents an animation for a model. Properties of a model can be animated based on a t
value that ranges from 0 and 1 which represents the animation progress.
Tip: The
Animate
method of animations should ideally be pure, as in it should ideally produce the same animation state when provided with the same value oft
. This will allow the animation to play predictably, especially when augmented using utility animations. However, there may be some cases where an animation may not be pure, such as when the model should face the direction of the camera.
Returns the interpolated game time of the client. Returns the non-interpolated game time if called on the server
Returns the aspect ratio of the window.
Returns the frames per second of the client.
Note: When the window is not in focus, this function assumes 30 FPS if the framerate is capped (
v_capped = true
) and 60 FPS if not.
Returns whether the client is also the server and vice versa.
Returns whether the onTick()
hook is paused when on localhost and the pause menu is visible.
Easing functions alter the rate of change of t
which ranges from 0 to 1. The optional power
parameter accepts any positive decimal value and specifies the intensity of the polynomial ease:
1.0f
is linear2.0f
is quadratic3.0f
is quartic4.0f
is quintic
Sinusoidal, exponential, and circular easing functions have not been implemented due to their increased performance impact from the use of sine, cosine, and square root operations. Polynomial easing functions accomplish a near identical effect without the performance hit.
Learn more: https://easings.net/
Start slow and end fast.
Start fast and end slow.
Start and end slow, increasing in speed at the middle.
An interface that represents an easing. All ease classes implement this interface.
Class version of no easing.
Class version of easeIn(float t, float power)
.
Class version of easeOut(float t, float power)
.
Class version of easeInOut(float t, float power)
.
Returns the shortest angle difference between angle1
and angle2
.
Clamps value
between bound1
and bound2
.
Interpolates between angle1
and angle2
, travelling the shortest angle distance.
Returns the sign of value
(-1
if negative, 1
is positive, 0
if zero).
Converts radians
to degrees.
Converts degrees
to radians.
Utility animations augment animations to help reduce the number of animations required to implement.
Tip: Utility animations implement the
IAnimation
interface just like any animation you will implement, so utility functions can be chained/nested to augment animations as required.
Plays several animations in sequence, increasing the duration accordingly.
// Play `animation1`, `animation2`, and `animation3` in sequence
CompositeAnimation().Add(animation1).Add(animation2).Add(animation3);
// Can also be initialized like so
IAnimation@[] animations = { animation1, animation2, animation3 };
CompositeAnimation(animations);
Overrides the duration of an animation.
// Override the duration of `animation` to two seconds
Duration(animation, 2.0f);
Interpolates between the end of an animation and the current time of another animation for a specified percentage of the animation.
// Interpolate between the end of `prevAnimation` and the current time of `animation` for a quarter of `animation`
Lerp(prevAnimation, animation, 0.25f);
Layers multiple animations, playing all animations for the duration of the first animation.
// Play `animation1`, `animation2`, and `animation3` at the same time for the duration of `animation1`
Multi().Add(animation1).Add(animation2).Add(animation3);
// Can also be initialized like so
IAnimation@[] animations = { animation1, animation2, animation3 };
Multi(animations);
Starts the animation at the specified offset.
// Start `animation` half way through
Offset(animation, 0.5f);
Pauses an animation at a desired t
for a specified duration.
// Pause `animation` at the half way point for two seconds
Pause(animation, 0.5f, 2.0f);
Scales the duration of an animation by a specified rate, even allowing animations to be reversed.
// Play `animation` at half speed
Rate(animation, 0.5f);
// Play `animation` at double speed
Rate(animation, 2.0f);
// Play `animation` in reverse
Rate(animation, -1.0f);
Plays an animation a specified number of times.
// Play `animation` twice
Repeat(animation, 2);
Reverses an animation.
// Play `animation` in reverse
Reverse(animation);
Trims the start and/or end of the animation, adjusting the duration accordingly. Can also be used to reverse, repeat and/or offset the animation.
// Play only the first half of `animation`
Trim(animation, 0.0f, 0.5f);
// Start `animation` half way through
Trim(animation, 0.5f, 1.5f);
// Play `animation` two and a half times
Trim(animation, 0.0f, 2.5f);
// Play `animation` in reverse
Trim(animation, 1.0f, 0.0f);
// The previous three examples combined
Trim(animation, 3.0f, 0.5f);
The shared
keyword is used to avoid an issue when attempting to use cast<>()
to convert the type of class handles. This issue is inevitably encountered when developing total conversion mods that have systems that handle various classes that inherit/implement a shared parent class/interface.
Put simply, AngelScript (in the context of KAG) sometimes 'forgets' what class/interfaces some classes inherit/implement. As a result, attempting to cast class handles to another valid class handle in some scenarios returns null
even though the cast should have worked.
Using the shared
keyword for classes and interfaces prevents this issue from occurring, but it unfortunately comes with some limitations:
-
shared
classes can only callshared
functions and inherit/implementshared
classes/interfaces. This prevents us from using the majority of classes, interfaces, and functions from the base game. -
Function handles (
funcdef
) cannot be used withshared
functions or methods inshared
classes.Tip: A better alternative is to use an interface instead of a function declaration. Classes that implement the interface can be instantiated with any dependencies, whereas a function definition only has access to the parameters defined in the function definition.
Husks are bare-bones blobs that are created for every player when they join and after every death, even when they are assigned to the spectator team. They are useful for various reasons:
- Preventing a
Connecting...
message from incessantly flashing on the screen above the 3D rendering layer. - Attributing kills to players via the CBlob
SetPlayerOfRecentDamage()
method. - Displaying kills and deaths in the killfeed and statistics on the scoreboard via the CBlob
server_Hit()
andserver_Die()
methods. - Checking for player input on the server via the CBlob key-related methods.
- Storing properties for the life of the blob (i.e. until the player is killed) via the CBlob set and get methods.