Let's say I have an Enemy class with a couple properties and a method AddPoints which will add experience points to an Enemy object. After a certain amount of experience points the Level property of the Enemy object will increase.
Initially I thought 'how can I make the program update the Level property when I don't know when the correct amount of experience points will be reached?. This made me think of events (have to listen for the event to occur, in this case the outcome of the LevelUp() method) so I decided to do something like
private void LevelUp()
{
if (ExperiencePoints > (5 * Level))
{
Level++;
}
}
public void AddPoints(int points)
{
this.ExperiencePoints += points;
LevelUp();
}
This way every time there are points added to the Enemy object the method will check whether or not the Level property needs to be incremented. Having one method call another method made think about containment/delegation (one method is 'nested' inside another). In this way, my AddPoints function sort of acts like a function pointer (at least in my mind).
Does anyone with a knowledge of language design or a good historical knowledge of C++/C# find this a helpful way of thinking about delegates? With the following code is there any way that a delegate can improve the program, or is it too simple?
full Enemy class
class Enemy
{
public int ExperiencePoints { get; set; }
public string Name { get; set; }
private int level;
public int Level
{
get { return level; }
private set { level = value; }
}
private void LevelUp()
{
if (ExperiencePoints > (5 * Level))
{
Level++;
}
}
public void AddPoints(int points)
{
this.ExperiencePoints += points;
LevelUp();
}
public Enemy()
{
ExperiencePoints = 1;
Level = 1;
}
}
testing
delegate void myDelegate(int x);
class Program
{
static void Main(string[] args)
{
Enemy e = new Enemy();
myDelegate del = e.AddPoints;
e.AddPoints(10); //Level =1 at runtime, after this call Level=2
del(20);//now Level=3
Console.WriteLine(e.Level);//output = 3
}
}
Related
I'm trying to cut down on how much duplication I have on my code, so I decided to make one of my classes a static class since I decided that its data should really be shared with everyone. Here's the static method below:
// A static class, that holds all object's coordinates, and methods to return & update their values.
internal static class Coordinate
{
private static int[,] PlayerCoordinate { get; set; }
public static int[,] GateCoordinate { get; }
public static int[,] FountainCoordinate { get; }
static Coordinate() // FIRST VALUE IS X (column), SECOND VALUE IS Y (row).
{
PlayerCoordinate = new int[,] { { 0, 0 } };
GateCoordinate = PlayerCoordinate; // Just starts off in the same place as player.
FountainCoordinate = new int[,] { { 2, 0 } };
}
// A static method, that sends the data of all object coordinates, deconstructed into seperate ints.
public static int PlayerColumn() { return PlayerCoordinate[0, 0]; }
public static int PlayerRow() { return PlayerCoordinate[0, 1]; }
public static int GateColumn() { return GateCoordinate[0, 0]; }
public static int GateRow() { return GateCoordinate[0, 1]; }
public static int FountainColumn() { return FountainCoordinate[0, 0]; }
public static int FountainRow() { return FountainCoordinate[0, 1]; }
// Updates the coordinates of the player.
public static void UpdatePlayerCoordinate(int column, int row) { PlayerCoordinate = new int[,] { { column, row } }; }
}
The main issue comes in from my GameManager class. On the console, the beginning section should print out "You are the room at (Column=0, Row=0), but it prints this instead:
Here is the code for my GameManager class:
internal class GameManager
{
private bool IsGameOver;
private Player Player;
private Updater Updater;
// Don't need to call Fountain or Coordinate since they're static
public GameManager()
{
IsGameOver = false;
Player = new();
Updater = new();
}
public void RunGame()
{
while (!IsGameOver)
{
Console.WriteLine("----------------------------------------------------------");
Updater.DisplayPlayerPosition(); // This is the main line that I'm having issues with as of right now. All other functions past this are another problem.
Updater.DisplayPlayerSenses();
string playerInput = Player.GetInput();
Updater.MovePlayer(playerInput);
IsGameOver = Updater.CheckForWin();
}
}
}
And just to make sure, here is the code from my updater class, with the specific method that I'm having issues with:
internal class Updater
{
// No fields
// Default constructor
// Gets the text to show the player his current position.
public void DisplayPlayerPosition() // This is the method that I'm having issues with.
{
Console.WriteLine($"You are in the room at (Column={Coordinate.PlayerColumn}, Row={Coordinate.PlayerRow})");
}
...
I'm fairly new to the static keyword so I believe that I may be missing smth. I personally believe that it's because the class itself hasn't been initialized (like I haven't called the constructor for the Coordinate class, and apparently you can't call a static constructor anyways), but that's just me. If I could get any help, I'd greatly appreciate it!
PlayerColumn() and PlayerRow() are methods, but you are accesing them in the WriteLine statement as if they are properties.
Update your WriteLine to:
Console.WriteLine($"You are in the room at (Column={Coordinate.PlayerColumn()}, Row={Coordinate.PlayerRow()})");
I have a few scripts which all inherit from an Interface I have called IPlayer. The goal of this interface is to register Damage, Experience, and LevelUp.
public interface IPlayer {
void TakeDamage(int damage);
void GiveExperience(int experience);
void LevelUp();
}
For example, 2 scripts at the moment which inherit from IPlayer:
PlayerStatus:
public void GiveExperience(int experience)
{
currentExperience += experience;
if (currentExperience >= maxExperience)
{
LevelUp();
return;
}
UpdateUI();
}
public void LevelUp()
{
print("Player has Leveled up!");
maxExperience *= 2;
if (maxExperience >= 2000)
{
return;
}
currentExperience = 0;
currentHealth = playerStats.maxHealth;
vitTime = (-1 * Mathf.Sqrt(playerStats.vit / 130) + 1) / 2;
currentMana = playerStats.maxMana;
wisTime = (-1 * Mathf.Sqrt(playerStats.wis / 130) + 1) / 2;
UpdateUI();
}
public void TakeDamage(int damage)
{
currentHealth -= damage;
if (currentHealth <= 0)
{
currentHealth = 0;
//UpdateUI(); /// MAYBE NEEDED LATER WHEN Death() actually does something.
Death();
}
UpdateUI();
}
PlayerStats:
public void LevelUp()
{
maxHealth += Random.Range(8, 16);
maxMana += Random.Range(8, 16);
level++;
uiStats.UpdateUI();
}
public void TakeDamage(int dmage)
{
}
public void GiveExperience(int exp)
{
}
Now the problem is, that in PlayMode, nothing actually happens, the health doesnt go down, experience doesnt go up, and ofcourse no levels are gained.
My first inclination is that when this is called for example:
IPlayer Iplayer = collision.transform.GetComponent<IPlayer>();
if (Iplayer != null)
{
Iplayer.TakeDamage(damage);
}
It will find the first script which inherits from IPlayer, and call that Method(TakeDamage). Instead I want it to find ALL scrips that inherit from IPlayer(scr_PlayerStatus, scr_PlayerStats, and more scripts that ALL inherit from IPlayer, and call ALL IPlayer methods on ALL Scripts attached to that gameobject, not just the first one it finds.
So my player basically has multiple scripts that all inherit from IPlayer, and I want them ALL to execute, when the interface is called.
I hope my explanation is clear and the code can hopefully paint a picture aswell.
BTW, I know this works when I use multiple Interfaces, one IDamage, IExperience and ILevelUp, but now I combined those 3 interfaces into one to make the code cleaner and easier to read, but that borked it unfortunately. There are no errors, nullreferences or anything like that, really I am convinced that the interface is only calling the first script it finds and not all of them attached to the GameObject.
use foreachmethod.
IPlayer[] Iplayers = collision.transform.GetComponents<IPlayer>();
if (Iplayers != null)
{
foreach (IPlayer iplayer in Iplayers)
{
iplayer.TakeDamage(damage);
}
}
First off, I know that you can't override static properties or functions in C#.
Here's what I need.
public abstract class Effect
{
public virtual const float duration = 1.0f;
public void boo() {
//do some stuff with duration
}
public void foo() {
//do some other stuff with duration
}
}
public class EffectA : Effect
{
public override const float duration = 3.0f;
}
There's some other stuff in the base and derived class, but the part that I'm having trouble with is this static constant. I need to refer it from other sections of code WITHOUT an instance, e.g. EffectA.duration. A function/property would also be fine, but those also can not be overriden if static.
I've seen similar questions, but all the answers seem to involve non-static solutions, i.e. instead of making it a static function, make it an instance function. In my case, in the places where I want to query EffectA.duration, it would not be desirable to create an instance. Also, I'd prefer not to have an instance variable since in reality it's these classes are Unity3D Monobehaviours, and it wouldn't make much sense to have a static instance since there are many being created and destroyed at various points.
What is the ideal work around if I want to be able to share the code in boo and still have access to the static duration for each derived class.
Here's a modified version of the relevant portion of the current code:
public abstract class Effect : MonoBehaviour
{
public virtual float kDuration { get { return 1.0f; }}
public float elapsed = 0.0f;
// Use this for initialization
protected virtual void Start()
{
elapsed = kDuration;
}
// Update is called once per frame
protected virtual void FixedUpdate()
{
elapsed -= Time.fixedDeltaTime;
if(elapsed <= 0) {
Destroy(this);
}
_doEffect();
}
protected abstract void _doEffect();
}
public class EffectA : Effect
{
public override float kDuration { get {return 3.0f; } }
protected override void _doEffect()
{
//Some behavior
}
}
The problem with this code is there's no static way to access kDuration for an Effect, and there are many portions in the code where I need to be able to get EffectA.kDuration or something similar without an instance.
What you're looking for is a bit strange, but one option to keep them static and provide new value/implementation is to just hide the inherited members, by simply using the same name:
public abstract class Effect
{
public const float duration = 1.0f;
public static void boo()
{
// this prints 1.0f
Console.WriteLine(duration);
}
}
public class EffectA : Effect
{
public new const float duration = 3.0f;
public new static void boo()
{
// this prints 3.0f
Console.WriteLine(duration);
}
}
Note the new keyword just gets rid of the compiler warning for you, using the same name is what results in hiding.
Update
Based on your comment, here's how you can avoid duplication and just call the shared implementation:
public abstract class Effect
{
public const float duration = 1.0f;
public static void boo(float val = duration)
{
// your complex shared implementation
Console.WriteLine(val);
}
}
public class EffectA : Effect
{
public new const float duration = 3.0f;
public new static void boo()
{
Effect.boo(duration);
}
}
Could try this but may not be the right approach:
class Program
{
static void Main(string[] args)
{
Console.WriteLine(" duration from Effect " + Effect.duration);
Console.WriteLine(" duration from EffectA " + EffectA.duration);
Console.WriteLine(" duration from EffectB " + EffectB.duration);
Console.Read();
}
}
class Effect
{
public const float duration = 1.0f;
}
class EffectA : Effect
{
public const float duration = 3.0f;
}
class EffectB : Effect
{
}
The result should be :
duration from Effect 1
duration from EffectA 3
duration from EffectB 1
There will be a warning in Visual Studio 2015 but can be by passed.
Not sure whether can work with Unity3D MonoDevelop.
Im fairly new to programming and am making a rpg battle simulator for practice. My problem is that I can't seem to make my attack method work. Heres the classes I have:
class Person
{
protected int attack;
protected int health;
public Person(int _attack, int _health)
{
attack = _attack;
health = _health;
}
public int GetAttack()
{
return attack;
}
public int GetHealth()
{
return health;
}
public int Attack(int _health)
{
_health -= attack;
return _health;
}
}
class Hero : Person
{
public Hero(int _attack, int _health)
:base (_attack , _health)
{
}
}
class Enemy : Person
{
public Enemy(int _attack, int _health)
:base (_attack , _health)
{
}
}
and heres the main:
class Program
{
static void Main(string[] args)
{
Hero Joe = new Hero(4, 10);
Enemy Tim = new Enemy(5, 20);
Joe.Attack(Tim.GetHealth());
Console.WriteLine(Tim.GetHealth());
Console.WriteLine(Tim.GetAttack());
Console.ReadLine();
}
}
My guess is that the attack method is doing the math, but is never changing the health that is passed into it. Or maybe it has something to do with the fact that their protected. Another thought of mine is that it doesn't need to return anything.
How would I go about making my attack method work? I just want it to take in somethings health value, subtract the attacking things attack value, and save the calculated value as the health? Thank you for reading this !
When you pass around an int, you are making copies of the number, not passing references to the same number in memory.
When you pass around an instance of a class, you are passing around references to the same object in memory.
Therefore, I suggest changing your design to something like this:
public void Attack(Person target)
{
target.health -= this.attack;
}
...
Joe.Attack(Jim);
You got a couple things you can improve here. First thing is naming conventions, I recommend reading the design guidelines.
First, If you change your Attack and Health to properties instead of protected fields, you expose getter and setter methods for it. Obviously you only want to set form the controller so make the set a private set:
public class Person
{
public int Attack { get; private set; }
public int Health { get; private set; }
public Person(int attack, int health)
{
Attack = attack;
Health = health;
}
// Rest of code
}
When you do it like this you eliminate the need for your individual GetAttack() and GetHealth() methods.
Next, the names of your parameter in Attack() is misleading. I assume you want the parameter to be "attack" and not "health" right? Since our setter is private this method allows us to only access health modifications inside the class. Since we already changed Health to be a property, we don't need to return it anymore so this method can now be void:
//Our property is named Attack so this has to be AttackAction or something different
public void AttackAction(int attack)
{
Health -= attack;
}
And if we put it all together:
public class Person
{
public int Attack { get; private set; }
public int Health { get; private set; }
public Person(int attack, int health)
{
Attack = attack;
Health = health;
}
public void AttackAction(int attack)
{
Health -= attack;
}
}
public class Hero : Person
{
public Hero(int attack, int health)
:base (attack , health)
{
}
}
public class Enemy : Person
{
public Enemy(int attack, int health)
:base (attack , health)
{
}
}
I made a fiddle here that shows this new code in action.
You are calling Attack() but are never saving the value returned by that method. You need to add a Setter for the health field, then set that value to the method's returned value. Something like
Health Property
public int Health
{
get { return health; }
set { health = value; }
}
Setting the Value
Tim.Health = Joe.Attack(Tim.Health);
If you want to keep the design pattern the same (you don't, see Blorgbeard's answer) you could add a SetHealth() method to Person and do something like this:
Tim.SetHealth(Joe.Attack(Tim.GetHealth());
This gets Tim's health total, passes that to Joe's attack method, which returns a value (what Tim's new health total should be) and then Tim's health is set to this value.
I have my base game class and an enemy class.
When I instantiate an enemy using the base game I would like a integer to increase
And when one dies I would need it to decrease the integer.
The end result being a new enemy spawns every few seconds so long as that integer is less than my MAX_ENEMIES
any way I'm currently clue less and was hoping someone could direct me with how I should arrange this ( do I have the enemies increase the number when they spawn? )
Here's the basic idea: use a Factory Method. You may want to handle some of the specifics differently.
void Main()
{
var game = new Game();
game.CreateEnemy("Blinky");
Console.WriteLine(game.EnemyCount);
game.CreateEnemy("Clyde");
Console.WriteLine(game.EnemyCount);
game.DestroyEnemy(game.Enemies[0]);
Console.WriteLine(game.EnemyCount);
}
public class Game
{
public List<Enemy> Enemies = new List<Enemy>();
public void CreateEnemy(string name)
{
if (EnemyCount >= MAX_ENEMIES) return;
var enemy = new Enemy { Name = name};
Enemies.Add(enemy);
}
public void DestroyEnemy(Enemy enemy)
{
Enemies.Remove(enemy);
}
public int EnemyCount
{
get { return Enemies.Count(); }
}
}
public class Enemy
{
public string Name { get; set; }
}