Unity3D position Update when gameObject is changed - c#

I am trying to make a vehicle changing game where there are 3 gameObject: car, tank and hover and if I press a button to change from car to a tank/hover i want them to be in a position where the car was.
the z axis is forward
I tried this code below but when I go backwards this will not work
UnityEngine;
public class Carswitcer : MonoBehaviour
{
public Transform car;
public Transform hover;
public Transform tank;
void Start()
{
car.gameObject.SetActive(true);
tank.gameObject.SetActive(false);
hover.gameObject.SetActive(false);
}
public void Car()
{
if (car.position.z < hover.position.z)
{
car.position = hover.position;
}
if (car.position.z < tank.position.z)
{
car.position = tank.position;
}
car.gameObject.SetActive(true);
tank.gameObject.SetActive(false);
hover.gameObject.SetActive(false);
}
public void Tank()
{
if (tank.position.z < hover.position.z)
{
tank.position = hover.position;
}
if (tank.position.z < car.position.z)
{
tank.position = car.position;
}
car.gameObject.SetActive(false);
tank.gameObject.SetActive(true);
hover.gameObject.SetActive(false);
}
public void Hover()
{
if (hover.position.z < car.position.z)
{
hover.position = car.position;
}
if (hover.position.z < tank.position.z)
{
hover.position = tank.position;
}
car.gameObject.SetActive(false);
tank.gameObject.SetActive(false);
hover.gameObject.SetActive(true);
}

Why compare the z at all? Simply always copy the position of the currently active vehicle:
public class Carswitcer : MonoBehaviour
{
public Transform car;
public Transform hover;
public Transform tank;
// Store the current vehicle
private Transform currentVehicle;
void Start()
{
tank.gameObject.SetActive(false);
hover.gameObject.SetActive(false);
SetActiveVehicle(car);
}
private void SetActiveVehicle(Transform newActiveVehicle)
{
// Is there a current vehicle?
if(currentVehicle)
{
// If so copy its position and set it inactive
newActiveVehicle.position = currentVehicle.position;
currentVehicle.gameObject.SetActive(false);
}
// Store the new active reference and set it active
currentVehicle = newActiveVehicle;
currentVehicle.gameObject.SetActive(true);
}
public void Car()
{
SetActiveVehicle(car);
}
public void Tank()
{
SetActiveVehicle(tank);
}
public void Hover()
{
SetActiveVehicle(hover);
}

Related

CreateRoom failed. Client is on MasterServer (must be Master Server for matchmaking)

I'm making a multiplayer game, when I create a room, there is an error, but I can still enter the room. Does the error affect the room? or do I just let it go? or is there something wrong with my coding? please help me fix it.
This is the error :
CreateRoom failed. Client is on MasterServer (must be Master Server
for matchmaking)but not ready for operations (State: Joining). Wait
for callback: OnJoinedLobby or OnConnectedToMaster.
UnityEngine.Debug:LogError (object)
Photon.Pun.PhotonNetwork:CreateRoom
(string,Photon.Realtime.RoomOptions,Photon.Realtime.TypedLobby,string[])
(at Assets/Photon/PhotonUnityNetworking/Code/PhotonNetwork.cs:1782)
Launcher:CreateRoom (int) (at Assets/Script/Launcher.cs:63)
Launcher:b__13_1 () (at Assets/Script/Launcher.cs:35)
UnityEngine.EventSystems.EventSystem:Update () (at
Library/PackageCache/com.unity.ugui#1.0.0/Runtime/EventSystem/EventSystem.cs:501)
This is the code :
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using Photon.Pun;
using TMPro;
using Photon.Realtime;
using System.Linq;
public class Launcher : MonoBehaviourPunCallbacks
{
public static Launcher Instance;
[SerializeField] TMP_InputField roomNameInputField;
[SerializeField] TMP_Text errorText;
[SerializeField] TMP_Text roomNameText;
[SerializeField] Transform roomListContent;
[SerializeField] GameObject roomListItemPrefab;
[SerializeField] GameObject PlayerListItemPrefab;
[SerializeField] Transform playerListContent;
[SerializeField] GameObject startGameButton;
public GameObject twoPlayerButton;
public GameObject threePlayerButton;
public GameObject fourPlayerButton;
void Awake(){
Instance = this;
}
// Start is called before the first frame update
void Start()
{
Debug.Log("Connecting to Master");
PhotonNetwork.ConnectUsingSettings();
twoPlayerButton.GetComponent<UnityEngine.UI.Button>().onClick.AddListener(() => CreateRoom(2));
threePlayerButton.GetComponent<UnityEngine.UI.Button>().onClick.AddListener(() => CreateRoom(3));
fourPlayerButton.GetComponent<UnityEngine.UI.Button>().onClick.AddListener(() => CreateRoom(4));
}
public override void OnConnectedToMaster()
{
Debug.Log("Connected to Master");
PhotonNetwork.JoinLobby();
PhotonNetwork.AutomaticallySyncScene = true;
}
public override void OnJoinedLobby()
{
MenuSetting.Instance.OpenMenu("firstmenu");
Debug.Log("Joined Lobby");
}
public void CreateRoom(int numPlayers){
if(string.IsNullOrEmpty(roomNameInputField.text)){
return;
}
RoomOptions roomOptions = new RoomOptions();
roomOptions.MaxPlayers = (byte)numPlayers;
ExitGames.Client.Photon.Hashtable customProperties = new ExitGames.Client.Photon.Hashtable();
customProperties.Add("MinPlayers", 2);
roomOptions.CustomRoomProperties = customProperties;
PhotonNetwork.CreateRoom(roomNameInputField.text + numPlayers, roomOptions);
MenuSetting.Instance.OpenMenu("Loading");
}
public override void OnJoinedRoom()
{
MenuSetting.Instance.OpenMenu("room");
roomNameText.text = PhotonNetwork.CurrentRoom.Name;
Player[] players = PhotonNetwork.PlayerList;
foreach(Transform child in playerListContent)
{
Destroy(child.gameObject);
}
for(int i = 0; i < players.Count(); i++){
Instantiate(PlayerListItemPrefab, playerListContent).GetComponent<PlayerListItem>().SetUp(players[i]);
}
if (players.Count() >= 2)
{
startGameButton.SetActive(PhotonNetwork.IsMasterClient); //only show the button if there are more than 2 players
}
else
{
startGameButton.SetActive(false); // hide the button if there are less than 2 players
}
}
public override void OnMasterClientSwitched(Player newMasterClient)
{
startGameButton.SetActive(PhotonNetwork.IsMasterClient);
}
public override void OnCreatedRoom()
{
Debug.Log("Room created successfully!");
}
public override void OnCreateRoomFailed(short returnCode, string message)
{
errorText.text = "Room Creation Failed: " + message;
MenuSetting.Instance.OpenMenu("error");
}
public void StartGame()
{
PhotonNetwork.LoadLevel(1);
}
public void LeaveRoom()
{
PhotonNetwork.LeaveRoom();
MenuSetting.Instance.OpenMenu("main_menu");
}
public void JoinRoom(RoomInfo info ){
PhotonNetwork.JoinRoom(info.Name);
MenuSetting.Instance.OpenMenu("loading");
}
public override void OnLeftRoom()
{
MenuSetting.Instance.OpenMenu("loading");
}
public override void OnRoomListUpdate(List<RoomInfo> roomList)
{
foreach(Transform trans in roomListContent){
Destroy(trans.gameObject);
}
for(int i = 0; i < roomList.Count; i++){
if(roomList[i].RemovedFromList)
continue;
Instantiate(roomListItemPrefab, roomListContent).GetComponent<RoomListItem>().SetUp(roomList[i]);
}
}
public override void OnPlayerEnteredRoom(Player newPlayer)
{
Instantiate(PlayerListItemPrefab, playerListContent).GetComponent<PlayerListItem>().SetUp(newPlayer);
}
}

After Game Over how to stop score from increasing

Im making a endless runner game and am using a 'ScoreManager' object with a box collider 2d set to 'is trigger' increasing the score every time a object hits it. But I want it to stop increasing the score if the health reaches 0. This is the ScoreManager code:
public int score;
public Text scoreDisplay;
void OnTriggerEnter2D(Collider2D other)
{
if (other.CompareTag("Obstacle"))
{
score++;
}
}
private void Update()
{
scoreDisplay.text = score.ToString();
}
I would like to add a:
public int health = 3;
and in the Update function:
if (health <= 0) {
Destroy(gameObject);
}
But that doesn't seem to work.
The health is displayed in a player script.
public class Player : MonoBehaviour
{
private Vector2 targetPos;
public float Yincrement;
public float speed;
public float maxHeight;
public float minHeight;
public Text healthDisplay;
public GameObject gameOver;
public int health = 3;
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
private void Update()
{
healthDisplay.text = health.ToString();
if (health <= 0) {
gameOver.SetActive(true);
Destroy(gameObject);
}
Any thoughts?
Wherever your health is defined, substitute it by a property that launches an event whenever set to a value < 0. Like this:
public class Player : MonoBehavior
{
public delegate void PlayerDiedDelegate();
public static event PlayerDiedDelegate onPlayerDied;
private int _health;
public int health
{
get
{
return _health;
}
set
{
_health = value;
if(_health < 0)
{
onPlayerDied?.Invoke();
}
}
}
}
Now you can attach any controller in your scene to the event:
public class ScoreController : MonoBehavior
{
private void Awake()
{
Player.onPlayerDied += OnPlayerDied;
}
private void OnPlayerDied()
{
// Put your logic here: stop collecting score etc.
}
}

Using A Dictionary To Hash <String,Class>

I am looking to do a specific task for a small unity game I am doing for class.
In it, I am trying to hash a class that contains variables and a method that is specific to each class created for the dictionary. The variables work fine as they do not need to be static and are not abstract, the method however I am struggling to work with.
Here is my entire script being used.
using System.Collections;
using System.Collections.Generic;
using System.Reflection;
using UnityEngine;
public class EnemyZ : MonoBehaviour
{
// Class used to hash names health assets and then move options
public class EnemySet
{
public string EnemyName { get; set; }
public float EnemyHealth { get; set; }
public void Moves()
{
}
}
//setting EnemySet with names health (assets and move options)
public static void Setup()
{
var cards = new Dictionary<string, EnemySet>()
{
{ "Slime", new EnemySet { EnemyName="Slime", EnemyHealth= 25} },
{ "Flaz", new EnemySet { EnemyName="Flaz", EnemyHealth= 34} },
{ "BandShee", new EnemySet { EnemyName="BandShee", EnemyHealth= 45} },
{"Fan-Natic", new EnemySet{EnemyName = "Fan-Natic", EnemyHealth = 20} }
};
}
void Update()
{
}
}
I am looking to have the Move function be overridden and callable.
How would I set this dictionary of class/method's up and how would I call it once it has been correctly added to the dictionary?
I think you are approaching your class structure and the approach to overwriting your abstract methods incorrectly which is causing the confusion around the dictionary.
I would create an interface for enemies that defines what your enemies need to contain and perform. You can then create an abstract base class the implements common functionality for enemies. Each enemy type should then inherit from your base class.
See below as an example:
// all enemy types must implement the following
public interface IEnemy {
string EnemyName { get; }
float EnemyHealth { get; }
void Move ();
}
// abstract base class for common functionality
public abstract class Enemy : IEnemy {
protected float speed = 0.1f;
public string EnemyName { get; protected set; }
public float EnemyHealth { get; protected set; }
public virtual void Move () {
Debug.Log ($"{EnemyName} moving at {speed}");
}
}
public class Slime : Enemy {
public Slime () {
speed = 0.1f;
EnemyName = "Slimer";
EnemyHealth = 100f;
}
public override void Move () {
Debug.Log ($"{EnemyName} moving at {speed}");
}
}
public class Flaz : Enemy {
public Flaz () {
speed = 0.5f;
EnemyName = "Flaz";
EnemyHealth = 50f;
}
public override void Move () {
Debug.Log ($"{EnemyName} moving at {speed}");
}
}
public class Test : MonoBehaviour {
readonly List<IEnemy> Enemies = new List<IEnemy> ();
void Start () {
var slimer = new Slime ();
Debug.Log ($"{slimer.EnemyName} initialized with health of {slimer.EnemyHealth}");
slimer.Move ();
var flaz = new Flaz ();
Debug.Log ($"{flaz.EnemyName} initialized with health of {flaz.EnemyHealth}");
flaz.Move ();
Enemies.Add (slimer);
Enemies.Add (flaz);
Debug.Log ($"Added {Enemies.Count} enemies");
}
}
I'd say that having a better understanding of classes and interfaces would be good if you wanted to store your enemies in code (the easy way if you're good at object oriented code).
However to answer the question directly I'm going to assume that you're loading enemies from a database or a file or some other non-code format.
In that case I'd go with something like
// Class used to hash names health assets and then move options
public class EnemySet
{
public string EnemyName { get; set; }
public float EnemyHealth { get; set; }
public Action Moves { get; set; }
}
Then when ever you are reading from your datasource to set up the dictionary of enemies I'd have something like
public class EnemyLoader
{
public void MovePawn() => console.WriteLine("I'm a chess piece");
public void MoveZombie() => console.WriteLine("Brains");
public void MoveSlime() => console.WriteLine("Wobbo");
public Action PickMovement(string moveType)
{
switch(moveType)
{
case "pawn": return MovePawn;
case "pawn": return MoveZombie;
default: return MoveSlime;
}
}
public Dictionary<string, EnemySet> LoadEnemies()
{
var dataSource = ReadDataFromSomewhere();
return dataSource.ToDictionary(
k => k.EnemyName,
v => new EnemySet
{
EnemyName = v.EnemyName,
EnemySpeed = v.EnemySpeed,
Move = PickMovement(v.MoveType)
});
}
}

Why are there no variables showing up in inspector

Trying to make a Tile system in Unity. I have my tile class done but when I create a list in the TileManager class it gives me the option to change the size of the list but gives me an empty element with no changeable variables.
Tile Class:
public class Tile : MonoBehaviour
{
public Sprite tileSprite;
public string tileName;
public int tileID;
public Tile(Sprite newTileSprite, string newTileName, int newTileID)
{
tileSprite = newTileSprite;
tileName = newTileName;
tileID = newTileID;
}
void Start()
{
SpriteRenderer spriteRenderer = gameObject.GetComponent(typeof(SpriteRenderer)) as SpriteRenderer;
if (spriteRenderer != null) spriteRenderer.sprite = tileSprite;
}
TileManager Class:
public class TileManager : MonoBehaviour {
public List<Tile> Tiles;
// Use this for initialization
void Start ()
{
}
// Update is called once per frame
void Update () {
}
}
Use the System.Serializable attribute on Tile class. Also be sure that the Tile class does not inherit from MonoBehaviour, otherwise it will still not appear in the inspector list.
[System.Serializable]
public class Tile
{
public Sprite tileSprite;
public string tileName;
public int tileID;
public Tile(Sprite newTileSprite, string newTileName, int newTileID)
{
tileSprite = newTileSprite;
tileName = newTileName;
tileID = newTileID;
}
}

unity turn base script for enemy

I have a list of enemys. so i want each enemy have their turn.
First of all :
Player turn --> enemys turn ("here each enemy move one by one untill the end then player move again"). how do i making some waiting time here and forcus on enemy turn?
Any help would be appreciated.
void Start()
{
// find list enemy
enemy = GameObject.FindGameObjectsWithTag("Enemy");
}
void Update()
{
//enemy turn reference to player. after move all enemy we change it to false to change the player turn.
if(StaticClass.enemyTurn == true )
{
for(int i=0;i<enemy.length;i++)
{
// how do i making some waiting time here and forcus on enemy turn?
EnemyTurn(i);
}
}
}
public void EnemyTurn(int id)
{
ChessMoveMent chessMoveScript = enemy[id].GetComponent<ChessMoveMent>();
chessMoveScript.ProcessMove();
id++;
if(id>=enemy.Length)
{
isMove = false;
}
}
I usually use StartCoroutine in this case.
Please try the below code:
public IEnumerator EnemyTurn(int id)
{
yield return null;
ChessMoveMent chessMoveScript = enemy[id].GetComponent<ChessMoveMent>();
chessMoveScript.ProcessMove();
id++;
if(id>=enemy.Length)
{
isMove = false;
}
}
When you want to use it, please use with "StartCoroutine()"
StartCoroutine(EnemyTurn(i));
More details here
You might have a coordinator, who tells the participants when it's their turn.
public class GameCoordinator : MonoBehaviour
{
public List<Participant> participants;
private int currentParticipantIdx = -1;
private Participant CurrentParticipant
{
get { return participants[currentParticipantIdx]; }
}
private void Start()
{
PlayNextMove();
}
private void PlayNextMove()
{
ProceedToNextParticipant();
CurrentParticipant.OnMoveCompleted += OnMoveCompleted;
CurrentParticipant.BeginMove();
}
private void OnMoveCompleted()
{
CurrentParticipant.OnMoveCompleted -= OnMoveCompleted;
StartCoroutine(PlayNextMoveIn(2.0f));
}
private IEnumerator PlayNextMoveIn(float countdown)
{
yield return new WaitForSeconds(countdown);
PlayNextMove();
}
private void ProceedToNextParticipant()
{
++currentParticipantIdx;
if (currentParticipantIdx == participants.Count)
currentParticipantIdx = 0;
}
}
public class Participant : MonoBehaviour
{
public event Action OnMoveCompleted;
public void BeginMove()
{
//
}
}

Categories

Resources