This is only related to Unity3D, the game engine.
So let's say I have one line of code, and then another. How would I make a delay between those two lines of code. To repeat, I'm also doing this for Unity3D.
I've looked everywhere, but nothing will work.
As a FRAME-BASED game engine, Unity of course, obviously, has every imaginable sort of timer and run loop control built-in.
It's absolutely trivial to make timers ...
Debug.Log("Race begins!");
// 3 seconds later, make the crowd cheer
Invoke("CrowdCheers", 3f);
// 7 seconds later, show fireworks
Invoke("Fireworks", 3f);
private void CrowdCheers()
{
crowd.Play();
}
private void Fireworks()
{
fireworks.SetActive(true);
}
If you are more advanced with coding, you can use "coroutines". Coroutines are a ridiculously simple way to access the run loop. Examples:
using UnityEngine;
using System.Collections;
public class demo : MonoBehaviour {
// Details at: http://docs.unity3d.com/Manual/Coroutines.html
// Use this for initialization
void Start () {
// Some start up code here...
Debug.Log("Co-1");
StartCoroutine("OtherThing");
Debug.Log("Co-2");
}
IEnumerator OtherThing()
{
Debug.Log("Co-3");
yield return new WaitForSeconds(0f);
Debug.Log("Co-4");
DoOneThing();
yield return new WaitForSeconds(1f);
Debug.Log("Co-5");
DoOtherThing();
}
void DoOneThing()
{
Debug.Log("Co-6");
}
void DoOtherThing()
{
Debug.Log("Co-7");
}
}
Related
I am developing a VR game in Unity (2020.3.15f2) using the XR Interaction Toolkit package (1.0.0-pre.5) for my Oculus Quest 2. At this stage in my development, I am trying to recognize presses to the trigger and grip buttons on the controllers respectively in order to animate some 3D hand models. Here's the script I've written to accomplish this:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.XR;
public class HandPresence : MonoBehaviour {
public InputDeviceCharacteristics controllerCharacteristics;
public GameObject handModelPrefab;
private InputDevice targetDevice;
private GameObject spawnedHandModel;
private Animator handAnimator;
void Start() {
TryInitialize();
}
void TryInitialize() {
List<InputDevice> devices = new List<InputDevice>();
InputDevices.GetDevicesWithCharacteristics(controllerCharacteristics, devices);
if (devices.Count > 0) {
targetDevice = devices[0];
spawnedHandModel = Instantiate(handModelPrefab, transform);
handAnimator = spawnedHandModel.GetComponent<Animator>();
}
}
void UpdateHandAnimation() {
if (targetDevice.TryGetFeatureValue(CommonUsages.trigger, out float triggerValue)) {
handAnimator.SetFloat("Trigger", triggerValue);
} else {
handAnimator.SetFloat("Trigger", 0);
}
if (targetDevice.TryGetFeatureValue(CommonUsages.grip, out float gripValue)) {
handAnimator.SetFloat("Grip", gripValue);
} else {
handAnimator.SetFloat("Grip", 0);
}
}
void Update()
{
if (!targetDevice.isValid) {
TryInitialize();
} else {
spawnedHandModel.SetActive(true);
UpdateHandAnimation();
}
}
}
The issue I'm experiencing is that the values of both triggerValue and gripValue are always 0. The value of targetDevice looks fine. I also tried using triggerButton, gripButton, primaryButton, etc. and they are always 0/false as well. The hand models show up just fine and their movement is in sync with the movement of the controllers, but they just don't seem to want to register any button presses.
I've been stuck on this one for hours and would very much appreciate any insight, thank you!
Is your project setup with the (new) Input System? I have no problem detecting there trigger and grip values.
Also make sure the targetDevice actually uses trigger and grip features, maybe it is another device such as the HMD.
I started my game dev journey a few weeks ago and I am enjoying it, but sometimes it can get frustrating when things do not work.
I wrote a very basic code for particle system, if we press space then particle should play. The problem is that its not playing, when I hit play it doesn't work for some reason. When I click the particle in the scene then it works and it also works when I check on the play on awake
The Code:
[SerializeField] ParticleSystem engineBoostParticle;
[SerializeField] ParticleSystem sideEngineParticles;
void Start()
{
}
void Update()
{
ThrustingInput();
}
void ThrustingInput()
{
if (Input.GetKey(KeyCode.Space))
{
if (!engineBoostParticle.isPlaying)
{
engineBoostParticle.Play();
}
}
else
{
AS.Stop();
engineBoostParticle.Stop();
}
}
You want to check engineBoostParticle.isEmitting as well as isPlaying in your if statement.
It's possible that your system is playing, but not emitting (because the loop is over), so make sure the particle system loops properly as well.
I'm trying to add a healthbar which is affected by the choices made and link the two but am unable to do so. Any help would be appreciated.
I will recommend you that before you go any further with your game development process, you research a bit more about general OOP programming (no offense or anything, it will just make things waaay easier, trust me).
That being said, here's an example to steer you to the right direction:
You can create a script with a global variable called health and subtract it every time the player makes a decision that would "punish" them, here's an example of how that could work:
PlayerManager.cs (put this script on your player)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerManager : MonoBehaviour {
public float health = 100f;
private void Update() {
if (health < 0)
Die();
}
private void Die () {
//Fancy animations and text can be added on this method
Destroy(gameObject);
}
}
And on your dialogue script, once they choose a wrong answer, then you can just decrease health on the proper player manager instance, like this:
DialogueSystem.cs
public PlayerManager playerManager;
public float damage = 10f;
private void Start() {
//You can initialize other stuff here as well
//This line is assuming you have the dialogue system script attach to your player as well
playerManager = GetComponent<PlayerManager>();
}
private void Update () {
//This is obviously going to change depending on how your system is built
if (wrongChoice) {
playerManager.health -= damage;
wrongChoice = false;
}
}
I am trying to create a simple 2D Turn based multiplayer game using Photon Unity Networking.
It is just a simple turn based game where a player 1 (host) presses his button and it adds his score and changes its turn to player 2 (client) who presses his button to add score and change turn to player 1. It continues to infinite.
I was able to connect two players in the game using the basic Photon documentation. Now I need to add the networking logic of taking turns and changing them.
I searched the internet but I can't understand the RPC and SerializeView of Photon. I am really confused with that. Please Help me. Thank you in future. Here is my GameManager Script
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
public class GameManager : Photon.PunBehaviour
{
public Text roomName;
public Text player1Name,player2Name;
public List<string> playersConnected = new List<string>();
int scoreP1 = 0, scoreP2 = 0;
public Text scoreTextP1, scoreTextP2;
public Button p1Btn, p2Btn;
int playerTurn = 1;
void Start()
{
roomName.text = SceneManager.GetActiveScene().name;
p2Btn.gameObject.SetActive(false);
p1Btn.gameObject.SetActive(true);
}
public void AddScoreP1()
{
scoreP1++;
scoreTextP1.text = scoreP1.ToString();
ChangePlayerTurn();
}
public void AddScoreP2()
{
scoreP2++;
scoreTextP2.text = scoreP2.ToString();
ChangePlayerTurn();
}
void ChangePlayerTurn()
{
if (playerTurn == 1)
{
playerTurn = 2;
p2Btn.gameObject.SetActive(true);
p1Btn.gameObject.SetActive(false);
}
else
{
playerTurn = 1;
p1Btn.gameObject.SetActive(true);
p2Btn.gameObject.SetActive(false);
}
print("Player Turn: P" + playerTurn);
}
void LoadArena()
{
if (!PhotonNetwork.isMasterClient)
{
Debug.LogError("PhotonNetwork : Trying to Load a level but we are not the master Client");
}
Debug.Log("PhotonNetwork : Loading Level : " + PhotonNetwork.room.PlayerCount);
PhotonNetwork.LoadLevel("Room for " + PhotonNetwork.room.PlayerCount);
}
public override void OnLeftRoom()
{
SceneManager.LoadScene(0);
}
public void LeaveRoom()
{
PhotonNetwork.LeaveRoom();
}
public override void OnPhotonPlayerConnected(PhotonPlayer other)
{
Debug.Log("OnPhotonPlayerConnected() " + other.NickName); // not seen if you're the player connecting
foreach (PhotonPlayer _player in PhotonNetwork.playerList)
{
playersConnected.Add(other.NickName);
}
if (PhotonNetwork.isMasterClient)
{
Debug.Log("OnPhotonPlayerConnected isMasterClient " + PhotonNetwork.isMasterClient); // called before OnPhotonPlayerDisconnected
LoadArena();
}
}
public override void OnPhotonPlayerDisconnected(PhotonPlayer other)
{
Debug.Log("OnPhotonPlayerDisconnected() " + other.NickName); // seen when other disconnects
foreach (PhotonPlayer _player in PhotonNetwork.playerList)
{
playersConnected.Remove(other.NickName);
}
if (PhotonNetwork.isMasterClient)
{
Debug.Log("OnPhotonPlayerDisonnected isMasterClient " + PhotonNetwork.isMasterClient); // called before OnPhotonPlayerDisconnected
LoadArena();
}
}
}
RPC is basically a way of invoking a function on a remote client.
Usually in a multiplayer setup you'd want your MasterClient to control the flow of the game. So, when two players join a room, what you need to do is from your MasterClient, decide which player goes first and then call a RPC function from MasterClient telling both client whose the first turn is. Then whichever player's turn it is, just activate its button and let them add score (Send RPC to MasterClient as well for that, so that everyone can stay in sync.) and the update turn and tell everyone via another RPC and so on.
though you can also use Events for such cases, they need less preparation to be used.
Both in a nutshell:
RPC, Remote Procedural calls, is used to call a certain method to all or certain clients/users in the same room/level. Example like this, you might want to use RCP to update the teams score if a team scored a goal.
SerializeView is used by PUN to synchronize and read data a few times per second, depending on the serialization rate. Example like this, you will use this to get and read to see each other's data like how much points another player have in realtime.
both of these functions are practically similar, but their use is entirely different.
There is more information about RCP and SerializeView on the Photon Website Link
I made a pretty basic 2D game to learn. I have 2 Scenes, and switching between them worked great. I used empty gameObjects as Start/Exit point of the Scene, so that the game would know to put player on point X after exiting through point X (for example exit outside house if I walk out the door).
Then I added a "Scene0", to use for persistent general scripts like GameManager, Sounds, Music, etc. With just one object called "Controller" that I DontDestroyOnLoad().
After adding this Scene and then just switching Scenes right away to my MainScene, all of a sudden the game starts acting really strange;
the first time I move from my MainScene (Scene1), to my secondary Scene (Scene2), it works fine, but then when I leave Scene2 to go back to Scene1, the player spawns in the middle of nowhere.
And this ONLY happens if I launch the game from my Persistent Scene.
I have no idea what is wrong, I don't add anything that interferes with my scene transitions, all I've added so far is playerHealth, for testing.
Scripts attached to my (persistent) Controller:
DDOL:
public class DDOL : MonoBehaviour {
// Use this for initialization
void Awake () {
DontDestroyOnLoad (gameObject);
}
}
GameManager:
public class GameManager : MonoBehaviour {
public static GameManager manager;
public int playerMaxHealth;
public int playerCurrentHealth;
void Awake(){
if (manager == null) {
manager = this;
} else if (manager != this) {
Destroy (gameObject);
}
}
// Use this for initialization
void Start () {
SceneManager.LoadScene("test_scene");
}
// Update is called once per frame
void Update () {
}
}
Scripts attached to my StartPoint:
PlayerStartPoint:
public class PlayerStartPoint : MonoBehaviour {
private PlayerController thePlayer;
private CameraController theCamera;
public Vector2 startDir;
public string pointName;
// Use this for initialization
void Start () {
thePlayer = FindObjectOfType<PlayerController> ();
if (thePlayer.startPoint == pointName) {
thePlayer.transform.position = transform.position;
thePlayer.lastMove = startDir;
theCamera = FindObjectOfType<CameraController> ();
theCamera.transform.position = new Vector3(transform.position.x, transform.position.y, theCamera.transform.position.z);
}
}
}
And finally ExitPoint:
LoadNewArea:
public class LoadNewArea : MonoBehaviour {
public string levelToLoad;
public string exitPoint;
private PlayerController thePlayer;
// Use this for initialization
void Start () {
thePlayer = FindObjectOfType<PlayerController> ();
}
void OnTriggerEnter2D(Collider2D other){
if (other.gameObject.name == "Player")
{
SceneManager.LoadScene(levelToLoad);
thePlayer.startPoint = exitPoint;
}
}
}
EDIT:
After moving all my DDOL gameObject to the Pre-Scene, it worked. So, I can assume the fault is inside Player or Cameras Start() functions since when they start in Scene1 they get called every time I enter the Scene (only DDOL).
I tried adjusting their Start()functions like follows:
Original camera:
void Start () {
Debug.Log("Starting camera");
if (!cameraExists) {
cameraExists = true;
DontDestroyOnLoad (gameObject);}
else{
Destroy (gameObject);
}
}
Changed Camera:
void Start () {
DontDestroyOnLoad (gameObject);
}
The exact same changes was made in Player.
Obviously this doesnt work because it creates a new Camera/Player every time I enter Scene1 (btw why does it not try to create them when I enter Scene2?, is it because they start in Scene1?). HOWEVER, the new player/camera do start at the correct position, and if I zoom out I can see the old player/camera at that same wrong position as before. So something weird happens when their Start() is called a second time it seems.
You've now mentioned that you had code something like this,
void Start () {
Debug.Log("Starting camera");
if (!cameraExists) {
cameraExists = true;
DontDestroyOnLoad (gameObject);}
else{
Destroy (gameObject);
}
}
Note that this is unfortunately just "utterly incorrect", heh :)
The issues you mention in the question (preload scenes etc) are just totally unrelated to the problem here.
In Unity if you have a character C that persists between scenes a, b, c as you load those scenes, you must kick-off C in it's own (perhaps otherwise empty) scene, you can not use "a" as a matter of convenience to kick off C.
The pattern is, in each of a, b, c just have a line of code like p = FindObjectOfType<Player>(); which runs when the scene loads, and position C as you wish.
Now, regarding your specific puzzle about the unusual behavior you are seeing.
I understand that you want to know why you are observing what you do.
It is a combination of confusion over the following issues: 1 - difference between Awake and Start, 2 - confusion over script execution order {but see below1} 3 - confusion about Destroy versus DestroyImmediate 4 - Not using Debug.Log enough, and not using gameObject.name in there (it's a common in Unity to be wildly confused about which object is talking in Debug.Log) 5 - where you mention you see the other object "off to the side", it's common to drastically confuse which one is which in such situations 6 - confusion between the computer programming concept of "instantiation" (ie, of a class or object) and "instantiating" (confusingly, it's the same word - utterly unrelated) game objects in nity.
If you fiddle around with all those issues, you'll discover an explanation for the behavior you're seeing!
But it doesn't amount to much; in Unity in the "C .. a b c" example you have to create C separately beforehand.
1 {aside, never fiddle with the script execution ordering system in Unity in an effort to solve problems; it's only there for R&D purposes; however it could in fact help you investigate the behavior at hand in this problem, if you are particularly keen to fully understand why you're seeing what you're apparently seeing}
Use the debugger. Have breakpoints at the relevant spots, like PlayerStartPoint.Start() and LoadNewArea.OnTriggerEnter2D() and check that they are executed
At the right time
The right number of times
With the expected values
This should make you see where things get out of hand.
If you use Visual Studio, install https://marketplace.visualstudio.com/items?itemName=SebastienLebreton.VisualStudio2015ToolsforUnity to be able to debug Unity from within Visual Studio.
If you are not using Visual Studio, you probably should.
Is player persistent between scenes (does he have DontDestroyOnLoad)? If no then this might be the reason - you can either try loading the scenes by using the additive mode or by instantiating the player on scene load in correct position.