I have some trouble initializing strings from their constructor when a new List element is created from the Unity inspector while in edit mode.
All it does is writing "Call test" to console, but not initializing its name and description to the placeholder texts.
public class StatsManager : MonoBehaviour {
[System.Serializable]
public class StatValue {
public string name;
public string description;
public int currentValue;
public StatValue(){
this.name = "Times hit";
this.description = "This is how much you have been hit since the start of the game.";
Debug.Log("Call test");
}
}
[SerializeField]
public List<StatsManager.StatValue> stats;
}
Ok I found a solution in case somebody has the same problem. No need of cTor or ISerializableCallbackReceiver. This uses the Reset Callback (from the coq) that will also call at instanciation. Cheers!
[System.Serializeable]
public class Test {
int value = 500;
}
public class TestManager : MonoBehaviour {
public Test testInt;
public List<Test> testInts;
void Reset(){
testInts = new List<Test>(){
new Test()
};
}
}
from https://answers.unity.com/questions/1467289/default-value-on-list-vanished.html?childToView=1467368#comment-1467368
Related
I am making a basic shop system includes car name, price and buyable. I am saving data to a text file. When I replay, I can't get the last variables I've changed. But, if I refresh at Editor by CTRL+R and start the game, variables are loading correct. What am I doing wrong? I am new at storage and JSON issues. Thanks for answers...
Here is the code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.IO;
using System;
public class GameHandler : MonoBehaviour
{
[Serializable]
public class Car
{
public string name;
public int price;
public bool unlocked;
}
[Serializable]
public class CarList{
public Car[] cars;
}
private Car cars = new Car();
public CarList myCars = new CarList();
//-------
public int chosenCar;
//-------
public TextAsset CARS;
//-------
private void Start() {
GetFromJSON();
}
private void Update() {
if(Input.GetKeyDown(KeyCode.L))
GetFromJSON();
if(Input.GetKeyDown(KeyCode.S))
SaveToJSON();
}
public void ChangeCarIndex(int a){
chosenCar = a;
}
//This is a button func.
public void ChangePrice(int a){
myCars.cars[chosenCar].price = a;
SaveToJSON();
}
public void GetCarName(){
Debug.Log(myCars.cars[chosenCar].name);
}
public void GetCarPrice(){
Debug.Log(myCars.cars[chosenCar].price);
}
public void SaveToJSON(){
string jsOutput = JsonUtility.ToJson(myCars);
File.WriteAllText(Application.dataPath + "/CARS.txt", jsOutput);
Debug.Log("SaveToJSON() called");
}
public void GetFromJSON(){
myCars = JsonUtility.FromJson<CarList>(CARS.text);
Debug.Log("GetFromJSON() called");
}
}
When running this in the editor try to add
public void SaveToJSON()
{
string jsOutput = JsonUtility.ToJson(myCars);
File.WriteAllText(Application.dataPath + "/CARS.txt", jsOutput);
Debug.Log("SaveToJSON() called");
#if UNITY_EDITOR
UnityEditor.AssetDatabase.Refresh();
#endif
}
Though actually this isn't really necessary! Afaik you could also simply set the text of the textasset:
public void SaveToJSON()
{
string jsOutput = JsonUtility.ToJson(myCars);
CARS.text = jsOutput;
Debug.Log("SaveToJSON() called");
}
BUT NOTE:
in general note that this makes only sense in the editor itself.
If you target to do this in an actually later built application you would rather go via a file in Application.persistentDataPath. Problem with that though: The data can easily be seen and edited by the user. So if this is anything sensitive you will need to go for a central database server with user login.
I have these classes, one is a model, other is Listener and the third one is an Util class. I want to access Terrains by the variable map in the first one, but don't want public access to the inner class Terrain. Is there any way to do it?
It prints error CS0052: Inconsistent accessibility: field type
System.Collections.Generic.List is less
accessible than field `MapaMundiInfoScript.map'
public class MapaMundiInfoScript : MonoBehaviour {
public static bool changeInMap= false;
public static List<Terrain>map = new List<Terrain>();
void Start(){
Terrain terrain = new Terrain(0,0);
Terrain.TerrainPart initialPart = new Terrain.TerrainPart(20,20,0,0);
terrain.terrainParts.Add (initialPart);
map.Add(terrain);
changeInMap=true;
}
class Terrain{
int XPosition;
int ZPosition;
public List <TerrainPart> terrainParts = new List<TerrainPart> ();
public Terrain(int XPosition, int ZPosition){
this.XPosition=XPosition; this.ZPosition=ZPosition;
}
public class TerrainPart
{
int XSize;
int ZSize;
int XPosition;
int ZPosition;
TerrainPartReturn ReturnTerrainPart(int num1,int num2,int num3,int num4)
{
return new TerrainPart (num1,num2,num3,num4);
}
public TerrainPart(int XSize,int ZSize,int XPosition,int ZPosition){
this.XSize = XSize;
this.ZSize = ZSize;
this.XPosition=XPosition;
this.ZPosition =ZPosition;
}
}
}
public class MapListener : MonoBehaviour {
void Update () {
if (MapaMundiInfoScript.changeInMap) {
foreach(MapaMundiInfoScript.Terrain terrain in MapaMundiInfoScript.mapMundi)
{
foreach(terrain.terrainPart terrainPart in terrain.terrainParts)
{
RegionDraw.Draw(terrainPart);
}
}
MapaMundiInfoScript.changeInMap = false;
}
}
public class RegionDraw
{
/***
Implementantion Draw Method
***/
}
You cannot reference a private class as a public property. You will need to have the class public for public access. Consider making your properties and methods private, private protected, internal etc.
If you need to provide read only attributes, you can use public getters and private setters, etc. If you need to prevent the execution of some methods consider setting those to private, etc. The class can be public while still locking down properties and methods inside the class. Consider what it is that you actually need to expose.
You could also expose the functionality of these hidden classes through interfaces
public interface ITerrain
{
List<ITerrainPart> TerrainParts { get; }
ITerrainPart CreateTerrainPart(int XSize, int ZSize, int XPosition, int ZPosition);
}
public interface ITerrainPart
{
// ...
}
Implement them like this
private class Terrain : ITerrain
{
int XPosition;
int ZPosition;
public List<ITerrainPart> TerrainParts { get; } = new List<ITerrainPart>();
public Terrain(int XPosition, int ZPosition)
{
this.XPosition = XPosition; this.ZPosition = ZPosition;
}
public ITerrainPart CreateTerrainPart(int XSize, int ZSize, int XPosition,
int ZPosition)
{
return new TerrainPart(XSize, ZSize, ZPosition, ZPosition);
}
private class TerrainPart : ITerrainPart
{
// ...
}
}
Your listener can then draw like this (after changing the parameter type of Draw to ITerrainPart):
void Update()
{
if (MapaMundiInfoScript.changeInMap) {
foreach (ITerrain terrain in MapaMundiInfoScript.map) {
foreach (ITerrainPart terrainPart in terrain.TerrainParts) {
RegionDraw.Draw(terrainPart);
}
}
MapaMundiInfoScript.changeInMap = false;
}
}
Let MapaMundiInfoScript have a method DrawTerrain() and let Terrain have a method DrawParts. Should you end up with to many incoherent methods in MapaMundiInfoScript, you might want to use a visitor.
I have a class with a PictureBox created as followed:
public class Tile
{
public PictureBox tilePB = new PictureBox(); //properties don't matter in this case
}
I also have a class GameManager. This is like a referee.
I want to make it so the BackColor of Tile.tilePB can only be edited by Gamemanager and nothing else, and no other class.
I currently have a public PictureBox for Gamemanager (to edit) and a public get function for other classes, but I want to actually make this a valid system instead of what I have right now.
Is this even possible? Please include explenation for the required code.
EDIT: I ran into an issue that I hadn't thought off: class Gamemanager is a static class. I do everything in that class via public static functions. Is this still possible? Since this doesn't work.
You can't do this at compile time, but it can be done at runtime:
public class PictureBox
{
private Color _backColor;
public void SetBackColor(Color color)
{
//getting class type that called this method
var stackTrace = new StackTrace();
var stackFrames = stackTrace.GetFrames();
var callingFrame = stackFrames[1];
var method = callingFrame.GetMethod();
//checking if the class type is GameManager
if (!method.DeclaringType.IsAssignableFrom(typeof(GameManager)))
{
throw new FieldAccessException("Only GameManager can set the background color of a PictureBox!");
}
_backColor = color;
}
public Color BackColor => _backColor;
}
public class Tile
{
public PictureBox tilePB { get; set; }
}
//example GameManager class
public class GameManager
{
public void SetBackground()
{
var someTile = new Tile()
{
tilePB = new PictureBox()
};
var someColor = new Color();
someTile.tilePB.SetBackColor(someColor);
}
}
//example class that may want to set picturebox background color
public class MaliciousClass
{
public void SetBackground()
{
var someTile = new Tile()
{
tilePB = new PictureBox()
};
var someColor = new Color();
someTile.tilePB.SetBackColor(someColor);
}
}
Then somewhere:
var gm = new GameManager();
var mc = new MaliciousClass();
gm.SetBackground(); //this is fine
mc.SetBackground(); //this will throw an exception
If you don't want to throw an exception or you want to do something different when "not authorized" class is trying to access the SetBackColor method then just replace throw new FieldAccessException() with return or whatever you want.
Bare in mind the approach presented here is inefficent and it just presents that in can be done at runtime and nothing more than that.
Not sure if this is exactly what you are looking for, but I made this quick test and it seems to be able to differentiate the calling class:
class Program
{
static void Main(string[] args)
{
Type1 something1 = new Type1();
Type2 something2 = new Type2();
something1.runTest();
something2.runTest();
Console.ReadKey();
}
public class Type1
{
public void runTest()
{
Testing.edit(this);
}
}
public class Type2
{
public void runTest()
{
Testing.edit(this);
}
}
public static class Testing
{
public static void edit(object obj)
{
// This is where you test the calling class to make sure
// it is allowed to edit.
Console.WriteLine(obj.GetType().ToString());
}
}
}
The only way I can think of where you enforce this at compile time, end up being a bit complicated. I don't think you'll want to do this.
You can create an interface with properties/methods for everything that only the GameManager is allowed to do. You can implement this interface in a private inner class below Tile, and make sure the only way this object is created is by passing in a GameManager that receives it. Now, the only way the access can 'leak' is if the GameManager 'gives away' the object.
public class GameManager {
public void AddTile(Tile t, Tile.IManagerHook m) {
m.SomeProperty = "set from manager";
}
}
public class Tile
{
public object SomeProperty { get; private set; }
public Tile(GameManager manager) {
manager.AddTile(this, new ManagerHook(this));
}
public interface IManagerHook {
object SomeProperty {get; set;}
}
private class ManagerHook : IManagerHook {
private Tile _tile;
public ManagerHook(Tile t) {
_tile = t;
}
public object SomeProperty {
get{ return _tile.SomeProperty;}
set { _tile.SomeProperty = value; }
}
}
}
(seems) Simply not possible
After asking several programmers, the way I have coded everything and what I want seems to be simply impossible without immensely complicated code - to the point you are better off refacturing everything. Since class Gamemanager is a static class, there will be no instances of it so you can not check if the 'object' that called it is of class Gamemanager. this also doesn't work since Gamemanager is, agian, static.
This is code inside Proizvod.cs file
namespace mateo_zadatak
{
class Proizvod
{
public string Šifra = "šifra";
public string Naziv = "naziv";
public string Proizvođač = "proizvođač";
public float Cijena;
public int Količina;
private float Ukupno;
private int Popust;
private float UkupnoPopust;
private void variable()
{
Ukupno = Cijena * Količina;
{
if (Količina < 10)
{
Popust = 0;
}
else if (Količina > 9 && Količina < 31)
{
Popust = 5;
}
else Popust = 10;
}
}
}
}
I have to use this variables in Form1.cs file , because i will need some calculations from datagrid. How to connect those two files?
There are no "Global" variables in C# but what you can do is create a new Class with Static variables and assign/use them. For example:
public static class GlobalVariables
{
public static int IntVariable;
public static string StringVariable;
}
And then you can reference them as GlobalVariables.IntVariable and GlobalVariables.StringVariable.
A Form is just a class - Add public properties/members to the Form and access them from a reference to the form.
Make your class public, and make sure you include Proizvod.cs file into your project or add a reference to it from your project.
You can use public properties instead of variables from another class
Perhaps I'm missing something, but:
public class Form1 : ...
{
public Proizvod Foo;
Form1()
{
Foo = new Proizvod();
}
SomeMethod()
{
MessageBox.Show(Foo.Naziv);
}
}
I have no clue how to write a title correctly but what I mean is to make something like this:
public static MusicPlayer _Player = new MusicPlayer();
_Player.Play.Song(TestPath);
where MusicPlayer is a class and in that class I want to make something like property or another class I don't know how to call it, which will have two methods. My code for now:
public class MusicPlayer
{
//Variables, Methods and Properties in MusicPlayer
//And then Play which can have two tipes of play.
public static class Play
{
//This one should be called if I want to play one song
public static void Song(String _path)[...]
//And this one when I want to play from list, defined in MusicPlayer class
public static void List()[...]
}
}
You should do this:
public class MusicPlayer
{
public class Player
{
public static void Song(String _path)[...]
public static void List()[...]
}
private Player m_player = new Player();
public Player Play
{
get { return m_player; }
}
}
This defines a Player class in MusicPlayer. Also it creates a member variable of type Player and a property that allows you to access the Player instance from the outside using an instance of MusicPlayer:
var mplayer = new MusicPlayer();
mplayer.Play.Song(...);
If you do not want to create an instance of MusicPlayer, you could also make this static:
public class MusicPlayer
{
public class Player
{
public static void Song(String _path)[...]
public static void List()[...]
}
private static Player m_player = new Player();
public static Player Play
{
get { return m_player; }
}
}
You can now use MusicPlayer.Play.Song(...) without having to create an instance.
You can do something like that
public class MusicPlayer
{
public MusicPlayer()
{
Play = new Play();
}
public Play Play { get; private set; }
}
public class Play
{
//This one should be called if I want to play one song
public void Song(String _path){}
//And this one when I want to play from list, defined in MusicPlayer class
public void List() { }
}
And then using like
new MusicPlayer().Play.Song("");