I've been doing some exercises to learn C#. I've been doing XNA and making a space invaders clone.
So far, everything is dandy, but I have come across some walls when coding.
The issues and the supporting code are as follows:
My top of row of invaders have 2 health points, take 2 hits to destroy and yield more points. However, when one is hit, and destroyed, the rest of the top of row are reduced to 1 HP, and take 1 hit to destroy - which is not my desired result.
The offending code I suspect is:
if (playerBullet != null && Type1Invaders != null)
{
Rectangle rectMissile = new Rectangle((int)playerBullet.getX(), playerBullet.getY(), playerBulletIMG.Width, playerBulletIMG.Height);
for (int count = 0; count < 11; count++)
{
Rectangle rectInvader = new Rectangle(Type1Invaders[count].getX(), Type1Invaders[count].getY(), invader1.Width, invader1.Height);
if (Type1Invaders[count].getVis() && rectMissile.Intersects(rectInvader))
{
Type1Invaders[count].setHP(Type1Invaders[count].getHP() - 1);
shootTimer = 0;
if (Type1Invaders[count].getHP() == 0)
{
explosionInstance.Play();
playerBullet = null;
Type1Invaders[count].setVis(false);
score = score + Type1Invaders[count].getPointValue();
}
}
}
}
My second error resides in how I'm detecting the leftmost and rightmost invaders in a row. When an entire row has been destroyed, I get a nullreferenceerror. (Those are a nightmare..)
Anyway, this is the offending code
The method of finding the left and right most invaders
var LeftMost5 = Type5Invaders.Where(i => i.getVis()).FirstOrDefault();
var RightMost5 = Type5Invaders.Where(i => i.getVis()).LastOrDefault();
And the if statement is throwing the null error
if (RightMost5.getX() >= RightGameEdge)
{
Type5.setDir(-1);
for (int count = 0; count < 11; count++)
{
invaderMoveInstance5.Play();
Type5Invaders[count].MoveY(8);
}
}
It only happens with the rightmost, but I can assume it will happen to the left too - I'm assuming I can apply the same logic to fix this error to the left side too.
I can supply more information and snippets if this is not sufficient.
Thanks in advance for the assistance!
For the first issue. I suppose that when a bullet kills an invader, you can say that that bullet won't kill another invader. Therefore, you can add a break; to stop looping. Like this:
if (Type1Invaders[count].getVis() && rectMissile.Intersects(rectInvader))
{
Type1Invaders[count].setHP(Type1Invaders[count].getHP() - 1);
shootTimer = 0;
if (Type1Invaders[count].getHP() == 0)
{
explosionInstance.Play();
playerBullet = null;
Type1Invaders[count].setVis(false);
score = score + Type1Invaders[count].getPointValue();
}
break;
}
For the second error, the FirstOrDefault method returns null in case your collection is empty (after you have killed all type 5 invaders). You simply need to check if it is null or not, like this:
var LeftMost5 = Type5Invaders.Where(i => i.getVis()).FirstOrDefault();
var RightMost5 = Type5Invaders.Where(i => i.getVis()).LastOrDefault();
if(RightMost5 != null)
{
// this means we have a non-null invader
if (RightMost5.getX() >= RightGameEdge)
{
Type5.setDir(-1);
for (int count = 0; count < 11; count++)
{
invaderMoveInstance5.Play();
Type5Invaders[count].MoveY(8);
}
}
}
else
{
//this means that the invader does not exist anymore, so we do nothing
}
Related
Not sure if I've numbed my mind trying to figure this but I'm trying to get a loop to trigger again after it runs by changing its condition in a later branch of code based on user input. Here's the code:
int moveend = 1;
for (int move = 0; move < moveend; move++)
{
if (move < 1)
{
Console.WriteLine("Enter a direction to move\n");
//forloop that allows the output to cycle the legth of array and branch to a new line on 4th output
for (int i = 0; i < width; i++)
{
//for loop code
}
//This is the code i'm using to re trigger the previous loop with "move = 0"
ConsoleKeyInfo kb = Console.ReadKey();
if (kb.Key == ConsoleKey.UpArrow)
{
map[7, 1] = 1;
map[11, 1] = 0;
move = 0;
Console.WriteLine("FIre");
}
}
else
{
Console.WriteLine("END");
}
}
I'm not sure why it is that I can see the "Fire" with this code but it doesn't loop again despite the loop condition being reset within the loop. I expected it to reprint the loop info with the updated array coordinates map[7, 1] = 1; map[11, 1] = 0; but it doesn't. Am I overlooking something or is there something I'm missing about loops?
The reason is that you set move to 0, but it is already zero.
The loop can loosely be translated to this:
int move = 0;
while (move < moveend)
{
... rest of your code
move++;
}
So move is 0 the whole time throughout the loop, and is increased at the end, and then it is no longer < moveend.
To keep running the loop, perhaps you don't want a for loop at all?
bool keepRunning = true;
while (keepRunning)
{
keepRunning = false;
... rest of your code
if (...)
keepRunning = true; // force another run through the loop
}
I am not sure why are you doing it like that I think this might help you to accomplish your task
bool dirtyBool = true;
while(dirtyBool)
{
if (move < 1)
{
Console.WriteLine("Enter a direction to move\n");
//forloop that allows the output to cycle the legth of array and branch to a new line on 4th output
for (int i = 0; i < width; i++)
{
//for loop code
}
//This is the code i'm using to re trigger the previous loop with "move = 0"
ConsoleKeyInfo kb = Console.ReadKey();
if (kb.Key == ConsoleKey.UpArrow)
{
map[7, 1] = 1;
map[11, 1] = 0;
move = 0;
dirtyBool=false;
Console.WriteLine("FIre");
}
}
else
{
dirtyBool=false;
Console.WriteLine("END");
}
}
I have added a variable dirtyBool of type Bool which will make loop it again. Modify the code according to your usablility
I roughly translated vb.net code to c# for a simple POS system i'm coding for school. But when i try to add things to the datagrid using button click event there is no change in the datagrid. there are no errors. the datagrid is not connected to a database, at least not yet.
here's the code where i insert things to the datagrid:
private void txtAdd_Click(object sender, EventArgs e)
{
if (!string.IsNullOrEmpty(txtProduct.Text) & !string.IsNullOrEmpty(txtQuantity.Text) & !string.IsNullOrEmpty(txtPrice.Text))
{
var with = dataSales;
int ii = 0;
int orderproduct = 0;
int count = 0;
for (ii = 0; ii <= with.RowCount - 1; ii++)
{
if (txtProduct.Text == Convert.ToString(dataSales[0, ii].Value))
{
count = count + 1;
if (count != 0)
{
orderproduct = Convert.ToInt32(dataSales[2, ii].Value) + Convert.ToInt32(txtQuantity.Text);
dataSales[2, ii].Value = orderproduct;
dataSales[3, ii].Value = Convert.ToInt32(dataSales[2, ii].Value) * Convert.ToInt32(dataSales[1, ii].Value);
}
else
{
if (count == 0)
{
float sum = Convert.ToInt32(txtPrice.Text) * Convert.ToInt32(txtQuantity.Text);
dataSales.Rows.Add(txtProduct.Text, txtPrice.Text, txtQuantity.Text, sum);
count = 0;
}
txtProduct.Clear();
txtQuantity.Clear();
txtPrice.Clear();
}
}
else
{
MessageBox.Show("Nothing is Selected", "Error");
}
}
}
}
Follow your counter and you will understand why you never get anything added. You start with 0 but add +1 every single time there is text to add. PUt it in debug and watch.
EDITED: Due to your comment you do not know how to debug. Open the .cs file in Visual Studio, Click on the left margin for the line that tests for text in the fields (the line below):
if (!string.IsNullOrEmpty(txtProduct.Text) & !string.IsNullOrEmpty(txtQuantity.Text) & !string.IsNullOrEmpty(txtPrice.Text))
Now start the program, enter text and run it. It will stop on that line. You can then hit F11 and it will go to the line that increments the counter. This means you will always run this branch.
if (count != 0)
{
orderproduct = Convert.ToInt32(dataSales[2, ii].Value) + Convert.ToInt32(txtQuantity.Text);
dataSales[2, ii].Value = orderproduct;
dataSales[3, ii].Value = Convert.ToInt32(dataSales[2, ii].Value) * Convert.ToInt32(dataSales[1, ii].Value);
}
NOTE: You do not need this:
if (count == 0)
{
}
Why? You have already sent anything not 0 to the other branch. The else is sufficient at this point, and no need to waste a cycle determining if something that will ALWAYS be zero is zero
Once again I cannot find a solution myself (I have tried using Array.IndexOf(db, accnum) with a pos > -1 return boolean, but have reverted to this loop after I couldn't make it work).
So, I thought using db.Length would leave 'a' at the length of all the non-null elements in the array, however it seems to count the whole array, meaning that when the loop reaches a null element it causes an error. Is there a way to halt the loop count when it runs out of objects in the array?
void withdrawal()
{
int accnum;
double withdrawal;
//get and parse input details
accnum = int.Parse(tbNameEnt.Text);
withdrawal = double.Parse(tbBalaEnt.Text);
//check if account exists within existing objects
int a = db.Length;
for (int i = 0; i < a; i++)
{
if (db[i].GetAccNo() == accnum)
{
pos = i;
//deduct from balance
db[pos].SetBalance(db[pos].GetBalance() - withdrawal);
WithMess(); //success message
hide_form();
MakeWith2.Visible = false;
show_menu();
break;
}
else if ((db[i].GetAccNo() != accnum) && (i == db.Length - 1))
{
//account doesn't exist message
MessageBox.Show("Account does not exist");
}
}
}
If there are null items that pad the array.. break out of the loop when you reach one:
for (int i = 0; i < a; i++) {
if (db[i] == null)
break;
// the rest
Alternatively, use LINQ to filter the null items out:
foreach (var item in db.Where(x => x != null)) {
// loop here
}
I have a game kinda like minecraft, but from a top down perspective, adding blocks is done by when the player left-clicks it adds the block at the specified position, right-clicking on a placed block deletes the block.
The problem I was having was that when the player left-clicks it adds the block and its position to a list (for saving to XML later), so the logical conclusion is that when the player right-clicks it removes said block from the game, and its position from its list.
This is the method that I was using which generated lag:
for (int b = 0; b < game.blocklist.Count; b++)
{
for (int v = 0; v < game.blockpos1.Count; v++)
{
if (game.blocklist[b].visible == true)
{
if (game.cursor.boundingbox.Intersects(game.blocklist[b].blockrectangle) && mousestate.RightButton == ButtonState.Pressed && game.player.Builder == true)
{
if (game.blocklist[b].blockposition.X == game.blockpos1[v].X && game.blocklist[b].blockposition.Y == game.blockpos1[v].Y)
{
game.blockpos1.RemoveAt(v);
game.blocklist.RemoveAt(b);
break;
}
}
}
}
}
Now this is the method that I replaced it with which reduces lag immensely and still achieves the same effect I want:
for (int b = 0; b < game.blocklist.Count; b++)
{
if (game.blocklist[b].visible == true)
{
if (game.cursor.boundingbox.Intersects(game.blocklist[b].blockrectangle) && mousestate.RightButton == ButtonState.Pressed && game.player.Builder == true)
{
if (game.blocklist[b].blockposition.X == game.blockpos1[b].X && game.blocklist[b].blockposition.Y == game.blockpos1[b].Y)
{
game.blockpos1.RemoveAt(b);
game.blocklist.RemoveAt(b);
break;
}
}
}
}
Why does this generate so much lag? I just need clarification as to what I did wrong so I don't do it again.
for (int b = 0; b < game.blocklist.Count; b++)
{
for (int v = 0; v < game.blockpos1.Count; v++)
{
if (game.blocklist[b].visible == true)
{
in this version, basically for every item in blocklist ( X ) whether it was visible or not you are iterating every item in blockpos1 (Y). So you do X * Y loops. You then reduced it to X loops and only evaluated visible items.
Given the way the code is written in the question, I'd check these two things before even trying to loop
mousestate.RightButton == ButtonState.Pressed && game.player.Builder == true
because they will never change during those loops. so if they aren't true to start with, don't even bother looping.
Also as Preseton says in the comments, no need to compare things to true.... you only need to do
mousestate.RightButton == ButtonState.Pressed && game.player.Builder
and
if (game.blocklist[b].visible)
For homework assignment we have to program a Intersection merge of 2 ArrayLists. I have done it using the following code
public void Intersection()
{
foreach (object obj1 in Developed)
{
Apps xApp = (Apps)obj1;
foreach (object obj2 in DPloyed)
{
Apps yApp = (Apps)obj2;
if (xApp.CompareName(yApp) == 0)
{
Inter.Add(yApp);
}
}
}
}
I would like to implement it rather using the while loop but the following code seems to keep missing elements in the list. It puts the first elements in the new intersection list but once the length of developed is increased from 1 element to 5 elements or more it does not add the new elements.
public void Intersection()
{
int i = 0;
int j = 0;
while (i < Developed.Count && j < DPloyed.Count)
{
Apps curA = (Apps)Developed[i];
Apps curB = (Apps)DPloyed[j];
if (curA.CompareName(curB) == 0)
{
Inter.Add(curA);
i++;
j++;
}
else if (curA.CompareName(curB) < 0)
{
i++;
}
else
j++;
}
}
Any help as to why the while loop does not work would be appreciated.
Thanks
Do this
while (i < Developed.Count || j < DPloyed.Count)
because may be both list may be having different Count.
and you need to put extra checks inside loop for indexes so that you don't get Index out of Range Exception.
Problem was not in the actual code for the merges. Problem found in my compare methods.