I am making a gunshot code for a zombie shooter, but for some reason whenever I fire more than once in the same time period as the other shot, they don't overlap? Is there any way I can make it so that they do? Also, it only plays occasionally when I wait
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class audioplay : MonoBehaviour
{
public AudioSource source;
public AudioClip clip;
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
if (Input.GetMouseButton(0))
{
source.PlayOneShot(clip);
}
}
}
You wouldn't want a shoot function without any cooldown, especially in update. Also check your audio file to see if has blank space in it, like the one I used:
I used Audacity to trim the audio file. (it's free and open source :D )
Code stuff:
using UnityEngine;
public class MyPlayAudio : MonoBehaviour {
public AudioSource audioSource;
public AudioClip audioClip;
public float shootCooldown; //change this according to how fast you want to shoot
private float currentShootCooldown;
void Update()
{
//if you are holding mouse button down and we are ready to shoot
if(Input.GetMouseButton(0) && currentShootCooldown <= 0)
{
Pewpew();
}
//make sure you are not changing the public value
currentShootCooldown -= Time.deltaTime;
}
public void Pewpew()
{
//code whatever gun is supposed to do, like dealing damage
//resets cooldown for pewpew
currentShootCooldown = shootCooldown;
//plays the audio
audioSource.PlayOneShot(audioClip);
}
}
I think .Play might be better if we are thinking about a gun. I don't know, try both and see which one is better for your needs
audioSource.clip = audioClip; //this is not necessary if your gun is only going to do 1 sound.
audioSource.Play();
`
If you want it to overlap, you could for example add that component to two different gameobjects in the scene, that way there will be one frame where the function is called twice. Since Update would run on two objects.
Related
I am trying to do when i destroy all boxes something happen.
My code is;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
public class destroy : MonoBehaviour
{
private string BALL_TAG = "ball";
public AudioClip coin;
public AudioSource src;
public float numBox = 120f;
public bool isDestroyed;
private void OnCollisionEnter2D(Collision2D collision)
{
if (collision.gameObject.CompareTag(BALL_TAG))
{
src.clip = coin;
src.Play();
Destroy(gameObject);
isDestroyed = true;
}
}
private void Update()
{
boxes();
}
public void boxes()
{
if(isDestroyed == true)
numBox -= 1f;
if(numBox == 119)
SceneManager.LoadScene("mainManu");
}
private IEnumerator Two()
{
yield return new WaitForSeconds(1f);
Destroy(gameObject);
}
}
But it doesn't work.
It is suppose to do when I broke 1 box it sends me to menu.
I think its problem in "numBox -= 1f;" because I don't know hot to make this.
I don't understand your code completely. So, I need to make some assumptions.
I think the Script is attached to the box and every box has this Script. I also think, that your player Shoots Ball. Those Balls have a collider with an ball tag.
There are multiple problems with your code.
The first one is, that your count variable, numBox, is saved in your destroy Script, which is placed on each box.
this means, that every Box is counting for itself.
You have to centralize this. There are multiple ways for doing this.
One way is to declare this variable as static(https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/static)
This is not best practice, but works.
A Better way is to have a Script on Your Player, which holds this number and every Box searches for this Script and change this number if it is destroyed.
The second big Problem is, that your are doing some really weird thing in your Update and the collision handling
First of all, you are setting isDestroyed to true. Then in your boxes method, which is called in every Frame, you are decrementing your numBox variable by one, if this is Destroyed is true.
So if your Box gets hit, you are decrementing every frame.
After that you are checking every frame if your numBox is 119
If so, you change the Scene.
This is the reason, why you are getting to your MainMenu after only one boy
This behaviour is very weird, because it is totally unnecessary. You can reduce your variable directly in in your OnCollisionEnter2D Method.
There are some little things, which can be improved.
When you are trying to play a Sound, you don't have to specify the AudioClip in code. You can assign this directly in Unity on the AudioSource Component via drag and drop. This makes your code simpler.
You are not calling the Two Coroutine. You've specified this Coroutine but don't call it.
//Script on Player
public class PlayerBoxDestroyManager:MonoBehaviour
{
public int StartBoxes = 120;
private int Boxes;
private void Start()
{
Boxes = StartBoxes;
}
public void DestroyBox()
{
//Reduce our Boxes count
//This is equal to Boxes -= 1
// Boxes = Boxes -1
Boxes--;
// If we have less or zero Boxes left, we End call our EndGame methode
if(Boxes <= 0)
{
EndGame();
}
}
private void EndGame()
{
// We change the Scene to the mainMenu
SceneManager.LoadScene("mainManu");
}
}
```
//Script on all Boxes
public class Box : MonoBehaviour
{
public string Balltag = "ball";
//Audio Source the Audio Clip has to be assigned in the Unity editor
public AudioSource Coin;
private void OnCollisionEnter2D(Collision2D collision)
{
//Check it colliding Object has the right Tag
if(collision.transform.tag == Balltag)
{
//Get the reference to the Player Script
PlayerBoxDestroyManager PBDM = FindObjectOfType<PlayerBoxDestroyManager>();
//We can now access the Destroy Box Methode
PBDM.DestroyBox();
//Play the sound
Coin.Play();
//If we destroy our Object now, the Sound would also be deletet.
//We want to hear the sound, so we have to wait, till the sound is finished.
StartCoroutine(WaitTillAudioIsFinished());
}
}
IEnumerator WaitTillAudioIsFinished()
{
//we wait till the sound is finished
while (Coin.isPlaying)
{
yield return null;
}
//if finished, we destroy the Gameobject
Destroy(gameObject);
}
}
I hope I helped you. If you have questions, feel free to ask.
And sorry for my English:)
First a screenshot of my Hierarchy :
Everything is inside a one scene name The :
The game start when Main Game is disabled. Inside Main Game sit all the game objects. The Main Menu and Game Manager are enabled.
When running the game first time, When the game start there is short animation of the player for 5 seconds. The player start from some rotating degrees on Z. Z = 50 when x and y both are 0. Then the player is rotating slowly over the Z to 0.
It's like the player is sleeping and awake up.
I'm using post processing stack by unity.
And here is the first problem. While the player is rotating on the Z and post processing effect is working if I press the Escape key it will bring me back to the Main Menu but then if I press the Escape key again it will start the game over again from the begin.
But if I'm waiting in my game for the player to finish rotating on the Z and the post processing effect is finished and then pressing on Escape it will bring the main menu and second time will resume the game from the same point.
I can't figure out why when the player is rotating and the post process is working the escape key make it start the game over again from the being ?
This is a screenshot of the game when start and after finish the rotating and the process stack :
Another problem I noticed now. After the game start using the post process and the player rotating finished if I press Escape it will go to main menu and escape again will be back to the game but for example in the second screenshot the conversation is not continue. It will return to the same point in the game but things not seems to continue like the conversation.
On the Back to main menu object I have a script attached to it :
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
public class BackToMainMenu : MonoBehaviour
{
private bool _isInMainMenu = false;
public GameObject mainGame;
public GameObject mainMenu;
void Update()
{
if (Input.GetKeyDown(KeyCode.Escape))
{
if (!_isInMainMenu)
{
// -- Code to freeze the game
mainGame.SetActive(false);
mainMenu.SetActive(true);
}
else
{
// -- Code to unfreeze the game
mainGame.SetActive(true);
mainMenu.SetActive(false);
}
_isInMainMenu = !_isInMainMenu;
}
}
}
On the Main Menu object under Main Menu I have attached this script :
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
public class MainMenu : MonoBehaviour
{
public GameObject mainGame;
public GameObject mainMenu;
public void PlayGame()
{
mainGame.SetActive(true);
mainMenu.SetActive(false);
}
public void QuitGame()
{
Application.Quit();
}
}
On the PLAY button I'm using this script method PlayGame from the MainMenu script.
In the Main Game object on the Player object attached to thew Player I have some scripts the controller :
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerController : MonoBehaviour
{
public float speed = 10.0f;
// Update is called once per frame
void Update()
{
float translatioin = Input.GetAxis("Vertical") * speed;
float straffe = Input.GetAxis("Horizontal") * speed;
translatioin *= Time.deltaTime;
straffe *= Time.deltaTime;
transform.Translate(straffe, 0, translatioin);
}
}
Player Lock Manager :
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerLockManager : MonoBehaviour
{
public PlayerCameraMouseLook playerCameraMouseLook;
public PlayerController playerController;
// Start is called before the first frame update
public void PlayerLockState(bool LockPlayer, bool LockPlayerCamera)
{
if (LockPlayer == true)
{
playerController.enabled = false;
}
else
{
playerController.enabled = true;
}
if (LockPlayerCamera == true)
{
playerCameraMouseLook.enabled = false;
}
else
{
playerCameraMouseLook.enabled = true;
}
}
}
And Mouse Lock State :
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MouseLockState : MonoBehaviour
{
public bool lockState = true;
private void Start()
{
LockState(lockState);
}
private void Update()
{
}
public void LockState(bool lockState)
{
if (lockState == false)
{
Cursor.visible = true;
Cursor.lockState = CursorLockMode.None;
}
else
{
Cursor.visible = false;
Cursor.lockState = CursorLockMode.Locked;
}
}
}
Under the Player as child I have the Player Camera object and attached to the Player Camera also some scripts :
Player Camera Mouse Look :
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerCameraMouseLook : MonoBehaviour
{
public float sensitivity = 5.0f;
public float smoothing = 2.0f;
private GameObject player;
private Vector2 mouseLook;
private Vector2 smoothV;
// Use this for initialization
void Start()
{
player = this.transform.parent.gameObject;
}
// Update is called once per frame
void Update()
{
var md = new Vector2(Input.GetAxisRaw("Mouse X"), Input.GetAxisRaw("Mouse Y"));
md = Vector2.Scale(md, new Vector2(sensitivity * smoothing, sensitivity * smoothing));
smoothV.x = Mathf.Lerp(smoothV.x, md.x, 1f / smoothing);
smoothV.y = Mathf.Lerp(smoothV.y, md.y, 1f / smoothing);
mouseLook += smoothV;
mouseLook.y = Mathf.Clamp(mouseLook.y, -90f, 90f);
transform.localRotation = Quaternion.AngleAxis(-mouseLook.y, Vector3.right);
player.transform.localRotation = Quaternion.AngleAxis(mouseLook.x, Vector3.up);
}
}
And Depth Of Field script :
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.PostProcessing;
public class DepthOfField : MonoBehaviour
{
public GameObject player;
public PostProcessingProfile postProcessingProfile;
public bool dephOfFieldFinished = false;
public PlayerLockManager playerLockManager;
private Animator playerAnimator;
private float clipLength;
// Start is called before the first frame update
void Start()
{
playerAnimator = player.GetComponent<Animator>();
AnimationClip[] clips = playerAnimator.runtimeAnimatorController.animationClips;
foreach (AnimationClip clip in clips)
{
clipLength = clip.length;
}
var depthOfField = postProcessingProfile.depthOfField.settings;
depthOfField.focalLength = 300;
StartCoroutine(changeValueOverTime(depthOfField.focalLength, 1, clipLength));
postProcessingProfile.depthOfField.settings = depthOfField;
}
IEnumerator changeValueOverTime(float fromVal, float toVal, float duration)
{
playerLockManager.PlayerLockState(true, true);
float counter = 0f;
while (counter < duration)
{
var dof = postProcessingProfile.depthOfField.settings;
if (Time.timeScale == 0)
counter += Time.unscaledDeltaTime;
else
counter += Time.deltaTime;
float val = Mathf.Lerp(fromVal, toVal, counter / duration);
dof.focalLength = val;
postProcessingProfile.depthOfField.settings = dof;
yield return null;
}
playerAnimator.enabled = false;
dephOfFieldFinished = true;
}
}
I have under Main Game also a object name Openning Scene and attached to it :
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class OpeningCutscene : MonoBehaviour
{
public NaviConversations naviConversation;
public DepthOfField dephOfField;
// Update is called once per frame
void Update()
{
if (dephOfField.dephOfFieldFinished == true)
{
naviConversation.PlayNaviConversation(0);
dephOfField.dephOfFieldFinished = false;
}
}
}
It's a bit long but everything is connected.
The game start with the main menu.
When clicking the PLAY button a new game start.
When a new game start the script Depth Of Field is in action using the post processing. Also I'm locking the player so the player will not be able to move either the mouse or the player it self.
When the depth of field script finished his work a conversation between Navi and the Player start. When a conversation is in action the player can move the mouse 360 degrees but cant move the player to any direction.
When the conversation ended the player can also move to any direction.
Problems :
When start a new game while the depth of field script is in work pressing escape will bring the main menu but pressing escape again will not resume the depth of field script but will start it all over again.
When waiting the conversation to end if not pressing escape until the conversation ended then when moving around and pressing escape it will bring the main menu and again will resume the game from the same point.
The problems is when the game is doing something like the depth of field it will start the game over again instead resuming or when in conversation in the middle the conversation will never continue.
The ides with the escape key is once to get to main menu and second to resume the game.
The PLAY button is what should only start a new game and not the escape key.
It's a bit long but everything is connected.
I can't see which objects you hooked up to mainGame and mainMenu in BackToMainMenu from your hierarchy, so I have some conjecture in here.
Sounds like you want Escape key to pause, and unpause, as well as bring up a menu, you want Play button in the menu to restart your game.
However, in both MainMenu and BackToMainMenu you use the same code:
mainGame.SetActive(true);
mainMenu.SetActive(false);
This just turns the objects on and off in the hierarchy. This means the first time you do one of these things, all objects turned on under the gameobject referenced by mainGame will run their Awake and Start methods, but not the second time. Also depending which objects are active (like I said I can't fully see what component is on what object and which objects are referenced by which serialized field) you might be able to introduce a state error on BackToMainMenu._isInMainMenu because that field isn't changed when you hit play. Here is a fantastic image showing execution timeline in Unity:
Monobehavior Timeline
In summary:
The second time you run the game DepthOfField won't call Start a second time. Instead try OnEnable.
The conversation and game logic is not shown in your post, but likely it also is initializing in Start and won't run a second time.
A bit of trickiness around Coroutines is likely to blame here. When DepthOfField starts it also starts a coroutine. That coroutine keeps going even if you set the gameobject inactive. So you run the game once, that coroutine starts, you turn the object off when you hit escape, the coroutine finishes, you hit play again, but DepthOfField.dephOfFieldFinished == true and your playerAnimator is disabled and won't enable again.
Also 5. This kind of behavior can be tricky and is usually dependent on what else you have going on in your scene. Since you have one scene with everything at once, you need to watch out for putting stuff in Awake and Start since this will only run once. Instead you can try a number of things, my favorite is usually to set up a singleton or static class that works as a state machine for the whole scene. It will call custom Initialize functions in your behaviors instead of using Awake and Start.
Keep references to your coroutines by doing things like:
private Coroutine depthOfFieldRoutineRef;
private OnEnable()
{
if (depthOfFieldRoutineRef != null)
{
StopCoroutine(depthOfFieldRoutineRef);
}
depthOfFieldRoutineRef =
StartCoroutine(changeValueOverTime
(depthOfField.focalLength, 1, clipLength));
// Don't forget to set depthOfFieldRoutineRef to null again at the end of routine!
}
For simple pausing behavior you can also try setting Time.timescale = 0; and back to 1 when you want play to resume.
Less a question than a set of problems, hopefully this set of solutions helps!
Tutorial on Awake and Start
Docs on Coroutines
Docs on Time.timescale
I'm trying to create a Unity 2018 1.4f1 project that will play a specific animation when a specific key is pressed and will play a copy of the animation if the same key is pressed while the first instance is still playing.
The idea is that the user can type a word and for every letter they input an animation is played to represent that letter.
I've tried using things like Animation.PlayQueued to queue up animations but to no success.
Here's what my basic code looks like (this is only trying to play an animation on a key press):
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class AnimateKey : MonoBehaviour
{
public Animator animator;
// Use this for initialization
void Start()
{
animator = GetComponent<Animator>();
}
// Update is called once per frame
void Update()
{
if (Input.GetKeyDown("1"))
{
animator.Play("Take1");
}
}
}
Any help would be greatly appreciated.
From this thread
You can check if an Animator already is in a certain state using GetCurrentAnimatorStateInfo and only make the call if IsName returns false:
if (!animator.GetCurrentAnimatorStateInfo(0).IsName("Take1"))
{
animator.Play("Take1");
}
Note: The parameter of GetCurrentAnimatorStateInfo is the layer index. So when you work with multiple layers you'll have to adopt that.
For multiple parallel Animations however you might want to checkout the Animation component maybe.
There you don't have to handle States but rather can simply start and stop AnimationClips. You would than do
public Animation animation;
private void Awake()
{
animation = GetComponent<Animation>();
}
private void Update()
{
if(!Input.GetKeyDown("1")) return;
if(animation.IsPlaying("Take1")) return;
animation.Play("Take1");
}
I have a beautifully simple script that displays a timer on Unity 5 UI. At a finish line the racer enters a trigger and the timer should stop. It doesn't. I get no errors it just keeps running like Forrest Gump! I plan to post timer results to a leaderboard if I could stop the timer. Here is my timer script:
using UnityEngine;
using UnityEngine.UI;
using System.Collections;
public class Timer : MonoBehaviour
{
public Text timerText;
private float startTime;
private bool finished = false;
// Use this for initialization
void Start () {
startTime = Time.time;
}
// Update is called once per frame
void Update () {
if(finished)
return;
float t = Time.time - startTime;
string minutes = ((int) t / 60).ToString();
string seconds = (t % 60).ToString("f2");
timerText.text = minutes + ":" + seconds;
}
public void finish()
{
finished = true;
timerText.color = Color.yellow;
}
}
On a triggered cube I haved placed the following script:
using UnityEngine;
using System.Collections;
public class WinBox : MonoBehaviour
{
private void onTriggerEnter(Collider other)
{
GameObject.Find("Green").SendMessage("Finish");
}
}
I've changed collision detection to continuous on the rigidbody to my it more sensitive with no luck. Made the cube thicker. Nope, it just keeps on ticking. The vehicle "Green" is in a indexed container/empty game object. It is a networked multiplayer game, so it should probably be rewritten to find the game object with the tag, player. Or somehow the first tagged game object to enter the trigger. I think the problem is 'Send Message' I've never worked with that. The text color change also didn't work, but that needs to be changed to enable confetti particles when the timer stops. Any assist would be greatly appreciated.
There are few problems in your code:
1.Your timer won't stop because the trigger callback function is not being called. The trigger callback function is not being called because onTriggerEnter is supposed to be OnTriggerEnter with the O capitalized.
When you fix this, make sure that the collider has IsTrigger property checked/enabled too.
2.Another problem is this line: GameObject.Find("Green").SendMessage("Finish");
You are calling a function called Finish but the actual name of your function is finish from the Timer class.
Finally, instead of doing GameObject.Find("Green"); in the OnTriggerEnter function, why not cache it in the Start function then re-use it? GameObject.Find is very expensive and doing it many times will slow down your game.
public class WinBox : MonoBehaviour
{
GameObject green;
void Start()
{
green = GameObject.Find("Green");
}
private void OnTriggerEnter(Collider other)
{
green.SendMessage("finish");
}
}
So, I am trying to make a cube move with the WSAD buttons and for some reason, even though I am not touching any buttons, it moves diagonally up and to the left. I am using Unity 4.5.1
Code:
using UnityEngine;
using System.Collections;
public class Movement : MonoBehaviour {
public float moveSpeed;
private Vector3 input;
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update () {
input = new Vector3(Input.GetAxis ("Horizontal"), 0, Input.GetAxis ("Vertical"));
print(input);
}
}
Your problem may be somewhere else, because the code seems just fine. If I were you, I'd try to take a look to this page. You might find the solution to this issue