I am making a Farming game in Unity and I tried to implement an EXP System. I can not implement a function where you can plant a crop from an X player level.
This Code manages the whole farm
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class FarmManager : MonoBehaviour
{
[Header("Money Settings")]
public PlantItem selectPlant;
public bool isPlanting = false;
public int money = 100;
public Text moneyTxt;
[Header("Button Color Settings")]
public Color buyColor = Color.green;
public Color cancelColor = Color.red;
public Color lockedColor = Color.grey;
[Header("Button Audio Settings")]
public AudioSource clickSound;
[Header("Cursor Settings")]
public Texture2D cursorArrow;
public Texture2D cursorPickaxe;
[Header("XP Settings")]
public int maxExp;
public float updatedExp;
public float plusXp;
public Image ExpBar;
public float expIncreasedPerSecond;
public int playerLevel;
public Text levelText;
public Text xpLevel;
// Start is called before the first frame update
void Start()
{
Cursor.SetCursor(cursorArrow, Vector2.zero, CursorMode.ForceSoftware);
moneyTxt.text = "$"+money;
playerLevel =1;
expIncreasedPerSecond =5f;
maxExp = 25;
updatedExp = 0;
plusXp = 0;
}
void Update () {
//updatedExp += expIncreasedPerSecond * Time.deltaTime;
ExpBar.fillAmount = updatedExp / maxExp;
levelText.text = playerLevel + "";
xpLevel.text = updatedExp + "/" + maxExp;
if (updatedExp >= maxExp)
{
plusXp = updatedExp-maxExp;
playerLevel++;
updatedExp=0+plusXp;
maxExp+=maxExp;
}
}
public void SelectPlant(PlantItem newPlant)
{
if(selectPlant == newPlant)
{
Debug.Log("Deselected" + selectPlant.plant.plantName);
selectPlant.btnImage.color = buyColor;
selectPlant.btnTxt.text = "Buy";
selectPlant = null;
isPlanting = false;
clickSound.Play();
}
else
{
if(selectPlant!=null)
{
selectPlant.btnImage.color = buyColor;
selectPlant.btnTxt.text = "Buy";
}
selectPlant = newPlant;
selectPlant.btnImage.color = cancelColor;
selectPlant.btnTxt.text = "Cancel";
Debug.Log("Selected" + selectPlant.plant.plantName);
isPlanting = true;
clickSound.Play();
}
}
public void Transaction(int value)
{
money+=value;
moneyTxt.text = "$"+money;
}
public void GiveXP (float value)
{
updatedExp += value;
}
}
And this is the code where I import the information from
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[CreateAssetMenu(fileName = "New Plant", menuName ="Plant")]
public class PlantObject : ScriptableObject
{
[Header("Plant settings")]
public string plantName;
public Sprite[] plantStages;
public float timeBtwStages;
[Header("Money Settings")]
public int buyPrice;
public int sellPrice;
[Header("XP Settings")]
public int xpAmount;
public int levelNeeded;
[Header("Plant Icon")]
public Sprite icon;
}
I tried doing it this way, but it would not fix my issue and would not disable the crop until the needed level was reached and it gave me a ton of errors.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class FarmManager : MonoBehaviour
{
[Header("Money Settings")]
public PlantItem selectPlant;
public bool isPlanting = false;
public int money = 100;
public Text moneyTxt;
[Header("Button Color Settings")]
public Color buyColor = Color.green;
public Color cancelColor = Color.red;
public Color lockedColor = Color.grey;
[Header("Button Audio Settings")]
public AudioSource clickSound;
[Header("Cursor Settings")]
public Texture2D cursorArrow;
public Texture2D cursorPickaxe;
[Header("XP Settings")]
public int maxExp;
public float updatedExp;
public float plusXp;
public Image ExpBar;
public float expIncreasedPerSecond;
public int playerLevel;
public Text levelText;
public Text xpLevel;
// Start is called before the first frame update
void Start()
{
Cursor.SetCursor(cursorArrow, Vector2.zero, CursorMode.ForceSoftware);
moneyTxt.text = "$"+money;
playerLevel =1;
expIncreasedPerSecond =5f;
maxExp = 25;
updatedExp = 0;
plusXp = 0;
}
void Update () {
//updatedExp += expIncreasedPerSecond * Time.deltaTime;
ExpBar.fillAmount = updatedExp / maxExp;
levelText.text = playerLevel + "";
xpLevel.text = updatedExp + "/" + maxExp;
if (updatedExp >= maxExp)
{
plusXp = updatedExp-maxExp;
playerLevel++;
updatedExp=0+plusXp;
maxExp+=maxExp;
}
}
public void SelectPlant(PlantItem newPlant)
{
if(selectPlant == newPlant)
{
Debug.Log("Deselected" + selectPlant.plant.plantName);
selectPlant.btnImage.color = buyColor;
selectPlant.btnTxt.text = "Buy";
selectPlant = null;
isPlanting = false;
clickSound.Play();
}
else
{
if(selectPlant!=null)
{
selectPlant.btnImage.color = buyColor;
selectPlant.btnTxt.text = "Buy";
}
selectPlant = newPlant;
selectPlant.btnImage.color = cancelColor;
selectPlant.btnTxt.text = "Cancel";
Debug.Log("Selected" + selectPlant.plant.plantName);
isPlanting = true;
clickSound.Play();
}
if (selectPlant.plant.levelNeeded > playerLevel)
{
selectPlant.btnImage.color = lockedColor;
}
}
public void Transaction(int value)
{
money+=value;
moneyTxt.text = "$"+money;
}
public void GiveXP (float value)
{
updatedExp += value;
}
}
I have been stuck on this for weeks now any ideas?
I just cant manage to add a public object to the dcript i have.
There is code:
public class Player : MonoBehaviour {
public string charName = "";
public int currentLevel = 0;
public int experiense = 0;
public int strength = 1;
public int agility = 1;
public int maxHealth = 30;
public float currentHealth = 30;
public int maxActionPoints = 5;
public int currentLevelPoints = 10;}
there is another script where i want to add a public property with this class
public class CharManager : MonoBehaviour {
public GameObject currentCharacter;
public GameObject charMenu;
public Player currentPlayerStats;
public void changeCharacter(GameObject character)
{
if (currentCharacter){
saveCharacter ();
}
currentCharacter = character;
loadSavedInfo ();
}
void loadSavedInfo()
{
string playerJson = "";
if (currentCharacter.tag== "Man")
{
if (File.Exists(Application.persistentDataPath +"/Char1.json"))
{
playerJson = File.ReadAllText(Application.persistentDataPath +"/Char1.json");
}
}
else
{
if (File.Exists(Application.persistentDataPath +"/Char2.json"))
{
playerJson = File.ReadAllText(Application.persistentDataPath +"/Char2.json");
}
}
if (playerJson != string.Empty)
{
Player thePlayer = JsonConvert.DeserializeObject<Player>(playerJson);
currentPlayerStats = thePlayer;
}
else
{
currentPlayerStats = gameObject.AddComponent<Player>() as Player;
}
}
This code add NEW player component and currentPlayerStats have class CharManager... what am i doing wrong?
Any help is very appreciated!
gameObject.AddComponent() adds a MonoBehaviour derived component to the game object. Player does not derive from MonoBehaviour thus it cannot be added
Looks like Player is just a regular class, so you can just create an object of that class
Player currentPlayerStats = new Player();
I figured it out.
Player class must be non MonoBehaviour class. A class where i have to access the player class should have a public property:
public Player thePlayer;
not
public GameObject thePlayer;
Thanks everyone!
I have a serializable class named DataSource:
namespace GraphLib
{
public struct cPoint
{
public float x;
public float y;
}
[Serializable]
public class DataSource
{
public delegate String OnDrawXAxisLabelEvent(DataSource src, int idx);
public delegate String OnDrawYAxisLabelEvent(DataSource src, float value);
public OnDrawXAxisLabelEvent OnRenderXAxisLabel = null;
public OnDrawYAxisLabelEvent OnRenderYAxisLabel = null;
private cPoint[] samples = null;
private int length = 0;
private String name = String.Empty;
private int downSample = 1;
private Color color = Color.Black;
public float VisibleDataRange_X = 0;
public float DY = 0;
public float YD0 = -200;
public float YD1 = 200;
public float Cur_YD0 = -200;
public float Cur_YD1 = 200;
public float grid_distance_y = 200; // grid distance in units ( draw a horizontal line every 200 units )
public float off_Y = 0;
public float grid_off_y = 0;
public bool yFlip = true;
public bool Active = true;
private bool YAutoScaleGraph = false;
private bool XAutoScaleGraph = false;
public float XAutoScaleOffset = 100;
public float CurGraphHeight = 1.0f;
public float CurGraphWidth = 1.0f;
public float InitialGraphHeight = 0;
public float InitialGraphWidth = 0;
public bool AutoScaleY
{
get
{
return YAutoScaleGraph;
}
set
{
YAutoScaleGraph = value;
}
}
public bool AutoScaleX
{
get
{
return XAutoScaleGraph;
}
set
{
XAutoScaleGraph = value;
}
}
public cPoint[] Samples
{
get
{
return samples;
}
set
{
samples = value;
length = samples.Length;
}
}
public float XMin
{
get
{
float x_min = float.MaxValue;
if (samples.Length > 0)
{
foreach (cPoint p in samples)
{
if (p.x < x_min) x_min=p.x;
}
}
return x_min;
}
}
public float XMax
{
get
{
float x_max = float.MinValue;
if (samples.Length > 0)
{
foreach (cPoint p in samples)
{
if (p.x > x_max) x_max = p.x;
}
}
return x_max;
}
}
public float YMin
{
get
{
float y_min = float.MaxValue;
if (samples.Length > 0)
{
foreach (cPoint p in samples)
{
if (p.y < y_min) y_min = p.y;
}
}
return y_min;
}
}
public float YMax
{
get
{
float y_max = float.MinValue;
if (samples.Length > 0)
{
foreach (cPoint p in samples)
{
if (p.y > y_max) y_max = p.y;
}
}
return y_max;
}
}
public void SetDisplayRangeY(float y_start, float y_end)
{
YD0 = y_start;
YD1 = y_end;
}
public void SetGridDistanceY( float grid_dist_y_units)
{
grid_distance_y = grid_dist_y_units;
}
public void SetGridOriginY( float off_y)
{
grid_off_y = off_y;
}
[Category("Properties")] // Take this out, and you will soon have problems with serialization;
[DefaultValue(typeof(string), "")]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
public String Name
{
get { return name; }
set { name = value; }
}
[Category("Properties")] // Take this out, and you will soon have problems with serialization;
[DefaultValue(typeof(Color), "")]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
public Color GraphColor
{
get { return color; }
set { color = value; }
}
[Category("Properties")] // Take this out, and you will soon have problems with serialization;
[DefaultValue(typeof(int), "0")]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
public int Length
{
get { return length; }
set
{
length = value;
if (length != 0)
{
samples = new cPoint[length];
}
else
{
// length is 0
if (samples != null)
{
samples = null;
}
}
}
}
[Category("Properties")] // Take this out, and you will soon have problems with serialization;
[DefaultValue(typeof(int), "1")]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
public int Downsampling
{
get { return downSample; }
set { downSample = value; }
}
}
}
and i want to serialize it in a form like this:
public partial class Form1 : Form
{
public GraphLib.PlotterDisplayEx display;
private void serialize()
{
System.IO.Stream TestFileStream = System.IO.File.Create(#"C:\Users\Public\Documents\test.txt");
System.Runtime.Serialization.Formatters.Binary.BinaryFormatter serializer = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
serializer.Serialize(TestFileStream, display.DataSources[0]);
TestFileStream.Close();
}
not that DataSource class that i want to serialize in Form1, is one of the attributes in GraphLib.PlotterDisplayEx class
but when i run the program it gives me the following error:
An unhandled exception of type 'System.Runtime.Serialization.SerializationException' occurred in mscorlib.dll
Additional information: Type 'KTK.Form1' in Assembly 'KTK, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' is not marked as serializable.
UPDATE
I updated the code for DataSource class.now it's complete code guys.
You probably didn't show the complete code of the DataSource class. It directly or indirectly holds a reference to an object of type KTK.Form1.
This might be through an event to which the form is subscribed.
In this case you probably don't want to serialize it an should mark it as NonSerialized:
[field:NonSerialized]
public event ...;
Now that you updated the question. Change
public OnDrawXAxisLabelEvent OnRenderXAxisLabel = null;
public OnDrawYAxisLabelEvent OnRenderYAxisLabel = null;
to
[NonSerialized]
public OnDrawXAxisLabelEvent OnRenderXAxisLabel;
[NonSerialized]
public OnDrawYAxisLabelEvent OnRenderYAxisLabel;
The delegates may hold references to non-serializable classes.
I want my player to give a speed boost for a few seconds. When it collects 4 items (paintCount = 4), the player gets a movement speed boost for a short period of time.
How do I code this time that my player moves faster?
I'm using c# and Unity.
using UnityEngine;
using System.Collections;
public class PowerUp : MonoBehaviour
{
void OnTriggerEnter2D(Collider2D other)
{
if (other.tag == "Player")
{
Paintser.SpeedUp();
Destroy(this.gameObject);
Paintser.paintCount++;
}
}
}
using UnityEngine;
using System.Collections;
public class Paintser : PowerUp
{
public static int paintCount = 0;
public int speedBoostTime = 3;
public static void SpeedUp()
{
if (paintCount == 4)
{
SimplePlayer0.speed = SimplePlayer0.speed * 2;
Paintser.paintCount = Paintser.paintCount = 0;
}
}
}
using UnityEngine;
using System.Collections;
public class Paintser : PowerUp
{
public float normalSpeed = 10;
public static int paintCount = 0;
public int speedBoostTime = 3;
public static void SpeedUp(){
SimplePlayer0.speed = SimplePlayer0.speed * 2;
Paintser.paintCount = Paintser.paintCount = 0;
StartCoroutine(duringBoost(speedBoostTime, normalSpeed));
}
private static IEnumerator duringBoost(int duration, int newSpeed){
yield return new WaitForSeconds(duration);
SimplePlayer0.speed = newSpeed;
}
}
}
A general idea should be:
Add this to the script of SimplePlayer0:
float speedBoostTime = 0;
void SpeedUp()
{
speed *= 2;
speedBoostTime = 3; // seconds
}
void Update()
{
while ( speedBoostTime > 0 )
{
speedBoostTime -= Time.deltaTime;
if ( speedBoostTime <= 0 ) speed /= 2;
}
}
And modify your code in this way:
public class Paintser : PowerUp
{
public static int paintCount = 0;
public int speedBoostTime = 3;
public static void SpeedUp()
{
if (paintCount == 4)
{
SimplePlayer0.SpeedUp();
Paintser.paintCount = Paintser.paintCount = 0;
}
}
}
So I'm quite new to programming in general. I'm currently working on a terrain generation program, everything is going great except for this:
public static class Desert
{
public const int iChance = 15;
public static int chance = iChance;
public static int chancepoint = 0;
public const int octaves = 4;
public const int lengthMin = 60;
public const int lengthMax = 90;
public const float scaleMin = 250;
public const float scaleMax = 350;
public const float persistenceMin = 0.5f;
public const float persistenceMax = 0.9f;
public const pType ptype = pType.Lowland;
public const bTag[] tags = { bTag.desert };
}
public static class Meadow
{
public const int iChance = 45;
public static int chance = iChance;
public static int chancepoint = 0;
public const int octaves = 4;
public const int lengthMin = 45;
public const int lengthMax = 70;
public const float scaleMin = 200;
public const float scaleMax = 470;
public const float persistenceMin = 0.35f;
public const float persistenceMax = 0.70f;
public const pType ptype = pType.noAbs;
public const bTag[] tags = { bTag.lush };
}
These are the properties for each different type of 'Biome'.
I currently have about 7 of these and they're all exactly the same except for the values of each field.
Is there a way that I can shorten the code? I looked into inheritance but I ended up with errors and I got a little confused. ><
It would be brilliant if all I had to write was:
public static class Desert
{
iChance = 15;
chance = iChance;
chancepoint = 0;
octaves = 4;
lengthMin = 60;
lengthMax = 90;
scaleMin = 250;
scaleMax = 350;
persistenceMin = 0.5f;
persistenceMax = 0.9f;
ptype = pType.Lowland;
strongTags = { bTag.desert };
}
Thanks in advance.
Oh, and sorry about the nubness of the question, you would probably scream at how terrible my code was if you saw the rest of the program. XD
EDIT: It's probably wise to tell you that I NEVER change the stuff within the class again with the exception of the value of 'chance'.
Instead of using a static class, you can use a non-static class.
public class Biome {
// Instance fields with default values
public int iChance = 15;
public int chance = iChance;
public int chancepoint = 0;
public int octaves = 4;
public int lengthMin = 60;
public int lengthMax = 90;
public float scaleMin = 250;
public float scaleMax = 350;
public float persistenceMin = 0.5f;
public float persistenceMax = 0.9f;
public pType ptype = pType.Lowland;
public bTag[] tags = { bTag.desert };
}
Here use the constructor for initializing:
public Biome(int iChance, int chance, int chancepoint, int octaves, public int lengthMin, int lengthMax, float scaleMin, float scaleMax, float persistenceMin, float persistenceMax,pType ptype, bTag[] tags) {
// init fields here
}
Then call the constructor:
Biome bimoe = new Biome(15, iChance, 0, 4, 60, 90, 250, 350, 0.5f, 0.9f, pType.Lowland, { bTag.desert });
With this it's difficult to see which parameter goes to which field, but it's much shorter.
If the fields must be read-only, you can make properties with only a public get and no set accessor. Example:
public Chance { get { return chance; } }
In this case make the fields private:
private int chance = iChance;
(Personally, for such a scenario, i would put all the data in a file)
The following would be shorter:
public const int iChance = 15, octaves = 4, lengthMin = 60, lengthMax = 90;
public const float scaleMin = 250, scaleMax = 350, persistenceMin = 0.5f,
persistenceMax = 0.9f;
public static int chance = iChance, chancepoint = 0;
However... these really don't look like things that should be static fields, or quite possibly not even const. They look like things that should be instance properties. Maybe something like:
public class Terrain {
public int Chance {get;private set;}
public int LengthMin {get;private set;}
// ...
private Terrain(int chance, int lengthMin, ...) {
Chance = chance;
LengthMin = lengthMin;
// ...
}
private static readonly Terrain
desert = new Terrain(45, 45, ...),
meadow = new Terrain(15, 60, ...),
...;
public static Terrain Desert { get { return desert;}}
public static Terrain Meadow { get { return meadow;}}
}
I don't know much about terrain generation programs, but you should store your data in a database.
Then create classes to map that data to your application.
I recommend you to lookup "Data structures" and see which one fits your application the best.
It's better to use only one class without inheritance, or even structure. Desert, Meadow and so on are not classes logically, it's have to be objects (maybe constants).
What you could do is use a single class called Terrain and Initialise this multiple times using a static constructor:
public class Terrain
{
public int IChance { get; private set; }
public int Chancepoint { get; private set; }
public int Octaves { get; private set; }
public int LengthMin { get; private set; }
public int LengthMax { get; private set; }
public float ScaleMin { get; private set; }
public float ScaleMax { get; private set; }
public float PersistenceMin { get; private set; }
public float PersistenceMax { get; private set; }
public pType Ptype { get; private set; }
public bTag[] Tags { get; private set; }
public static Terrain Desert()
{
return new Terrain
{
IChance = 15,
Chancepoint = 0,
Octaves = 4,
LengthMin = 60,
LengthMax = 90,
ScaleMin = 250,
ScaleMax = 350,
PersistenceMin = 0.5f,
PersistenceMax = 0.9f,
Ptype = pType.Lowland,
Tags = new bTag[] {bTag.Desert}
};
}
}
joe's answer is good, but the constructor call has far too many unnamed parameters - what does the 350 mean?
This is an ideal candidate for data driven design.
Rather than define all the Biome types in the code, put all the data for the Biome types into a file and read the file at run time. The C# language has a lot of stuff to help you do this, the key word to search for is Serialisation (and here's a link to MSDN about it).
The big advantage is that you can change the data values without needing to recompile the code.
The disadvantage is that is takes a lot more code to define the first instance, but after that, you can easily create as many instances as you want.
You could do something like declaring an abstract class like this and then inherting from it:
public abstract class Terrain
{
public int iChance;
public int chance;
public int chancepoint;
public int octaves;
public int lengthMin;
public int lengthMax;
public float scaleMin;
public float scaleMax;
public float persistenceMin;
public float persistenceMax;
public pType ptype;
public Tag[] strongTags;
}
public class Desert : Terrain
{
}
public enum pType
{
Desert = 1,
LowLand = 2
}
public enum Tag
{
desert = 1,
lush = 2
}
You can then instantiate desert like :
var desert = new Desert()
{
iChance = 15
,chance = 15
,chancepoint = 0
,octaves = 4
,lengthMin = 60
,lengthMax = 90
,scaleMin = 250
,scaleMax = 350
,persistenceMin = 0.5f
,persistenceMax = 0.9f
,ptype = pType.Desert
,strongTags = new Tag[]{Tag.desert}
};
Not sure what your exact requirements are but wouldn't this be a better approach:
public abstract class BiomeBase
{
public int Chance { get; set; }
public int Chancepoint { get; set; }
public int Octaves { get; set; }
// you get the idea ...
}
Then you have Desert and Meadow inheriting:
public class Desert : BiomeBase
{
// everything is inherited ...
// you can also add your own properties meant for Desert only (if needed)
}
public class Meadow : BiomeBase
{
// everything is inherited ...
}
Now Desert has everything Biome has and you can use it like this:
var desert = new Desert
{
Chance = 5,
Octaves = 1,
/// etc
};
Firstly you cant do inheritance on static classes. So you would have to start using instances.
Secondly you would use inheritance if you wanted to extend the object. So for instance if you wanted to add a new property "bool HasScorpions" onto Desert but not on Meadow.
Since your using the same properties but want to use different values I personally use an Interface. This way you can make the properties readonly ect while still easily setting the values.
public interface Terrain
{
int iChance = {get { return 15; private set; } ..and repeat.
int chance = iChance;
int chancepoint = 0;
int octaves = 4;
int lengthMin = 60;
int lengthMax = 90;
float scaleMin = 250;
float scaleMax = 350;
float persistenceMin = 0.5f;
float persistenceMax = 0.9f;
pType ptype = pType.Lowland;
bTag[] tags = { bTag.desert };
}