Procedure names should start with a verb that says what the procedure does.
Sub dogame()
That doesn't say much; "do" is as general as it gets. Also, by convention, procedure names should be PascalCase
, so Sub DoGame()
would follow that.
You're not showing where loadedgame
is declared, but if it's declared, I suspect it's a Boolean
variable, at module level. If dogame
is the only procedure that uses this variable, then loadedgame
should be scoped to that procedure, and declared as close as possible to its usage:
Sub RunGame()
Dim loadedGame As Boolean
Boolean
variables get initialized with a False
value, so if loadedgame
is scoped at procedure level, this line isn't needed:
loadedgame = False
It's a very, very good idea to always declare all variables you're using. One way of forcing yourself to do that, is to specify Option Explicit
at the top of every code module you're writing - whether it's a form's code-behind, a class module, or a standard module: with that option specified, VBA will refuse to compile your project if an undeclared identifier is used anywhere.
Your indentation is somewhat broken in the inner For
loop, and I strongly recommend indenting the entire procedure's body too:
Sub RunGame()
'<~ indented
End Sub
The If Worksheets("options").Range("B3").Value = True Then
condition doesn't need to be indented - it's at the same level as the previous fmChooseWeapon.Show
line.
VBA module members are Public
by default, but in other languages it's Private
by default; it's always best to be explicit about access modifiers:
Public Sub RunGame()
I think there's way too much vertical whitespace. There shouldn't be 2 empty lines in a row.
Boolean
values can be used as a condition's expression - If [Boolean expression] Then
can also be If [Boolean value] Then
, so this:
If loadedgame = False Then
'block A
ElseIf loadedgame = True Then
'block B
End If
Is better written like this:
If Not loadedgame Then
'block A
Else
'block B
End If
...and best written like that:
If loadedgame Then
'block B
Else
'block A
End If
Positive conditions are always easier to mentally process; don't be afraid to reverse the If
and Else
blocks to reverse a negative condition! Also, a Boolean
can only ever be True
or False
, so there's no need to evaluate the False
condition if you've already checked the True
condition - the ElseIf
block can become an Else
block without altering the logic.
This part is weird:
If obj.Name = "fmMusic" Then
Else
Debug.Print "unloaded form" & obj.Name
Unload obj
End If
If there's nothing to execute in the If
block, only in the Else
part, then you need to reverse your condition:
If obj.Name <> "fmMusic" Then
Unload obj
Debug.Print "unloaded form" & obj.Name
End If
Notice I've moved the Debug.Print
call after the Unload
instruction - this way the immediate window will not say "unloaded form xyz" before the form is actually unloaded. Alternatively, you could edit the message to say "unloading form " & obj.Name & "..."
- the idea is to avoid telling confusing lies if anything goes wrong with that Unload
call. That said, obj
is a very bad name to use - why not call it form
or window
?
The procedure is quite long - I'd consider extracting smaller private procedures out of it, perhaps starting with the two branches in the If loadedgame
condition. A procedure should do one thing (and do it well), so as to have as few reasons to change as possible. Having more specialized procedures helps making your code more manageable, too.
Lastly, I suspect this is all written in a standard code module; I would encapsulate the game logic inside a class module, and have the dogame
procedure instantiate an object of that type and call some Run
method. The entire dogame
procedure/macro could then possibly look like this:
Public Sub RunGame()
On Error GoTo ErrHandler
Dim game As New GameLogic
game.Run
CleanExit:
Exit Sub
ErrHandler:
Debug.Print "An error has occurred: " Err.Description
Resume CleanExit
End Sub
ame
;) \$\endgroup\$