Graphics Related Components

In this page you'll find all the 3D Graphics related Components and their Python API documentation.

Meshes

cave.MeshComponent

Variables

The MeshComponent only have one variable: the tint color. All the others parameters must be manipulated using their getters and setters. The tint is the color you want to tint the mesh to. Defaults to white (meaning no tint). Reference:

tint : cave.Vector4
Methods

The first thing that you may want to do is manipulate the Mesh used by this component (please read the cave.Mesh documentation for details). You can do it so by calling one of the following methods:

getMesh() -> cave.Mesh
setMesh(meshName: str)
setMesh(mesh: cave.Mesh)

Then you may want to manipulate the Material, that works in the same way. (Please read the cave.Material documentation for details). Reference:

getMaterial() -> cave.Material
setMaterial(matName: str)
setMaterial(mat: cave.Material)

You can also change the Armature used by the Mesh Component. Note that this one does not have a Python API yet, so you can only get and set it using its name (as a string). As you can see here:

# Will return the name of the armature!
getArmature() -> str
setArmature(armatureName: str)

- Working with Animations

Cave's animation system is simple but versatile: Every MeshComponent have an Animation Stack, that is a list of animations currently being played. The purpose of this list is to allow you to blend different animations together or even play multiple ones at the same time. The Stack stores what we call cave.AnimationHandler (more on that later in this page). At the moment, you can't fully manipulate this stack via Python API, but you can do it so by using one of Cave's Animators assets.

Still, there are some very useful things already possible to do via Python. The reason why it was important to explain the existance of this stack is because there is an important different between the animation at the top of the animation stack and the animation assigned to the MeshComponent itself. Let's use the RandomAnimator Asset for example. It is an animation type that you can actually set to the Mesh Component. But it's not a "raw" animation that the engine can directly execute for the Armature. But the RandomAnimator may have raw animations inside of it. The animations in the Animation Stack will most likely to be raw animations (that can be internally player directly by the Armature) and the animation in the MeshComponent itself can be anything, including a higher level one (such as the RandomAnimator).

For instance, that's why you can't fully manipulate the animation stack via Python: most of the times, the engine itself will internally decide what to do with it based on the actual animation asset you've added to the MeshComponent. But as you'll see below, it's useful for you to know the existence of the stack and even get the cave.AnimationHandler on top of it.

So let's get started!

First of all, if you want to change the actual Animation Asset of the MeshComponent, you can do it so by using their getter and setter. Notice that the animation asset does not have a Python representation yet, so you'll be manipulating them using their names (as they appear in the Asset Browser).

getAnimation() -> str

# If the blendTime is greated than zero, it will blend in the new animation!
setAnimation(animation: str, blendTime=0.0)

If you want to know the exact "raw" animation being executed or some of its current playing status (such as its execution progress or how many times it looped), you can use one of those APIs:

# Will return the Animation name on top of the stack
getAnimationFromStack() -> str

# Returns how many times the current animation (top of the stack) looped the execution
getAnimationLoops() -> int

# Returns the animation progress, from [0 to 1]
getAnimationProgress() -> float

Or if you want even more information (and control) of the animation, you can consider getting its cave.AnimationHandler directly. IMPORTANT: Do NOT store this handler into a variable for more than a frame, because it may be freed internally by the engine, causing your game to "explode"! (crash)

getAnimationHandler() -> cave.AnimationHandler

Check the cave.AnimationHandler class reference below for more information on it.


cave.AnimationHandler

As explained, this Handler will give you information and control over the currently played animation (by the MeshComponent). Do NOT store this handler into a variable for more than a frame, because it may be freed internally by the engine, causing your game to "explode"! (crash)

The handler will give you a lot of freedom and options when manipulating the Animations, so enjoy it!

Variables
Variable Description
frame The scurrent Animation Frame.
speed The animation execution Speed. 1.0 means normal speed.
influence Influence ranges from [0.0 to 1.0] and determines how much this animation will influence the final Armature Pose. If the animation stack have multiple animations, this will also determine the blend between them (and it is used by the engine to blend in/out animations). Note: If you set the influence, it will also cancel any existing blend.

Here is the Python API for Reference:

frame : float
speed : float
influence : float
Methods

Another way to set/set the animation frame, speed and influence (other than by their variables), is to call their getters and setters:

getCurrentFrame() -> float
setCurrentFrame(frame: float)

getSpeed() -> float
setSpeed(speed: float)

getInfluence() -> float
# Note: If you set the influence, it will also cancel any existing blend
setInfluence(influence: float)

The methods below will provide you additional information regarding the execution progress.

# Returns how many times the animation looped:
getLoops() -> int

# Range [0 to 1], the animation's execution progress:
getProgress() -> float

# True if the animation is Paused:
isPaused() -> bool

# Returns true if, for some reason, the animation is finished.
# For example: if the user asked to play it only once or a blendOut()
isFinished() -> bool

Tip: If you want to see if the animation "finished" its execution without the isFinished(that may not work in all situations), a good and easy option is to see if the getLoops() value is greated than zero.

To control the animation execution, you can use one of those methods:

pause()
resume()

# Freezes the animation on a specific frame:
freeze(frame: float)

And last but not least, you can blend in or out an animation any time you want by calling:

blendIn(durationInSeconds= 1.0, resetInfluence=True)
blendOut(durationInSeconds= 1.0)

Particles

cave.ParticleComponent

The ParticleComponent actually **inherits from MeshComponent, meaning that everything that you've already learned at the Mesh Component's documentation will actually work here (and I'll not explain it twice). The only different is those two extra variables:

Variables
Variable Description
instance Stores all the details on how the Particles will behave. See cave.ParticleInstanceDescriptor's documentation below for more details on it.
duration The current duration time of the particle. Used to determine its behavior.

Here is the Python API for Reference:

instance : cave.ParticleInstanceDescriptor
duration : cave.SceneTimer

cave.ParticleInstanceDescriptor

As you saw above, the cave.ParticleInstanceDescriptor is a storage class containing all the information on how the Particles will behave in the ParticleComponent.

Variables
Variable Description
count The amount of particles spawned by the component. Keep in mind that a lot of particles costs performance.
spawnArea The boxed area that the particles should spawn at.

Regarding the Spawn, you can specify a minimum and maximum range for the particle's scaleand rotation by using the scaleMin/Max and rotationMin/Max variables.

Variable Description
isDynamic Dynamic particles basically means that they will be updated every frame. You want this to be True for all the Particle Systems that moves in your scene. If you're using the Particle System to add static elements such as Stars or Trees, then they should not be Dynamic. Dynamic particles are slower.
useParent If truTrue, the particles will be parented to the Entity and move with it.
life The particle's Lifetime (in seconds). ZERO means it will life forever.
respawn Respawn window of the particles. In other words, for for many time (in seconds) should the ParticleComponent keep respawning particles. ZERO means forever.

Other than controlling the Particle's Spawn settings, you can also control its lifetime behavior using those variables below: | Variable | Description | |:-----------|-------------------------| | gravity | Gravity applied to the Particles. Tip: If you want to make smoke, you can apply a negative gravity, so they will fly to the air! |

In order to move the particles, you can rely on the linear and angular forces, that will affect the particle's position and rotation, respectively. For each force, you'll be prompted with a Velocity variable (linearVelocity and angularVelocity) and a Friction (linearFriction and angularFriction), that represents the resistance that the particle will find regarding that specific force.

Here is the Python API for Reference:

count : int

spawnArea   : cave.Vector3 
scaleMin    : cave.Vector3
scaleMax    : cave.Vector3
rotationMin : cave.Vector3
rotationMax : cave.Vector3

isDynamic : bool
useParent : bool
life      : float
respawn   : float

gravity         : cave.Vector3
linearVelocity  : cave.Vector3
linearFriction  : cave.Vector3
angularVelocity : cave.Vector3
angularFriction : cave.Vector3

Others

cave.DecalComponent

Variables
Variable Description
material The cave.Material used by the Decal.
opacity Decal opacity, ranging from [0 to 1].
layer Used to sort the decals.
angleFade If True, it will fade out according to the angle.

Here is the Python API for Reference:

material  : cave.Material
opacity   : float
layer     : int
angleFade : bool

cave.LightComponent

You can adjust various light parameters. Here is a sample code that makes the light color pulse using some timers and the python native math.sin() function:

import cave
import math
import random

class PulsingLight(cave.Component):
    def start(self, scene):
        self.speed = 2.0

        # Creating some timers with a random value to sample from
        self.colorX = cave.SceneTimer(random.random())
        self.colorY = cave.SceneTimer(random.random())
        self.colorZ = cave.SceneTimer(random.random())

    def compute(self, value):
        # Maps the timer into a sin curve ranged [0 - 1]
        return (math.sin(value * self.speed) + 1) / 2

    def update(self):       
        light = self.entity.get("Light Component")

        light.color.x = self.compute(self.colorX.get())
        light.color.y = self.compute(self.colorY.get())
        light.color.z = self.compute(self.colorZ.get())

        print(light.color.x, light.color.y, light.color.z)

        # Don't forget to reload the light, otherwise it will not be updated:
        light.reload()

    def end(self, scene):
        pass

NOTE: Lights are pre cached so the changes you made in the following parameters will not be effective (applied to the light) until you call the reload() method.

Variables
color     : cave.Vector3
radius    : float
intensity : float