I'm trying to make use of the Blur effect but I'm getting an error reading that the the type or namespace cannot be found. Thanks in advance.
I'm new to unity so I apologize if this is an easy fix. Here is a screenshot of my code.
using UnityEngine;
using System.Collections;
using UnityStandardAssets.Characters.FirstPerson;
using UnityStandardAssets.ImageEffects;
using System;
using System.Reflection;
using Assets.SwimmingSystem.Scripts;
namespace Assets.SwimmingSystem.Scripts
{
public class Swim : MonoBehaviour
{
private FirstPersonController _firstPersonController;
private CharacterController _characterController;
private Blur _blur;
private Color _fogColorWater;
// Default settings on start
private float _defWalkspeed, _defJumpspeed, _defRunspeed, _defGravityMultiplier;
private FogMode _defFogMode;
private float _defFogDensity;
private Color _defFogColor;
private bool _defFogEnabled;
private Camera _camera;
private bool _isInWater = false;
private float _waterSurfacePosY = 0.0f;
public float _aboveWaterTolerance = 0.5f;
[Range(0.5f, 3.0f)]
public float _upDownSpeed = 1.0f;
// Use this for initialization
void Start()
{
_firstPersonController = GetComponent<FirstPersonController>();
_characterController = GetComponent<CharacterController>();
_fogColorWater = new Color(0.2f, 0.65f, 0.75f, 0.5f);
Transform fpChar = transform.FindChild("FirstPersonCharacter");
_blur = fpChar.GetComponent<Blur>();
_camera = fpChar.GetComponent<Camera>();
// Default values for FirstPersonController on start
_defWalkspeed = WalkSpeed;
_defRunspeed = RunSpeed;
_defJumpspeed = JumpSpeed;
_defGravityMultiplier = GravityMultiplier;
_defFogMode = RenderSettings.fogMode;
_defFogDensity = RenderSettings.fogDensity;
_defFogColor = RenderSettings.fogColor;
_defFogEnabled = RenderSettings.fog;
}
// Update is called once per frame
void Update()
{
// Set underwater rendering or default
if (IsUnderwater())
{
SetRenderDiving();
}
else
{
SetRenderDefault();
}
// Handle swimming
// 1. If camera underwater we dive
if (_isInWater)
{
if (IsUnderwater())
{
DoDiving();
}
else
{
// we are grounded and not underwater, we might walk as well
if (_characterController.isGrounded)
{
DoWalking();
}
else
{
// we are not grounded so we are swimming above the surface
HandleUpDownSwimMovement();
}
}
}
else
{
DoWalking();
}
}
// Check if we are underwater
private bool IsUnderwater()
{
return _camera.gameObject.transform.position.y < (_waterSurfacePosY);
}
// Let's walk
private void DoWalking()
{
StickToGroundForce = 10;
WalkSpeed = Mathf.Lerp(WalkSpeed, _defWalkspeed, Time.deltaTime * 3.0f);
RunSpeed = Mathf.Lerp(RunSpeed, _defRunspeed, Time.deltaTime * 3.0f);
JumpSpeed = _defJumpspeed;
GravityMultiplier = _defGravityMultiplier;
UserHeadBob = true;
}
// Let's dive
private void DoDiving()
{
WalkSpeed = 1.0f;
RunSpeed = 2.0f;
JumpSpeed = 0.0f;
UserHeadBob = false;
HandleUpDownSwimMovement();
}
private void HandleUpDownSwimMovement()
{
StickToGroundForce = 0.0f;
GravityMultiplier = 0.1f;
Vector3 mv = MoveDir;
if (Input.GetKey(KeyCode.E))
{
// go upwards
if (_camera.gameObject.transform.position.y < _waterSurfacePosY + _aboveWaterTolerance)
{
mv.y = _upDownSpeed;
}
}
else if (Input.GetKey(KeyCode.Q))
{
// go down
mv.y = -_upDownSpeed;
}
MoveDir = mv;
}
// Rendering when diving
private void SetRenderDiving()
{
RenderSettings.fog = true;
RenderSettings.fogColor = _fogColorWater;
RenderSettings.fogDensity = 0.1f;
RenderSettings.fogMode = FogMode.Exponential;
_blur.enabled = true;
}
// Rendering when above water
private void SetRenderDefault()
{
RenderSettings.fogColor = _defFogColor;
RenderSettings.fogDensity = _defFogDensity;
RenderSettings.fog = _defFogEnabled;
RenderSettings.fogMode = _defFogMode;
_blur.enabled = false;
}
public void OnTriggerEnter(Collider other)
{
if (LayerMask.LayerToName(other.gameObject.layer) == "Water")
{
// We enter the water... doesn't matter if we return from unserwater, we are still in the water
_isInWater = true;
Debug.Log("Water Trigger Enter : " + _isInWater);
}
}
public void OnTriggerExit(Collider other)
{
if (LayerMask.LayerToName(other.gameObject.layer) == "Water" && _isInWater)
{
// we are leaving the water, or are we under the sureface?
_waterSurfacePosY = other.transform.position.y;
float fpsPosY = this.transform.position.y;
if (fpsPosY > _waterSurfacePosY)
{
// ok we really left the water
_isInWater = false;
}
Debug.Log("Water Trigger Exit : " + _isInWater);
}
}
#region Properties by reflection
private Vector3 MoveDir
{
get
{
return (Vector3)ReflectionUtil.GetFieldValue(_firstPersonController, "m_MoveDir");
}
set
{
ReflectionUtil.SetFieldValue(_firstPersonController, "m_MoveDir", value);
}
}
public float WalkSpeed
{
get
{
return (float)ReflectionUtil.GetFieldValue(_firstPersonController, "m_WalkSpeed");
}
set
{
ReflectionUtil.SetFieldValue(_firstPersonController, "m_WalkSpeed", value);
}
}
public float RunSpeed
{
get
{
return (float)ReflectionUtil.GetFieldValue(_firstPersonController, "m_RunSpeed");
}
set
{
ReflectionUtil.SetFieldValue(_firstPersonController, "m_RunSpeed", value);
}
}
public float JumpSpeed
{
get
{
return (float)ReflectionUtil.GetFieldValue(_firstPersonController, "m_JumpSpeed");
}
set
{
ReflectionUtil.SetFieldValue(_firstPersonController, "m_JumpSpeed", value);
}
}
public float GravityMultiplier
{
get
{
return (float)ReflectionUtil.GetFieldValue(_firstPersonController, "m_GravityMultiplier");
}
set
{
ReflectionUtil.SetFieldValue(_firstPersonController, "m_GravityMultiplier", value);
}
}
public float StickToGroundForce
{
get
{
return (float)ReflectionUtil.GetFieldValue(_firstPersonController, "m_StickToGroundForce");
}
set
{
ReflectionUtil.SetFieldValue(_firstPersonController, "m_StickToGroundForce", value);
}
}
public bool UserHeadBob
{
get
{
return (bool)ReflectionUtil.GetFieldValue(_firstPersonController, "m_UseHeadBob");
}
set
{
ReflectionUtil.SetFieldValue(_firstPersonController, "m_UseHeadBob", value);
}
}
#endregion
}
}
Make sure you are using the pro version of unity to make use of ImageEffects feature.
"The Blur image effect blurs the rendered image in real-time.
As with the other image effects, this effect is only available in Unity Pro and you must have the Pro Standard Assets installed before it becomes available."
Taken from : https://docs.unity3d.com/462/Documentation/Manual/script-BlurEffect.html
Related
So I have Ctr C Ctr V an Interaction System from YT channel.
I have perfectly copied line by line But the only issue was that he was using the old input system and used KeyPressedDown and keyPressedUp to make 2 boolean's which change according what state is the keypressed, I tried to mimic it with new Input system by making it from a button to a Axis value which follows the logic of if its ClickedAxis>0.4 its true and ClockedAxis==0 false, as a quick press it worked so I was happy BUT here comes the bug
My if statement is Being Spammed Constantly like none stop. My statement basically say's that if the Interacting is true Do :
bool interacting;
If(interacting)
{
float HoldingDownTimer+=Time.DeltaTime;
if(HoldingDownTimer>=5)
{
//Do your task;
}
}
but When I run the statement For some reason it prints 0.0110823 values which are stuck at that range of number's no lower no higher, My theory is that its been spam called.
Here's the Script
If your interested for all the components the YT channel is this guy's VeryHotShark
using UnityEngine;
using NaughtyAttributes;
public class LocomotionScript : MonoBehaviour
{
#region Data
[BoxGroup("Animation Handling Data")]
Animator animator;
int isWalkingHash;
[SerializeField] bool movementPressed;
[BoxGroup("Input Handling Data")]
private CharacterController controller;
public MovementInput input;
Vector2 currentMovement;
[SerializeField] float speed = 1;
private Vector3 velocity;
private float gravity = -9.81f;
public Transform ground;
public float distanceToGround = 0.4f;
public LayerMask groundMask;
private Vector2 smoothinMovement;
private float smoothInputSpeed;
private Vector2 tempCurrentMovement;
private bool isGrounded;
public InteractionInputData interactionInput;
#endregion
private void Awake()
{
animator = GetComponent<Animator>();
input = new MovementInput();
controller = GetComponent<CharacterController>();
input.KeyBoard.ASWD.performed += ctx =>
{
currentMovement = ctx.ReadValue<Vector2>();
movementPressed = currentMovement.x != 0 || currentMovement.y != 0;
};
}
private void Start()
{
interactionInput.Reset();
}
void GetInteractionInputData()
{
interactionInput.InteractedClicked = input.KeyBoard.Interact.ReadValue<float>() > 0.1f;
interactionInput.InteractedReleased = input.KeyBoard.Interact.ReadValue<float>() == 0f;
}
private void Update()
{
LocoMotion();
Grav();
Interact();
GetInteractionInputData();
}
void Grav()
{
isGrounded = Physics.CheckSphere(ground.position, distanceToGround, groundMask);
if (isGrounded && velocity.y<0)
{
velocity.y = -2f;
}
velocity.y += gravity * Time.deltaTime;
controller.Move(velocity * Time.deltaTime);
}
void Interact()
{
}
void LocoMotion()
{
tempCurrentMovement=Vector2.SmoothDamp(tempCurrentMovement, currentMovement, ref smoothinMovement, smoothInputSpeed);
Vector3 movement = (tempCurrentMovement.y * transform.forward) + (tempCurrentMovement.x * transform.right);
WalkAnimation();
controller.Move(movement * speed * Time.deltaTime);
}
void WalkAnimation()
{
animator.SetBool("WalkingHush", movementPressed);
}
private void OnEnable()
{
input.KeyBoard.ASWD.Enable();
input.KeyBoard.Interact.Enable();
}
private void OnDisable()
{
input.KeyBoard.ASWD.Enable();
input.KeyBoard.Interact.Enable();
}
}
//
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
namespace th
{
public class InteractionController : MonoBehaviour
{
#region Variables
[Header("Data")]
public InteractionData interactionData;
public InteractionInputData interactionInputData;
[Space]
[Header("RaySetting's")]
public float rayDistance;
public float raySphereRadius;
public LayerMask interactableLayer;
#endregion
#region Private
private Camera m_cam;
private bool m_interacting;
private float m_holderTimer = 0.0f;
#endregion
#region BuildIn
private void Awake()
{
m_cam = FindObjectOfType<Camera>();
}
private void Update()
{
CheckForInteractable();
CheckForInteractableInput();
}
#endregion
#region Crafted Methodds
void CheckForInteractable()
{
Ray _ray = new Ray(m_cam.transform.position, m_cam.transform.forward);
RaycastHit _hitInfo;
bool _hitSomething = Physics.SphereCast(_ray, raySphereRadius, out _hitInfo,
rayDistance,interactableLayer);
if (_hitSomething)
{
InteractableBase _interactable = _hitInfo.transform.GetComponent<InteractableBase>();
if (_interactable != null)
{
if (interactionData.isEmpty())
{
interactionData.Interactable = _interactable;
}
else
{
if (!interactionData.IsSameInteractible(_interactable))
interactionData.Interactable = _interactable;
}
}
}
else
{
interactionData.ResetData();
}
Debug.DrawRay(_ray.origin, _ray.direction * rayDistance, _hitSomething ? Color.green : Color.red);
}
void CheckForInteractableInput()
{
if (interactionData.isEmpty())
{
return;
}
if (interactionInputData.InteractedClicked)
{
m_interacting = true;
m_holderTimer = 0f;
}
if (interactionInputData.InteractedReleased)
{
m_interacting = false;
m_holderTimer = 0f;
}
if (m_interacting)
{
if (!interactionData.Interactable.IsInteractible)
return;
if (interactionData.Interactable.HoldInteract)
{
m_holderTimer += Time.deltaTime;
Debug.Log(m_holderTimer);
if (m_holderTimer >= interactionData.Interactable.holdDuration)
{
interactionData.Interact();
m_interacting = false;
}
}
else
{
interactionData.Interact();
m_interacting = false;
}
}
}
#endregion
}
}
///
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace th
{
[CreateAssetMenu(fileName ="Interaction Data",menuName = "InteractionSystem/InteractionData")]
public class InteractionData : ScriptableObject
{
private InteractableBase m_interactible;
public InteractableBase Interactable
{
get => m_interactible;
set => m_interactible = value;
}
public void Interact()
{
m_interactible.OnInteract();
ResetData();
}
public bool IsSameInteractible(InteractableBase _newInteractible) => m_interactible == _newInteractible;
public bool isEmpty() => m_interactible == null;
public void ResetData()=> m_interactible = null;
}
}
//
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[CreateAssetMenu(fileName = "InteractionInputData", menuName = "InteractionSystem/InputData")]
public class InteractionInputData : ScriptableObject
{
private bool m_interactedClicked;
private bool m_interactRelease;
public bool InteractedClicked
{
get => m_interactedClicked;
set => m_interactedClicked = value;
}
public bool InteractedReleased
{
get => m_interactRelease;
set => m_interactRelease = value;
}
public void Reset()
{
m_interactedClicked = false;
m_interactRelease = false;
}
}
//
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace th
{
public interface IInteractible
{
float HoldDurration { get; }
bool HoldInteract { get; }
bool MultipleUse { get;}
bool IsInteractible { get; }
void OnInteract();
}
}
//
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace th{
public class InteractableBase : MonoBehaviour,IInteractible
{
#region Variables
[Header("Interactible Settings")]
public float holdDuration;
[Space]
public bool holdInteract;
public bool multipleUse;
public bool isInteractible;
#endregion
#region Properties
public float HoldDurration => holdDuration;
public bool HoldInteract => holdInteract;
public bool MultipleUse => multipleUse;
public bool IsInteractible => isInteractible;
#endregion
#region Methods
public void OnInteract()
{
Debug.Log("Interacted: " + gameObject.name);
}
#endregion
}
}
Well without parsing through your entire code:
once
HoldingDownTimer >= 5
is true you still keep adding more time in the next frame so the condition is still true in the next frame => you will keep calling it all the following frames as well.
You could introduce a flag somewhat like e.g.
private bool alreadyCalled;
and then
if(interacting)
{
if(!alreadyCalled)
{
HoldingDownTimer += Time.DeltaTime;
if(HoldingDownTimer >= 5)
{
alreadyCalled = true;
//Do your task;
}
}
}
else
{
alreadyCalled = false;
}
As far as I understood your code I think:
I found the issue in it actually you are checking if the 'm_holdTimer' >= 'holdDuration' then perform interaction and you are making it equal to 0 on click start and click end.
So it means if the player has continuously held the button then it will not reset 'm_holdTimer'... so it will continue to call the function recursively because player hasn't actually ended the click so there is not any single function which is reseting 'm_holdTimer' to 0. still if you didn't get my point just copy this function and paste it instead of your own and see if it works, if it do work then you can check the difference between line of code then you'll understand it for sure.
void CheckForInteractableInput()
{
if (interactionData.isEmpty())
{
return;
}
if (interactionInputData.InteractedClicked)
{
m_interacting = true;
m_holderTimer = 0f;
}
if (interactionInputData.InteractedReleased)
{
m_interacting = false;
m_holderTimer = 0f;
}
if (m_interacting)
{
if (!interactionData.Interactable.IsInteractible)
return;
if (interactionData.Interactable.HoldInteract)
{
m_holderTimer += Time.deltaTime;
Debug.Log(m_holderTimer);
if (m_holderTimer >= interactionData.Interactable.holdDuration)
{
m_holderTimer = 0f;
interactionData.Interact();
m_interacting = false;
}
}
else
{
interactionData.Interact();
m_interacting = false;
}
}
}
Hope it helps... Happy coding :)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Fading : MonoBehaviour
{
[Header("Fading")]
public List<GameObject> objectsToFade = new List<GameObject>();
public float duration;
public Coroutine fadeCoroutine;
public bool automatic = false;
public bool startFading = false;
[Header("Random")]
public bool randomObjects = false;
public bool randomDuration = false;
public bool faded = false;
private bool fadeInOut = false;
private bool coroutineIsRunning = false;
private List<Material> objectsToFadeMaterials = new List<Material>();
private bool randomOnce = false;
private Material randomMaterial;
private float originalDuration;
private void Start()
{
originalDuration = duration;
for (int i = 0; i < objectsToFade.Count; i++)
{
objectsToFadeMaterials.Add(objectsToFade[i].GetComponent<Renderer>().material);
}
}
private void Update()
{
if (startFading)
{
if (automatic)
{
if (!coroutineIsRunning)
{
Fade();
}
}
else
{
if (Input.GetKeyDown(KeyCode.G))
{
Fade();
}
}
}
}
private void Fade()
{
fadeInOut = !fadeInOut;
if (fadeCoroutine != null)
StopCoroutine(fadeCoroutine);
if(randomDuration)
{
duration = Random.Range(1, 20);
}
else
{
duration = originalDuration;
}
if (randomObjects && objectsToFade.Count > 1)
{
if (randomOnce == false)
{
randomMaterial = objectsToFadeMaterials[Random.Range(0, objectsToFadeMaterials.Count)];
randomOnce = true;
}
if (fadeInOut)
{
fadeCoroutine = StartCoroutine(FadeTo(randomMaterial, 0, duration));
}
else
{
fadeCoroutine = StartCoroutine(FadeTo(randomMaterial, 1, duration));
}
}
else
{
for (int i = 0; i < objectsToFadeMaterials.Count; i++)
{
if (fadeInOut)
{
fadeCoroutine = StartCoroutine(FadeTo(objectsToFadeMaterials[i], 0, duration));
}
else
{
fadeCoroutine = StartCoroutine(FadeTo(objectsToFadeMaterials[i], 1, duration));
}
}
}
}
public IEnumerator FadeTo(Material material, float targetOpacity, float duration)
{
Color color = material.color;
float startOpacity = color.a;
float t = 0;
coroutineIsRunning = true;
while (t < duration)
{
t += Time.deltaTime;
float blend = Mathf.Clamp01(t / duration);
color.a = Mathf.Lerp(startOpacity, targetOpacity, blend);
material.color = color;
if(t > duration)
{
coroutineIsRunning = false;
}
if(color.a == 1)
{
randomOnce = false;
}
if(color.a == 0)
{
faded = true;
}
yield return null;
}
}
}
I know that if the color.a is 0 then the object faded out finished then I set faded to true.
In the second script that is attached to a teleporter I want to start teleporting if the object faded out then teleport to the next teleporter and fade in back and so on.
This script is attached to each teleporter :
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
public class Teleport : MonoBehaviour
{
public Fading fading;
public List<GameObject> objectsToTeleport = new List<GameObject>();
//Start is called before the first frame update
void Start()
{
objectsToTeleport = GameObject.FindGameObjectsWithTag("ObjectToTeleport").ToList();
}
// Update is called once per frame
void Update()
{
}
private void OnTriggerEnter(Collider other)
{
StartCoroutine(fading.FadeTo(objectsToTeleport[0].GetComponent<Renderer>().material, 0, 2));
}
}
and this script is the teleporting script :
using System;
using System.Collections;
using System.Collections.Generic;
using System.Net.WebSockets;
using UnityEngine;
using UnityEngine.Scripting.APIUpdating;
public class Teleporting : MonoBehaviour
{
public List<ObjectToTeleport> objectsToTeleport;
public List<ObjectToTeleport> currentlyTeleportedObjects;
public List<GameObject> teleporters;
public float teleportingTime;
public float teleportingStartTime;
public bool startTeleporting = false;
public GameObject[] groups;
public bool loop = false;
public bool random = false;
public int teleportationsCount = 0;
[Serializable]
public class ObjectToTeleport
{
public GameObject teleportableObject;
public int teleportOrder;
}
public void Start()
{
StartTeleporting();
}
private void Update()
{
}
public void StartTeleporting()
{
if (startTeleporting)
{
if (teleporters.Count > 1 && objectsToTeleport.Count > 0)
{
InvokeRepeating("MoveTeleportableObjects", teleportingStartTime, teleportingTime);
}
}
}
private void MoveTeleportableObjects()
{
if (teleportationsCount < objectsToTeleport.Count)
currentlyTeleportedObjects.Add(objectsToTeleport[teleportationsCount]);
for (int i = 0; i < currentlyTeleportedObjects.Count; i++)
{
if (!loop)
{
MoveObjects(i);
}
else
{
MoveObjects(i);
}
}
teleportationsCount++;
}
private void MoveObjects(int i)
{
GameObject destinationTeleporter = teleporters[currentlyTeleportedObjects[i].teleportOrder];
currentlyTeleportedObjects[i].teleportableObject.transform.position = destinationTeleporter.transform.position;
if (currentlyTeleportedObjects[i].teleportOrder < teleporters.Count - 1)
{
currentlyTeleportedObjects[i].teleportOrder++;
}
else if (loop == true)
{
{
currentlyTeleportedObjects[i].teleportOrder = 0;
}
}
}
}
I need somehow a synchronization between the fading and the teleporting in the Teleport script.
But it seems a bit complicated.
The Fading script on it's own and the Teleporting script on it's own are working fine but making a synchronization between them is the problem.
Update :
What I tried :
In the Fading script I added two methods FadIn and FadeOut and calling the FadeOut in the Teleport script :
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Fading : MonoBehaviour
{
[Header("Fading")]
public List<GameObject> objectsToFade = new List<GameObject>();
public float duration;
public Coroutine fadeCoroutine;
public bool automatic = false;
public bool startFading = false;
[Header("Random")]
public bool randomObjects = false;
public bool randomDuration = false;
public bool faded = false;
private bool fadeInOut = false;
private bool coroutineIsRunning = false;
private List<Material> objectsToFadeMaterials = new List<Material>();
private bool randomOnce = false;
private Material randomMaterial;
private float originalDuration;
private void Start()
{
originalDuration = duration;
for (int i = 0; i < objectsToFade.Count; i++)
{
objectsToFadeMaterials.Add(objectsToFade[i].GetComponent<Renderer>().material);
}
}
private void Update()
{
if (startFading)
{
if (automatic)
{
if (!coroutineIsRunning)
{
Fade();
}
}
else
{
if (Input.GetKeyDown(KeyCode.G))
{
Fade();
}
}
}
}
private void Fade()
{
fadeInOut = !fadeInOut;
if (fadeCoroutine != null)
StopCoroutine(fadeCoroutine);
if(randomDuration)
{
duration = Random.Range(1, 20);
}
else
{
duration = originalDuration;
}
if (randomObjects && objectsToFade.Count > 1)
{
if (randomOnce == false)
{
randomMaterial = objectsToFadeMaterials[Random.Range(0, objectsToFadeMaterials.Count)];
randomOnce = true;
}
if (fadeInOut)
{
fadeCoroutine = StartCoroutine(FadeTo(randomMaterial, 0, duration));
}
else
{
fadeCoroutine = StartCoroutine(FadeTo(randomMaterial, 1, duration));
}
}
else
{
for (int i = 0; i < objectsToFadeMaterials.Count; i++)
{
if (fadeInOut)
{
fadeCoroutine = StartCoroutine(FadeTo(objectsToFadeMaterials[i], 0, duration));
}
else
{
fadeCoroutine = StartCoroutine(FadeTo(objectsToFadeMaterials[i], 1, duration));
}
}
}
}
private IEnumerator FadeTo(Material material, float targetOpacity, float duration)
{
Color color = material.color;
float startOpacity = color.a;
float t = 0;
coroutineIsRunning = true;
while (t < duration)
{
t += Time.deltaTime;
float blend = Mathf.Clamp01(t / duration);
color.a = Mathf.Lerp(startOpacity, targetOpacity, blend);
material.color = color;
if(t > duration)
{
coroutineIsRunning = false;
}
if(color.a == 1)
{
randomOnce = false;
}
yield return null;
}
}
public IEnumerator FadeIn(Material material, float duration)
{
StartCoroutine(FadeTo(material, 1, duration));
yield return new WaitForSeconds(duration);
}
public IEnumerator FadeOut(Material material, float duration)
{
StartCoroutine(FadeTo(material, 0, duration));
yield return new WaitForSeconds(duration);
}
}
In the Teleport script
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
public class Teleport : MonoBehaviour
{
public Fading fading;
public List<GameObject> objectsToTeleport = new List<GameObject>();
//Start is called before the first frame update
void Start()
{
objectsToTeleport = GameObject.FindGameObjectsWithTag("ObjectToTeleport").ToList();
}
// Update is called once per frame
void Update()
{
}
private void OnTriggerEnter(Collider other)
{
StartCoroutine(fading.FadeOut(objectsToTeleport[0].GetComponent<Renderer>().material, 3));
}
private void OnTriggerExit(Collider other)
{
}
}
How do I continue from here ? what should I do next ?
There are multiple ways.
Simply yield the routine
You already have both as Coroutines so you could wrap them in another Coroutine and yield return it instead of StartCoroutine (this is something you should do in FadeIn and FadeOut anyway!)
// If this returns IEnumerator Unity automatically runs it as Coroutine
private IEnumerator OnTriggerEnter(Collider other)
{
yield return fading.FadeOut(objectsToTeleport[0].GetComponent<Renderer>().material, 3));
// Something after fading finished
Debug.Log("Fade Out finished!");
}
You could of course as well have them separately like
private void OnTriggerEnter(Collider other)
{
StartCorouine (EnterRoutine(other));
}
private IEnumerator EnterRoutine ()
{
yield return fading.FadeOut(objectsToTeleport[0].GetComponent<Renderer>().material, 3));
// Something after fading finished
Debug.Log("Fade Out finished!");
}
Callback
Another way would be passing in a callback that is executed once the routine finishes like e.g.
private void OnTriggerEnter(Collider other)
{
StartCoroutine(fading.FadeOut(objectsToTeleport[0].GetComponent<Renderer>().material, 3, OnFadeOutFinished));
}
private void OnFadeOutFinished ()
{
Debug.Log("Fade Out finished!", this);
}
or using a lambda, especially helpful if you want to do something with the other reference
private void OnTriggerEnter(Collider other)
{
StartCoroutine(fading.FadeOut(objectsToTeleport[0].GetComponent<Renderer>().material, 3, () => {
Debug.Log("Fade Out finished!");
}));
}
and have it as parameter in your routine like
private IEnumerator FadeTo(Material material, float targetOpacity, float duration, Action callback)
{
Color color = material.color;
float startOpacity = color.a;
float t = 0;
coroutineIsRunning = true;
while (t < duration)
{
t += Time.deltaTime;
float blend = Mathf.Clamp01(t / duration);
color.a = Mathf.Lerp(startOpacity, targetOpacity, blend);
material.color = color;
if(t > duration)
{
coroutineIsRunning = false;
}
if(color.a == 1)
{
randomOnce = false;
}
yield return null;
}
callback?.Invoke();
}
public IEnumerator FadeIn(Material material, float duration, Action callback = null)
{
yield return FadeTo(material, 1, duration, callback));
}
public IEnumerator FadeOut(Material material, float duration, Action callback = null)
{
yield return FadeTo(material, 0, duration, callback));
}
There are a lot of ways you could do this, but I personally in this case would create new coroutines FadeIn and FadeOut, instead of directly calling the following:
fadeCoroutine = StartCoroutine(FadeTo(objectsToFadeMaterials[i], 0, duration));
Then, at the end of your FadeOut coroutine you can take some additional step(s) to trigger a teleport or whatever else you need to trigger. It looks like you don't want your Fading to hold a reference to your Teleporting, which is smart, so you could choose to fire an event instead that your Teleporting component can subscribe to.
I am working on a 2D, topdown, roguelike game but i got stuck when i tried to make a shooting system.
when i run it and press the arrow keys, the bullet spawns and points in the right direction. It juste doesn't move in any way.
This is my code and i hope someone can figure it out. Btw, everything is connected. The player and the bullet prefab.
using System.Collections;
using System.Linq;
using UnityEngine;
namespace Assets.Scripts
{
[RequireComponent(typeof(Player))]
public class PlayerShootController : ShootControllerBase
{
[SerializeField]
private int _numberOfBombs;
public int NumberofBombs
{
get { return _numberOfBombs; }
set { _numberOfBombs = value; }
}
[SerializeField]
private PlayerHeadController _headObject;
public PlayerHeadController HeadObject
{
get { return _headObject; }
set { _headObject = value; }
}
[SerializeField]
private Bomb _bombPrefab;
public Bomb BombPrefab
{
get { return _bombPrefab; }
set { _bombPrefab = value; }
}
public bool IsShooting { get; private set; }
private KeyCode _shootKey;
private Vector2 _shootDirection;
private Player _player;
public override void Start()
{
base.Start();
_player = GetComponent<Player>();
}
public override void Update()
{
base.Update();
if (IsShooting)
{
SetHeadDirection(_shootKey);
return;
}
if (InputHelpers.IsAnyKey(KeyCode.UpArrow, KeyCode.DownArrow, KeyCode.LeftArrow, KeyCode.RightArrow))
{
if (Input.GetKey(KeyCode.UpArrow))
{
_shootDirection = new Vector2(0, BulletSpeed);
_shootKey = KeyCode.UpArrow;
}
else if (Input.GetKey(KeyCode.DownArrow))
{
_shootDirection = new Vector2(0, -BulletSpeed);
_shootKey = KeyCode.DownArrow;
}
else if (Input.GetKey(KeyCode.LeftArrow))
{
_shootDirection = new Vector2(-BulletSpeed, 0);
_shootKey = KeyCode.LeftArrow;
}
else if (Input.GetKey(KeyCode.RightArrow))
{
_shootDirection = new Vector2(BulletSpeed, 0);
_shootKey = KeyCode.RightArrow;
}
StartCoroutine(Shoot());
}
if (NumberofBombs > 0 && InputHelpers.IsAnyKeyDown(KeyCode.LeftShift, KeyCode.RightShift, KeyCode.E))
{
var bomb = (Bomb) Instantiate(BombPrefab);
bomb.transform.position = transform.position;
NumberofBombs--;
}
}
IEnumerator Shoot()
{
IsShooting = true;
while (Input.GetKey(_shootKey))
{
var bullet = (Rigidbody2D)Instantiate(BulletPrefab);
bullet.GetComponent<BulletScript>().Shooter = transform.gameObject;
bullet.transform.position = transform.position;
if (_shootDirection.y > 0)
{
bullet.transform.Rotate(0, 0, -90);
}
else if (_shootDirection.y < 0)
{
bullet.transform.Rotate(0, 0, 90);
}
else if (_shootDirection.x > 0)
{
TransformHelpers.FlipX(bullet.gameObject);
}
bullet.AddForce(_shootDirection);
bullet.AddForce(_player.GetComponent<Rigidbody2D>().GetPointVelocity(_player.transform.position) * 0.02f);
if (ShootClips.Any())
{
var clipToPlay = ShootClips[Random.Range(0, ShootClips.Count)];
clipToPlay.pitch = Random.Range(MinShootPitch, MaxShootPitch);
clipToPlay.Play();
}
yield return new WaitForSeconds(ShootingSpeed);
}
IsShooting = false;
//Reset head flipping
if (_headObject.transform.localScale.x < 0)
{
TransformHelpers.FlipX(_headObject.gameObject);
}
}
private void SetHeadDirection(KeyCode shootKey)
{
switch (shootKey)
{
case KeyCode.UpArrow:
_headObject.SetHeadDirection(PlayerHeadController.HeadDirection.Up);
break;
case KeyCode.DownArrow:
_headObject.SetHeadDirection(PlayerHeadController.HeadDirection.Down);
break;
case KeyCode.LeftArrow:
_headObject.SetHeadDirection(PlayerHeadController.HeadDirection.Left);
break;
case KeyCode.RightArrow:
_headObject.SetHeadDirection(PlayerHeadController.HeadDirection.Right);
break;
}
}
}
}
try this:
bullet.AddForce(_shootDirection*moveSpeed*Time.deltaTime);
instead of this:
bullet.AddForce(_shootDirection);
bullet.AddForce(_player.GetComponent<Rigidbody2D>().GetPointVelocity(_player.transform.position) * 0.02f);
tweak the speed for desired result, and if you want the bullet to follow the player you will need to update the shoot direction every certain time with a couroutine
I'm creating a FPS game and I have the following issue:
Sometimes, when I shoot at the enemies the hit is not recognized, even if the player is shooting in front of them. However, when they attack the player, the hit is recognized normally.
They have a box collider and a rigidbody attached to them.
This script is attached to the player:
using System.Collections.Generic;
using UnityEngine;
public class DisparaArma : MonoBehaviour
{
private GerenciaArma gerenciaArma;
public float nDisparo = 15f;
private float TempoProximoDisparo;
public float damage = 20f;
private Animator ZoomCameraIn;
private bool zoomed;
private Camera Maincamera;
private GameObject mira;
// Start is called before the first frame update
void Start()
{
gerenciaArma = GetComponent<GerenciaArma>();
ZoomCameraIn = transform.Find(Tags.LOOK_ROOT).transform.Find(Tags.ZOOM_CAMERA).GetComponent<Animator>();
mira = GameObject.FindWithTag(Tags.MIRA);
Maincamera = Camera.main;
}
// Update is called once per frame
void Update()
{
Atira();
ZoomInAndOut();
}
void Atira()
{
if (Input.GetMouseButtonDown(0))
{
if(gerenciaArma.SelecionaArma().tipoBala == WeaponBulletType.BULLET)
{
gerenciaArma.SelecionaArma().AnimacaoTiro();
DisparaBala();
}
}
}
void ZoomInAndOut()
{
if (gerenciaArma.SelecionaArma().mira_tipo == TipoMira.AIM)
{
if (Input.GetMouseButtonDown(1))
{
ZoomCameraIn.Play(Animacoes.ZOOM_IN_ANIM);
// gerenciaArma.SelecionaArma().Aim(true);
mira.SetActive(false);
print("VaiZoom");
}
if (Input.GetMouseButtonUp(1))//
{
ZoomCameraIn.Play(Animacoes.ZOOM_OUT_ANIM);
//gerenciaArma.SelecionaArma().Aim(false);
mira.SetActive(true);
}
}
}
void DisparaBala()
{
RaycastHit hit;
if(Physics.Raycast(Maincamera.transform.position, Maincamera.transform.forward, out hit))
{
if (hit.transform.tag == Tags.ENEMY_TAG)
{
hit.transform.GetComponent<ScriptVida>().DanoAplicado(damage);
}
}
}
}
And this one is attached to the enemies:
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AI;
public class ScriptVida : MonoBehaviour
{
private IndioAnimações indio_Anim;
private NavMeshAgent navAgent;
private IndioController indio_Controller;
public float vida = 100f;
public bool is_Player, is_Cannibal, is_Tiger;
private bool morto;
// Start is called before the first frame update
void Awake()
{
if (is_Tiger || is_Cannibal)
{
indio_Anim = GetComponent<IndioAnimações>();
indio_Controller = GetComponent<IndioController>();
navAgent = GetComponent<NavMeshAgent>();
}
if (is_Player)
{
}
}
public void DanoAplicado(float damage)
{
if (morto)
return;
vida -= damage;
if (is_Player)
{
}
if (is_Tiger || is_Cannibal)
{
if (indio_Controller.EnemyState == EnemyState.PATROL)
{
indio_Controller.chase_Distance = 50f;
}
}
if (vida <= 0)
{
JogadorMorre();
morto = true;
print(vida);
}
}
void JogadorMorre()
{
if (is_Cannibal)//
{
GetComponent<Animator>().enabled = false;
GetComponent<BoxCollider>().isTrigger = false;
GetComponent<Rigidbody>().AddTorque(-transform.forward * 50f);
indio_Controller.enabled = false;
navAgent.enabled = false;
indio_Anim.enabled = false;
}
if (is_Tiger)
{
GetComponent<Animator>().enabled = false;
GetComponent<BoxCollider>().isTrigger = false;
GetComponent<Rigidbody>().AddTorque(-transform.forward * 50f);
indio_Controller.enabled = false;
navAgent.enabled = false;
indio_Anim.enabled = false;
}
if (is_Player)
{
GameObject[] enemies = GameObject.FindGameObjectsWithTag(Tags.ENEMY_TAG);
for (int i = 0; i < enemies.Length; i++)
{
enemies[i].GetComponent<IndioController>().enabled = false;
}
GetComponent<Movimentação>().enabled = false;
GetComponent<DisparaArma>().enabled = false;
GetComponent<GerenciaArma>().SelecionaArma().gameObject.SetActive(false);
}
if (tag == Tags.PLAYER_TAG)
{
Invoke("RestartGame", 3f);
}
else
{
Invoke("TurnOffGameObject", 3f);
}
}
void RestartGame()
{
UnityEngine.SceneManagement.SceneManager.LoadScene("Gameplay");
}
void TurnOffGameObject()
{
gameObject.SetActive(false);
}
}
I think the problem is related to the box collider.
How could I solve this guys?
I've just updated to the new Input System from 2.7 to 2.8.
How the new Input System works is you create an input actions asset by going to Create-> Input Actions
.
This creates an asset where actions can be mapped to keys. One then create a C# script from this asset and use it in their code. Which is what I did. I called the Asset MyInput.inputactions and the C# script is MyInput.cs
When you use the generated C# script this way you need to reference the asset in your script. However, after the update, it seems this is impossible to do from the editor. When I define a public MyInput variable in my class, like so:
public class ShapeMover: MonoBehaviour
{
public MyInput controls;
private float _lastFallTime;
private float _fallSpeed;
private ShapeSpawner _spawn;
private GameObject _shapeToMove;
private Transform _shapeToMoveTransform;
private bool _isGameOver;
private const float _leftRotationAngle = (float) -1.57079633;
private const float _rightRotationAngle = (float) 1.57079633;
}
It isn't exposed in the inspector:
And I get an obvious NullReferenceExceptionerror when I try to access the controls variable.
Am I doing something wrong?
How can I reference the asset from the inspector? I have tried adding [SerializeField] to the public declaration, it didn't help.
I was following this video and it worked fine until I updated to a newer Input System version.
For reference, this is the full ShapeMover class:
using System.Collections.Generic;
using System.Linq;
using UnityEditor;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
namespace _Scripts
{
public class ShapeMover : MonoBehaviour
{
[SerializeField]
public MyInput controls;
private float _lastFallTime;
private float _fallSpeed;
private ShapeSpawner _spawn;
private GameObject _shapeToMove;
private Transform _shapeToMoveTransform;
private bool _isGameOver;
private const float _leftRotationAngle = (float) -1.57079633;
private const float _rightRotationAngle = (float) 1.57079633;
private void Awake()
{
_spawn = FindObjectOfType<ShapeSpawner>();
_lastFallTime = 0f;
_fallSpeed = GameGrid.Instance.GetFallSpeed();
_isGameOver = false;
Debug.Log("Registering controls callbacks...");
controls.Player.Movement.performed += ctx => Movement(ctx.ReadValue<Vector2>(), true);
controls.Player.Drop.performed += ctx => Drop();
controls.Menu.Reset.performed += ctx => Restart();
controls.Menu.Pause.performed += ctx => PauseToggle();
SetShapeToMove();
}
private void Restart()
{
GameGrid.Instance.ResetGame();
_isGameOver = false;
SetShapeToMove();
}
private void PauseToggle()
{
Debug.Log("Got Pause input");
var currentPauseState = GameGrid.Instance.IsPaused;
//If not paused, will pause
if (!currentPauseState)
{
// controls.Player.Movement.Disable();
// controls.Player.Drop.Disable();
// controls.Player.Menu.Disable();
// controls.Player.Disable();
GameGrid.Instance.IsPaused = true;
}
else
{
// controls.Player.Movement.Enable();
// controls.Player.Drop.Enable();
// controls.Player.Menu.Enable();
// controls.Player.Enable();
GameGrid.Instance.IsPaused = false;
}
}
private void Drop()
{
// Debug.Log("Should Drop Shape!");
bool didMove = true;
while (didMove)
{
didMove = Movement(new Vector2(0, -1), false);
}
}
private bool Movement(Vector2 direction, bool isFromInput)
{
if (isFromInput)
{
Debug.Log($"Got input {direction.ToString()}");
}
//Disable movement controls when game is over.
if (_isGameOver)
{
return false;
}
var oldPosition = _shapeToMoveTransform.position;
var oldRotation = _shapeToMoveTransform.rotation;
// Transform[] children = _shapeToMoveTransform.Cast<Transform>().ToArray();
var didMove = true;
var didEndMovement = false;
GameGrid.Instance.RemoveShapeFromGrid(_shapeToMoveTransform);
if (direction.x < 0)
{
didMove = MoveLeft();
}
else if (direction.x > 0)
{
didMove = MoveRight();
}
else if (direction.y > 0)
{
didMove = RotateLeft();
}
else if (direction.y < 0)
{
didMove = MoveDown();
if (!didMove)
{
didEndMovement = true;
}
}
//If Shape didn't move, restore previous position.
if (!didMove)
{
_shapeToMoveTransform.position = oldPosition;
_shapeToMoveTransform.rotation = oldRotation;
}
GameGrid.Instance.AddShapeToGrid(_shapeToMoveTransform);
// Debug.Log($"Shape {_shapeToMove.name} Position after movement Did Move: {didMove.ToString()}");
// Transform[] children = _shapeToMoveTransform.Cast<Transform>().ToArray();
// var lowestChild = children.OrderBy(x => x.position.y).First();
// Debug.Log($"{lowestChild.position.ToString()}");
if (didEndMovement)
{
GameGrid.Instance.ClearRows(_shapeToMoveTransform);
_isGameOver = GameGrid.Instance.IsGameOver(_shapeToMoveTransform);
if (!_isGameOver)
{
SetShapeToMove();
}
}
return didMove;
}
private void SetShapeToMove()
{
_shapeToMove = _spawn.SpawnShape();
_shapeToMoveTransform = _shapeToMove.transform;
}
private void Update()
{
if (_isGameOver)
{
return;
}
if (GameGrid.Instance.IsPaused)
{
return;
}
var time = Time.time;
if (!(time - (_lastFallTime + _fallSpeed) > 0))
{
return;
}
Movement(new Vector2(0, -1), false);
_lastFallTime = time;
_fallSpeed = GameGrid.Instance.GetFallSpeed();
}
private bool MoveLeft()
{
_shapeToMoveTransform.position += Vector3.right;
return GameGrid.Instance.CanMove(_shapeToMoveTransform);
}
private bool MoveRight()
{
_shapeToMoveTransform.position += Vector3.left;
return GameGrid.Instance.CanMove(_shapeToMoveTransform);
}
private bool MoveDown()
{
_shapeToMoveTransform.position += Vector3.down;
return GameGrid.Instance.CanMove(_shapeToMoveTransform);
}
private bool RotateLeft()
{
_shapeToMoveTransform.Rotate(0, 0, -90);
// foreach (Transform child in _shapeToMoveTransform)
// {
// RotateTransform(child, _leftRotationAngle);
// }
return GameGrid.Instance.CanMove(_shapeToMoveTransform);
}
private void RotateTransform(Transform transformToRotate, float rotationAngleRadian)
{
var currentLocalPosition = transformToRotate.localPosition;
var currentX = currentLocalPosition.x;
var currentY = currentLocalPosition.y;
var rotatedX = currentX * Mathf.Cos(rotationAngleRadian) - currentY * Mathf.Sin(rotationAngleRadian);
var rotatedY = currentX * Mathf.Sin(rotationAngleRadian) + currentY * Mathf.Cos(rotationAngleRadian);
transformToRotate.localPosition = new Vector2(rotatedX, rotatedY);
// Debug.Log($"Position after rotation is: {transformToRotate.localPosition.ToString()}");
}
private bool RotateRight()
{
_shapeToMoveTransform.Rotate(0, 0, -90);
return GameGrid.Instance.CanMove(_shapeToMoveTransform);
}
private void OnEnable()
{
Debug.Log("Controls Enabled...");
controls.Enable();
}
// private void OnDisable()
// {
// Debug.Log("Controls Disabled...");
// controls.Disable();
// }
}
}
Just as you said, you can't reference the new generated input class anymore.
To make it works, i instantiated the class, and use the SetCallbacks method, like this :
private MyInput _inputs;
public void Awake()
{
_inputs = new MyInput();
}
Truth be told, i don't know if it's the intended way of using the input class, but it works.
EDIT :
Starting from the 2.8 preview, an interface is automatically generated. I can only recommend it, cause it's very easy to use, you just need to inherits from IYourActionsSetNameActions and add the callbacks. (Also, you have to enable / disable the actions set, but you should be able to do it in another script)
Here is a complete base example, using your naming :
public class ShapeMover : MonoBehaviour, MyInput.IPlayerActions
{
private MyInput _inputs;
public void Awake()
{
_inputs = new MyInput();
_inputs.Player.SetCallbacks(this);
}
public void OnEnable()
{
_inputs.Player.Enable();
}
public void OnDisable()
{
_inputs.Player.Disable();
}
public void OnMovement(InputAction.CallbackContext context)
{
Vector2 delta = context.ReadValue<Vector2>();
transform.position += new Vector3(delta.x, 0, delta.y);
}
public void OnDrop(InputAction.CallbackContext context)
{
//TODO
}
// ...
}