Tween color overlay of Spine animation - unity3d

Im using Unity3D and character animations imported from Spine. I want to add a color overlay over those characters. For example, I have one character, I want to make it a "shadow" character, so I add the black color over it in this way:
GetComponent<SkeletonAnimation>().Skeleton.color = new Color(0f,0f,0f);
Nevertheless, I want a Tween between the regular color, and the new color. But, unfortunately, I can't do it with the DOColor method of DOTween. I try
GetComponent<SkeletonAnimation>().Skeleton.DOColor(Color.Black,1);
But the method DOColor for Skeleton doesn't exists. So which is the way to follow to accomplish this?

DoColor, DoMove, etc are shortcuts and extension method that written for unity's built-in components. SkeletonAnimation is not supported by DoTween extension methods. You can tween its color property like this:
Color yourColor = Color.white; //GetComponent<SkeletonAnimation>().Skeleton.color
Color targetColor = Color.black;
float duration = 1f;
DOTween.To(() => yourColor, co => { yourColor = co; }, targetColor, duration);
Also, You can write your own extension:
public static class MyExtensions{
public static Tweener DOColor(this SkeletonAnimation target,
Color endValue, float duration)
{
DOTween.To(() => target.color,
co => { target.color = co; },
endValue,
duration);
}
}

If you are working with UI, For SkeletonGraphic, following code works.
public static class Utilities
{
public static void DOColor(SkeletonGraphic skeletonGraphic, Color endValue, float duration)
{
DOTween.To(() => skeletonGraphic.color,
newColor => { skeletonGraphic.color = newColor; },
endValue,
duration);
}
}
And then you can call like:
private SkeletonGraphic _skeletonGraphic;
private void Start()
{
_skeletonGraphic = spineAnimationParent.GetComponentInChildren<SkeletonGraphic>();
}
Utilities.DOColor(_skeletonGraphic, Color.grey, 0.5f);
It is important to NOT pass the color by value (i.e. _skeletonGraphic.color as input of DOColor function would be bad), because since you want to change the color inside of your class, you need to pass reach reference in Utilities.DOColor().

Related

(Unity) Is it possible to animate an object from a color back to it's original using an Animator?

The behavior I'm trying to get out of Unity's Animator looks like this in code:
Color animationColor = Color.red;
Color originalColor = GetComponent<Renderer>().material.GetColor("_Color");
//...
renderer.material.SetColor("_Color", Color.Lerp(animationColor, originalColor, timeElapsed/animationTime));
I have no problem getting the animator to Lerp between two set colors, but I would like to have destination color be the original color of the object. Can this be done with the Animation system?
I am not sure if it is possible just with the Animation System itself but you could just have a script attached which assigns a property named OriginalColor and have a function to return to this color when ever you want.
Such script could look like:
using UnityEngine;
using System.Collections;
public class ChangeColor : MonoBehaviour {
public Renderer Renderer;
public Color OriginalColor;
private bool _isOriginal
public bool DoLerp = false;
void Start() {
Renderer = GetComponent<Renderer>()
OriginalColor = Renderer .material.GetColor("_Color");
}
void Update() {
if(!DoLerp)
return;
// timeElepsed stuff
if(!isOriginal) {
renderer.material.SetColor(
"_Color",
Color.Lerp(
animationColor,
originalColor,
timeElapsed/animationTime
)
);
} else {
renderer.material.SetColor(
"_Color",
Color.Lerp(
originalColor,
animationColor,
timeElapsed/animationTime
)
);
}
// If timeElepsed = end time then set DoLerp to false
}
}

Unity renders object before updating Rigidbody2D's properties

I am trying to implement a way for the player to switch between a square and a circle. For this to work my player object has two colliders, one circle and one box. When switching between them I simply disable one collider and enable the other, and switch the current sprite. The issue arises when I switch from a circle to a square.
I want the square to be able to glide across the floor, whereas the circle is supposed to roll. In order to make the switch seamless I have to reorient the square to be aligned with the current velocity, and remove the angular velocity. This does seem to work, however there is a slight period of frames (or frame) where the square has the same rotation the circle had before switching. This seems odd to me since the new rotation and sprite is changed in the same part of the code. This is a video showcasing the issue.
If this is an issue resulting from the way the objects are rendered I can solve this another way. I would just like to understand why it happens.
Code snippet of the part that changes the properties from circle to square when switching:
else if (Input.GetKeyDown("2"))
{
// Update rotation of box to velocity:
float newAngleRadians = Mathf.Atan2(rb.velocity.y, rb.velocity.x);
float newAngleDegrees = newAngleRadians * 180 / Mathf.PI;
rb.rotation = newAngleDegrees;
rb.angularVelocity = 0;
Debug.Log(rb.rotation);
playerShape = Shape.SQUARE;
spriteRenderer.sprite = spriteArray[1];
circleCollider.enabled = false;
boxCollider.enabled = true;
updateShape = true;
}
Logging the angle of the rigidbody directly after setting it to newAngleDegrees shows that the rotation has been set correct, yet the issue persists.
And just in case it is needed, full code of the script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class scr_StateMachine : MonoBehaviour
{
// Types of shapes:
public enum Shape { SQUARE, CIRCLE, TRIANGLE }
// Variables:
public Rigidbody2D rb;
public SpriteRenderer spriteRenderer;
public Sprite[] spriteArray;
public Shape playerShape;
public CircleCollider2D circleCollider;
public BoxCollider2D boxCollider;
private bool updateShape;
void Start()
{
playerShape = Shape.CIRCLE;
updateShape = true;
}
void Update()
{
// Get input for shape change:
if(Input.GetKeyDown("1"))
{
playerShape = Shape.CIRCLE;
spriteRenderer.sprite = spriteArray[0];
circleCollider.enabled = true;
boxCollider.enabled = false;
updateShape = true;
}
else if (Input.GetKeyDown("2"))
{
// Update rotation of box to velocity:
float newAngleRadians = Mathf.Atan2(rb.velocity.y, rb.velocity.x);
float newAngleDegrees = newAngleRadians * 180 / Mathf.PI;
rb.rotation = newAngleDegrees;
rb.angularVelocity = 0;
Debug.Log(rb.rotation);
playerShape = Shape.SQUARE;
spriteRenderer.sprite = spriteArray[1];
circleCollider.enabled = false;
boxCollider.enabled = true;
updateShape = true;
}
// Update movement script's shape:
if (updateShape)
{
GetComponent<scr_Movement>().shape = playerShape;
updateShape = false;
}
}
}
I think the issue is Rigidbody/Rigidbody2D physics are applied in fixed time steps (see FixedUpdate). Therefore yes, on a strong device it can definitely happen that you render some frames before the next FixedUpdate call kicks in and changes the Rigidbody/Rigidbody2D behavior.
I think what you could do is actually wait with the change for the next FixedUpdate call e.g. using a Coroutine and WaitForFixedUpdate like e.g.
public class scr_StateMachine : MonoBehaviour
{
// Types of shapes:
public enum Shape { SQUARE, CIRCLE, TRIANGLE }
// Variables:
public Rigidbody2D rb;
public SpriteRenderer spriteRenderer;
public Sprite[] spriteArray;
public Shape playerShape;
public CircleCollider2D circleCollider;
public BoxCollider2D boxCollider;
[SerializeField] private scr_Movement _scrMovement;
void Start()
{
if(!_scrMovement) _scrMovement = GetComponent<scr_Movement>();
ChangeShape(Shape.CIRCLE);
}
// Still get User Input in Update
void Update()
{
// Get input for shape change:
if(Input.GetKeyDown("1"))
{
ChangeShape(Shape.CIRCLE);
}
else if (Input.GetKeyDown("2"))
{
ChangeShape(Shape.SQUARE);
}
}
private void ChangeShape(Shape newShape)
{
// if the same shape comes in we already have -> nothing to do
if(newShape == playerShape) return;
// Stop any already running coroutine since we only want to handle the last input before the FixUpdate call
// https://docs.unity3d.com/ScriptReference/MonoBehaviour.StopAllCoroutines.html
StopAllCoroutines();
// Start a new coroutine for the new shape
// see https://docs.unity3d.com/ScriptReference/MonoBehaviour.StartCoroutine.html
StartCoroutine(ChangeShapeInNextFixedUpdate(newShape));
}
private IEnumerator ChangeShapeInNextFixedUpdate(Shape newShape)
{
// just in case again, if the same shape comes in we already have -> nothing to do
if(newShape == playerShape) yield break;
// Wait until the next FixedUpdate call
// see https://docs.unity3d.com/ScriptReference/WaitForFixedUpdate.html
yield return new WaitForFixedUpdate();
// Now do your required changes depending on the new shape
circleCollider.enabled = newShape == Shape.CIRCLE;
boxCollider.enabled = newShape == Shape.SQUARE;
switch(newShape)
{
case Shape.CIRCLE:
spriteRenderer.sprite = spriteArray[0];
break;
case Shape.SQUARE:
// Update rotation of box to velocity:
var newAngleRadians = Mathf.Atan2(rb.velocity.y, rb.velocity.x);
// see https://docs.unity3d.com/ScriptReference/Mathf.Rad2Deg.html
var newAngleDegrees = newAngleRadians * Mathf.Rad2Deg;
rb.rotation = newAngleDegrees;
rb.angularVelocity = 0;
Debug.Log(rb.rotation);
spriteRenderer.sprite = spriteArray[1];
break;
}
playerShape = newShape;
_scrMovement.shape = playerShape;
}
}

Align variables horizontally in unity inspector

I'm writing a very simple class for storing data (at least, for now) for use in a Unity project to do with a learning AI. I want to be able to easily customize multiple agents in the inspector and the number of checkboxes stacked vertically makes this part of my project dominate the inspector. If I could simply have one section make use of the ample empty space on the right side of the inspector, that would be considerably less ugly.
I've been reading a lot about custom property drawers and inspector windows, but it seems like a lot of work, involving rewriting how the entire class is displayed, for one change.
For reference, here is the class itself.
[System.Serializable]
public class NNInfo
{
public string networkName = "Agent";
[Header("Movement Properties")]
public float movementSpeed = 10f;
public float rotationSpeed = 1f;
[Header("Learning Properties")]
public float learningRate = 0.1f;
public float momentum = 0f;
public Rewards rewardFunc;
public int[] hiddenLayers;
[Header("Other Properties")]
public int maxHealth = 1000;
[Header("Optional Inputs")]
public bool m_PointToNearestBall = false; // input which is 1 while the agent is facing a ball and -1 when facing away
public bool m_DistanceToNearestBall = false; // input which is 1 while the agent is at the ball and -1 when at max possible distance away
public bool m_PointToEndzone = false; // similar to m_PointToNearestBall but for the endzone
public bool m_Position = false; // two inputs which inform the player of its normalized x and y coordinates on the field
public bool m_WhetherHoldingBall = false; // tells the player whether its holding a ball
public bool m_CanSeeHealth = false; // Whether the player can know its own health
[Header("Optional Outputs")]
public bool m_ForwardLeft = false; // turn left and move forward simultaneously
public bool m_ForwardRight = false; // turn right and move forward simultaneously
public bool m_Reverse = false; // move backwards
public bool m_Flip = false; // instantly switch to opposite direction
public bool m_TurnToBall = false; // instantly turn to face nearest ball
public bool m_TurnToLeft = false; // instantly turn to face left side of field
public bool m_Attack = false; // attack a player (or idle if no contact)
}
Custom Property Drawer is keyword which should be interesting for you.
Writing your own code for managing those - lets you describe how you want to show your properties inside Inspector View in Unity editor.
To start, go to official documentation site, which contains code you can base on.
Code snippets (Javacrpt, c# version can be found under the link):
Object's code:
enum IngredientUnit { Spoon, Cup, Bowl, Piece }
// Custom serializable class
class Ingredient extends System.Object {
var name : String;
var amount : int = 1;
var unit : IngredientUnit;
}
var potionResult : Ingredient;
var potionIngredients : Ingredient[];
function Update () {
// Update logic here...
}
Editor code:
#CustomPropertyDrawer(Ingredient)
class IngredientDrawer extends PropertyDrawer {
// Draw the property inside the given rect
function OnGUI (position : Rect, property : SerializedProperty, label : GUIContent) {
// Using BeginProperty / EndProperty on the parent property means that
// prefab override logic works on the entire property.
EditorGUI.BeginProperty (position, label, property);
// Draw label
position = EditorGUI.PrefixLabel (position, GUIUtility.GetControlID (FocusType.Passive), label);
// Don't make child fields be indented
var indent = EditorGUI.indentLevel;
EditorGUI.indentLevel = 0;
// Calculate rects
var amountRect = new Rect (position.x, position.y, 30, position.height);
var unitRect = new Rect (position.x+35, position.y, 50, position.height);
var nameRect = new Rect (position.x+90, position.y, position.width-90, position.height);
// Draw fields - passs GUIContent.none to each so they are drawn without labels
EditorGUI.PropertyField (amountRect, property.FindPropertyRelative ("amount"), GUIContent.none);
EditorGUI.PropertyField (unitRect, property.FindPropertyRelative ("unit"), GUIContent.none);
EditorGUI.PropertyField (nameRect, property.FindPropertyRelative ("name"), GUIContent.none);
// Set indent back to what it was
EditorGUI.indentLevel = indent;
EditorGUI.EndProperty ();
}
}

How to do "highlighting" on gameObject

I'm making an block-like game and now I want to implement highlighting block (gameobject) while there is mouseOver that specific block.
I tried something like this (I'm not sure that this is best way to do this, but it's only one I got idea for):
#pragma strict
public class BlockSelecting extends MonoBehaviour {
public var hovering : boolean = false;
public var xpos : float;
public var ypos : float;
function Start () {
}
function Update () {
}
function OnMouseExit () {
hovering = false;
}
function OnMouseOver ()
{
hovering = true;
xpos = Input.mousePosition.x;
ypos = Input.mousePosition.y;
}
function OnGUI ()
{
GUI.DrawTexture(new Rect(xpos, xpos, 26, 26), (Resources.Load("highlight") as Texture2D));
}
}
This is not working, since Texture is not showing where mouse pointer is. Is there something I can't see or is this wrong way to do this? My highlight resource is just an 26x26 (block is 25x25) 2D texture of transparent rectangle, so it looks like it's highlighted...
P.S. My plan is to use hovering boolean to check if player is still hovering, if not texture should be deleted/hidden (any ideas on how to do this?).
lets say you want to change the color of the object that mouse is on to red so
you should use OnMouseEnter to check if mouse is on your object and OnMouseExit for when mouse exits the objects area and we set the it`s color back to its original color that was before changing it
private color tempColor;
void OnMouseEnter()
{
tempColor = renderer.material.color;
renderer.material.color = Color.red;
}
void OnMouseExit()
{
renderer.material.color = tempColor;
}

Filling a custom-shaped Clutter Actor with a Cairo-drawn canvas

Clutter 1.12
Cogl 1.10
Vala or C or Python.
I might have a fundamental misunderstanding here —
I think of "Actors" as 3D polygon things. I think of their colours as either vertex colors or as texture-mapping. In this light, I have been trying to draw a custom Actor and fill it with stuff drawn via Cairo. I'm not getting anywhere.
Code is included below (in Vala). Can anyone set me right about Clutter's basics (the docs just don't cut it) or, if I'm close, help me get that code working.
I expect to see a rounded rectangle with a smiley face within. What I'm seeing instead is the Cogl path fill covering* the face. I think the paint() is being done after the drawme()
*If you set the Clutter.Color to "#0001" in method paint(), you'll see this.
/*
Clutter Actor with custom paint() and filled with a Cairo-drawn texture.
(NOT yet working.)
Compile with:
valac \
--pkg clutter-1.0 \
--pkg cogl-1.0 \
somename.vala
*/
public class SmileyRect : Clutter.Actor {
//private vars
private Clutter.Canvas _canvas;
private bool _flip = false;
private int _w = 300;
private int _h = 300;
//Constructor
construct {
_canvas = new Clutter.Canvas();
_canvas.set_size( this._w, this._h );
this.set_size( this._w, this._h );
this.set_content( _canvas );
//Connect to the draw signal - this is as-per Clutter docs.
_canvas.draw.connect( drawme );
//Make it reactive and connect to the button-press-event
this.set_reactive( true );
this.button_press_event.connect( button_press );
}
/*
Button press signal handler.
Changes the colour of what will be painted on the canvas.
*/
private bool button_press ( Clutter.ButtonEvent evt ) {
this._flip = !this._flip; //Jiggle a value.
this.redraw(); // Forces re-run of the drawme() method.
return true; //all done with this signal.
}
//Common function to draw Cogl stuff - used in paint and pick.
private void draw_rr( Clutter.Color? color ) {
if (color != null ) { Cogl.set_source_color4ub(color.red,color.green,color.blue,color.alpha); }
Cogl.Path.round_rectangle( 0, 0, this._w, this._h, 15, 0.3f );
Cogl.Path.close();
// When from paint():
// Is there some way to fill this Cogl path with the contents
// of this._canvas? Or some other paradigm?
if (color != null ) { Cogl.Path.fill(); }
}
/* Some kind of freaky, this magic paint() thing.
Took me ages to get it running.
I want to draw a rounded rectangle as the basic shape
of this actor.
*/
public override void paint() {
stdout.printf("paint runs.\n");
// I did try a transparent color #0000 - just to see. No go.
// #000f - draws a black rounded rect *OVER* the Cairo canvas. It covers
// the smiley face.
this.draw_rr( Clutter.Color.from_string("#0000") );
}
/* I followed paint() example, but the argument was tricky.
I eventually found it from some PyClutter source code.
*/
public override void pick(Clutter.Color color) {
stdout.printf("pick runs.\n");
this.draw_rr( color );
}
/*
Draws the Cairo art to the canvas.
I want this art to be the bitmap/pixmap that *fills* the
basic rounded rectangle shape of this actor.
i.e I want the smile face cairo rectangle to be *within* the
polygon that is draw via Cogl in paint() method.
Does this even make sense?
*/
private bool drawme( Cairo.Context ctx, int width, int height) {
//Draw a rectangle
double[] col;
if (this._flip) {
col = {1f,0f,0f};
}
else {
col = {0f,1f,0f};
}
ctx.set_source_rgb( col[0], col[1], col[2] );
ctx.rectangle( 0, 0, width, height );
ctx.fill();
//Draw a smiley face.
// Aside: Been trying to avoid all the weird casting of the floats/doubles used below
// (see the generated c source.) Not at all sure what's going on there.
// Also not sure about that 'f' on the numbers. Where/when do I have to use it?
double pi = 3.14f;
double w = (double) width;
double h = (double) height;
ctx.set_line_width( 6f );
ctx.set_source_rgb( 0f, 0f, 0.8f );
//eyes
ctx.move_to( w/3f, h/3f );
ctx.rel_line_to( 0f, h/6f );
ctx.move_to( 2*(w/3f), h/3f );
ctx.rel_line_to( 0f, h/6f );
ctx.stroke();
ctx.set_source_rgb( 1f, 1f, 0f );
double rad = (w > h) ? h : w;
//face
ctx.arc( w/2f, h/2f, (rad/2f) - 20f,0f,2f * pi );
ctx.stroke();
//smile
ctx.arc( w/2f, h/2f, (rad/3f) -10f, pi/3f, 2f * (pi/3f) );
ctx.stroke();
return true;
}
//Redraw - forces invalidate which trips the draw event
public void redraw() {
this._canvas.invalidate();
}
} //end SmileyRect class
void main( string[] args ) {
Clutter.init(ref args);
var stage = new Clutter.Stage();
stage.set_size(400,400);
var rs = new SmileyRect();
stage.add_child(rs);
rs.redraw();
stage.destroy.connect(Clutter.main_quit);
stage.show();
Clutter.main();
}