Krotox Engine › Docs › Scripting API › Graphics, UI & Audio
Scripting 2D visuals: sprite colour, textures and flipping, animated sprite states and the Animator, particles, lines and trails, shapes, sprite effects (hit flash, outline, dissolve), 2D lights, the camera and screen-to-world conversions.
What each component *is* is covered in the 2D component reference. This page is about changing them from C#.
var sprite = GetComponent<SpriteRendererComponent>();
sprite.Color = new Vector4(1, 0.5f, 0.5f, 1); // RGBA tint; alpha < 1 for transparency
sprite.TilingFactor = new Vector2(4, 1); // repeat the texture
sprite.FlipX = m_FacingLeft; // face the way you move
sprite.MaskInteraction = SpriteMaskInteraction.VisibleInsideMask;
// Change the texture: a path, a handle, or a Texture2D field
sprite.Texture = "Textures/Skins/Gold.png";
public Texture2D AltSkin; // inspector field
sprite.SetTexture(AltSkin);
There is no Color type: colours are Vector4 (red, green, blue, alpha from 0 to 1).
IEnumerator FadeOut(SpriteRendererComponent sprite, float seconds)
{
yield return Tween.To(1.0f, 0.0f, seconds, Ease.QuadOut,
a => sprite.Color = new Vector4(1, 1, 1, a));
Destroy();
}
With Use State Machine on, switch between named states:
void OnUpdate(float ts)
{
var rb = GetComponent<Rigidbody2DComponent>();
float speed = Mathf.Abs(rb.LinearVelocity.X);
if (!m_Grounded) SetAnimationState("Jump");
else if (speed > 0.1f) SetAnimationState("Run");
else SetAnimationState("Idle");
GetComponent<AnimatedSpriteComponent>().FlipX = rb.LinearVelocity.X < 0;
}
string current = GetAnimationState();
Calling SetAnimationState every frame is safe: it ignores the state that is already playing.
For animation authored in the State Machine panel, drive the controller's parameters and let its transitions pick the state:
var animator = GetComponent<AnimatorComponent>();
animator.SetFloat("Speed", Mathf.Abs(velocity.X));
animator.SetBool("Grounded", m_Grounded);
animator.SetTrigger("Attack");
animator.SetInt("Combo", 2);
float speed = animator.GetFloat("Speed");
bool exists = animator.HasParameter("Grounded");
string state = animator.CurrentState;
float t = animator.NormalizedTime; // 0 to 1 through the current state
animator.Speed = 1.5f;
animator.Play("Hurt"); // jump straight to a state
Animation timelines (AnimationComponent): Play(), Pause(), Stop(), Seek(time), SetSpeed(speed), IsPlaying, CurrentTime.
var particles = GetComponent<ParticleSystemComponent>();
particles.Play();
particles.Emit(30); // or Burst(30): an instant burst
particles.Stop();
particles.Clear(); // remove live particles
particles.EmissionRate = 50.0f;
particles.IsEmitting = false;
particles.StartSpeed = 8.0f;
particles.GravityModifier = 1.0f;
particles.LifeTime = 1.2f;
bool busy = particles.IsPlaying;
int alive = particles.AliveCount;
Other members: IsPaused, Looping, Duration, LifeTimeVariation, SimulationSpeed, Velocity, VelocityVariation. Colour and size curves are edited in the inspector only.
public Prefab ExplosionPrefab; // a prefab with a Particle System
void Explode()
{
Entity fx = Instantiate(ExplosionPrefab, WorldPosition);
fx.GetComponent<ParticleSystemComponent>().Emit(40);
Invoke(() => fx.Destroy(), 2.0f);
}
var line = GetComponent<LineRenderer2DComponent>();
line.Points = new[] { Vector2.Zero, new Vector2(1, 0.5f), new Vector2(2, 0) }; // assign a new array
line.Width = 0.08f;
line.Color = new Vector4(1, 1, 0, 1);
line.UseWorldSpace = true;
// Lines that change every frame: per-point access allocates nothing
for (int i = 0; i < line.PointCount; i++)
line.SetPoint(i, PredictPosition(i * 0.1f));
var trail = GetComponent<TrailRenderer2DComponent>();
trail.Emitting = m_Dashing;
trail.StartWidth = 0.3f; trail.EndWidth = 0.0f;
trail.Time = 0.25f;
trail.Clear(); // drop the trail (for example after teleporting)
void DrawTrajectory(Vector2 start, Vector2 velocity)
{
var line = GetComponent<LineRenderer2DComponent>();
Vector2 gravity = Physics2D.Gravity;
var points = new Vector2[20];
for (int i = 0; i < points.Length; i++)
{
float t = i * 0.05f;
points[i] = start + velocity * t + gravity * (0.5f * t * t);
}
line.UseWorldSpace = true;
line.Points = points;
}
var shape = GetComponent<ShapeRendererComponent>();
shape.Type = Shape2DType.Star;
shape.Sides = 5;
shape.InnerRadius = 0.4f;
shape.Thickness = 1.0f; // 1 filled, less for an outline
shape.Color = new Vector4(1, 0.8f, 0.2f, 1);
var circle = GetComponent<CircleRendererComponent>();
circle.Thickness = 0.1f; // a ring
circle.Fade = 0.05f; // soft edge
var fx = GetComponent<SpriteEffects2DComponent>();
fx.HitFlash(0.1f); // flash white for 0.1 s when hit
fx.FlashColor = new Vector3(1, 0, 0); // ...or red
fx.Outline = m_Selected; // highlight a selected unit
fx.OutlineColor = new Vector4(0.6f, 1, 0.2f, 1);
fx.OutlineWidth = 2.0f; // screen pixels
// Burn away over one second
StartCoroutine(Tween.To(0.0f, 1.0f, 1.0f, Ease.Linear, v => fx.DissolveAmount = v));
var light = GetComponent<Light2DComponent>();
light.Type = Light2DType.Point; // Point, Spot, Global
light.Color = new Vector3(1.0f, 0.8f, 0.5f);
light.Intensity = 1.5f;
light.OuterRadius = 6.0f;
light.Enabled = !m_PowerOut;
// A flickering torch
light.Intensity = 1.2f + 0.2f * Mathf.Sin(Time.ElapsedTime * 15.0f);
SceneManager.AmbientLight2D = new Vector3(0.15f, 0.15f, 0.25f); // darken the scene
Spot lights use InnerAngle and OuterAngle (radians in scripts). ShadowSoftness is the light's size in world units (0 = hard shadows).
GetComponent<ParallaxLayer2DComponent>().Factor = new Vector2(0.2f, 0.0f); // far background
GetComponent<CameraZone2DComponent>().Enabled = m_BossActive; // lock the arena camera
var cam = GetComponent<CameraComponent>();
cam.Projection = CameraComponent.ProjectionType.Orthographic;
cam.OrthographicSize = 8.0f; // smaller = zoomed in
cam.MakeMain(); // make this the primary camera
Entity main = CameraComponent.Main; // static get and set
// The follow camera's target
GetComponent<CameraFollow2DComponent>().Target = m_Player;
The static Camera class works through the primary camera, so gameplay code does not need to find it:
Vector2 world = Camera.ScreenToWorldPoint(Input.MousePosition); // screen pixels to world
Vector2 screen = Camera.WorldToScreenPoint(new Vector2(3, 4)); // world to screen pixels
Vector2 vp = Camera.ScreenToViewportPoint(Input.MousePosition); // 0 to 1
Vector3 center = Camera.ViewportToWorldPoint(new Vector3(0.5f, 0.5f, 0));
Camera.BackgroundColor = new Vector4(0.1f, 0.1f, 0.2f, 1); // the clear colour
The same conversion methods exist on CameraComponent and on any Entity that has a camera.
Screen positions are in the game's own pixels, the same space as Input.MousePosition and touches, so no correction is needed for letterboxing or a zoomed Game view.
void OnLateUpdate(float ts)
{
Vector3 min = Camera.ViewportToWorldPoint(new Vector3(0, 0, 0)); // bottom-left of the view
Vector3 max = Camera.ViewportToWorldPoint(new Vector3(1, 1, 0)); // top-right
Vector3 p = Translation;
p.X = Mathf.Clamp(p.X, min.X + 0.5f, max.X - 0.5f);
Translation = p;
}
var text = GetComponent<TextComponent>();
text.Text = quot;x{m_Combo}"; text.Color = new Vector4(1, 1, 1, 1); text.Bold = true;
For HUD text, use UITextComponent (see UI scripting API).