I'm trying to do a fade between two colors on a weather system in C#. I'm using the following code to fade the color of the keys of a gradient used by the clouds:
void ChangeWeather(string to)
{
Gradient g = skyController.WispyColorGradientColor[0];
GradientColorKey[] gck = new GradientColorKey[5];
GradientAlphaKey[] gak = new GradientAlphaKey[2];
gak[0].alpha = 1f;
gak[1].alpha = 1f;
gak[0].time = 0f;
gak[1].time = 100f;
Color color = new Color();
skyController.WispyColorGradientColor[0] = g;
//Set the initial value
gck[0] = g.colorKeys[0];
gck[1] = g.colorKeys[1];
gck[2] = g.colorKeys[2];
gck[3] = g.colorKeys[3];
gck[4] = g.colorKeys[4];
//refer te variables
g.colorKeys[0] = gck[0];
g.colorKeys[1] = gck[1];
g.colorKeys[2] = gck[2];
g.colorKeys[3] = gck[3];
g.colorKeys[4] = gck[4];
//set the times
gck[0].time = .209f;
gck[1].time = .238f;
gck[2].time = .50f;
gck[3].time = .756f;
gck[4].time = .791f;
if (to == "clear")
{
ColorUtility.TryParseHtmlString(cleanCloudsColors[0], out color);
gck[0].color = Color.Lerp(g.colorKeys[0].color, color, changeSpeed * Time.deltaTime);
gck[4].color = Color.Lerp(g.colorKeys[4].color, color, changeSpeed * Time.deltaTime);
ColorUtility.TryParseHtmlString(cleanCloudsColors[1], out color);
gck[1].color = Color.Lerp(g.colorKeys[1].color, color, changeSpeed * Time.deltaTime);
gck[3].color = Color.Lerp(g.colorKeys[3].color, color, changeSpeed * Time.deltaTime);
ColorUtility.TryParseHtmlString(cleanCloudsColors[2], out color);
gck[2].color = Color.Lerp(g.colorKeys[2].color, color, changeSpeed * Time.deltaTime);
Debug.Log("Changing");
}
}
The "skyController.WispyColorGradientColor[0]" refers to a Gradient in a array list and "ColorUtility.TryParseHtmlString" just convert a hex color (like #fff) to RGB. It log "Changing" but, well, the clouds were changing color without fade, so I made these changes and it does not change more. I NEED THE FADE, but nothing seems to work. :(
EDIT: I used a code like it to try to fade between colors in 5 seconds:
float fadeTime = 5f;
void Update(){
//...
if (param)
StartCoroutine(fadeColor(0, Color.grey, Color.white));
//...
}
IEnumerator fadeColor (int index, Color from, Color to){
float counter = 0;
while (counter < fadeTime){
counter += Time.deltaTime;
gradient.colorKeys[index].color = Color.Lerp(from, to, counter / fadeTime);
}
yield return null;
}
It change the color, but change instantly and I want to change over time.
Not able to understand your code and but all I know is that you want to fade between two Colors. This should be done with Coroutine. The function below should fade between two colors in any GameObject. You can easily modify it to suit whatever you are doing.
The function call below will change the GameObject's color to red in 5 seconds.
StartCoroutine(fadeColor(obj, Color.red, 5));
Fade Function:
IEnumerator fadeColor(GameObject objectToFade, Color newColor, float fadeTime = 3)
{
int mode = 0;
Color currentColor = Color.clear;
SpriteRenderer tempSPRenderer = objectToFade.GetComponent<SpriteRenderer>();
Image tempImage = objectToFade.GetComponent<Image>();
RawImage tempRawImage = objectToFade.GetComponent<RawImage>();
Renderer tempRenderer = objectToFade.GetComponent<Renderer>();
//Check if this is a Sprite
if (tempSPRenderer != null)
{
currentColor = tempSPRenderer.color;
mode = 0;
}
//Check if Image
else if (tempImage != null)
{
currentColor = tempImage.color;
mode = 1;
}
//Check if RawImage
else if (tempRawImage != null)
{
currentColor = tempRawImage.color;
mode = 2;
}
//Check if 3D Object
else if (tempRenderer != null)
{
currentColor = tempRenderer.material.color;
mode = 3;
}
else
{
yield break;
}
float counter = 0;
while (counter < fadeTime)
{
counter += Time.deltaTime;
switch (mode)
{
case 0:
tempSPRenderer.color = Color.Lerp(currentColor, newColor, counter / fadeTime);
break;
case 1:
tempImage.color = Color.Lerp(currentColor, newColor, counter / fadeTime);
break;
case 2:
tempRawImage.color = Color.Lerp(currentColor, newColor, counter / fadeTime);
break;
case 3:
tempRenderer.material.color = Color.Lerp(currentColor, newColor, counter / fadeTime);
break;
}
yield return null;
}
}
Related
The default color now is mixed of colors with the default material :
I want that at runtime or before running the game if i set the mode to None set the whole linerenderer in red color :
I tried this but this coloring the linerenderer in white even if i set the color property to red :
IEnumerator SelectAnimation(AnimationType animType)
{
switch (animType)
{
case AnimationType.SingleColorMorph:
yield return RandomSingleColorMorphing(myLineRenderer, morphTime);
break;
case AnimationType.MultiColorMorph:
yield return RandomMultiColorMorphing(myLineRenderer, morphTime);
break;
case AnimationType.Shuffle:
yield return ShuffleGradient(myLineRenderer, .5f);
break;
case AnimationType.Shift:
yield return AnimateLoop(myLineRenderer);
break;
default:
yield return ggg(Color.red);
break;
}
}
private Color ggg(Color color)
{
Material whiteDiffuseMat = new Material(Shader.Find("Unlit/Texture"));
whiteDiffuseMat.color = Color.red;
myLineRenderer.material = whiteDiffuseMat;
return color;
}
I also tried inside the method ggg to set myLineRenderer startcolor and endcolor to red without changing the material but it didn't change anything.
I managed to solve this problem. Here I will explain how you can change the color of a two-point gradient, for example, but it is up to you to add the desired details. First you need to define a gradient with some key-point's, and since the gradient cannot be lerp into another gradient directly, you need to lerp its colors. A main hint is to display the gradient on the line renderer, you need a material that supports it. I used Particle/ Standard Unlit that work's fine.
Ok Here I setup the lineRenderer with a two-point red and blue gradient (for e.g):
private LineRenderer _lineRenderer;
void Start()
{
_lineRenderer = GetComponent<LineRenderer>();
// how to create gradient in script?
var gradient = new Gradient();
gradient.mode = GradientMode.Blend;
var gradientColorKeys = new GradientColorKey[2]
{
new GradientColorKey(Color.red, .2f),
new GradientColorKey(Color.blue, .8f)
};
var alphaKeys = new GradientAlphaKey[2]
{
new GradientAlphaKey(1f, .2f),
new GradientAlphaKey(1f, .8f)
};
gradient.SetKeys(gradientColorKeys, alphaKeys);
_lineRenderer.colorGradient = gradient;
// This enumerator changes color within a specified time
StartCoroutine(MorphToColor(Color.green, Color.magenta, 2f));
}
I also wrote a color change Enumarator in the same class that lerps the color of two specific points:
public IEnumerator MorphToColor(Color color1, Color color2, float morphTime = 1f)
{
Debug.Log("start morph");
var c1 = _lineRenderer.colorGradient.Evaluate(.2f);
var c2 = _lineRenderer.colorGradient.Evaluate(.8f);
var fade = 0f;
while (fade <= 1)
{
var gradient = new Gradient();
gradient.mode = GradientMode.Blend;
var gradientColorKeys = new GradientColorKey[2]
{
new GradientColorKey(Color.Lerp(c1, color1, fade), .2f),
new GradientColorKey(Color.Lerp(c2, color2, fade), .8f)
};
var alphaKeys = new GradientAlphaKey[2]
{
new GradientAlphaKey(1f, .2f),
new GradientAlphaKey(1f, .8f)
};
gradient.SetKeys(gradientColorKeys, alphaKeys);
_lineRenderer.colorGradient = gradient;
yield return new WaitForEndOfFrame();
fade += Time.deltaTime/morphTime;
}
}
As you can see, the result will be like this. I hope it be useful.
I copied the whole switch/case part to the Update to be able to change the modes also at runtime.
but I want also to be able to change the morphTime at runtime without the need to switch a mode first. for example if the enum mode is now MultiColorMorph and then if i'm changing only the morphTime then affect the change on the current mode.
I'm not sure about the other modes but the two modes that use the morphTime are :
RandomSingleColorMorphing and RandomMultiColorMorphing
IEnumerator RandomSingleColorMorphing(LineRenderer lineRendererToChange, float timeToMorph)
{
float time = 0;
Color initialColor = lineRendererToChange.colorGradient.colorKeys[0].color;
//this reduces colorkey amount to 2 just in case.
SetSingleColor2(lineRendererToChange, initialColor);
while (true)
{
initialColor = lineRendererToChange.colorGradient.colorKeys[0].color;
Color targetColor = RandomColor();
time = 0;
while (time < timeToMorph)
{
time += Time.deltaTime;
float progress = time / timeToMorph;
Color currentColor = Color.Lerp(initialColor, targetColor, progress);
SetSingleColor(lineRendererToChange, currentColor);
yield return null;
}
yield return null;
}
}
And
IEnumerator RandomMultiColorMorphing(LineRenderer lineRendererToChange, float timeToMorph)
{
float time = 0;
while (true)
{
GradientColorKey[] initialColorKeys = lineRendererToChange.colorGradient.colorKeys;
GradientColorKey[] newColorKeys = GenerateRandomColorKeys(initialColorKeys);
time = 0;
while (time < timeToMorph)
{
time += Time.deltaTime;
float progress = time / timeToMorph;
GradientColorKey[] currentColorKeys = GradientColorKeyLerp(initialColorKeys, newColorKeys, progress);
Gradient tempGradient = lineRendererToChange.colorGradient;
tempGradient.colorKeys = currentColorKeys;
lineRendererToChange.colorGradient = tempGradient;
yield return null;
}
yield return null;
}
}
The full code :
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[RequireComponent(typeof(LineRenderer))]
public class LineRendererColors : MonoBehaviour
{
public enum AnimationType { None, SingleColorMorph, MultiColorMorph, Shuffle, Shift };
public AnimationType myAnimationType;
LineRenderer myLineRenderer;
public float morphTime;
void Start()
{
myLineRenderer = this.GetComponent<LineRenderer>();
switch (myAnimationType)
{
case AnimationType.SingleColorMorph:
StartCoroutine(RandomSingleColorMorphing(myLineRenderer, morphTime));
break;
case AnimationType.MultiColorMorph:
StartCoroutine(RandomMultiColorMorphing(myLineRenderer, morphTime));
break;
case AnimationType.Shuffle:
StartCoroutine(ShuffleGradient(myLineRenderer, .5f));
break;
case AnimationType.Shift:
StartCoroutine(AnimateLoop(myLineRenderer));
break;
}
}
private void Update()
{
switch (myAnimationType)
{
case AnimationType.SingleColorMorph:
StartCoroutine(RandomSingleColorMorphing(myLineRenderer, morphTime));
break;
case AnimationType.MultiColorMorph:
StartCoroutine(RandomMultiColorMorphing(myLineRenderer, morphTime));
break;
case AnimationType.Shuffle:
StartCoroutine(ShuffleGradient(myLineRenderer, .5f));
break;
case AnimationType.Shift:
StartCoroutine(AnimateLoop(myLineRenderer));
break;
}
}
void SetSingleColor(LineRenderer lineRendererToChange, Color newColor)
{
lineRendererToChange.startColor = newColor;
lineRendererToChange.endColor = newColor;
}
void SetSingleColor2(LineRenderer lineRendererToChange, Color newColor)
{
Gradient tempGradient = new Gradient();
GradientColorKey[] tempColorKeys = new GradientColorKey[2];
tempColorKeys[0] = new GradientColorKey(newColor, 0);
tempColorKeys[1] = new GradientColorKey(newColor, 1);
tempGradient.colorKeys = tempColorKeys;
lineRendererToChange.colorGradient = tempGradient;
}
void SetSingleColor3(LineRenderer lineRendererToChange, Color newColor)
{
Gradient tempGradient = lineRendererToChange.colorGradient;
GradientColorKey[] tempColorKeys = tempGradient.colorKeys;
for (int i = 0; i < tempColorKeys.Length; i++)
{
tempColorKeys[i].color = newColor;
}
tempGradient.colorKeys = tempColorKeys;
lineRendererToChange.colorGradient = tempGradient;
}
IEnumerator ShuffleGradient(LineRenderer targetLineRenderer, float waitTime)
{
while (true)
{
ShuffleGradient(targetLineRenderer);
yield return new WaitForSeconds(waitTime);
}
}
void ShuffleGradient(LineRenderer targetLineRenderer)
{
GradientColorKey[] newColorKeys = targetLineRenderer.colorGradient.colorKeys;
for (int i = 0; i < newColorKeys.Length; i++)
{
Color tempColor = newColorKeys[i].color;
int randomIndex = Random.Range(0, newColorKeys.Length - 1);
newColorKeys[i].color = newColorKeys[randomIndex].color;
newColorKeys[randomIndex].color = tempColor;
}
Gradient tempGradient = targetLineRenderer.colorGradient;
tempGradient.colorKeys = newColorKeys;
targetLineRenderer.colorGradient = tempGradient;
}
IEnumerator RandomMultiColorMorphing(LineRenderer lineRendererToChange, float timeToMorph)
{
float time = 0;
while (true)
{
GradientColorKey[] initialColorKeys = lineRendererToChange.colorGradient.colorKeys;
GradientColorKey[] newColorKeys = GenerateRandomColorKeys(initialColorKeys);
time = 0;
while (time < timeToMorph)
{
time += Time.deltaTime;
float progress = time / timeToMorph;
GradientColorKey[] currentColorKeys = GradientColorKeyLerp(initialColorKeys, newColorKeys, progress);
Gradient tempGradient = lineRendererToChange.colorGradient;
tempGradient.colorKeys = currentColorKeys;
lineRendererToChange.colorGradient = tempGradient;
yield return null;
}
yield return null;
}
}
GradientColorKey[] GradientColorKeyLerp(GradientColorKey[] initialColorKeys, GradientColorKey[] endColorKeys, float progress)
{
GradientColorKey[] newColorKeys = new GradientColorKey[initialColorKeys.Length];
for (int i = 0; i < newColorKeys.Length; i++)
{
newColorKeys[i].color = Color.Lerp(initialColorKeys[i].color, endColorKeys[i].color, progress);
newColorKeys[i].time = initialColorKeys[i].time;
}
return newColorKeys;
}
//assigns new color to each colorkey and uses Time from incomingColorKeys
GradientColorKey[] GenerateRandomColorKeys(GradientColorKey[] incomingColorKeys)
{
GradientColorKey[] newColorKeys = new GradientColorKey[incomingColorKeys.Length];
for (int i = 0; i < newColorKeys.Length; i++)
{
newColorKeys[i].color = RandomColor();
newColorKeys[i].time = incomingColorKeys[i].time;
}
return newColorKeys;
}
//asumes Single color, 2 colorkeys
IEnumerator RandomSingleColorMorphing(LineRenderer lineRendererToChange, float timeToMorph)
{
float time = 0;
Color initialColor = lineRendererToChange.colorGradient.colorKeys[0].color;
//this reduces colorkey amount to 2 just in case.
SetSingleColor2(lineRendererToChange, initialColor);
while (true)
{
initialColor = lineRendererToChange.colorGradient.colorKeys[0].color;
Color targetColor = RandomColor();
time = 0;
while (time < timeToMorph)
{
time += Time.deltaTime;
float progress = time / timeToMorph;
Color currentColor = Color.Lerp(initialColor, targetColor, progress);
SetSingleColor(lineRendererToChange, currentColor);
yield return null;
}
yield return null;
}
}
//Basically Color.Lerp?
Color ColorLerpMath(Color firstColor, Color secondColor, float progress)
{
Vector3 firstRGB = new Vector3(firstColor.r, firstColor.g, firstColor.b);
Vector3 secondRGB = new Vector3(secondColor.r, secondColor.g, secondColor.b);
Vector3 difference = secondRGB - firstRGB;
Vector3 lerpedRGB = firstRGB + (progress * difference);
return new Color(lerpedRGB.x, lerpedRGB.y, lerpedRGB.z);
}
Color RandomColor()
{
return new Color(Random.Range(0f, 1f), Random.Range(0f, 1f), Random.Range(0f, 1f));
}
//returns the gradient with a copy of the first key for intersection purposes.
Gradient AddInitialCopy(Gradient incomingGradient)
{
List<GradientColorKey> newColorKeys = new List<GradientColorKey>(incomingGradient.colorKeys);
Color interSectionColor = newColorKeys[0].color;
newColorKeys.Insert(0, new GradientColorKey(interSectionColor, 0));
Gradient newInitGradient = new Gradient();
newInitGradient.colorKeys = newColorKeys.ToArray();
return newInitGradient;
}
//remove first and last keys since they dont shift.
List<GradientColorKey> RemoveFirstAndLast(Gradient incomingGradient)
{
List<GradientColorKey> currentColorKeys = new List<GradientColorKey>(incomingGradient.colorKeys);
currentColorKeys.RemoveAt(currentColorKeys.Count - 1);
currentColorKeys.RemoveAt(0);
return currentColorKeys;
}
Color GetIntersectionColor(List<GradientColorKey> incomingKeys, int lowestIndex, int highestIndex)
{
Color firstColor = incomingKeys[lowestIndex].color;
Color lastColor = incomingKeys[highestIndex].color;
float distance = 1 - (incomingKeys[highestIndex].time - incomingKeys[lowestIndex].time);
float colorLerpAmount = (1f - incomingKeys[highestIndex].time) / distance; ;
Color newIntersectionColor = Color.Lerp(lastColor, firstColor, colorLerpAmount);
return newIntersectionColor;
}
//accepts max 7 colors, 1st and last should be at 0 and 1
IEnumerator AnimateLoop(LineRenderer lineRendererToChange, float movementPerTick = .001f)
{
lineRendererToChange.colorGradient = AddInitialCopy(lineRendererToChange.colorGradient);
while (true)
{
List<GradientColorKey> currentColorKeys = RemoveFirstAndLast(lineRendererToChange.colorGradient);
float highestTime = 0;
float lowestTime = 1;
int highestIndex = currentColorKeys.Count - 1;
int lowestIndex = 0;
//Move all inner ones.
for (int i = 0; i < currentColorKeys.Count; i++)
{
GradientColorKey tempColorKey = currentColorKeys[i];
float newTime = tempColorKey.time + movementPerTick;
if (newTime > 1)
{
newTime = newTime - 1;
}
tempColorKey.time = newTime;
currentColorKeys[i] = tempColorKey;
if (newTime < lowestTime)
{
lowestTime = newTime;
lowestIndex = i;
}
if (newTime > highestTime)
{
highestTime = newTime;
highestIndex = i;
}
}
Color newIntersectionColor = GetIntersectionColor(currentColorKeys, lowestIndex, highestIndex);
currentColorKeys.Insert(0, new GradientColorKey(newIntersectionColor, 0));
currentColorKeys.Add(new GradientColorKey(newIntersectionColor, 1));
Gradient tempGradient = lineRendererToChange.colorGradient;
tempGradient.colorKeys = currentColorKeys.ToArray();
lineRendererToChange.colorGradient = tempGradient;
yield return null;
}
}
void AssignGradient(LineRenderer targetLineRenderer, Gradient newGradient)
{
targetLineRenderer.colorGradient = newGradient;
}
void DrawTestLine()
{
Vector3 firstPos = new Vector3(-5, 0, 0);
Vector3 secondPos = new Vector3(5, 0, 0);
int resolution = 100;
myLineRenderer.positionCount = resolution;
myLineRenderer.SetPositions(MakeLine(firstPos, secondPos, 100));
}
//makes a line from point A to point B with resolution of size points
Vector3[] MakeLine(Vector3 initPos, Vector3 endPos, int points)
{
Vector3 difference = endPos - initPos;
Vector3[] newLine = new Vector3[points];
Vector3 differencePerPoint = difference / (float)(points - 1);
for (int i = 0; i < points; i++)
{
newLine[i] = initPos + (differencePerPoint * i);
}
return newLine;
}
}
Before 5.5 particle system variables could be accessed via ParticleSystem and were read/write. Now they're accessed via ParticleSystem.MainModule and thus a lot of code has become obsolete. The API Updater has not been able to fix most of the issues. I've read through the new documentation but I can't figure out how the new variable types are supposed to be used. For example in JetParticleEffect.cs this line causes a warning:
// set the original properties from the particle system
m_OriginalLifetime = m_System.startLifetime;
The warning states: 'ParticleSystem.startLifetime' is obsolete: 'startLifetime property is deprecated. Use main.startLifetime or main.startLifetimeMultiplier instead.'
I've tried the following:
m_OriginalLifetime = m_System.main.startLifetime;
// error: Cannot implicitly convert type 'UnityEngine.ParticleSystem.MinMaxCurve' to 'float'
I believe the answer has something to do with the minMaxCurve constant variables as this compiles:
m_OriginalLifetime = m_System.main.startLifetime.constant;
But there is almost no explaination in the docs. Can anyone shed some light on this?
Also, where do the new multipliers fit in? I assume where previously you could do this:
particle.startSize *= myMultiplier
... you should now do this?
particle.main.startSizeMultiplier = myMultiplier
particle.startLifetime:
First of all, what Unity did in Unity 5.5 was to add new futures to the ParticleSystem. They also exposed some ParticleSystem API that was hidden before.
ParticleSystem.MainModule.startLifetime is now a type of MinMaxCurve instead of float like ParticleSystem.startLifetime.
By doing this, you are now given more options such as modifying the startLifetime as a curve.
Reading or writing to ParticleSystem.MainModule.startLifetime depends on the value of ParticleSystem.MainModule.startLifetime.mode which is set through the Editor or via code.
The default value of ParticleSystem.MainModule.startLifetime.mode is ParticleSystemCurveMode.Constant
So your m_OriginalLifetime = m_System.main.startLifetime.constant; is fine.
If startLifetime is dynamically or randomly changed to another mode during run-time, then you will have to do something like this:
ParticleSystem m_System = GetComponent<ParticleSystem>();
ParticleSystem.MainModule main = m_System.main;
ParticleSystem.MinMaxCurve minMaxCurve = main.startLifetime;
if (minMaxCurve.mode == ParticleSystemCurveMode.Constant)
{
m_OriginalLifetime = m_System.main.startLifetime.constant;
}
else if (minMaxCurve.mode == ParticleSystemCurveMode.Curve)
{
AnimationCurve animCurveLifetime = m_System.main.startLifetime.curve;
}
...
particle.startSize:
The-same thing apply to particle.startSize.
The particle.startSize property is now m_System.main.startSize;
Although you can't do m_System.main.startSize.constant *= myMultiplier; because your old code was particle.startSize *= myMultiplier.
You need to get m_System.main.startSize, modify it then assign the modified m_System.main.startSize back to m_System.main.startSize.
particle.startSize *= myMultiplier should be:
ParticleSystem m_System = GetComponent<ParticleSystem>();
ParticleSystem.MainModule main = m_System.main;
ParticleSystem.MinMaxCurve minMaxCurve = main.startSize; //Get Size
minMaxCurve.constant *= myMultiplier; //Modify Size
main.startSize = minMaxCurve; //Assign the modified startSize back
Then, what are particle.main.startSizeMultiplier and particle.main.startSize used for?
This two variables can also be used to change startLifetime and startSize. It's main advantage is that it is very efficient. It does not not require that you make a copy of MinMaxCurve like we did above, in order to change startSize or startSizeMultiplier.
ParticleSystem m_System = GetComponent<ParticleSystem>();
ParticleSystem.MainModule main = m_System.main;
main.startSizeMultiplier = 5;
and
ParticleSystem m_System = GetComponent<ParticleSystem>();
ParticleSystem.MainModule main = m_System.main;
main.startLifetimeMultiplier = 8;
Use them if your ParticleSystem.MainModule.startLifetime.mode is constant. This will to change the overall lifetime multiplier or the the overall size multiplier efficiently.
Changing Color and Color Modes
Color:
There is an implicit operator that lets you use:
ParticleSystem.MainModule main = trailPartical.main;
main.startColor = Color.red;
but startColor is not actually type of Color. The startColor variable is now a type of ParticleSystem.MinMaxGradient.
This is how you should be changing the particle startColor:
//Create Color
ParticleSystem.MinMaxGradient color = new ParticleSystem.MinMaxGradient();
color.mode = ParticleSystemGradientMode.Color;
color.color = Color.red;
//Assign the color to your particle
ParticleSystem.MainModule main = trailPartical.main;
main.startColor = color;
Gradient:
public ParticleSystem particleSystem;
void Start()
{
//Create Gradient key
GradientColorKey[] gradientColorKey;
gradientColorKey = new GradientColorKey[3];
gradientColorKey[0].color = Color.red;
gradientColorKey[0].time = 0f;
gradientColorKey[1].color = Color.blue;
gradientColorKey[1].time = 0.5f;
gradientColorKey[2].color = Color.green;
gradientColorKey[2].time = 1f;
//Create Gradient alpha
GradientAlphaKey[] gradientAlphaKey;
gradientAlphaKey = new GradientAlphaKey[3];
gradientAlphaKey[0].alpha = 1.0f;
gradientAlphaKey[0].time = 0.0f;
gradientAlphaKey[1].alpha = 0.5f;
gradientAlphaKey[1].time = 0.5f;
gradientAlphaKey[2].alpha = 1f;
gradientAlphaKey[2].time = 1f;
//Create Gradient
Gradient gradient = new Gradient();
gradient.SetKeys(gradientColorKey, gradientAlphaKey);
//Create Color from Gradient
ParticleSystem.MinMaxGradient color = new ParticleSystem.MinMaxGradient();
color.mode = ParticleSystemGradientMode.Gradient;
color.gradient = gradient;
//Assign the color to particle
ParticleSystem.MainModule main = particleSystem.main;
main.startColor = color;
}
Random Between Two Colors:
//Create Color from Gradient
ParticleSystem.MinMaxGradient color = new ParticleSystem.MinMaxGradient();
color.mode = ParticleSystemGradientMode.TwoColors;
color.colorMin = Color.red;
color.colorMax = Color.green;
//Assign the color to the particle
ParticleSystem.MainModule main = particleSystem.main;
main.startColor = color;
Random Between Two Gradients:
public ParticleSystem particleSystem;
void Start()
{
//Create Gradient key Min
GradientColorKey[] gradientColorKeyMin;
gradientColorKeyMin = new GradientColorKey[3];
gradientColorKeyMin[0].color = Color.red;
gradientColorKeyMin[0].time = 0f;
gradientColorKeyMin[1].color = Color.blue;
gradientColorKeyMin[1].time = 0.5f;
gradientColorKeyMin[2].color = Color.green;
gradientColorKeyMin[2].time = 1f;
//Create Gradient alpha Min
GradientAlphaKey[] gradientAlphaKeyMin;
gradientAlphaKeyMin = new GradientAlphaKey[3];
gradientAlphaKeyMin[0].alpha = 1.0f;
gradientAlphaKeyMin[0].time = 0.0f;
gradientAlphaKeyMin[1].alpha = 0.5f;
gradientAlphaKeyMin[1].time = 0.5f;
gradientAlphaKeyMin[2].alpha = 1f;
gradientAlphaKeyMin[2].time = 1f;
//Create Gradient key Max
GradientColorKey[] gradientColorKeyMax;
gradientColorKeyMax = new GradientColorKey[3];
gradientColorKeyMax[0].color = Color.red;
gradientColorKeyMax[0].time = 0f;
gradientColorKeyMax[1].color = Color.blue;
gradientColorKeyMax[1].time = 0.5f;
gradientColorKeyMax[2].color = Color.green;
gradientColorKeyMax[2].time = 1f;
//Create Gradient alpha Max
GradientAlphaKey[] gradientAlphaKeyMax;
gradientAlphaKeyMax = new GradientAlphaKey[3];
gradientAlphaKeyMax[0].alpha = 1.0f;
gradientAlphaKeyMax[0].time = 0.0f;
gradientAlphaKeyMax[1].alpha = 0.5f;
gradientAlphaKeyMax[1].time = 0.5f;
gradientAlphaKeyMax[2].alpha = 1f;
gradientAlphaKeyMax[2].time = 1f;
//Create Gradient Min
Gradient gradientMin = new Gradient();
gradientMin.SetKeys(gradientColorKeyMin, gradientAlphaKeyMin);
//Create Gradient Max
Gradient gradientMax = new Gradient();
gradientMax.SetKeys(gradientColorKeyMax, gradientAlphaKeyMax);
//Create Color from Gradient
ParticleSystem.MinMaxGradient color = new ParticleSystem.MinMaxGradient();
color.mode = ParticleSystemGradientMode.TwoGradients;
color.gradientMin = gradientMin;
color.gradientMax = gradientMax;
//Assign the color to the particle
ParticleSystem.MainModule main = particleSystem.main;
main.startColor = color;
}
Random Color:
public ParticleSystem particleSystem;
void Start()
{
//Create Gradient key Min
GradientColorKey[] gradientColorKeyMin;
gradientColorKeyMin = new GradientColorKey[3];
gradientColorKeyMin[0].color = Color.red;
gradientColorKeyMin[0].time = 0f;
gradientColorKeyMin[1].color = Color.blue;
gradientColorKeyMin[1].time = 0.5f;
gradientColorKeyMin[2].color = Color.green;
gradientColorKeyMin[2].time = 1f;
//Create Gradient alpha Min
GradientAlphaKey[] gradientAlphaKeyMin;
gradientAlphaKeyMin = new GradientAlphaKey[3];
gradientAlphaKeyMin[0].alpha = 1.0f;
gradientAlphaKeyMin[0].time = 0.0f;
gradientAlphaKeyMin[1].alpha = 0.5f;
gradientAlphaKeyMin[1].time = 0.5f;
gradientAlphaKeyMin[2].alpha = 1f;
gradientAlphaKeyMin[2].time = 1f;
//Create Gradient key Max
GradientColorKey[] gradientColorKeyMax;
gradientColorKeyMax = new GradientColorKey[3];
gradientColorKeyMax[0].color = Color.red;
gradientColorKeyMax[0].time = 0f;
gradientColorKeyMax[1].color = Color.blue;
gradientColorKeyMax[1].time = 0.5f;
gradientColorKeyMax[2].color = Color.green;
gradientColorKeyMax[2].time = 1f;
//Create Gradient alpha Max
GradientAlphaKey[] gradientAlphaKeyMax;
gradientAlphaKeyMax = new GradientAlphaKey[3];
gradientAlphaKeyMax[0].alpha = 1.0f;
gradientAlphaKeyMax[0].time = 0.0f;
gradientAlphaKeyMax[1].alpha = 0.5f;
gradientAlphaKeyMax[1].time = 0.5f;
gradientAlphaKeyMax[2].alpha = 1f;
gradientAlphaKeyMax[2].time = 1f;
//Create Gradient Min
Gradient gradientMin = new Gradient();
gradientMin.SetKeys(gradientColorKeyMin, gradientAlphaKeyMin);
//Create Gradient Max
Gradient gradientMax = new Gradient();
gradientMax.SetKeys(gradientColorKeyMax, gradientAlphaKeyMax);
//Create Color from Gradient
ParticleSystem.MinMaxGradient color = new ParticleSystem.MinMaxGradient();
color.mode = ParticleSystemGradientMode.RandomColor;
color.gradientMin = gradientMin;
color.gradientMax = gradientMax;
//Assign the color to the particle
ParticleSystem.MainModule main = particleSystem.main;
main.startColor = color;
}
So I have a script that shoots an arrow when you click and drag, kinda like Angry Birds.
I want it to work with the 2D RigidBody and 2D collider but when I change the rigidbody.AddForce to rigidbody2D.AddForce, It doesn't work.
How can I fix this to work for 2D?
I also want the arrow to rotate in 2D space either up or down depending on where mouse is pulled back. When I try the mouse look script, it rotates it in the z axis (I think) and distorts the arrow. Any easy solution to fix this??
Thanks guys. I'm new to game making and I've been trying to figure this stuff out for like the last 10 hours. I need some pros to help!
Thanks!!!
Heres my script
using UnityEngine;
using System.Collections;
public class DragShotMover2 : MonoBehaviour {
public float maxDragLength = 2; // this is the base magnitude and the maximum length of the line drawn in the user interface
public float maxMultiplier = 5; // multiply the line length by this to allow for higher force values to be represented by shorter lines
public Vector3 dragPlaneNormal = Vector3.up; // a vector describing the orientation of the drag plan relative to world-space but centered on the target
public SnapDir snapDirection = SnapDir.away; // force is applied either toward or away from the mouse on release
public ForceMode forceTypeToApply = ForceMode.VelocityChange;
public bool overrideVelocity = true; // cancel the existing velocity before applying the new force
public bool pauseOnDrag = true; // causes the simulation to pause when the object is clicked and unpause when released
public Color noForceColor = Color.yellow; // color of the visualization helpers at force 0
public Color maxForceColor = Color.red; // color of the visualization helpers at maximum force
public enum SnapDir {toward, away}
private Vector3 forceVector;
private float magPercent = 0;
private bool mouseDragging = false;
private Vector3 mousePos3D;
private float dragDistance;
private Plane dragPlane;
private Ray mouseRay;
private GameObject dragZone;
private string shaderString = "Transparent/Diffuse";
private Material dzMat;
void Start (){
Color currentColor = noForceColor;
dzMat = new Material(Shader.Find(shaderString));
// create the dragzone visual helper
dragZone = new GameObject("dragZone_" + gameObject.name);
dragZone.AddComponent<MeshFilter>().mesh = MakeDiscMeshBrute(maxDragLength/4);
//dragZone.GetComponent.MeshFilter.
dragZone.AddComponent<MeshRenderer>();
dragZone.renderer.enabled = false;
dragZone.name = "dragZone_" + gameObject.name;
dragZone.transform.localScale = new Vector3(maxDragLength*2, 0.025f, maxDragLength*2);
dragZone.renderer.material = dzMat;
dragZone.renderer.material.color = currentColor * new Color(1,1,1,0.2f);
// create the dragplane
dragPlane = new Plane(dragPlaneNormal, transform.position);
// orient the drag plane
if (dragPlaneNormal != Vector3.zero) {
dragZone.transform.rotation = Quaternion.LookRotation(dragPlaneNormal) * new Quaternion(1, 0, 0, 1);
}
else Debug.LogError("Drag plane normal cannot be equal to Vector3.zero.");
//update the position of the dragzone
dragZone.transform.position = transform.position;
}
void OnMouseDown (){
mouseDragging = true;
if (pauseOnDrag) {
// pause the simulation
Time.timeScale = 0;
}
// update the dragplane
dragPlane = new Plane(dragPlaneNormal, transform.position);
// orient the drag plane
if (dragPlaneNormal != Vector3.zero) {
dragZone.transform.rotation = Quaternion.LookRotation(dragPlaneNormal) * new Quaternion(1, 0, 0, 1);
}
else Debug.LogError("Drag plane normal cannot be equal to Vector3.zero.");
//update the position of the dragzone
dragZone.transform.position = transform.position;
dragZone.renderer.enabled = true;
}
void OnMouseDrag (){
Color currentColor = noForceColor;
// update the plane if the target object has left it
if (dragPlane.GetDistanceToPoint(transform.position) != 0) {
// update dragplane by constructing a new one -- I should check this with a profiler
dragPlane = new Plane(dragPlaneNormal, transform.position);
}
// create a ray from the camera, through the mouse position in 3D space
mouseRay = Camera.main.ScreenPointToRay(Input.mousePosition);
// if mouseRay intersects with dragPlane
float intersectDist = 0.0f;
if (dragPlane.Raycast(mouseRay, out intersectDist)) {
// update the world space point for the mouse position on the dragPlane
mousePos3D = mouseRay.GetPoint(intersectDist);
// calculate the distance between the 3d mouse position and the object position
dragDistance = Mathf.Clamp((mousePos3D - transform.position).magnitude, 0, maxDragLength);
// calculate the force vector
if (dragDistance*maxMultiplier < 1) dragDistance = 0; // this is to allow for a "no move" buffer close to the object
forceVector = mousePos3D - transform.position;
forceVector.Normalize();
forceVector *= dragDistance * maxMultiplier;
// update color the color
// calculate the percentage value of current force magnitude out of maximum
magPercent = (dragDistance * maxMultiplier) / (maxDragLength * maxMultiplier);
// choose color based on how close magPercent is to either 0 or max
currentColor = noForceColor * (1-magPercent) + maxForceColor * magPercent;
// dragzone color
dragZone.renderer.material.color = currentColor * new Color(1,1,1,0.2f);
// draw the line
Debug.DrawRay(transform.position, forceVector / maxMultiplier, currentColor);
}
//update the position of the dragzone
dragZone.transform.position = transform.position;
}
void OnMouseUp (){
mouseDragging = false;
if (overrideVelocity) {
// cancel existing velocity
rigidbody.AddForce(-rigidbody.velocity, ForceMode.VelocityChange);
}
// add new force
int snapD = 1;
if (snapDirection == SnapDir.away) snapD = -1; // if snapdirection is "away" set the force to apply in the opposite direction
rigidbody.AddForce(snapD * forceVector, forceTypeToApply);
// cleanup
dragZone.renderer.enabled = false;
if (pauseOnDrag) {
// un-pause the simulation
Time.timeScale = 1;
}
}
void OnGUI (){
if (mouseDragging) {
Vector2 guiMouseCoord = GUIUtility.ScreenToGUIPoint(Input.mousePosition);
GUI.Box ( new Rect(guiMouseCoord.x-30, Screen.height-guiMouseCoord.y+15, 100, 20), "force: "+Mathf.Round((forceVector).magnitude));
}
}
Mesh MakeDiscMeshBrute ( float r ){
Mesh discMesh;
Vector3[] dmVerts = new Vector3[18];
Vector3[] dmNorms = new Vector3[18];
Vector2[] dmUVs = new Vector2[18];
int[] dmTris = new int[48];
int i = 0;
discMesh = new Mesh();
dmVerts[0] = new Vector3(0,0,0);
dmVerts[1] = new Vector3(0,0,r);
dmVerts[2] = new Vector3(1,0,1).normalized * r; // find the vector at the correct distance the hacky-hillbilly way!
dmVerts[3] = new Vector3(r,0,0);
dmVerts[4] = new Vector3(1,0,-1).normalized * r;
dmVerts[5] = new Vector3(0,0,-r);
dmVerts[6] = new Vector3(-1,0,-1).normalized * r;
dmVerts[7] = new Vector3(-r,0,0);
dmVerts[8] = new Vector3(-1,0,1).normalized * r;
// set the other side to the same points
for (i = 0; i<dmVerts.Length/2; i++) {
dmVerts[dmVerts.Length/2 + i] = dmVerts[i];
}
for (i = 0; i<dmNorms.Length; i++) {
if (i<dmNorms.Length/2) dmNorms[i] = Vector3.up; // set side one to face up
else dmNorms[i] = -Vector3.up; // set side two to face down
}
dmUVs[0] = new Vector2(0,0);
dmUVs[1] = new Vector2(0,r);
dmUVs[2] = new Vector2(1,1).normalized * r;;
dmUVs[3] = new Vector2(r,0);
dmUVs[4] = new Vector2(1,-1).normalized * r;;
dmUVs[5] = new Vector2(0,-r);
dmUVs[6] = new Vector2(-1,-1).normalized * r;;
dmUVs[7] = new Vector2(-r,0);
dmUVs[8] = new Vector2(-1,1).normalized * r;;
// set the other side to the same points
for (i = 0; i<dmUVs.Length/2; i++) {
dmUVs[dmUVs.Length/2 + i] = dmUVs[i];
}
dmTris[0] = 0;
dmTris[1] = 1;
dmTris[2] = 2;
dmTris[3] = 0;
dmTris[4] = 2;
dmTris[5] = 3;
dmTris[6] = 0;
dmTris[7] = 3;
dmTris[8] = 4;
dmTris[9] = 0;
dmTris[10] = 4;
dmTris[11] = 5;
dmTris[12] = 0;
dmTris[13] = 5;
dmTris[14] = 6;
dmTris[15] = 0;
dmTris[16] = 6;
dmTris[17] = 7;
dmTris[18] = 0;
dmTris[19] = 7;
dmTris[20] = 8;
dmTris[21] = 0;
dmTris[22] = 8;
dmTris[23] = 1;
// side two
dmTris[24] = 9;
dmTris[25] = 11;
dmTris[26] = 10;
dmTris[27] = 9;
dmTris[28] = 12;
dmTris[29] = 11;
dmTris[30] = 9;
dmTris[31] = 13;
dmTris[32] = 12;
dmTris[33] = 9;
dmTris[34] = 14;
dmTris[35] = 13;
dmTris[36] = 9;
dmTris[37] = 15;
dmTris[38] = 14;
dmTris[39] = 9;
dmTris[40] = 16;
dmTris[41] = 15;
dmTris[42] = 9;
dmTris[43] = 17;
dmTris[44] = 16;
dmTris[45] = 9;
dmTris[46] = 10;
dmTris[47] = 17;
discMesh.vertices = dmVerts;
discMesh.uv = dmUVs;
discMesh.normals = dmNorms;
discMesh.triangles = dmTris;
return discMesh;
}
}
If you want to keep using the 3D Rigidbody, I'd suggest just using RigidbodyConstraints, so you can lock the z (or whatever) axis/rotation, and it will perform exactly the same as a 2D platformer.
so i have drawn a few objects , circles squares or even lines. This is the code i use to draw the images:
Graphics surface = this.splitContainer1.Panel2.CreateGraphics();
Pen pen1 = new Pen(ColorR.BackColor, float.Parse(boxWidth.Text));
switch (currentObject)
{
case "line":
if (step == 1)
{
splitContainer1.Panel2.Focus();
one.X = e.X;
one.Y = e.Y;
boxX.Text = one.X.ToString();
boxY.Text = one.Y.ToString();
step = 2;
}
else
{
two.X = e.X;
two.Y = e.Y;
boxX2.Text = two.X.ToString();
boxY2.Text = two.Y.ToString();
surface.DrawLine(pen1, one, two);
step = 1;
}
break;
case "circle":
if (step == 1)
{
boxX.Text = e.X.ToString();
boxY.Text = e.Y.ToString();
step = 2;
}
else
{
int tempX = int.Parse(boxX.Text);
int tempY = int.Parse(boxY.Text);
int tempX2 = e.X;
int tempY2 = e.Y;
int sideX, sideY;
if (tempX > tempX2)
{
sideX = tempX - tempX2;
}
else
{
sideX = tempX2 - tempX;
}
if (tempY > tempY2)
{
sideY = tempY - tempY2;
}
else
{
sideY = tempY2 - tempY;
}
double tempRadius;
tempRadius = Math.Sqrt(sideX * sideX + sideY * sideY);
tempRadius *= 2;
bWidth.Text = bHeight.Text = Convert.ToInt32(tempRadius).ToString();
surface.DrawEllipse(
pen1,
int.Parse(boxX.Text) - int.Parse(bWidth.Text) / 2,
int.Parse(boxY.Text) - int.Parse(bHeight.Text) / 2,
float.Parse(bWidth.Text), float.Parse(bHeight.Text));
step = 1;
}
break;
case "square":
if (step == 1)
{
boxX.Text = e.X.ToString();
boxY.Text = e.Y.ToString();
step = 2;
}
else if (step == 2)
{
int tempX = e.X;
if (tempX > int.Parse(boxX.Text))
{
bWidth.Text = (tempX - int.Parse(boxX.Text)).ToString();
}
else
{
bWidth.Text = (int.Parse(boxX.Text) - tempX).ToString();
}
step = 3;
}
else
{
int tempY = e.Y;
if (tempY > int.Parse(boxY.Text))
{
bHeight.Text = (tempY - int.Parse(boxY.Text)).ToString();
}
else
{
bHeight.Text = (int.Parse(boxY.Text) - tempY).ToString();
}
surface.DrawRectangle(
pen1,
int.Parse(boxX.Text),
int.Parse(boxY.Text),
int.Parse(bWidth.Text),
int.Parse(bHeight.Text));
step = 1;
}
break;
}
So after I draw the images, I want to be able to select a figure and--for example--change the color or rotate it. But I cant seem to figure it out how to do it.
I suggest defining a base abstract shape class that has methods all shapes should provide, such as a method to draw itself on a graphics object, a method that says whether a point is within it / should could as selecting it, a method to rotate it by a given amount and a method to change the color.
Once you've got your shape class then you've got to work out how to fill in the methods for each derived shape. For drawing you've already got the code. For selecting it, that will be dependent on the shape. For something like a circle it's fairly easy, just calculate the distance between the center of the circle, and the point clicked, for something like a line it's harder as you don't want the user to have to click it exactly.
That leaves rotating and changing the colour. Changing the colour is easy, just have a Color property on the Shape class, then when you draw your shapes, use that colour to create a brush or pen.
As for rotation, take a look at Graphics.RotateTransform.
public abstract class Shape
{
public Color Color { get; set; }
public float Rotation { get; set; }
public Point Position { get; set; }
public Shape(Color color, float rotation, Point position)
{
Color = color;
Rotation = rotation;
Position = position;
}
public void ChangeRotation(float amount)
{
Rotation += amount;
}
public abstract void Draw(Graphics graphics);
public abstract bool WithinBounds(Point point);
}
public class Circle : Shape
{
public float Radius { get; set; }
public Circle(Color color, float rotation, Point position)
:base(color, rotation, position)
{
}
public override void Draw(Graphics graphics)
{
}
public override bool WithinBounds(Point point)
{
if (Math.Sqrt(Math.Pow(point.X - Position.X, 2) + Math.Pow(point.Y - Position.Y, 2)) <= Radius)
return true;
else
return false;
// Note, if statement could be removed to become the below:
//return Math.Sqrt(Math.Pow(point.X - Position.X, 2) + Math.Pow(point.Y - Position.Y, 2)) <= Radius;
}
}
Have a look at the RotateTransform method of the Graphics object. There is a TranslateTransform method too.