Unity Script - VideoPlayer Doesn't Pause - c#

I have a really simple script where I have a video start playing in Unity on start, and then pause at a specific time in the movie:
public class PlayVideoScript : MonoBehaviour
{
public UnityEngine.Video.VideoPlayer videoPlayer;
// Start is called before the first frame update
void Start()
{
// Will attach a VideoPlayer to the main camera.
GameObject camera = GameObject.Find("Main Camera");
// VideoPlayer automatically targets the camera backplane when it is added
// to a camera object, no need to change videoPlayer.targetCamera.
videoPlayer = camera.AddComponent<UnityEngine.Video.VideoPlayer>();
// Play on awake defaults to true. Set it to false to avoid the url set
// below to auto-start playback since we're in Start().
videoPlayer.playOnAwake = false;
// By default, VideoPlayers added to a camera will use the far plane.
// Let's target the near plane instead.
videoPlayer.renderMode = UnityEngine.Video.VideoRenderMode.CameraNearPlane;
// This will cause our Scene to be visible through the video being played.
videoPlayer.targetCameraAlpha = 0.5F;
// Set the video to play. URL supports local absolute or relative paths.
// Here, using absolute.
videoPlayer.url = "Assets/Movie.mp4";
// Skip the first 100 frames.
videoPlayer.frame = 100;
// Restart from beginning when done.
videoPlayer.isLooping = false;
// Each time we reach the end, we slow down the playback by a factor of 10.
//videoPlayer.loopPointReached += EndReached;
// Start playback. This means the VideoPlayer may have to prepare (reserve
// resources, pre-load a few frames, etc.). To better control the delays
// associated with this preparation one can use videoPlayer.Prepare() along with
// its prepareCompleted event.
videoPlayer.Play();
}
// Update is called once per frame
void Update()
{
print(videoPlayer.time);
print(videoPlayer.time);
if (videoPlayer.time == 15.0) {
print("paused;");
videoPlayer.Pause();
}
}
}
I can verify that I've reached the time I want in the Update function, but the videoPlayer doesn't pause at all. I'm pretty new to Unity, so any help appreciated!

In your Update method, you check if the video reached exactly 15s.
The thing is, from one frame to another, you may go further than 15 and so never equal 15.
I will suggest you to do as the following :
void Update()
{
if (videoPlayer.time >= 15.0) {
print("paused;");
videoPlayer.Pause();
}
}

Related

In unity how i can i save a position of the object and make it return to that position?

I am trying to make a script that saves a moving object's position when a certain amount of time passes and then when i press a button i want that object to return to that saved position, but i don't have any idea on how to save the position of the object. can anyone help me with this?
As I understand the main challenge is that you do not want only one single position stored but rather a continuous storage of the positions up to 3 seconds ago.
So as I see it this means you would need to keep track of all frames positions within the last 3 seconds.
Not sure about performance - there might be way better solutions - but the most straight forward I came up with for now would be using a Queue<Vector3> (= first-in fist-out) and a simple initial delay of 3 seconds
The idea here is:
You have a Queue<Vector3> (= first-in / first-out) for the past frames positions
Each frame in Update you add the current transform.position to the end of the queue
You have an initial delay of 3 seconds - during this period you simply pile up positions into the Queue
Once this initial delay has passed, once a frame you pull out the first stored position (from 3 seconds ago) of the Queue and assign it to a field currentResetPostion
=> When you press your key the position from 3 seconds ago is always available in currentResetPostion. Then you reset and restart the position tracking
This could look somewhat like e.g.
[Header("Settings")]
[SerializeField] private float timeToTrackBack = 3f;
[SerializeField] private KeyCode keyToPressForReset = KeyCode.Space;
// keeps track of all frames positions
private readonly Queue<Vector3> previousPositions = new();
// The current valid position to reset to when pressing the button
private Vector3 currentResetPostion;
// Timer field for the initial delay
private float delayTimer;
// doing this in OnEnable so you could even decide to disable and enable this component rather then tracking always
private void OnEnable()
{
RestartTracking();
}
private void Update()
{
// was space pressed this frame?
if (Input.GetKeyDown(KeyCode.Space))
{
ResetPosition();
}
else
{
// otherwise pile up positions to be handled later on
TrackPosition();
// and handle the next position from the queue
HandleQueueDelayed();
}
}
private void HandleQueueDelayed()
{
// reduce the timer by the time passed since last frame
delayTimer -= Time.deltaTime;
// Only once the timer reached 0 we start to pull out the first stored position
// (from 3 seconds ago) once a frame
if (delayTimer <= 0 && previousPositions.Count > 0)
{
currentResetPostion = previousPositions.Dequeue();
}
}
private void TrackPosition()
{
previousPositions.Enqueue(transform.position);
}
private void ResetPosition()
{
// reset position
transform.position = currentResetPostion;
// and restart the tracking
RestartTracking();
}
private void RestartTracking()
{
// forget any remaining positions since we want to start a new fresh tracking
previousPositions.Clear();
// store the current positions as the reset fallback for the next 3 seconds
currentResetPostion = transform.position;
// restart the timer
delayTimer = timeToTrackBack;
}
You might of course want to extend this e.g. including the rotation or in case you are using a Rigidbody you would rather want to shift this into FixedUpdate and only go through Rigidbody.position and additionally reset the Rigidbody.velocity etc

Player unable to move after being teleported/transported Unity3d

I've been trying to fix this one bug in my code for over 7 hours now, upon being teleported, the movement controls cease to function, the mouse works fine, you can look around, but you can't move around.
I wanted to set up some simple code that would teleport the player to a "checkpoint" upon achieving a negative or null y level. I was doing this for a parkour based game, if the player fell off the platform they would have to start over, but after teleporting, it becomes impossible to move as I'm sure I have already said. My code is pretty simple:
public class Main : MonoBehaviour
{
float Fall;
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
Vector3 Checkpoint = new Vector3 (0,3,0);
GameObject Player = GameObject.FindGameObjectWithTag("Player");
Fall = GameObject.FindGameObjectWithTag("Player").transform.position.y;
if (Fall<-4)
{
Player.transform.position = Checkpoint;
}
}
}
You would think that this would just simply change the coordinates of the player, but I think this might be screwing with the FPSController script.
I am using Unity3d, with Standard Assets imported, All of the code is in C#.
Instead of checking the Y value of your character, I would instead place a death collider under the map. Make this a trigger and if the player touches this trigger, then teleport them back. Nothing with your code should screw with the FPS controller so it might be something else. I would also highly recommend not using a FindGameObjectWithTag in the Update() method as it is extremely expensive to use this every frame, especially twice. If you would rather keep the Update() Y component of the position check, please rewrite the code to something like this:
public class Main : MonoBehaviour
{
// assign this object of your player in the inspector - it stores the reference to reuse
// instead of grabbing it every frame
[SerializeField] private Transform playerTransform = null;
// make this a variable as it is not changing - might as well make this const too
private Vector3 checkpoint = new Vector3(0, 3, 0);
// constant value of what to check for in the Y
private const int FALL_Y_MARKER = -4;
// Update is called once per frame
void Update()
{
if (playerTransform.position.y < FALL_Y_MARKER)
{
playerTransform.position = checkpoint;
}
}
}
With your current code, there should be nothing breaking your input/movement, but with that said, we can not see your input/movement code. All the above snippet does is check if the Y component of the player objects position is below a certain value, and if it is, it sets the position to a new vector. Can you post a bit more movement code or somewhere else it can go wrong that you think is the issue?

Unity - C# - Power up a shot before firing

I'm trying to launch a projectile which is simple enough using the UI Button's onClick property but what I also want to allow the player to do is charge up their shot. I have it working on the keyboard by using Input.GetButton("Fire") then I add Fire to the input manager and for the key I choose space. But what I'm trying to do now is add the same functionality to a virtual button for touch screen players. The problem is onClick can't check if the button is continuously pressed it can only be called once. So for that I'm trying to use the IPointer Up and Down Handlers in the button's script like this:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
public class FireButton : MonoBehaviour, IPointerDownHandler, IPointerUpHandler
{
public bool buttonPressed;
public void OnPointerDown(PointerEventData eventData)
{
buttonPressed = true;
}
public void OnPointerUp(PointerEventData eventData)
{
buttonPressed = false;
}
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
}
}
The problem is there seems to be an infinite loop in my logic for the tank script. As soon as the Update() function is called and the if statement below for fire button.buttonPressed is true for some reason it loops there and doesn't continue. Here's the following code (I commented out the logic for the keyboard input):
using UnityEngine;
using UnityEngine.UI;
public class TankShooting : MonoBehaviour
{
public int m_PlayerNumber = 1; // Used to identify the different players.
public Rigidbody m_Shell; // Prefab of the shell.
public Transform m_FireTransform; // A child of the tank where the shells are spawned.
public Slider m_AimSlider; // A child of the tank that displays the current launch force.
public AudioSource m_ShootingAudio; // Reference to the audio source used to play the shooting audio. NB: different to the movement audio source.
public AudioClip m_ChargingClip; // Audio that plays when each shot is charging up.
public AudioClip m_FireClip; // Audio that plays when each shot is fired.
public float m_MinLaunchForce = 15f; // The force given to the shell if the fire button is not held.
public float m_MaxLaunchForce = 30f; // The force given to the shell if the fire button is held for the max charge time.
public float m_MaxChargeTime = 0.75f; // How long the shell can charge for before it is fired at max force.
FireButton firebutton;
private string m_FireButton; // The input axis that is used for launching shells.
private float m_CurrentLaunchForce; // The force that will be given to the shell when the fire button is released.
private float m_ChargeSpeed; // How fast the launch force increases, based on the max charge time.
private bool m_Fired; // Whether or not the shell has been launched with this button press.
private void OnEnable()
{
// When the tank is turned on, reset the launch force and the UI
m_CurrentLaunchForce = m_MinLaunchForce;
m_AimSlider.value = m_MinLaunchForce;
}
public void Start()
{
firebutton = FindObjectOfType<FireButton>();
// The fire axis is based on the player number.
m_FireButton = "Fire" + m_PlayerNumber;
// The rate that the launch force charges up is the range of possible forces by the max charge time.
m_ChargeSpeed = (m_MaxLaunchForce - m_MinLaunchForce) / m_MaxChargeTime;
}
public void Update()
{
// The slider should have a default value of the minimum launch force.
m_AimSlider.value = m_MinLaunchForce;
// If the max force has been exceeded and the shell hasn't yet been launched...
if(m_CurrentLaunchForce >= m_MaxLaunchForce && !m_Fired)
{
// ... use the max force and launch the shell.
m_CurrentLaunchForce = m_MaxLaunchForce;
Fire();
}
// Otherwise, if the fire button has just started being pressed...
//else if(Input.GetButtonDown(m_FireButton))
**//there is an infinite loop here needs fixing**
else if (firebutton.buttonPressed)
{
Debug.Log("Test1 " + firebutton.buttonPressed);
// ... reset the fired flag and reset the launch force.
m_Fired = false;
m_CurrentLaunchForce = m_MinLaunchForce;
// Change the clip to the charging clip and start it playing.
m_ShootingAudio.clip = m_ChargingClip;
m_ShootingAudio.Play();
}
// Otherwise, if the fire button is being held and the shell hasn't been launched yet...
//else if(Input.GetButton(m_FireButton) && !m_Fired)
else if (firebutton.buttonPressed && !m_Fired)
{
Debug.Log("Test2 " + firebutton.buttonPressed);
// Increment the launch force and update the slider.
m_CurrentLaunchForce += m_ChargeSpeed * Time.deltaTime;
m_AimSlider.value = m_CurrentLaunchForce;
}
// Otherwise, if the fire button is released and the shell hasn't been launched yet...
//else if(Input.GetButtonUp(m_FireButton) && !m_Fired)
else if (firebutton.buttonPressed && !m_Fired)
{
Debug.Log("Test3 " + firebutton.buttonPressed);
// ... launch the shell.
Fire();
}
}
public void Fire()
{
// Set the fired flag so Fire is only called once.
m_Fired = true;
// Create an instance of the shell and store a reference to it's rigidbody.
Rigidbody shellInstance =
Instantiate(m_Shell, m_FireTransform.position, m_FireTransform.rotation) as Rigidbody;
// Set the shell's velocity to the launch force in the fire position's forward direction.
shellInstance.velocity = m_CurrentLaunchForce * m_FireTransform.forward; ;
// Change the clip to the firing clip and play it.
m_ShootingAudio.clip = m_FireClip;
m_ShootingAudio.Play();
// Reset the launch force. This is a precaution in case of missing button events.
m_CurrentLaunchForce = m_MinLaunchForce;
}
}
Also if you think there's an easier way to do this by using the input manager or some other way please feel free to share. Happy to change all this logic and try something else, been working on it for 13 hours now. Thanks in advance!
I got it working! Dropped the whole UIButton approach and went with Input.touches
I couldn't see a fire rate logic which stops infinite shots. You can define a fire rate so it do not fire infinite logic might be
float fireRate = 0.25f;
float lastFireTime; // Must be global
if(Time.time - lastFireTime> fireRate)
{
Fire();
lastFireTime = Time.time;
}
End you may use Object Pool pattern instead of Instantiate for performance issues.
Rigidbody shellInstance =
Instantiate(m_Shell, m_FireTransform.position, m_FireTransform.rotation) as Rigidbody;

Play sound while button is held down

I have a 1.5 seconds audio file - a single gunshot sound. I want to be able to play the sound while the mouse is pressed (like an automatic weapon), and I used InvokeRepeating to call the shoot method, with a very low repeatRate:
if (Input.GetButtonDown("Fire1"))
{
InvokeRepeating("Shoot", 0f, 1f/currentWeapon.fireRate);
} else if (Input.GetButtonUp("Fire1"))
{
CancelInvoke("Shoot");
}
And this is the Shoot method:
void Shoot()
{
shootSound.PlayOneShot(shoot);
}
The problem is the sound cuts off and the shot can't be heard, it's playing for a fraction of a second instead of the whole audio clip. I tried play() and playOneShot().
Is there an option to play each clip to its fullest separately, like creating clones of it?
Thanks!
Most things in your code are just unnecessary. You don't need InvokeRepeating for this. Since you want to continue to player sound(shooting effect) while the button is held down, Input.GetButton should be used instead of Input.GetButtonDown because Input.GetButton is true every frame the button is held down and is made for things like auto fire.
A simple timer with Time.time should also be used to determine the rate to play the sound then play the sound with the PlayOneShot function.
This is what that should look like:
public float playRate = 1;
private float nextPlayTime = 0;
public AudioSource shootSound;
public AudioClip shoot;
void Update()
{
if (Input.GetButton("Fire1") && (Time.time > nextPlayTime))
{
Debug.Log("Played");
nextPlayTime = Time.time + playRate;
shootSound.PlayOneShot(shoot);
}
}
The playRate variable is set to 1 which means 1 sound per-sec. You can use this variable to control the play rate. Lower it to play many sounds. The value of 0.1f seems to be fine but it depends on the sound.
I solved it, I used an empty GameObject with an AudioSource, and instantiated a copy of it in each Shoot method:
GameObject gunObj = Instantiate(gunObject);
Destroy(gunObj, 1f);
Works perfectly now!

unity particle doen't play second time

I have a particle system defined in my game objects. When I call Play it plays (it plays for 5 seconds by design). when I call Play again nothing happens. I tried to call Stop and Clear before recalling Play but that didn't help.
Can particle systems play more than once?
My code is in this method, which is called when a button is clicked.
public void PlayEffect()
{
for (int i=0;i<3;i++)
{
NextItemEffectsP[i].Stop();
NextItemEffectsP[i].Clear();
NextItemEffectsP[i].Play();
}
}
NextItemEffectsP is an array that contains particles that I populate in the editor
You should rework how your bullet works. Have some code on the bullet Prefab to control when it gets destroyed.
private float fuse = 1.0;
private float selfDestructTimer;
void Awake() {
// Time.time will give you the current time.
selfDestructTimer = Time.time + fuse;
}
void Update() {
if (selfDestructTimer > 0.0 && selfDestructTimer < Time.time) {
// gameObject refers to the current object
Destroy(gameObject);
}
}
Then with that control set up, you'll always just create new bullets whenever the fire button is pressed.

Categories