I am creating a game in Unity3d.
Somewhere I have hints appearing in the bottom of the HUD (Something like "press A for Action"). I want my game to support more languages and I don't want these hints to be hard-coded in the script.
What is the most elegant way to solve this task? I am thinking about txt file, where I will have all my hints in all languages. But I am not sure, if it is a good idea.
Thanks in advance.
A common way that is used is to have an XML-file for each language. The XML-file should contain every phrase you use in your game with a unique ID.
In your code, you can then get the correct phrase out of the current language's XML, using the correct ID.
If you don't know about XML files, read this tutorial about using XML files in Unity: http://xeophin.net/en/blog/2010/05/13/reading-strings-out-xml-file-using-c-unity-3d
However if you are willing to spend some money on your game, you should check this out: http://u3d.as/content/rodrigo-barros/my-menu/32E
I haven't tried that yet but it seems good.
Hardcoding is not that bad if you do it correctly.
For example create an abstract class with all the messages that you want to have and language autodetection:
public abstract class Lang {
static Lang currentLang;
public static Lang Get {
get {
if(currentLang == null)
switch(Application.systemLanguage) {
case SystemLanguage.Polish:
currentLang=new LangPL();
break;
default:
case SystemLanguage.English:
currentLang=new LangEN();
break;
}
return currentLang;
}
}
public abstract string MenuTime {get;}
public abstract string MenuPoints {get;}
public abstract string YouWon {get;}
public abstract string YouLost {get;}
public abstract string Point(int p);
}
And then implement each language as a separate class:
public class LangPL:Lang {
public override string MenuTime {get {return "CZAS";}}
public override string MenuPoints {get {return "WYNIK";}}
public override string YouWon {get {return "Gratuluję, wygrałeś!";}}
public override string YouLost{get {return "Może następnym razem...";}}
public override string Point(int p) {
if(p == 1)
return "1 punkt";
return p+" punktów";
}
}
public class LangEN:Lang {
public override string MenuTime {get {return "TIME";}}
public override string MenuPoints {get {return "SCORE";}}
public override string YouWon {get {return "You won!";}}
public override string YouLost{get {return "Maybe next time...";}}
public override string Point(int p) {
if(p == 1)
return "1 point";
return p+" points";
}
}
Usage is a simple:
GUILayout.Label(Lang.Get.YouWon);
GUILayout.Label(Lang.Get.Point(5));
This way you have most control, and can easily support complex translations. Also this approach helps to trim down on errors - if you forget or misstype a text anywhere it throws a syntax error.
You can try to create a Javascript script or a C# script for each language and then depending of the language choosen, you call the specific script.
e.g
public class English : MonoBehaviour{
public string jump = "Press 'space' to jump";
//etc
}
public class French : MonoBehaviour{
public string jump = "Appuyer sur 'espace' pour sauter";
//etc
}
In your function for GUIText
public GameController gameController;
public GUIText text;
private string languageSelected;// obtain from the user input on language selection (better if registered in the gameController)
void Awake(){
languageSelected = System.Activator.CreateInstance(Type.GetType(gameController.languageSelected));
// where languageSelected will be e.g English
text.text = languageSelected.jump;
}
I strongly advise against embedding text into your code. It will slow down the localization process (having to look through code to find text is not the quickest and best way to approach localization).
Go with separate files. It's easier to maintain and translators don't have to access the code.
Have a look at l2 localization. It's a pretty handy Unity plugin that allows you to manage translations of your game.
All your localized strings in a single Google Spreadsheet. Once set up, all you need to do is fill it out to see the results in the game.
I am a game translator myself and happen to be managing a small team of game translators called Level Up Translation. We posted a beginner's guide for localization in Unity in our blog a couple of months ago. Feel free to check it out!
For example, you can save language file for france.txt in format:
hello=Bonjour
goodbye=Au Revoir
And than, read file and convert it to dictionary:
string[] lines = File.ReadAllLines("france.txt");
var dict = lines.Select(l => l.Split('=')).ToDictionary(a => a[0], a => a[1]);
Now you can read from dictionary by key:
string hello = dict["hello"];
Related
I just started using Unity (which came with VSC), but I had better experience using JetBarin products such as IntelliJ IDEA, so I went and switched to Rider. However, I am now unable to connect public variables (int, float, GameObject) to my Unity projects.
I tried updating Rider and changing some setting, but came none the wiser.
UPDATE: There have been (obvious) request for my code to see the exact issue, so I hope this helps clear up the issue a little bit:
Code written in VSC
The resulting public variables showing up in Unity
Similar code written using Rider
No interactive variables showing up in Unity
Unity serializes only fields (not properties with get or set) of MonoBehaviours. All public fields are serialized unless have [System.NonSerialized] attribute.
DO NOT get confused with the [HideInInspector] attribute, it won't be visible in the inspector (if you don't have a custom inspector) but WILL BE serialized.
class Foo
{
// Bar won't be shown in the inspector or serialized.
[System.NonSerialized]
public int Bar = 5;
}
To serialize a non-public field use [SerializeField] attribute for primitive types (such as int, float, bool).
public class SomePerson : MonoBehaviour
{
// This field gets serialized because it is public.
public string name = "John";
// This field does not get serialized because it is private.
private int age = 40;
// This field gets serialized even though it is private
// because it has the SerializeField attribute applied.
[SerializeField]
private bool isMale = true;
}
If you wanna serialize own class or struct, use [System.Serializable] attribute.
[System.Serializable]
public struct PlayerStats
{
public int level;
public int health;
}
What is the use of constructor here ?
This is script A :
[SerializeField]
private LobbyFunction _lobbyFunction;
public LobbyFunction LobbyFunction
{
get { return _lobbyFunction; }
}
This is script B:
private void Start()
{
GameObject lobbyCanvasGO = CanvasManager.Instance.LobbyFunction.gameObject;
if (lobbyCanvasGO == null) return;
}
what if I choose not to use the encapsulation ? no error , I guess .Any help would be greatly appreciated ,thanks!
edit: I guess using encapsulation here make the var read- only , only get... and therefore increase the security , people from outside can't change the value ,is it the ans?
This is no constructor but a Property
A property is a member that provides a flexible mechanism to read, write, or compute the value of a private field. Properties can be used as if they are public data members, but they are actually special methods called accessors. This enables data to be accessed easily and still helps promote the safety and flexibility of methods.
In your case it is for granting Read-Only access to the private backing field _lobbyFunction so no other class can change its value since only the class "A" containing _lobbyFunction itself is allowed to assign it.
Btw the way you have it it is equivalent to simply write
public LobbyFunction LobbyFunction { get; private set; }
without the need for a backing field. Then still only the containing class "A" itself is allowed to assign a value while everyone else can read it.
Should I rather create a public static class or use internal constants?
I am working on a very large application and noticed the use of const string at numerous places.This is used to compare the users selection
const string Thatch = "Thatch";
const string BrickAndTimberFrame= "Brick And Timber Frame";
const string OtherRoof = "Other";
etc......
etc......
What I want to do is to rather create public static class in the Core Application (see code below). The reason for this is that I only have to change/add a value at one place only.
public static class RoofConstruction
{
public static String Thatch{ get { return "Thatch"; } }
public static String BrickAndTimberFrame { get { return "Brick And Timber Frame"; } }
etc....
etc....
}
The compare function will then look like this
internal bool SlateTileOrConcreteRoof()
{
return RiskInformation.RoofConstruction.Value == RoofConstruction.Slate ||
RiskInformation.RoofConstruction == RoofConstruction.TileAndSlate ||
RiskInformation.RoofConstruction == RoofConstruction.Concrete;
}
Please add any comments/improvements etc
Generally speaking, I think that “the defining characteristic of ‘a Good Class™’,” is that “it does the right thing, nevermind(!) ‘how, exactly,” it does it.”
When you export constants from the class, this suggests that an unknown-number of other sections of the application (present and future ...) will contain logic that tests against that string.
Therefore, the question that only you can really answer: “do they really care about ‘the value of that string,’ or do they want ‘the answer to a yes-or-no question, which is answered in part based on the value of that string?’” This might guide your decision about what is best to do. (Mind you, I do not think that there is any sort of bright-line rule. I have done it both ways...)
I read it from vala tutorial
for readonly: vala
public int b { get; private set; }
in Genie:
prop readonly b: int
for writeonly:
Vala:
public int b { private get; set; }
Genie: [this line: syntax error]
prop writeonly b: int
How to declare an one-line writeonly property in Genie?
maybe something like?
prop XXX b: int
We can write a FOUR lines writeonly property:
class Wonly
_b: int
prop b: int
set
_b = value
init
var w = new Wonly
// print w.b // ERROR!! writeonly!!
w.b = 456 // OK
but How to write an one-line writeonly property?
I will do my best to answer your question here, however some aspects of your question are not clear. Maybe it would be help to give a bit more context, explaining better what you are planning to achieve and a little bit more of code for contextualization.
That said, I will assume you are asking about the syntax for class properties in Genie.
Properties are ways of hiding the implementation details from the users of the class you developed. According to Vala's tutorial this move is also called the information hiding principle in computer science.
In Vala, a propertie would be defined within a in the following way:
static int current_year = 2525;
class Person : Object {
private int year_of_birth = 2493;
public int age {
get { return current_year - year_of_birth; }
set { year_of_birth = current_year - value; }
}
}
In Genie, it would look like this:
class Foo : Object
prop name : string
prop readonly count : int
[Description(nick="output property", blurb="This is the output property of the Foo class")]
prop output : string
get
return "output"
set
_name = value
Now for the write only properties. It is a bit of a controversial matter based on this and this questions at SO. It seems to be useful only when you are not planning to read what you write. But as you can see on the questions above, most of the answers suggest the creation of methods instead of using write only properties.
That takes us to the syntax you are pointing to:
public int b { private get; set; }
You state that this is the syntax to a write only property in Vala, and it seems to be true. This is because, by setting the get as private you prevent the user to read the value. You can make the get or set as private in Vala by leaving it out of the set block as well, ie, in Vala you could simply remove the private get part.
Now this is where I am unsure, but I suggest you try it out in your code. Based on Vala's ability to set private getters or setters by removing them from the set block, I suspect that the same applies to Genie.
I removed the setting of the get from the following code and it compiled:
[indent=4]
class Foo : Object
prop name : string
prop readonly count : int
[Description(nick="output property", blurb="This is the output property of the Foo class")]
prop output : string
set
_name = value
init
var foo = new Foo()
Maybe that is what you are looking for, but I am not sure it would work in real code. If it does not, perhaps you would be better off with methods instead.
Some I do quite a lot of is read integers from AppSettings. What's the best way to do this?
Rather than do this every time:
int page_size;
if (int.TryParse( ConfigurationManager.AppSettings["PAGE_SIZE"], out page_size){
}
I'm thinking a method in my Helpers class like this:
int GetSettingInt(string key) {
int i;
return int.TryParse(ConfigurationManager.AppSettings[key], out i) ? i : -1;
}
but this is just to save some keystrokes.
Ideally, I'd love to put them all into some kind of structure that I could use intellisense with so I don't end up with run-time errors, but I don't know how I'd approach this... or if this is even possible.
What's a best practices way of getting and reading integers from the AppSettings section of the Web.Config?
ONE MORE THING...
wouldn't it be a good idea to set this as readonly?
readonly int pageSize = Helpers.GetSettingInt("PAGE_SIZE") doesn't seem to work.
I've found an answer to my problem. It involves extra work at first, but in the end, it will reduce errors.
It is found at Scott Allen's blog OdeToCode and here's my implementation:
Create a static class called Config
public static class Config {
public static int PageSize {
get { return int.Parse(ConfigurationManager.AppSettings["PAGE_SIZE"]); }
}
public static int HighlightedProductId {
get {
return int.Parse(ConfigurationManager.AppSettings["HIGHLIGHT_PID"]);
}
}
}
Advantage of doing this are three-fold:
Intellisense
One breakpoint (DRY)
Since I only am writing the Config String ONCE, I do a regular int.Parse.
If someone changes the AppSetting Key, it will break, but I can handle that, as those values aren't changed and the performance is better than a TryParse and it can be fixed in one location.
The solution is so simple... I don't know why I didn't think of it before. Call the values like so:
Config.PageSize
Config.HighlightedProductId
Yay!
I know that this question was asked many years ago, but maybe this answer could be useful for someone. Currently, if you're already receiving an IConfiguration reference in your class constructor, the best way to do it is using GetValue<int>("appsettings-key-goes-here"):
public class MyClass
{
private readonly IConfiguration _configuration;
public MyClass(IConfiguration configuration)
{
_configuration = configuration;
}
public void MyMethod()
{
int value = _configuration.GetValue<int>("appsettings-key-goes-here");
}
}
Take a look at T4Config. I will generate an interface and concrete implementation of your appsettings and connectionstringsections of you web/app config using Lazyloading of the values in the proper data types. It uses a simple T4 template to auto generate things for you.
To avoid creating a bicycle class you could use the following:
System.Configuration.Abstractions.AppSettings.AppSetting<int>("intKey");
https://github.com/davidwhitney/System.Configuration.Abstractions