I’ve been wondering if video games (RPG mainly) could be developed under Excel+VBA.
When open Excel looks like a plain table, nothing that can resemble a dynamic environment. That is a fairly untrue statement. Even from the first MsOffice version, it has embebded easter-eggs full of motion.
Aside from easter-eggs, that are specifically coded inside Office, with a little help of imagination cells, formulas, charts and shapes can be turned into objects that do not behave as static ones.
It’s cristal clear that Excel by itself can be turned into a time consuming machine. For this task, simple games were developed by Andrew Engwirda, and even the Excel gurus Chip Pearson and Andy Pope have posts on games. Also, a fun version of Mine Sweeper can be downloaded at the great https://www.vertex42.com/ExcelArticles/fun-with-excel.html. But it seems these examples had no real intention to be more than table games, like the Sudokus, Chess, Monopoly and a myriad of things like that. Even a more evolved, as The game of life, is kind of obvious to be rightly implemented into Excel, as they are mostly “table formated”. There are a lot of samples of this kind on Keko’s site, on ExcelGame’s site, and on DzikoSoft.
For more complex creations, and one that really have perplexed myself since long time ago, are that from George Lungu’s ExcelUnusual, Excel as pure art. But it also seems difficult to extend this concept for using Excel as a game developing environment.
But the thing we are looking after resembles more to the new mobile games. They, for sure, can be emulated in Excel, for example, Angry Birds, or the short lived FlappyBird one, here in three flavours, Cells scent, throughly explained here, Chart scent (not downloadable any more), and Forms scent.
An approximation to the game world via Flash, as depicted in most of the links at https://www.exceltrick.com/interesting/excel-games-free-download/, is not a feasible solution, as has little to do with Excel+VBA, beeing an embedded Flash object (an it’s security implications), and need a javascriptish language to be learned, which is not very VBA look alike.
So, if we want to go further on Excel, things start to get tricky, as usually they are lost on dead sites or are not yet fully developed.
Legendary Colo’s Excel Junk Room maintained a list of Excel games that leaded me to Kouichi Tani’s dead web site, which contains a bunch of games made entirely on Excel (the site is dead, so again archive.org came to the recue).
Looks like japanese people really enjoy “playing” with Excel, as you can see in any of the games linked at http://www1.plala.or.jp/chikada/vba/vba.htm which also has a better looking site http://www.geocities.jp/excel_game/. They are in most cases 2D, but the ideas underneath must be of some value, and can be borrowed for the development.
Newer good approximations to this subject are triyed and described by:
- C Bel has created an incredible 3D engine (Doom alike) which surely could be improved if some calculations were coded with VBA, but so far is looks like this:
- Cary Walkin in creating a maze, and an incursion in RPG with his Arena.xlsm. Simple, very simple, but effective.
- A pretty good looking game is at http://www.frayn.net/games/ddxl/index.html
- An even better looking 3D maze is at https://cellsdungeon.blogspot.com/ which should be combined with C Bel’s creation for better looking.
Excel as a Game Engine Motor
Following is my intro into the “game business”… Lets throw some code into the VBA editor. Open the code module of a worksheet, put code PlayScreen inside. Code PlayScreen:
Option Explicit
'Move After Return Direction
Dim OldMARD As Excel.XlDirection 'Global
Dim NewMARD As Excel.XlDirection 'Global
Private Sub WorkSheet_Activate()
Call fSetPlayScreen(ActiveSheet, OldMARD, NewMARD)
End Sub
Private Sub WorkSheet_Deactivate()
Call fRestorePlayScreen(OldMARD)
End Sub
This procedures will trigger any time Worksheet get activated/desactivated, and their purpose is setting whole Columnwidth and Rowheight in order to achieve movements.
Also, some key events are captured and assigned to game events, “{LEFT}”, “{RIGHT}”, “{UP}”, “{DOWN}” for obvious reasons, “f” (as there is no {SPACE} chance no recalling to GetAsyncKeyState) can be assigned to fire of any ammo the character has in its bag, and even some combinations like “+{UP}” can be used to jump or “+{DOWN}” to crawl, “+{RIGHT} to run faster,…
For achieving this, paste the following code in a module:
Option Explicit
Const BulletSize As Single = 1
Public Function fBuildCaller(ByVal bWorkbookName As Boolean, _
ByVal ProcName As String, _
ParamArray Args() As Variant) As Variant
' Function to build procedure with variable number of arguments
' Take care that if bWorkBookName = True, will be permanent linked to the Workbook
Dim oItem As Variant
Dim oSubItem As Variant
Dim strDebug As String
Dim lgRetVal As Long
For Each oItem In Args
If IsArray(oItem) Then
For Each oSubItem In oItem
strDebug = strDebug & " """ & oSubItem & ""","
Next oSubItem
Else
strDebug = strDebug & " """ & oItem & ""","
End If
Next oItem
If bWorkbookName Then
lgRetVal = VBA.MsgBox("If bWorkbookName is set to True, will be permanently linked to Workbook, go with it?", _
vbYesNo + vbExclamation, "I N F O")
If lgRetVal = vbNo Then bWorkbookName = False
End If
If strDebug = vbNullString Then
strDebug = VBA.IIf(bWorkbookName, "'" & ThisWorkbook.Name & "'!", "") & _
"'" & ProcName & "'"
Else
strDebug = VBA.IIf(bWorkbookName, "'" & ThisWorkbook.Name & "'!", "") & _
"'" & ProcName & VBA.Mid$(strDebug, 1, Len(strDebug) - 1) & "'"
End If
fBuildCaller = strDebug
End Function
Public Function fBuildCaller2(ByVal ProcName As String, _
ParamArray Args() As Variant) As Variant
' Only working for PopUpMenus... better use fBuildCaller
' Has the advantage that "OnAction" is not linked to the WorkBook name
Dim oItem As Variant
Dim strDebug As String
For Each oItem In Args
strDebug = strDebug & Chr(34) & oItem + Chr(34) & ","
Next
If strDebug = vbNullString Then
strDebug = ProcName
Else
strDebug = ProcName & "(" & VBA.Mid$(strDebug, 1, Len(strDebug) - 1) & ")"
End If
fBuildCaller2 = strDebug
End Function
Public Function fWalk(ByVal oDirection As Excel.XlDirection, _
Optional ByVal bFast As Boolean = False)
Dim oWsh As Excel.Worksheet
Dim sgSpeed As Single
Set oWsh = ActiveSheet
sgSpeed = oWsh.Cells(1, 1).Column.Width
'Application.ScreenUpdating = False
With ActiveWindow
If bFast Then
Select Case oDirection
Case Is = xlToLeft
'.LargeScroll ToRight:=-1
oWsh.Shapes("Body").IncrementLeft -(2 * sgSpeed)
Case Is = xlDown:
'.LargeScroll Down:=-1
oWsh.Shapes("Body").IncrementTop -(2 * sgSpeed)
Case Is = xlToRight
'.LargeScroll ToRight:=1
oWsh.Shapes("Body").IncrementLeft (2 * sgSpeed)
Case Is = xlUp
'.LargeScroll Down:=1
oWsh.Shapes("Body").IncrementTop (2 * sgSpeed)
End Select
Else
Select Case oDirection
Case Is = xlToLeft
.SmallScroll ToRight:=-1
oWsh.Shapes("Body").IncrementLeft -(1 * sgSpeed)
Case Is = xlDown
'.SmallScroll Down:=-1
oWsh.Shapes("Body").IncrementTop -(1 * sgSpeed)
Case Is = xlToRight
.SmallScroll ToRight:=1
oWsh.Shapes("Body").IncrementLeft (1 * sgSpeed)
Case Is = xlUp
'.SmallScroll Down:=1
oWsh.Shapes("Body").IncrementTop (1 * sgSpeed)
End Select
End If
'.LargeScroll ToRight:=-1
'.LargeScroll Down:=1
End With
'Application.ScreenUpdating = True
End Function
Public Function fSetPlayScreen(ByVal oWsh As Excel.Worksheet, _
ByRef OldMARD As Excel.XlDirection, _
Optional ByRef NewMARD As Excel.XlDirection = xlDown)
Dim oCells As Excel.Range
Dim BulletSize As Single
' Set zoom
ActiveWindow.Zoom = 70
With oWsh
Set oCells = .Cells
oCells.RowHeight = 15
oCells.ColumnWidth = 2.14
Set oCells = Nothing
End With
With Application
Call set_MARD(NewMARD, OldMARD)
'MARD = Application.MoveAfterReturnDirection
'.MoveAfterReturnDirection = xlToLeft 'xlToRight
'Restore OnKey Events
.OnKey "{LEFT}", fBuildCaller(False, "fWalk", xlToLeft)
.OnKey "{RIGHT}", fBuildCaller(False, "fWalk", xlToRight)
.OnKey "{DOWN}", fBuildCaller(False, "fWalk", xlUp)
.OnKey "{UP}", fBuildCaller(False, "fWalk", xlDown)
.OnKey "f", fBuildCaller(False, "fFire", BulletSize)
.OnKey "g", fBuildCaller(False, "fGetObject")
.OnKey "a", fBuildCaller(False, "fAmmo")
.OnKey "d", fBuildCaller(False, "fDestroy")
.OnKey "+{LEFT}", fBuildCaller(False, "fWalk", xlToLeft, "True")
.OnKey "+{RIGHT}", fBuildCaller(False, "fWalk", xlToRight, "True")
.OnKey "+{DOWN}", fBuildCaller(False, "fCrawl")
.OnKey "+{UP}", fBuildCaller(False, "fJump")
End With
End Function
Public Function fJump()
' Make the character jump to gather a platform or to avoid an enemy
End Function
Public Function fCrawl()
' Make the character crawl to gather some tight space, or to avoid high enemy attack
End Function
Public Function fGetObject()
' Make the character get any object
End Function
Public Function fFire(ByVal BulletSize As Single)
' Generate a bullet that moves BulletSize
End Function
Public Function fAmmo()
' Let the character get any ammo it has... can be implemented as a roulette... next ammo, next ammo,...
End Function
Public Function fDestroy()
' Let the character destroy any object in front of him
End Function
'Public Sub sRestorePlayScreen()
' Call fRestorePlayScreen
'End Sub
Public Function fRestorePlayScreen(Optional ByRef OldMARD As Excel.XlDirection = xlDown)
With Application
Call restore_MARD(OldMARD)
'.MoveAfterReturnDirection = MARD
'Restore OnKey Events
.OnKey "{LEFT}"
.OnKey "{RIGHT}"
.OnKey "{DOWN}"
.OnKey "{UP}"
.OnKey "+{LEFT}"
.OnKey "+{RIGHT}"
.OnKey "+{DOWN}"
.OnKey "+{UP}"
End With
End Function
Public Sub set_MARD(ByRef OldMARD As Excel.XlDirection, _
Optional ByRef NewMARD As Excel.XlDirection = xlDown)
OldMARD = Application.MoveAfterReturnDirection
Application.MoveAfterReturnDirection = NewMARD 'xlDown, xlUP, xlToLeft, xlToRight
End Sub
Public Sub restore_MARD(Optional ByRef OldMARD As Excel.XlDirection = xlDown)
Application.MoveAfterReturnDirection = OldMARD
End Sub
In the worksheet, we need a character, named “Body” in this sample that must exists on the worksheet, this should be a shape (of any kind). So insert one to keep things moving.
From here on, we need a label in order to show score and other information (like number of lifes, health status, ammo,…). Lets call this shape “Info”.
We can add a physical green ground, and some deep background with clouds or sunny sky.
There can be enemies of different kinds, and for these we need a collision detection procedure (that will be implemented soon and posted here).
This could be a simple RPG game engine. Possibilities are endless.