have to transform a RPG game that I've created in a console application to a windows form application for a Intro to Programming class. Everything was going as expected but then I got stuck on transforming the combat system. Below are the button click event that calls the combat function and the combat function:
private void btStoryProgression_Click(object sender, EventArgs e)
{
{...}
else if (flagControl == 20)
{
Enemy enemy = new Enemy("Hellhound", "Oblivion Cave", 1);
if (combat(player, enemy) == true)
{
Lines.Text += "You won!\n";
player.itemList.Add(new Item("Fruit", 22));
}
else
{
Lines.Text = "YOU DIED.";
Lines.Text += "GAME OVER.";
return;
}
}
}
bool combat(Player player, Enemy enemy)
{
Lines.Text = enemy.getName() + " appeared!\n";
int damage;
bool battle = true;
int battleChoice = 0, itemChoice = -1;
turns = 0;
Lines.Text += "What are you going to do?";
buttonVisibility();
buttonChoices("Attack", "Item");
while (battle)
{
if (player.getSpeed() > enemy.getSpeed())
{
//Player turn
if (battleChoice == 1)
{
Lines.Text = player.getName() + " attacked!\n";
if (player.getAccuracy() < 100)
{
Random rnd = new Random();
if (rnd.Next(1, 100) > player.getAccuracy())
{
Lines.Text += "The attack missed!\n";
goto enemyturn;
}
}
damage = player.getAtk() - enemy.getDef();
if (damage < 0)
damage = 0;
enemy.setHP(enemy.getHP() - damage);
if (enemy.getHP() < 0)
enemy.setHP(0);
Lines.Text += "You dealt " + damage + " damage to " + enemy.getName();
Lines.Text += "Enemy HP is now " + enemy.getHP();
if (enemy.getHP() == 0)
return true;
}
else if (battleChoice == 2)
{
Lines.Text += "Your items: ";
foreach (Item item in player.itemList)
{
Lines.Text += item.getName();
}
Lines.Text += "Choose a number based on the order the items appeared";
try
{
do
{
itemChoice = Convert.ToInt32(Console.ReadLine());
itemChoice--;
} while (itemChoice > player.itemList.Count());
}
catch (FormatException)
{
Console.WriteLine("SOMETHING WRONG!!");
}
Lines.Text += "Player HP was: " + player.getHP();
player.setHP(player.getHP() + player.itemList[itemChoice].getRecoverQtd());
Lines.Text += "Player HP is now: " + player.getHP();
player.itemList.RemoveAt(itemChoice);
}
enemyturn:
//Enemy turn
if (battleChoice != 0)
{
Lines.Text += enemy.getName() + " attacked!\n";
damage = enemy.getAtk() - player.getDef();
if (damage < 0)
damage = 0;
player.setHP(player.getHP() - damage);
if (player.getHP() < 0)
player.setHP(0);
Lines.Text += enemy.getName() + " dealt " + damage + " damage to " + player.getName();
Lines.Text += player.getName() + " HP is now " + player.getHP();
}
if (player.getHP() == 0)
return false;
turns++;
}
else
{
enemyturn:
//Enemy turn
if (battleChoice != 0)
{
Lines.Text += enemy.getName() + " attacked!\n";
damage = enemy.getAtk() - player.getDef();
if (damage < 0)
damage = 0;
player.setHP(player.getHP() - damage);
if (player.getHP() < 0)
player.setHP(0);
Lines.Text += enemy.getName() + " dealt " + damage + " damage to " + player.getName();
Lines.Text += player.getName() + " HP is now " + player.getHP();
if (player.getHP() == 0)
return false;
}
//Player turn
if (battleChoice == 1)
{
Lines.Text += player.getName() + " attacked!\n";
if (player.getAccuracy() < 100)
{
Random rnd = new Random();
if (rnd.Next(1, 100) > player.getAccuracy())
{
Lines.Text += "The attack missed!";
goto enemyturn;
}
}
damage = player.getAtk() - enemy.getDef();
if (damage < 0)
damage = 0;
enemy.setHP(enemy.getHP() - damage);
if (enemy.getHP() < 0)
enemy.setHP(0);
Lines.Text += "You dealt " + damage + " damage to " + enemy.getName();
Lines.Text += "Enemy HP is now " + enemy.getHP();
if (enemy.getHP() == 0)
return true;
}
else if (battleChoice == 2)
{
Lines.Text += "Your items: ";
for (int i = 0; i < player.itemList.Count; ++i)
{
Lines.Text += player.itemList[i].getName();
}
Lines.Text += "Choose a number based on the order the items appeared";
}
turns++;
}
return true;
}
Basically, when I press the button and the combat is called, the whole function is skipped until some loose "else" is found or, if I restrict each comparison, the program just freezes. I've made some searches and I saw people suggesting using Delegate or BackgroundWorker but I'm still confused on using them. This link was the closest question to mine that I've found but it couldn't help me as well (maybe because I'm a newbie...).
Can you guys please help me? Thank you in advance :)
Your first issue is that your method to calculate combat is running on the GUI thread. Since it is busy, it cannot actually do its real job of updating the GUI and the GUI freezes. You should never do long running tasks on the GUI thread.
You can correct this using async and await by creating a new async method and just running that inside your button click:
private async Task RunCombat()
{
Enemy enemy = new Enemy("Hellhound", "Oblivion Cave", 1);
//this next line will run async now and will not block your gui thread.
bool combatResult = await Task.Run(() => combat(player, enemy));
if (combatResult)
{
Lines.Text += "You won!\n";
player.itemList.Add(new Item("Fruit", 22));
}
else
{
Lines.Text = "YOU DIED.";
Lines.Text += "GAME OVER.";
return;
}
and then just call this method inside your button click instead of what you already have. Once you do that, you will no longer be able to use Lines.Text += in your combat method as it will be running on a different thread.
I would create a delegate called LineAppenderDelegate just above your form class declaration:
public delegate void LineAppenderDelegate(string lineToAdd);
and then create a AppendLine method:
private void AppendLine(string lineToAdd)
{
if(InvokeRequired) //if we are not on the gui thread
{
//re-call the same method on the gui thread
LineAppenderDelegate d = new LineAppenderDelegate(AppendLine);
Invoke(d, new object[]{lineToAdd});
}
else //we are on the gui thread and can just do the work
{
Lines.Text += lineToAdd;
}
}
and use this to add lines instead. This method basically checks to see if you are on the correct thread to interact with the gui. If you are not, it recalls the method on the gui thread. If you are, it just does its work.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With