Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 2 months ago.
This post was edited and submitted for review 2 months ago and failed to reopen the post:
Original close reason(s) were not resolved
Improve this question
hey everyone
I asked this question in unity answers but I didn't get any answers.
I'm new to programming and I have a question about scriptable objects. I'm making a strategy management game and I have characters in the game with unique information like name, age, cloth, skills, and many more (+35 variables include int, strings, Lists, and GameObjects), I made a scriptable object for this purpose and read each character data from it and change them if needed.
firstly, I want to know is it logical to have 100+ characters with these scriptable objects attached to each one of them or just use a simple script for my character to handle variables.
secondly, make them from the start or instantiate them in the middle of the game which one is better?
thirdly, how about saving and using them in runtime?
Thanks
Edit:
After searching for answers finally, it is obvious that there is no need for scriptable objects for this type of variables and GameObjects. so I decided to update my question.
now my question is what is the best way to use this type of character variable? my characters heavily depend on stats and variables that need to change or read all of the time like stress of the character drop over time and needs to show always.
I use this simple, easy to edit and maintain method, which purists will probably poo-har, but it will get you running quick and easy. Put it all in your class constructor method, with a switch statement.
You set shared attributes outside, and specific attributes inside the switch statement.
Then you can create an NPC as easy as MyNpc = new NPC(16) Where 16 is Warrior type or whatever. Its easy to add new attributes at the top without editing 100 scriptable objects, you can see everything in one spot.
I've got five as an example, but you could have a 100 here without taking up much space. You can add one without doing any modifications.
You can create them at runtime.
public class NPC
{
public int NPC_ID; // the unique ID of the NPC
public string Name;
public bool active;
public string SpriteName;
public int PassiveAbility; // The passive ability the NPC grants 0= none
public int Dice_ID; // The Dice ID the NPC adds to the party 0=none
public int HP; // Max hit points (fully healed)
public int HPR; // Hit points remaining
public int FP; // Max food points
public int FPR; // food points remaining
public int MaxSlots; // Number of item slots
public bool Fem; // Use female audio
public NPC(int ID) // Pass the ID to create the NPC of that ID
{
NPC_ID = ID;
HP = 2;
PassiveAbility = 0;
MaxSlots = 3;
FP = 5;
Fem = false;
switch (ID)
{
case 1:
Name = "Bisky"; SpriteName = "N25"; PassiveAbility = 12; MaxSlots = 0; FP = 20; break;
case 2:
Name = "Zahid"; SpriteName = "N28"; PassiveAbility = 2; MaxSlots = 4; break;
case 3:
Name = "Anna"; SpriteName = "N17"; HP = 1; PassiveAbility = 3; FP = 8; Fem = true; break;
case 4:
Name = "Carl"; SpriteName = "N30"; PassiveAbility = 4; MaxSlots = 4; break;
case 5:
Name = "Max"; SpriteName = "N06"; PassiveAbility = 5; break;
default:
Debug.Log("ERROR: Got passed a bad NPC number: {NPC constructor}");
break;
}
HPR = HP; // Set current hit points to Max Hit points
FPR = FP; // Set current food points to Max Food points
}
} // End Class
Related
Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed last month.
Improve this question
What I want to achieve is to make sure that my property is always 0 or greater. The type doesn't matter.
Lets say:
var x = 3;
var y = 5;
And after x -= y x is supposed to be 0.
Currently using this way and was wondering of there is a way without member variables:
public int Coins
{
get { return Math.Max(0, _coins); }
set { _coins = value; }
}
Couldn't either figure out a way with uint.
All suggestions appreciated.
uint x = 3;
uint y = 5;
Expected x beeing 0 after x -= y but received unit max.
If you implement the get and set differ from the automatic properties, then you always need to declare a private member to store the value. This is by design.
Even if you use the automatic properties and don't declare the private member, the compiler will do it anyway. You just see less code, but the computer sees no differences.
Source: https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/auto-implemented-properties
Anyway, I would suggest 1 small change:
public int Coins
{
get { return _coins; }
set { _coins = Math.Max(0, value); }
}
This way, the "wrong" _coins value don't get stored. But of course, it based on your bussiness logic, so the suggested code might not the right one for you
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 11 months ago.
Improve this question
I have 50 levels, these levels are prefabs (not scenes) and are being loaded by the help of script. What I want is that when I have played 50 levels. It should start randomizing levels from those 50 levels I have played earlier. Currently I have used a list for this purpose which stores integers from 0 to 49 since my levels identify as 0 to 49 for level to level 50 respectively. It worked for once like it loaded a random level once and then for example if the random level was 30 it would start loading levels from 30 onwards, i.e. 31, 32, 32 and so on. Currently, I get an error of transform child out of bounds when I win level 50 and click next button.
Here is the logic: Here I am making a bool variable set to true when I start level 50.
if (EnvirenmentNo == 49)
{
lastLevel = true;
PlayerPrefs.SetInt("startRandom",startRandom?1:0);
startRandom = true;
//PlayerPrefs.SetInt("CurrentLevel", EnvirenmentNo);
}
This is the logic for loading next level. The else part of the code loads the next levels normally, the if part is where I want the level to be loaded randomly from my played levels till they are all played. For this I am using a list and removing the random number before starting the level. Nothing seems to work rn.
else if (btn == "next")
{
if (lastLevel)
{
int nextLevelIndex = Random.Range(0,randomLevels.Count);
int nextLevel = randomLevels[nextLevelIndex];
EnvirenmentNo = nextLevel;
randomLevels.Remove(nextLevelIndex);
lastLevel = true;
startRandom = true;
EnvirenmentNo = Random.Range(0, 50);
//currentLevel++;
LoadingPanel.SetActive(true);
Finish.Instance.collider2D.enabled = false;
LevelCompletePanel.SetActive(false);
PlayerPrefs.SetInt("restart", 1);
Application.LoadLevel(Application.loadedLevel);
//VehicleSimpleControl._instance.rigidBody.bodyType = RigidbodyType2D.Static;
}
else
{
//DrawingManager.Instance.posCount = 0;
EnvirenmentNo ++;
//currentLevel++currentLevel++;
LoadingPanel.SetActive(true);
Finish.Instance.collider2D.enabled = false;
LevelCompletePanel.SetActive(false);
PlayerPrefs.SetInt("restart", 1);
Application.LoadLevel(Application.loadedLevel);
//VehicleSimpleControl._instance.rigidBody.bodyType = RigidbodyType2D.Static;
}
This is the list and integer I have created,
protected const int MAX = 50;
public static List<int> randomLevels = new List<int>();
Earlier I was not able to randomize the levels. Now the levels are being randomized once the user finishes level 50. But there is still one problem, the levels are repeating. I am removing the index of the level randomized but still after few levels it somehow occurs again. Like currently I had level 49 come 3 times, level 18 and 25 2times. I have also added the list and the integer I am using in list in my question. Thanks in Advance!
Well all I can tell from the little code you provide is that you completely ignore the
EnvirenmentNo = nextLevel;
and overwrite it again using a hard coded
EnvirenmentNo = Random.Range(0, 50);
just a few lines later, which doesn't prevent any duplicate levels.
Beyond that it is really hard to tell since as said we don't know your full code but most probably you should also somewhere store which levels have already been played so you don't repeat the random ones later.
You could e.g. save and load them using
PlayerPrefs.SetString("randomLevels", string.Join(",", randomLevels.ToArray()));
and
using System.Linq;
...
randomLevels.Clear();
randomLevels.AddRange(PlayerPrefs.GetString("randomLevels").Split(',').Select(s => int.Parse(s)));
Also note
Here I am making a bool variable set to true when I start level 50.
this is logically wrong. You would want to do this after finishing level 50 only, not when you start it!
You should change startRandom to true before PlayerPrefs.SetInt to save the right value.
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 3 years ago.
Improve this question
I am looking for the best way to create a "best" list for a group of lists. Here's the shorthand of what I have:
public class Tank
{
public int id;
public string name;
List<Volume> volume; //Volume for each day for two years
}
public class Volume
{
public DateTime date;
public double volume;
public string status;
}
public class Master
{
public DateTime date;
public string bestTankName;
public int id;
public double bestVolume;
}
Main
{
List<Master> masterVolume = new List<Volume>();
List<Tank> Tanks = SQLQueryToGetVolumes();
for (int i = 720; i < 0; i--)
{
masterVolume.Add(new Master
{
date = DateTime.Today.AddDays(-i)
});
}
//for each date in the master volume list, I need to get the
//highest volume from the other lists for that day,
//along with the other information associated with that day
foreach (Master m in masterVolume)
{
//Compare all the Tanks and get the best one for that day*******
}
}
I have made a mess of foreach loops that result in roughly 100 Billion computations for all of the data that needs to be processed. There are thousands of these groups of tanks that need to processed in this way.
Is there a better way to go about doing this? I need to get the highest volume, for every day. I then need to record that volume along with the other tank class properties into a master list without it taking 15 hours.
Any help or direction would be much appreciated.
An optimal solution for this would have you traverse the entire list of volumes only once, or O(n). The loops you mentioned were doing some multiple of that. There may be a way to do this with Linq to attain O(n) efficiency, but without more testing I do not know.
However, you can get O(n) with a nested for loop. For my suggestion, you could use a dictionary where the key is the date (in format MM/DD/YYYY) and the value is the Master.
Dictionary<DateTime, Master> masterVolumes = new Dictionary<DateTime, Master>();
List<Tank> tanks = SQLQueryToGetVolumes();
DateTime dt;
Master m;
foreach(Tank tank in tanks)
{
foreach(Volume volume in tank.volume)
{
//Since dates may have times associated, we strip the time.
dt = new DateTime(volume.date.Year, volume.date.Month, volume.date.Day);
//See if the day already exists
if (masterVolumes.ContainsKey(dt))
{
//If so, compare the current best volume
m = masterVolumes[dt];
if (m.bestVolume < volume.volume)
{
//There is a new master!
m.bestTankName = tank.name;
m.id = tank.id;
m.bestVolume = volume.volume;
}
}
else
{
//This date doesn't exist yet, so add it
m = new Master()
{
date = dt,
bestTankName = tank.name,
id = tank.id,
bestVolume = volume.volume
};
masterVolumes.Add(dt, m);
}
}
}
//At the end of this, the masterVolumes.Values will hold a collection of
// the highest volume Master for each day.
I am creating a Dungeons and Dragons Character Creator. There is a randomize feature that is going to create a complete character sheet. There is a part that I have gotten to and I am not quite sure the best way to proceed.
The way I have the racial modifiers set up is with if statements. Here is an example.
if (raceInt == 0 || raceInt == 2 || raceInt == 10)
{
raceStrMod = 2;
}
if (raceInt == 3 || raceInt == 4 || raceInt == 5 || raceInt == 11 || raceInt == 12)
{
raceDexMod = 2;
}
However there are races that have modifiers that let you select two stats to add a modifier to, such as Strength or Dexterity. What would be the best way to select two random ints for just those races?
For example, the half-elf race which would get +2 to Dex and then +1 to two other random stats. So I need to find a way to randomly select two of the remaining ints to make the value = 1.
My race mod ints are initialized as
int raceStrMod = 0;
int raceDexMod = 0;
int raceConMod = 0;
int raceIntMod = 0;
int raceWisMod = 0;
int raceChaMod = 0;
Then the if statements assign a value dependent on which race was randomly selected.
Thank you all for the input! This is how I ended up coding it
if (raceInt == 9)
{
int randomX = rnd.Next(1, 5);
int randomY = rnd.Next(1, 5);
int attempts = 0;
while (randomX == randomY && attempts < 10)
{
randomY = rnd.Next(1, 5);
attempts++;
}
//if they are still not unique after 10 attempts
if (randomX == randomY)
{
if (randomX == 5)
randomY = 1;
else
randomY = randomX + 1;
}
int[] randomNumbers = { randomX, randomY };
foreach (int i in randomNumbers)
{
switch (i)
{
case 1:
raceStrMod = 1;
break;
case 2:
raceDexMod = 1;
break;
case 3:
raceConMod = 1;
break;
case 4:
raceIntMod = 1;
break;
case 5:
raceWisMod = 1;
break;
}
}
}
Has your class introduced you to enum types yet? If not, is there any restriction on your final project with respect to using language features that weren't taught in the class?
Your question is arguably too broad, as there are many different ways to address this sort of thing even in real-world code, and the classroom context introduces potential roadblocks that while might constrain the question, being unknown they make it impossible to know what answer is actually going to work for you.
That said…
Ignoring the classroom aspect and focusing only on the problem itself, I would use enum types and dictionaries for this sort of thing. For example:
enum Attribute
{
Strength,
Dexterity,
Constitution,
Charisma,
Intelligence,
Wisdom,
Count, // must always be last
}
Dictionary<Attribute, int> modifiers = new Dictionary<Attribute, int>();
Then you can pick a random attribute like (assuming you have a random variable referencing a Random object…don't make the classic newbie mistake of creating a new Random object every time you want to pick a new random number):
Attribute attributeToModify = (Attribute)random.Next((int)Attribute.Count);
And you can store that selection like:
modifiers[attributeToModify] = 1;
This can be used to store however many modifiers you like. You can encapsulate that in an object representing the character itself, or you could put it into a separate AttributeModifiers class. One advantage of doing the latter would be that if you have modifiers that come from different sources, you can track that in the character object as a list of AttributeModifier instances, each in turn keeping track of what the actual source of those modifiers are.
This just barely scratches the surface. As I noted, the question itself is fairly broad. But I strongly recommend using the available language features to ensure that your variables represent things in a type-specific way, rather than just using int values for things that aren't really integers, and to use collection classes that more correctly represent the semantics of what your code is intended to do.
Note that this also means you probably should have an enum type for the races. E.g.:
enum Race
{
Dwarf,
Elf,
HalfElf,
Halfling,
HalfOrc,
Human,
// etc.
}
And your chain of if statements is probably better represented as a switch:
Attribute racialMod;
switch (race)
{
case Human:
case Halfling:
// etc.
racialMod = Attribute.Strength;
break;
case Elf:
case HalfElf:
// etc.
racialMod = Attribute.Dexterity;
break;
}
modifiers[racialMod] = 2;
Something like that. The point is to make sure the code reads more like what the original specification would say (if you actually had written one). This will make the code easier to understand, and it will be less likely for you to put bugs in the code (e.g. you accidentally type the wrong magic, unnamed integer).
I am creating a Dungeons and Dragons Character Creator.
That's a fun beginner project; I did the same when I was learning to program.
I need to find a way to randomly select two of the remaining...
You need to find two distinct values, call then x and y. The solution you've arrived at is:
Generate x
Try to generate y ten times
If no attempt succeeded to find a distinct y, hard-code a choice.
That works, and you almost never have to use the hard-coded choice. But I thought you might be interested to know that there is an easier way to generate two distinct numbers. Let's suppose we want two distinct numbers from 0, 1, 2, 3 or 4. (Obviously if you want a different range, say, 1 through 5, you can solve that problem by generating two distinct numbers 0->4 and then adding one to each.)
The improved algorithm is:
Choose x between 0 and 4 as usual.
Choose n between 1 and 4.
y = (x + n) % 5;
Think about it this way. Suppose we make a list like this:
0, 1, 2, 3, 4, 0, 1, 2, 3
We randomly choose x from the first five entries on the list, and then we choose y by stepping forwards between 1 and 4 steps. Since the list does not repeat in one to four steps, we know that we'll get two unique elements. The math does the equivalent of that.
You could similarly have used % in your program:
if (randomX == 5)
randomY = 1;
else
randomY = randomX + 1;
could be written
randomY = randomX % 5 + 1
If you're unfamiliar with %, it is the remainder operator. It is the complement of the / operator. The rule is:
int x = whatever;
int y = whatever;
int r = x % y;
is the same as:
int r = x - (x / y) * y;
That is, it is the remainder when x is divided by y. Keep in mind that the remainder can be negative!
(Disclaimer: I don't love this option, but couldn't think of another way other than reflection which is even nastier)
You could define a class that masks the fact that all of the mods are stored as an array and therefore can be indexed using a random number.
Something like the following:
public class StatMods
{
public int RaceStrMod { get { return this.mods[0]; } set { this.mods[0] = value; } }
public int RaceDexMod { get { return this.mods[1]; } set { this.mods[1] = value; } }
public int RaceConMod { get { return this.mods[2]; } set { this.mods[2] = value; } }
public int RaceIntMod { get { return this.mods[3]; } set { this.mods[3] = value; } }
public int RaceWisMod { get { return this.mods[4]; } set { this.mods[4] = value; } }
public int RaceChaMod { get { return this.mods[5]; } set { this.mods[5] = value; } }
private readonly int[] mods;
private static readonly Random rand = new Random();
public StatMods()
{
this.mods = new int[6];
}
public void ApplyRandomMod(int modification)
{
this.mods[rand.Next(0, 6)] += modification;
}
}
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 7 years ago.
Improve this question
Can anyone explain to me, how to save "score" with PlayerPrefs and display it on the screen?
public class record : MonoBehaviour{
private Text counterText;
public float score;
void Start()
{
counterText = GetComponent<Text>() as Text;
}
void Update()
{
score += Time.deltaTime;
counterText.text = "Score: " + score.ToString("00");
}}
You can add 2 methods to your class
void SaveScore()
{
PlayerPrefs.SetFloat("score", score);
}
void LoadScore()
{
PlayerPrefs.GetFloat("score");
}
More informations about PlayerPrefs here: http://docs.unity3d.com/ScriptReference/PlayerPrefs.html
PlayerPrefs are stored in the system registry. It's not a good idea to use them to save the score, prefer a simple text file with encryption: (Stack Overflow, Unity Forum)
PlayerPrefs utility is use to store data permanently till the app installed on device. And types supported to store is limited, such as float, int, string. You can further use it, derive new methods using int and string, its up to you.
PlayerPrefs uses Key-Value structure, that means it will store a value (int, float, string) against a string key. For example I'd save high score against the key "highscore", and by the same string key I'd get back the stored value.
Now, to save score you can use
// To set high score
int scoreToSet = 140;
PlayerPrefs.SetInt("highscore", scoreToSet);
// To get high score
int scoreToGet = 0;
scoreToGet = PlayerPrefs.GetInt("highscore");
where "highscore" is the string key. Key must match in order to get and set values.