I have an animation in 4 PNG images. I want to have the frames played through over the course of 1/2 second in the order 1-2-3-4-2-1 with transparency transitions.
What I wrote was supposed to have the first frame appear immediately when the parent object holding the different sprites is generated, then have it turn transparent over 1/12 of a second while the second frame turns opaque, and so forth until the last frame ends its transparent-opaque-transparent cycle.
It's probably not the most efficient way, but I made a prefab of en empty object under which are placed the 6 sprite-frames, with each sprite given an individual script.
I'm posting the first three scripts as an example:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Frame1 : MonoBehaviour
{
private SpriteRenderer thisSprite;
private Color alpha;
private float timer;
// Start is called before the first frame update
void Start()
{
alpha.a = 255;
thisSprite.GetComponent<SpriteRenderer>().color = alpha;
}
// Update is called once per frame
void Update()
{
timer = timer + Time.deltaTime;
alpha.a -= timer * 3060;
thisSprite.GetComponent<SpriteRenderer>().color = alpha;
if (timer >= 1/12)
{
Destroy(gameObject);
}
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Frame2 : MonoBehaviour
{
private SpriteRenderer thisSprite;
private Color alpha;
private float timer;
private int direction;
// Start is called before the first frame update
void Start()
{
alpha.a = 0;
thisSprite.GetComponent<SpriteRenderer>().color = alpha;
}
// Update is called once per frame
void Update()
{
if (direction == 0)
{
timer = timer + Time.deltaTime;
alpha.a += timer * 3060;
thisSprite.GetComponent<SpriteRenderer>().color = alpha;
if (timer >= 1/12)
{
direction = 1;
}
}
if (direction == 1)
{
timer = timer - Time.deltaTime;
alpha.a += timer * 3060;
thisSprite.GetComponent<SpriteRenderer>().color = alpha;
if (timer >= 1/6)
{
Destroy(gameObject);
}
}
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Frame3 : MonoBehaviour
{
private SpriteRenderer thisSprite;
private Color alpha;
private float timer;
private int direction;
// Start is called before the first frame update
void Start()
{
alpha.a = 0;
thisSprite.GetComponent<SpriteRenderer>().color = alpha;
timer -= 1 / 12;
}
// Update is called once per frame
void Update()
{
if (direction == 0)
{
timer = timer + Time.deltaTime;
alpha.a += timer * 3060;
thisSprite.GetComponent<SpriteRenderer>().color = alpha;
if (timer >= 1 / 12)
{
direction = 1;
}
}
if (direction == 1)
{
timer = timer - Time.deltaTime;
alpha.a += timer * 3060;
thisSprite.GetComponent<SpriteRenderer>().color = alpha;
if (timer >= 1 / 6)
{
Destroy(gameObject);
}
}
}
}
They all seem to be visible the moment they are generated, and they don't fade away or even get destroyed at all. What is the issue?
Thanks.
As the comments suggest, using animations is a viable alternative. However, your code will not work simply because alpha accepts a value from 0 to 1 instead of 0 to 255.
So simply adjust your logic to fade from 1 down to 0 and you should see your fade transitions.
Related
So i need to disable 2 components which are scripts.
They both have the same name (RotateAround)
I wrote some code which will disable rotatearound 30 seconds after the Game starts running.
Here is the Code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.SceneManagement;
public class CompDel : MonoBehaviour
{
public Text TimeText;
public float Timer = 30;
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
Timer = Timer - 1 * Time.deltaTime;
if (Timer < 0)
{
this.GetComponent<RotateAround>().enabled=false;
};
if (Timer > -10)
{
TimeText.enabled = false;
};
if (Timer < 0)
{
TimeText.enabled = true;
};
if (Timer < -10)
{
int buildIndex = 1;
//Load the scene with a build index
SceneManager.LoadScene(buildIndex);
}
}
}
So how to edit this so i can disble both instances of the RotateAround Script
Here how you can do it find all object of type RotateAround put them in array and use foreach loop to disale it.
public Text TimeText;
public float Timer = 30;
// Update is called once per frame
void Update()
{
Timer = Timer - 1 * Time.deltaTime;
if (Timer < 0)
{
GetComponent();
TimeText.enabled = true;
}
if (Timer > -10)
{
TimeText.enabled = false;
}
if (Timer < -10)
{
int buildIndex = 1;
//Load the scene with a build index
SceneManager.LoadScene(buildIndex);
}
}
void GetComponent()
{
var array = FindObjectsOfType<RotateAround>();
foreach (var comp in array)
{
comp.enabled = false;
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.PlayerLoop;
public class ChangeShaders : MonoBehaviour
{
private int val;
// Start is called before the first frame update
void Start()
{
//StartCoroutine(EffectSliderChanger());
}
private void Update()
{
gameObject.GetComponent<Renderer>().material.SetFloat("Effect Slider", val);
Mathf.Lerp(-1, 1, Time.deltaTime);
}
/*IEnumerator EffectSliderChanger()
{
gameObject.GetComponent<Renderer>().material.SetFloat("Effect Slider", 1);
}*/
}
I want to change the effect value between -1 and 1 nonstop from -1 to 1 when it's getting to 1 back to -1 and so on.
I'm not sure how to do it and if to use StartCoroutine or to do it inside the Update.
You could use Mathf.PingPong for this
Material material;
// Adjust via Inspector
public float duration = 1;
private void Awake()
{
material = GetComponent<Renderer>().material;
}
void Update()
{
var currentValue = Mathf.Lerp(-1 , 1, Mathf.PingPong(Time.time / duration, 1));
material.SetFloat("Effect Slider", currentValue);
}
Alternatively you could also simply shift the range like
This will move between -1 and 1 using the result of PingPong as the interpolation factor which moves between 0 and 1 in the given duration.
Alternatively you could also directly shift the range of PingPong like
var currentValue = Mathf.PingPong(Time.time / duration, 2) - 1f;
Try this (I haven't tested it but it should work):
public class ChangeShaders : MonoBehaviour
{
private float fromValue = -1f;
private float toValue = 1f;
private float timeStep = 0f;
private float val = 0f;
private void Update()
{
gameObject.GetComponent<Renderer>().material.SetFloat("Effect Slider", val);
val = Mathf.Lerp(fromValue, toValue, timeStep);
timeStep += Time.deltaTime;
// If you want the values to go back and forth faster use the line below instead
// timeStep += 0.2f + Time.deltaTime;
if (timeStep >= 1f) {
float tempVal = toValue;
toValue = fromValue;
fromValue = tempVal;
timeStep = 0f;
}
}
}
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using UnityEditor;
using UnityEngine;
public class ShootBullets : MonoBehaviour
{
public float bulletDistance;
public bool automaticFire = false;
public float fireRate;
public Rigidbody bullet;
private float gunheat;
private bool shoot = false;
private GameObject bulletsParent;
private GameObject[] startpos;
// Start is called before the first frame update
void Start()
{
bulletsParent = GameObject.Find("Bullets");
startpos = GameObject.FindGameObjectsWithTag("Pod_Weapon");
}
void Fire()
{
for (int i = 0; i < startpos.Length; i++)
{
Rigidbody bulletClone = (Rigidbody)Instantiate(bullet, startpos[i].transform.position, startpos[i].transform.rotation, bulletsParent.transform);
bulletClone.velocity = transform.forward * bulletDistance;
// The bullet or any ammo/weapon should be on Y rotation = 0
Destroy(bulletClone.gameObject, 0.5f);
}
}
// Update is called once per frame
void Update()
{
if (automaticFire == false)
{
if (Input.GetMouseButtonDown(0))
{
Fire();
}
}
else
{
if (shoot == true)
{
Fire();
shoot = false;
}
}
if (gunheat > 0) gunheat -= Time.deltaTime;
if (gunheat <= 0)
{
shoot = true;
gunheat = fireRate;
}
}
}
I want to keep the distance like in this line :
bulletClone.velocity = transform.forward * bulletDistance;
but also to control the bullet speed. maybe it's a problem when using physics ?
my problem is that the bullets shot too fast.
the question is if it's possible to control the speed and keep the distance using physics ?
and does the function Fire should be called from Update or FixedUpdate ?
I meant something different with "over lifetime" but it doesn't matter. The speed is currently only set once so it is only dependent on the distance you shot the bullet from. Not the distance left to the target.
If you want to keep distance in the equation but decrease the result, have you thought about dividing the speed? IE add something like this
bulletClone.velocity = transform.forward * bulletDistance / 3;
you can also compare the speed to a maximum value and decide on which to pick IE
if(bulletDistance < 30)
{
bulletClone.velocity = transform.forward * bulletDistance;
}
else
{
bulletClone.velocity = transform.forward * 30
}
You can set the speed to anything you want.
I have 2 images (2 players), these will be refilled each time a player fires (working as a reload animation). Here is the code for the Reload class
using System.Collections;
using UnityEngine;
using System.Collections.Generic;
using UnityEngine.UI;
public class Timer : MonoBehaviour {
public Image fillImg1;
public Image fillImg2;
float timeAmt = 1;
float time;
void Start() {
// GameObject RC = GameObject.Find("ReloadCanvas");
fillImg2 = GetComponent<Image>();
time = timeAmt;
}
public void Update() {
if (Input.GetKeyDown("space"))
{
if (fillImg2 != null)
{
Debug.Log("Got to P2 Reload");
while (time > 0)
{
time -= Time.deltaTime;
fillImg2.fillAmount = time / timeAmt;
}
Debug.Log("Time reset - " + Time.deltaTime);
time = timeAmt;
}
else { Debug.Log("Fill Image 2 is null"); }
}
if (Input.GetKeyDown(KeyCode.LeftShift))
{
if (fillImg2 != null)
{
Debug.Log("Got to P1 Reload");
while (time > 0)
{
time -= Time.deltaTime;
fillImg1.fillAmount = time / timeAmt;
}
Debug.Log("Time reset - " + Time.deltaTime);
time = timeAmt;
}
else { Debug.Log("Fill Image 1 is null"); }
}
}
}
My problem is that even though i have the images filled in the canvas, the 'else if the images are null' check are being triggered.
Here is an image of the ReloadCanvas
The issue is that on Start() you are pointing your fillImg2 image to a null. When you use GetComponent<>() you are checking the component of a GameObject which your fillImg2 is already an image.
Remove fillImg2 = GetComponent<Image>(); from your Start method and it should no longer be null.
I am working on a 'Shield' script (sci-fi, not RPG, imagine a spaceship) that only becomes active once a collision has happened. I'm trying to achieve this by having the alpha value of the material be set to 0f - then once 'hit' going straight up to 1f and then lerping back down to 0f. Rinse, repeat. However i'm having a problem coming up with the timer element of the lerp. The timers i've looked at tend to involve the update method or do not allow me to use it in the lerp. This is my code so far:
using UnityEngine;
using System.Collections;
public class Shield : MonoBehaviour {
public int shieldHealth;
private SpriteRenderer sRend;
private float alpha = 0f;
void Start () {
shieldHealth = 10;
sRend = GetComponentInChildren<SpriteRenderer>();
}
void OnCollisionEnter2D (Collision2D other) {
shieldHealth --;
LerpAlphaOfShield ();
if(shieldHealth <= 0) {
Destroy(this.gameObject);
}
}
void LerpAlphaOfShield () {
float lerp = Mathf.SmoothStep(1.0f, 0.0f, /*missing timer*/);
alpha = Mathf.Lerp(0.0f, 1.0f, lerp);
sRend.material.color = new Color(1, 1, 1, alpha);
}
}
Now i've thought that the SmoothStep part may be unnecessary once I have a timer, however this part I found in another question that was originally a PingPong that allowed the alpha values to go back and forth: I was trying to get it to do it just once then, obviously, reset with a timer.
Thanks in advance for any advice!
SOLUTION
I finally came up with this to reset and trigger again every hit and turn the alpha values of the shield from 1 - 0 in 1 second. If anyone thinks this code that I have could be improved please let me know, I would be very interested!
using UnityEngine;
using System.Collections;
public class Shield : MonoBehaviour {
public int shieldHealth;
private SpriteRenderer sRend;
private float alpha = 0f;
private bool hasCollided = false;
private float timer = 1f;
void Start () {
shieldHealth = 10;
sRend = GetComponentInChildren<SpriteRenderer>();
}
void Update () {
timer -= Time.deltaTime;
if(timer >= 0.001) {
alpha = Mathf.Lerp(0.0f, 1.0f, timer);
sRend.material.color = new Color(1, 1, 1, alpha);
}
if (timer <= 0) {
hasCollided = false;
}
}
void OnCollisionEnter2D (Collision2D other) {
shieldHealth --;
hasCollided = true;
timer = 1f;
if(shieldHealth <= 0) {
Destroy(this.gameObject);
}
}
}
A possible solution is to do this:
public float lerpSpeed = 5f;
float currAlpha;
float goal = 0f;
void Update()
{
currAlpha = Mathf.Lerp(currAlpha, goal, lerpSpeed * Time.deltaTime;
sRend.material.color = new Color(1f, 1f, 1f, alpha);
if(1f - currAlpha > .001f)
{
goal = 0f;
}
}
And then in the OnCollisionEnter2D function set goal = 1f;
lerpSpeed is a variable you can play with to change how fast it lerps.