I have an issue I'd appreciate help with. I'm trying to create game manager script that simply dictates if I have 5 objective game objects, the player is only allowed to complete them from the smallest (the smallest available objective will be indicated by the game manager) and it becomes a foul if he attempts the 2nd objective if the first is still there.
public class gameobjects : MonoBehaviour {
// Use this for initialization
int ballsLeft = 0;
bool PocketedAllBalls = false;
void Start () {
ballsLeft = 10; // or more;
}
// Update is called once per frame
void Update () {
GameObject[] balls = GameObject.FindGameObjectsWithTag("balls");
ballsLeft = balls.Length;
if(Input.GetKeyDown(KeyCode.A))
{
ballsLeft --;
}
if(ballsLeft == 0)
{
endGame();
}
}
void endGame()
{
PocketedAllBalls = true;
}
void OnGUI()
{
if(PocketedAllBalls)
{
GUI.Label(new Rect (0,0,200,20),"all gone");
}
else
{
GUI.Label(new Rect (0,0,200,20),"Balls Remaining : " + ballsLeft);
}
}
}
Related
recently I have started creating a mobile game and decided to have a multiplayer feature. I watched youtube tutorials and got the basics but for some unknown reason players can't see each other.
What I want to do:
Connect to the server
Join the lobby
Join the room, if there's no room - create a new one
As soon as there're 2 players in one room start the game (2 players is the minumum number of players and the maximum as well)
What I do:
I build the project and get the .exe file
I run the .exe file in order to connect to the server and create a new room (I know that at the beginning there's no room yet)
I run the project in Unity
I connect to the server to join the room created in 2., but for some reason I cannot see the room and I am creating a new one
As a result I get two separate rooms with only one player in each of them instead of getting one room with two players
What I did:
I have spent last two days reading documentation and forum but to no success.
I have found similar problems and implemented the proposed solutions (like adding IsVisible = true or IsOpen = true whenever I create a new room) but in my case they didn't work
I added lots of Debug logs but my knowledge of Unity and Photon is not enough to fully use their potential
Here's the code responsible for Internet connection:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Photon.Pun;
using Photon.Realtime;
using UnityEngine.SceneManagement;
public class PhotonLobby : MonoBehaviourPunCallbacks
{
public static PhotonLobby lobby;
public GameObject battleButton;
public GameObject cancelButton;
private void Awake(){
// creates the singleton, lives within the main menu screen
lobby = this;
}
// Start is called before the first frame update
void Start()
{
// connects to master photon server
PhotonNetwork.ConnectUsingSettings();
}
public override void OnConnectedToMaster()
{
Debug.Log("Player has connected to the Photon master server");
Debug.Log("Number of players connected to the master: " + PhotonNetwork.CountOfPlayersOnMaster);
PhotonNetwork.JoinLobby();
Debug.Log("Joined lobby");
PhotonNetwork.AutomaticallySyncScene = true;
battleButton.SetActive(true);
}
public void OnBattleButtonClicked()
{
Debug.Log("Battle button was clicked");
battleButton.SetActive(false);
cancelButton.SetActive(true);
PhotonNetwork.JoinRandomRoom();
}
public override void OnJoinRandomFailed(short returnCode, string message)
{
Debug.Log("Tried to join a random game but failed. There must be no open games available");
CreateRoom();
}
void CreateRoom()
{
Debug.Log("Trying to create a new room");
int randomRoomName = Random.Range(0,10000);
RoomOptions roomOps = new RoomOptions() {IsVisible = true, IsOpen = true, MaxPlayers = (byte) MultiplayerSetting.multiplayerSetting.maxPlayers};
PhotonNetwork.CreateRoom("Room" + randomRoomName, roomOps);
Debug.Log("Created room " + randomRoomName);
}
public override void OnCreateRoomFailed(short returnCode, string message)
{
Debug.Log("Tried to create a new room but failed. There must already be a room with the same name");
CreateRoom();
}
public void OnCancelButtonClicked()
{
Debug.Log("Cancel button was clicked");
cancelButton.SetActive(false);
battleButton.SetActive(true);
PhotonNetwork.LeaveRoom();
SceneManager.LoadScene(1);
}
}
And the code responsible for joining/creating rooms:
using System.IO;
using System.Collections;
using Photon.Pun;
using Photon.Realtime;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
public class PhotonRoom : MonoBehaviourPunCallbacks, IInRoomCallbacks
{
// room info
public static PhotonRoom room;
private PhotonView PV;
public bool isGameLoaded;
public int currentScene;
// player info
Player[] photonPlayers;
public int playersInRoom;
public int myNumberInRoom;
public int playerInGame;
// delayed start
private bool readyToCount;
private bool readyToStart;
public float startingTime;
private float lessThanMaxPlayers;
private float atMaxPlayers;
private float timeToStart;
private void Awake()
{
// set up singleton
if(PhotonRoom.room == null)
{
PhotonRoom.room = this;
}
else
{
if(PhotonRoom.room != this)
{
Destroy(PhotonRoom.room.gameObject);
PhotonRoom.room = this;
}
}
DontDestroyOnLoad(this.gameObject);
}
public override void OnEnable()
{
// subscribe to functions
base.OnEnable();
PhotonNetwork.AddCallbackTarget(this);
SceneManager.sceneLoaded += OnSceneFinishedLoading;
}
public override void OnDisable()
{
base.OnDisable();
PhotonNetwork.RemoveCallbackTarget(this);
SceneManager.sceneLoaded -= OnSceneFinishedLoading;
}
// Start is called before the first frame update
void Start()
{
// set private variables
PV = GetComponent<PhotonView>();
readyToCount = false;
readyToStart = false;
lessThanMaxPlayers = startingTime;
atMaxPlayers = 6;
timeToStart = startingTime;
}
// Update is called once per frame
void Update()
{
// for delay start only, count down to start
if(MultiplayerSetting.multiplayerSetting.delayStart)
{
if(playersInRoom == 1)
{
RestartTimer();
}
if(!isGameLoaded)
{
if(readyToStart)
{
atMaxPlayers -= Time.deltaTime;
lessThanMaxPlayers = atMaxPlayers;
timeToStart = atMaxPlayers;
}
else if(readyToCount)
{
lessThanMaxPlayers -= Time.deltaTime;
timeToStart = lessThanMaxPlayers;
}
Debug.Log("Display time to start to the players " + timeToStart);
if(timeToStart<=0)
{
Debug.Log("We have started the game!");
StartGame();
}
}
}
}
public override void OnJoinedRoom()
{
// sets player data when we join the room
base.OnJoinedRoom();
Debug.Log("We are now in a room");
photonPlayers = PhotonNetwork.PlayerList;
playersInRoom = photonPlayers.Length;
myNumberInRoom = playersInRoom;
PhotonNetwork.NickName = myNumberInRoom.ToString();
// for delay start only
if(MultiplayerSetting.multiplayerSetting.delayStart)
{
Debug.Log("Displayer players in room out of max players possible (" + playersInRoom + ":" + MultiplayerSetting.multiplayerSetting.maxPlayers + ")");
if(playersInRoom > 1)
{
readyToCount = true;
}
if(playersInRoom == MultiplayerSetting.multiplayerSetting.maxPlayers)
{
readyToStart = true;
if(!PhotonNetwork.IsMasterClient)
return;
PhotonNetwork.CurrentRoom.IsOpen = false;
}
}
// for non delay start
else if (playersInRoom == 2)
{
Debug.Log("We have started the game!");
StartGame();
}
else {
Debug.Log("There's only 1 player");
}
}
public override void OnPlayerEnteredRoom(Player newPlayer)
{
base.OnPlayerEnteredRoom(newPlayer);
Debug.Log("A new player has joined the room");
photonPlayers = PhotonNetwork.PlayerList;
playersInRoom++;
if(MultiplayerSetting.multiplayerSetting.delayStart)
{
Debug.Log("Displayer players in room out of max players possible (" + playersInRoom + ":" + MultiplayerSetting.multiplayerSetting.maxPlayers + ")");
if(playersInRoom > 1)
{
readyToCount = true;
}
if(playersInRoom == MultiplayerSetting.multiplayerSetting.maxPlayers)
{
readyToStart = true;
if(!PhotonNetwork.IsMasterClient)
return;
PhotonNetwork.CurrentRoom.IsOpen = false;
}
}
}
void StartGame()
{
isGameLoaded = true;
if(!PhotonNetwork.IsMasterClient)
return;
if(MultiplayerSetting.multiplayerSetting.delayStart)
{
PhotonNetwork.CurrentRoom.IsOpen = false;
}
PhotonNetwork.LoadLevel(MultiplayerSetting.multiplayerSetting.multiplayerScene);
}
void RestartTimer()
{
lessThanMaxPlayers = startingTime;
timeToStart = startingTime;
atMaxPlayers = 6;
readyToCount = false;
readyToStart = false;
}
void OnSceneFinishedLoading(Scene scene, LoadSceneMode mode)
{
// called when multiplayer scene is loaded
currentScene = scene.buildIndex;
if(currentScene == MultiplayerSetting.multiplayerSetting.multiplayerScene)
{
isGameLoaded = true;
// for delay start game
if(MultiplayerSetting.multiplayerSetting.delayStart)
{
PV.RPC("RPC_LoadedGameScene", RpcTarget.MasterClient);
}
// for non delay start game
else
{
RPC_CreatePlayer();
}
}
}
[PunRPC]
public void RPC_LoadedGameScene()
{
playersInRoom++;
if(playerInGame == PhotonNetwork.PlayerList.Length)
{
PV.RPC("RPC_CreatePlayer", RpcTarget.All);
}
}
[PunRPC]
public void RPC_CreatePlayer()
{
PhotonNetwork.Instantiate(Path.Combine("PhotonPrefabs", "PhotonNetworkPlayer"),transform.position,Quaternion.identity, 0);
}
public override void OnPlayerLeftRoom(Player otherplayer)
{
base.OnPlayerLeftRoom(otherplayer);
Debug.Log(otherplayer.NickName+ "Has left the game");
playersInRoom--;
}
}
Thank you in advance for any help :)
If you connect to Photon Cloud, make sure clients are connected to the same virtual application (AppId, AppVersion) and to the same servers (Region).
If you are using the default Best Region connection method, you need to consider that clients could end up connected to two different regions.
Go through our "Matchmaking Checklist".
I have finally found the solution, the problem were regions to which my players connected. I have set the region to eu and it worked. I believe that preciously each player connected to different region.
I hope it will help someone in the future
Summary
My player lives is not reseting to the default value when they start the game over or enter the next level. When I die once and then complete the first level. The 2nd lvl loads and I start out with 2 lives. When I die 3xs it loads the main menu and when I click on start button it starts me off with 1 life.
LayOut:
Unity Hierarchy LayOut
Goal:
To have the player lives reset to 3 when re/starting the game/next Level.
Expected Results:
When the player completes a level with 2 lives left. The next level should load displaying that the player has 3 lives.
Actual Results:
When the player completes a level with 2 lives left. The next level displays that the player has 2 lives instead of 3.
Error Messages:
NONE
What I Tried
I am lost this is my first time creating a game. Where a player has multiple lives.
SpaceShip CODE:
public void completeSequence()
{
player = playerState.Transcending;
SFX.Stop();
SFX.PlayOneShot(completed);
death.Stop();
victory.Play();
Invoke("loadNextLevel", lvlLoadDelay);
}
public void resetLvl()
{
//print("Dead");
player = playerState.Dying;
SFX.Stop();
SFX.PlayOneShot(dead);
death.Play();
Invoke("loadCurrentSccene", lvlLoadDelay);
}
public void deadSequence()
{
//print("Dead");
player = playerState.Dying;
SFX.Stop();
SFX.PlayOneShot(dead);
death.Play();
Invoke("loadMainLevel", lvlLoadDelay);
}
public void loadCurrentSccene()
{
var currentScene = SceneManager.GetActiveScene().buildIndex;
SceneManager.LoadScene(currentScene);
}
public void loadMainLevel()
{
SceneManager.LoadScene(0);
}
public void loadNextLevel()
{
int currentScene = SceneManager.GetActiveScene().buildIndex;
//print(currentScene);
int nextScene = currentScene +1;
SceneManager.LoadScene(nextScene);
}
public void loadPreviousLevel()
{
int currentScene = SceneManager.GetActiveScene().buildIndex;
int nextScene = currentScene -1;
SceneManager.LoadScene(nextScene);
}
}
GameSession Code:
{
[SerializeField] int playerLives = 3;
[SerializeField] Text livesText;
private void Awake()
{
int numSessions = FindObjectsOfType<gameSession>().Length;
if (numSessions > 1)
{
Debug.Log("I am the NOT Original");
Destroy(gameObject);
}
else
{
Debug.Log("I am the Original");
DontDestroyOnLoad(gameObject);
}
}
// Start is called before the first frame update
void Start()
{
livesText.text = playerLives.ToString();
}
public void initiateDeath()
{
if (playerLives > 1)
{
reduceLives();
}
else
{
FindObjectOfType<spaceShip>().deadSequence();
}
}
public void reduceLives()
{
playerLives--;
FindObjectOfType<spaceShip>().resetLvl();
livesText.text = playerLives.ToString();
}
}
Currently, playerLives is being initialized to 3, and reduced by one whenever reduceLives() is called. None of your code sets playerLives back to 3, so when you enter a new level or call deadSequence() the lives stay at their previous value.
Adding a reset method to GameSession and calling this whenever you want to set the playerLives back to 3 (so presumably inside of both deadSequence() and completeSequence()) will fix this issue.
public void ResetLives()
{
playerLives = 3;
livesText.text = playerLives.ToString();
}
Now I am doing a project for my final term in university and my area changed the scene by gazing(google VR SDK).
At first, I just put a code to change the scene. It worked. But I want some enhance, so I used gaze timer which I watched at youtube (link: https://www.youtube.com/watch?v=bmMaVTV8UqY)
Now, the gaze Timer animation is working but the SceneSwitcher function in NexScene1 code isn't working.
I've done 'build' after adding the new scene that I add gaze timer function.
Also, I used tagged which shown in the youtube.
That's all I did.
public class VRGaze : MonoBehaviour {
public Image imgGaze;
public float totalTime = 2;
bool gvrStatus;
float gvrTimer;
public int distanceOfRay = 10;
private RaycastHit _hit;
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update () {
if (gvrStatus)
{
gvrTimer += Time.deltaTime;
imgGaze.fillAmount = gvrTimer / totalTime;
}
Ray ray = Camera.main.ViewportPointToRay(new Vector3(0.5f, 0.5f, 0.5f));
if(Physics.Raycast(ray, out _hit, distanceOfRay))
{
if(imgGaze.fillAmount == 1 && _hit.transform.CompareTag("NexScene1"))
{
_hit.transform.gameObject.GetComponent<NexScene1>().SceneSwitcher();
}
}
}
public void GVROn() {
gvrStatus = true;
}
public void GVROff() {
gvrStatus = false;
gvrTimer = 0;
imgGaze.fillAmount = 0;
}
}
public class NexScene1 : MonoBehaviour {
public UnityEngine.UI.Scrollbar obj_scroll_;
public GameObject player;
public void PointEnter()
{
StartCoroutine(TimeToAction());
}
public void PointExit()
{
StopAllCoroutines();
}
public void SceneSwitcher()
{
SceneManager.LoadScene("Page2");
}
void Start () {
}
// Update is called once per frame
void Update () {
}
}
Not an actual error but just the SwitchScene function is not called at VRGaze
Not an error but the console says:
It is recommended to use GvrPointerPhysicsRaycaster or
GvrPointerGrahpicRaycaster with GvrPointerInputModule.
I am working on 2D game.
When player collides with BOMBPrefab lose 1 heart (initial 3 heart), if collides 3 times = GameOver.
Thats is the code (works fine for BombPrefab):
using UnityEngine;
using System.Collections;
public class Heart : MonoBehaviour {
public Texture2D[] initialHeart;
private int heart;
private int many;
// Use this for initialization
void Start () {
GetComponent<GUITexture>().texture = initialHeart[0];
heart = initialHeart.Length;
}
// Update is called once per frame
void Update () {}
public bool TakeHeart()
{
if (heart < 0) {
return false;
}
if (many < (heart - 1)) {
many += 1;
GetComponent<GUITexture> ().texture = initialHeart [many];
return true;
} else {
return false;
}
}
}
I have a second HeartPrefab, I want to check when player collides... IF I have 3 hearts do nothing, IF have 1 or 2 hearts ADD extra heart.
BombPrefab Scrip:
using UnityEngine;
using System.Collections;
public class Bomb : MonoBehaviour
{
public AudioClip clipBomba;
private Heart heart;
private Gerenciador gerenciador;
void Awake ()
{
}
// Use this for initialization
void Start ()
{
gerenciador = FindObjectOfType (typeof(Gerenciador)) as Gerenciador;
}
// Update is called once per frame
void Update ()
{
}
void OnCollisionEnter2D (Collision2D colisor)
{
if (colisor.gameObject.tag == "floor") {
Destroy (gameObject, 2f);
} else {
if (colisor.gameObject.tag == "Bee") {
Som();
heart= GameObject.FindGameObjectWithTag ("Heart").GetComponent<Vidas> () as Vidas;
if (heart.TakeHeart ()) {
Destroy (gameObject);
} else {
gerenciador.GameOver ("GameOver");
}
}
}
}
void Som()
{
GetComponent<AudioSource> ().clip = clipBomb;
AudioSource.PlayClipAtPoint (clipBomb, transform.position);
}
}
First of all try not use GetComponent<>() in update and functions that are run often. It is better to cache components in Start() method. Using FindGameObjectWith...() is also not very efficient.
I would make it differently, each heart as a separate UI element (Toggle), with two states active and inactive. Then your player should have a list of those hearts and methods that allow to take damage and gain life.
int currentHeartsCount = 3;
int maxHeartsCount = 3;
List<Heart> hearts = new List<Heart>();
public void TakeDamage(int damage) {
ChangeHearts(-damage);
}
public void GainLife(int life) {
ChangeHearts(life);
}
private void ChangeHearts(int amount) {
currentHeartsCount += amount;
if(currentHeartsCount> maxHeartsCount)
currentHeartsCount = maxHeartsCount;
if(currentHeartsCount<=0) {
// call player dead code
}
int i = 1;
foreach(Heart heart in hearts) {
heart.SetHeartActive(i<=currentHeartsCount);
i++;
}
}
This is a simplified solution to give you an idea. It is more robust than yours because you can easily change start heart count, and make things like heart "overcharge". Just add base hearts, set max to desired value, and now you can create some special power ups which increase hearts over the initial limit.
I am creating a 2D game and I've hit a serious road block when trying to 'randomly' spawn power ups. Basically what I am attempting to do is spawn the power ups off screen and then they move onto the screen (at the same speed as my scrolling background) Once one of the three power ups has been spawned another one won't spawn until 10 to 30 seconds has passed. I also understand that the shield power Up is the only one that I am trying to get spawning randomly at the moment. I have been researching for hours and writing code that I will post below. I have tried to do this all by myself so I apologize for the quality of the code, I am still a novice and learning. Any help or links to websites would be greatly appreciated as I have no idea where to proceed from here.
Thanks in advance.
game1.cs
public List<PowerUps> powerUpList = new List<PowerUps>();
public double counterPower = 0;
public bool powerUpCollision = false;
public bool invincibility = false;
Sprite shieldPower;
Sprite infiniteAmmoPower;
Sprite livesPower;
bool isVisible = true;
public bool infiniteAmmoBool = false;
public bool infiniteAmmoCol = false;
protected override void Initialize()
{
shieldPower = new Sprite();
infiniteAmmoPower = new Sprite();
livesPower = new Sprite();
}
protected override void LoadContent()
{
spriteBatch = new SpriteBatch(GraphicsDevice);
shieldPower.LoadContent(this.Content, "powerUpShield");
infiniteAmmoPower.LoadContent(this.Content, "infinitePowerUp");
livesPower.LoadContent(this.Content, "livePowerUp");
}
protected override void Update(GameTime theGameTime)
{
}
public void powerUps(GameTime theGameTime)
{
//if (mPlayer.boundingBox.Intersects(shieldPower.boundingBoxShieldPower))
{
Console.WriteLine(shieldPower.Position.X);
if (shieldPower.isVisible == true)
{
Console.WriteLine("collision working");
powerUpCollision = true;
invincibility = true;
shieldPower.isVisible = false;
if (powerUpCollision == true && invincibility == true)
{
lives = lives - 0;
}
counterPower = 0;
}
}
counterPower += theGameTime.ElapsedGameTime.TotalSeconds;
{
// Console.WriteLine(counterPower);
if (counterPower > 7)
{
powerUpCollision = false;
invincibility = false;
}
}
if (mPlayer.boundingBox.Intersects(livesPower.boundingBoxLives))
{
if (livesPower.isVisible == true)
{
lives = lives + 1;
livesPower.isVisible = false;
}
}
}
public void loadPowerUps()
{
int randPowerX = random.Next(850, 1400); // spawns randomly between these coordinates
int randPowerY = random.Next(-300, 300);
Console.WriteLine(shieldPower.Position.X);
if (powerUpList.Count < 1) // limits the powerUp count to 1 at a time
{
powerUpList.Add(new PowerUps(Content.Load<Texture2D>("powerUpShield"), new Vector2(randPowerX, randPowerY)));
}
for (int i = 0; i < powerUpList.Count; i++)
{
if (powerUpList[i].isVisible == false)
{
powerUpList.RemoveAt(i);
i--;
}
}
}
protected override void Draw(GameTime theGameTime)
{
foreach (PowerUps powerup in powerUpList)
{
powerup.Draw(spriteBatch);
}
mPlayer.Draw(this.spriteBatch);
enemyShip.Draw(this.spriteBatch);
if (shieldPower.isVisible == true)
{
shieldPower.Draw(this.spriteBatch);
}
if (livesPower.isVisible == true)
{
livesPower.Draw(this.spriteBatch);
}
if (infiniteAmmoPower.isVisible == true)
{
infiniteAmmoPower.Draw(this.spriteBatch);
}
}
PowerUps.cs
public class PowerUps : Game1
{
Random randomPower = new Random();
int minPowerSpawnTimer = 10000; // 10 seconds
int maxPowerSpawnTimer = 30000; // 30 seconds
double nextSpawnTime;
float powerUpSpeed = -0.5f;
Vector2 position;
Texture2D texture;
public PowerUps(Texture2D newText, Vector2 newPos)
{
position = newPos;
texture = newText;
}
public void Update(GameTime theGameTime)
{
position.X += powerUpSpeed;
nextSpawnTime -= theGameTime.ElapsedGameTime.Milliseconds;
if (nextSpawnTime < 0)
{
loadPowerUps();
resetSpawnTime();
}
}
public void resetSpawnTime()
{
nextSpawnTime = randomPower.Next(minPowerSpawnTimer, maxPowerSpawnTimer);
}
public void Draw(SpriteBatch spriteBatch)
{
spriteBatch.Draw(texture, position, Color.White);
}
}
Your problem is the class structure you've created. Your should not be inheriting Game1 in your PowerUps class. It is creating multiple instances of Game1 objects each of which has its own list of PowerUps.
It doesn't appear to me that any of the Update() methods in the PowerUps instances will ever be called.
I think you may be wanting to access functionallity of your Game1 class from your PowerUps class. Inheriting (PowerUps : Game1) is not the way to do it here.
Instead, make a PowerUps class that does not inherit anything. Then from your Game1 Update method, call your PowerUps instances' Update method and pass what variables it needs. Same with the drawing.
In order for your Update method to be called, your PowerUps class must inherit from GameComponent, not Game1.
Since you also have a Draw method, to have your Draw method also called automatically your must inherit from DrawableGameComponent instead.
Those base classes take your Game1 as a parameter, so you will have to modify your constructor:
public class PowerUps : DrawableGameComponent
{
//Variables
public PowerUps(Texture2D newText, Vector2 newPos, Game1 game) : base(game)
{
position = newPos;
texture = newText;
}
Now that you have a GameComponent, you must register it in your Game1 class upon creation. So, when creating your power ups in your powerUpList, change your code from
powerUpList.Add(new PowerUps(Content.Load<Texture2D>("powerUpShield"), new Vector2(randPowerX, randPowerY)));
to:
PowerUps powerUp = new PowerUps(Content.Load<Texture2D>("powerUpShield"), new Vector2(randPowerX, randPowerY))
powerUpList.Add(powerUp);
Components.Add(powerUp);
When your component is registered within the Components list, the Game can start calling the Draw and Update methods of your component. Once you're finish with it, remove it from the list.