I'm making a Console game where a moving character has to move left and right to intercept falling 'fruit'/ASCII characters, only I'm having trouble. I'm using a timer with a 1 second interval, and every time it elapses it's supposed to check a list of fruit that's already on the board and move each fruit down by one, and then it randomly inserts a new fruit onto the board. Fruits are all kept as objects in a class.
Here's the timer code:
Sub FruitTick() Handles FruitTimer.Elapsed
Dim RandomNumber As Integer
Dim Fruit As Fruit
For i = 0 To FruitList.Count - 1
If FruitList(i).Position.Y < FruitBoard.Height - 1 Then
FruitList(i).LowerFruitByOne()
End If
Next
PeriodUntilFruitAppears -= 1
If PeriodUntilFruitAppears <= 0 Then
PeriodUntilFruitAppears = FruitFrequency
RandomNumber = New Random().Next(1, 5)
If RandomNumber = 1 Then
Fruit = New Fruit()
Fruit.AddToList()
Fruit.PlaceOnBoard()
End If
End If
End Sub
And here's the class for Fruit:
Public Class Fruit
Private FruitIcons() As Char = {"#", "ð", "ó", "ç", "%", "$"}
Public Icon As Char
Public Position As Location
Public Colour As ConsoleColor
Sub New()
Me.Icon = FruitIcons(New Random().Next(FruitIcons.Length))
Me.Position = New Location(New Random().Next(FruitBoard.Width), 0)
Me.Colour = New Random().Next(1, 16)
End Sub
Sub New(_Icon As Char, _
_Position As Location, _
_Colour As ConsoleColor)
Me.Icon = _Icon
Me.Position = New Location(_Position.X, 0)
Me.Colour = _Colour
End Sub
Sub PlaceOnBoard()
Console.SetCursorPosition(FruitBoard.Position.X + Me.Position.X, FruitBoard.Position.Y + Me.Position.Y)
Console.ForegroundColor = Me.Colour
Console.BackgroundColor = FruitBoard.BackColour
Console.Write(Me.Icon)
End Sub
Sub AddToList()
FruitList.Add(Me)
End Sub
Sub LowerFruitByOne()
Dim DrawInstruction As Instruction
DrawInstruction = New Instruction(" ", _
New Location(FruitBoard.Position.X + Me.Position.X, _
FruitBoard.Position.Y + Me.Position.Y), _
FruitBoard.BackColour, _
FruitBoard.BackColour)
DrawInstruction.Execute()
Me.Position.Y += 1
DrawInstruction = New Instruction(Me.Icon, _
New Location(FruitBoard.Position.X + Me.Position.X, _
FruitBoard.Position.Y + Me.Position.Y), _
Me.Colour, _
FruitBoard.BackColour)
DrawInstruction.Execute()
End Sub
End Class
The Instruction class referred to is simply used to redraw characters in the Console.
I'm having weird problems, such as trailing characters where they should have been drawn over by a blank space, the fruit falling two characters instead of one, fruit spawning to the left of the previous fruit and then stopping, etc... but I'm especially having a problem debugging it. When I put a breakpoint in and step into the code, the debugger seems to go from place to place erratically, as if the timer's still running while it's paused and I'm too slow.
Is there any way to debug it properly, line-by-line, or am I going to have to make intelligent guesses about what's going on?
You should stop the timer while in the elapsed method. Try to stop the timer on the beggning and enabling it on the last line.
Sub FruitTick() Handles FruitTimer.Elapsed
FruitTimer.Enabled = False
' Your actual code
FruitTimer.Enabled = True
End Sub
Probably, your code last more than a second and the code starts again before the last execution is complete. Which is more evident when debugging. It will probably be generating all your problems and it will cause memory issues on the end.
Related
I have a program that collects information based on the radio buttons that are checked, as well as a checkbox.
Private Sub calculateBtn_Click(sender As Object, e As EventArgs) Handles calculateBtn.Click
Dim TypeCost As Integer
Dim ColorCost As Integer
Dim Foldable As Integer
If standardRbtn.Checked() Then
TypeCost = 99
End If
If deluxRbtn.Checked() Then
TypeCost = 129
End If
If premiumRbtn.Checked() Then
TypeCost = 179
End If
If blueRbtn.Checked() Then
ColorCost = 0
End If
If redRbtn.Checked() Then
ColorCost = 10
End If
If pinkRbtn.Checked() Then
ColorCost = 15
End If
If foldableCheckBox.Checked() Then
Foldable = 25
Else
Foldable = 0
End If
Dim Price As String = TypeCost + ColorCost + Foldable
priceTextBox.Text() = "$" & Price
End Sub
I have a strong feeling that this code can be simplified, but I just can't seem to think of what it is. My friend suggested Enumerations and Arrays, but I don't think those would work. Would they?
I have been searching around for a question similar to this for a while now.
I would also like to point out that the type radio buttons and the color radio buttons are in separate group boxes, so they function separately. Making it impossible for more than one type or color to be selected at the same time.
I have uptade the code to:
If standardRbtn.Checked() Then
TypeCost = 99
ElseIf deluxRbtn.Checked() Then
TypeCost = 129
ElseIf premiumRbtn.Checked() Then
TypeCost = 179
End If
If blueRbtn.Checked() Then
ColorCost = 0
ElseIf redRbtn.Checked() Then
ColorCost = 10
ElseIf pinkRbtn.Checked() Then
ColorCost = 15
End If
If foldableCheckBox.Checked() Then
Foldable = 25
Else
Foldable = 0
End If
I knew there was something extremely simply I would be able to do to sort of get rid of some of the repetitiveness. Thank you, phatfingers.
If there's any other ideas anyone would like to throw out, I would love to hear them. But this solution is good enough for me.
I simply went from using a bunch of if statements to "ElseIf". The updated code is in the original thread. :) - Thank you to phatfingers for the idea.
You could use a dropdown, which would probably be the lowest effort solution and allow you to dynamically add new options without rewriting anything.
You can then just fetch the value of the selected item.
https://forums.asp.net/t/988528.aspx?Dynamically+adding+items+in+DropDownList
So something like:
Private Sub OnFormLoad() //I forgot the exact name of the load event of the form and what it looks like
typeDropDown.Items.Add(New ListItem("Standard", "99"))
typeDropDown.Items.Add(New ListItem("Premium", "129"))
typeDropDown.Items.Add(New ListItem("Deluxe", "179"))
colorDropDown.Items.Add(New ListItem("Blue", "0"))
colorDropDown.Items.Add(New ListItem("Red", "10"))
colorDropDown.Items.Add(New ListItem("Pink", "15"))
End Sub
Private Sub calculateBtn_Click(sender As Object, e As EventArgs) Handles calculateBtn.Click
Dim Price as String = typeDropDown.SelectedValue + _
colorDropDown.SelectedValue + _
iif(foldableCheckBox.Checked(), 25, 0)
priceTextBox.Text() = "$" & Price
End Sub
I have a vb application with a listview.
I was testing and ended up with this sub for my dragover event:
Private Sub ListView1_DragOver(sender As Object, e As DragEventArgs) Handles ListView1.DragOver
XToolStripLabel.Text = "X:" & e.X
YToolStripLabel.Text = "Y:" & e.Y
Dim Insertion As Integer = GetInsertion(MousePosition, ListView1)
SelectionTestTSlabel.Text = "SEL " & Insertion
If CurrentlyDragging Then
Dim gr As Graphics = ListView1.CreateGraphics
Windows.Media.VisualTreeHelper.GetChild(New Windows.DependencyObject(), 0) 'I know this seems like it doesn't do much
MsgBox("") 'I actually added this later because the rest of the code did not run normally.
Dim InsertionY As Integer = 24 + (Insertion * TestItemHeight)
If MyLastInsPoint = Insertion Then
Else
ListView1.Refresh()
gr.DrawLine(New Pen(Color.Gray, 3), New Point(0, InsertionY), New Point(ListView1.Width, InsertionY))
End If
MyLastInsPoint = Insertion
End If
End Sub
I realized that the MsgBox("") doesn't popup a message box then i spammed breakpoints on the whole sub.
The sub ran as normal but after this line,
Windows.Media.VisualTreeHelper.GetChild(New Windows.DependencyObject(), 0)
the program returned to the form and did not execute the MsgBox("") line.
What's wrong with the line? The program did not even stop at the End Sub breakpoint.
New Windows.DependencyObject() has no children, so index 0 is not available
See the remaks on MSDN
Call the GetChildrenCount method to determine the total number of
child elements of a parent visual.
The value of reference can
represent either a Visual or Visual3D object, which is why the common
base type DependencyObject is used here as a parameter type.
I need some help.
I'm currently creating a Hangman Game in VB.Net.
I'm at the stage where a random word is loaded in from a text file of 6 words, and you can click buttons to guess it. If you guess letters wrong, the frame is shown etc, if they're right, the letter shows in the word through labels.
The next bit, that I'm stuck on, is that multiple rounds are needed. I need there to be 3 turns of this hangman game, so, if you guess the word right you get 10 points, and if you fail, you get 0, And then the game resets with your points and you can play again in Turn 2. Then again in Turn 3, and after Turn 3 finishes, the High Score Form is loaded.
You could create a variable to hold the current round in your Module, at the beginning of each round increase it, and at the end of the round check the current round and make a if then logic.
Dim myRound as Integer = 0
And in the PlayForm in the constructor.
myRound += 1
Once the round is complete.
if myRound >= 3 Then
'open the score page
Else
'start the next round
End if
'In General Declarations:
Dim ButtonList As New List(Of Button) 'or Of Control if you have other types of controls
Dim HgmList As New List(Of PowerPacks.Shape)
Dim AnswerList As New List(Of Label)
'In PlayForm_Load:
With ButtonList
.Clear()
.Add(Me.BtnA)
.Add(Me.BtnB)
.Add(Me.BtnC)
'You get the idea
'Add all your buttons you want to re-enable to the list
End With
With HgmList
.Clear()
.Add(Me.SideFrameLine)
.Add(Me.TopFrameLine)
.Add(Me.CornerFrameLine)
'etc.
End With
With AnswerList
.Add(Me.FirstLetterLbl)
'etc. Just like the other two.
End With
'At the end of your `If Correct = False Then` Block:
Else 'Check for win after each correct guess
Dim Winner As Boolean = True
Dim CheckLetter As Label
For Each CheckLetter in AnswerList
If Not CheckLetter.Visible Then
Winner = False
Exit For
End If
Next
If Winner Then
NextRound(10)
End If
End If
'Somewhere inside your form code:
Private Sub NextRound(RoundScore As Integer)
UserScore += RoundScore
If TurnNumber = 3 Then 'Game Over
MsgBox("Game Over" & vbNewLine & "Score: " & UserScore)
Else 'This is the part you asked about: resetting the form
TurnNumber += 1
PlayForm_Load(Nothing, Nothing)
Dim ResetControl As Control
Dim ResetShape As PowerPacks.Shape
For Each ResetControl In ButtonList
ResetControl.Enabled = True
Next
For Each ResetShape In HgmList
ResetControl.Visible = False
Next
End If
End Sub
I only added the .Clear() to the list builders because you already have your code to get a new word in PlayForm_Load. If you move it (say to a new Sub called NewWord), you don't need .Clear, and you would call your new sub instead of PlayForm_Load.
Here is my code,
Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
For Each kthread As Thread In _threads
If kthread.Name = "123" Then
_threads.Remove(kthread)
kthread.Abort()
killedthreads += 1 'a integer
End If
Next
End Sub
I added the killedthreads integer at last as a check, vb executes the whole function good but at the last line it always throw the error said in title.
Not sure why, if killedthreads += 1 is not there then the error goes to kthread.Abort()
I had the same problem with C# with a different app earlier this year.
Edit,
Public Sub KillThread(kThread As Thread)
For i As Integer = (_threads.Count - 1) To 0 Step -1
If _threads.Item(i).Name = kThread.Name Then
_threads.Item(i).Abort()
_threads.RemoveAt(i)
End If
Next
End Sub
I did this code as Eminem said it. This gets in kThread from the running threads if something is not good or it has finished all its functions. But my problem is that, only the first thread that sends it gets abort and removed from list, others seem to get stuck once the first thread is aborted.
I create threads using,
Public Sub multiThreader(int As Integer, link As String)
Dim tCount As Integer = _threads.Count
If tCount >= Form1.ListView1.Items.Count Then
Else
Dim dy As Integer = DateTime.Now.Day
Dim mo As Integer = DateTime.Now.Month
Dim fileNum As String = dy.ToString() + "-" + mo.ToString() + "_" + int.ToString
botThread = New Thread(Sub() MainThread(fileNum, link, botThread, int.ToString()))
botThread.IsBackground = True
botThread.Name = String.Format("AutoBotThread{0}", fileNum)
_threads.Add(botThread)
botThread.Start()
End If
End Sub
and _threads is publicly, Public _threads As New List(Of Thread)
MainThread is a Public Sub which runs functions and gets return and send KillThread under certain conditions.
The problem is that you remove an item from an enumeration, before you finished iterating through it.
It's like trying to iterate from 0 to list.count, when the count changes from an iteration to another. As Bjørn-Roger Kringsjå said, you should do something like this:
For i As Integer = (_threads.count - 1) to 0 Step -1
If _threads.Item(i).Name = "123" Then
_threads.Item(i).Abort
_threads.RemoveAt(i)
killedthreads += 1 'a integer
End If
Next
By using Step -1 you make sure that an Index was out of range error will not occur, and make sure that your operations are fitted, and execute on the right order/item.
I'm very new to programming and vb.net, trying to self teach more so as a hobby, as I have an idea for a program that I would find useful, but I am having trouble getting past this issue and I believe it is to do with the timer.
I have a form of size.(600,600) with one button of size.(450,150) that is set location(100,50) on the form. When clicked I want to move down it's own height, then add a new button in it's place. The code included below works as desired for the first two clicks, but on the third click the button keeps moving and the autoscroll bar extends. I initially thought it was the autoscroll function or the location property, but realised that as the button keeps moving, the timer hasn't stopped. I am aware that the code is probably very clunky in terms of achieving the outcome, and that there are a few lines/variables that are currently skipped over by the compiler (these are from older attempts to figure this out).
I have looked around and can't find the cause of my problem. Any help would be greatly appreciated. Apologies if the code block looks messy - first go.
Public Class frmOpenScreen
Dim intWButtons, intCreateButtonY, intCreateButtonX 'intTimerTick As Integer
Dim arrWNames() As String
Dim ctrlWButtons As Control
Dim blnAddingW As Boolean
Private Sub btnCreateW_Click(sender As System.Object, e As System.EventArgs) Handles btnCreateW.Click
'Creates new Button details including handler
Dim strWName, strWShort As String
Dim intCreateButtonY2 As Integer
Static intNumW As Integer
Dim B As New Button
strWName = InputBox("Please enter the name name of the button you are creating. Please ensure the spelling is correct.", "Create W")
If strWName = "" Then
MsgBox("Nothing Entered.")
Exit Sub
End If
strWShort = strWName.Replace(" ", "")
B.Text = strWName
B.Width = 400
B.Height = 150
B.Font = New System.Drawing.Font("Arial Narrow", 21.75)
B.AutoSizeMode = Windows.Forms.AutoSizeMode.GrowAndShrink
B.Anchor = AnchorStyles.Top
B.Margin = New Windows.Forms.Padding(0, 0, 0, 0)
'Updates Crucial Data (w name array, number of w buttons inc Create New)
If intNumW = 0 Then
ReDim arrWNames(0)
Else
intNumW = UBound(arrWNames) + 1
ReDim Preserve arrWNames(intNumW)
End If
arrWNames(intNumW) = strWShort
intNumW = intNumW + 1
intWButtons = WButtonCount(intWButtons) + 1
'updates form with new button and rearranges existing buttons
intCreateButtonY = btnCreateW.Location.Y
intCreateButtonX = btnCreateW.Location.X
‘intTimerTick = 0
tmrButtonMove.Enabled = True
‘Do While intTimerTick < 16
‘ 'blank to do nothing
‘Loop
'btnCreateW.Location = New Point(intCreateButtonX, intCreateButtonY + 150)
B.Location = New Point(intCreateButtonX, intCreateButtonY)
Me.Controls.Add(B)
B.Name = "btn" & strWShort
intCreateButtonY2 = btnCreateW.Location.Y
If intCreateButtonY2 > Me.Location.Y Then
Me.AutoScroll = False
Me.AutoScroll = True
Else
Me.AutoScroll = False
End If
'MsgBox(intCreateButtonY)
End Sub
Function WButtonCount(ByRef buttoncount As Integer) As Integer
buttoncount = intWButtons
If buttoncount = 0 Then
Return 1
End If
Return buttoncount
End Function
Public Sub tmrButtonMove_Tick(sender As System.Object, e As System.EventArgs) Handles tmrButtonMove.Tick
Dim intTimerTick As Integer
If intTimerTick > 14 Then
intTimerTick = 0
End If
If btnCreateW.Location.Y <= intCreateButtonY + 150 Then
btnCreateW.Top = btnCreateW.Top + 10
End If
intTimerTick += 1
If intTimerTick = 15 Then
tmrButtonMove.Enabled = False
End If
End Sub
End Class
So my current understanding is that the tick event handler should be increasing the timertick variable every time it fires, and that once it has hits 15 it should diable the timer and stop the button moving, but it is not doing so.
Thanks in advance.
IntTimerTick is initialized to 0 at the beginning of every Tick event. This won't happen if you declare it to be static:
Static Dim intTimerTick As Integer