先日の日曜日、エクセルでテトリスを作りました。半日でできました。ブログで、コードをさらしたのですが、その翌日に、私はいくつか書き直して、もう少しマシなものにしました。
前回からの変更点を書きますね。
まず、少し不具合があったのです。右に行くとき、すり抜けてしまうという不具合がありました。これは、原因を見つけて直しました。数字を1箇所、間違えていました。もう不具合はないだろうと思っています。
また、前回のは、「クリア」がありませんでした。終了するのは「ゲームオーバー」しかなかったのです。ひどい話ですよね(笑)。ちょっと考えまして、「10回消したらクリア」としました。
それから、速さの段階が極端でした。もう少し速さの段階をマメにしまして、「ゆっくり」「ややゆっくり」「普通」「やや速い」「速い」「すごく速い」の6段階にいたしました。私自身はあまりテトリスが強くないので、レベル3(「普通」)くらいでちょうどよいです。
あと、色を変えました。いままでのは、濃い中間色がほとんどだったと思います。今度は、原色を中心として、カラフルにしました。パソコンは3色(赤、緑、青)が基本で、さらに白や黒、シアンやマゼンタといった色(すみません。よくわかりません。私自身は色弱で、色がよくわからないのです。数字で操作しているだけです)がありますが、そのちょうど8色で書いています。ずっと見やすくなったと言われます。昔ながらのファミコンみたいな感じの色になったみたいです。レトロな感じですかね。
セルの大きさも少し変えました。大きめのバージョンも作ったのです。でも、もしこのゲームで遊んでくださるかたがいらっしゃったとして、そのかたのマシンで画面に入りきらなかったらいけないと思い(下が入りきらなかったらプレイできないですよね)、いままでと同じ大きさ(小さめ)のコードをさらしますね。
画面が左寄りなのはすみません。タテが30、ヨコが15というのもいくらでも変えられるのですが、最初に30×15で作ってみて、ちょうどいい気がしましたので、そのままです。
「10回消したらクリア」の「10回」というのもいくらでも変えられるのですが、プレイしてみて、10回消したらクリアというのがちょうどよいと感じますので、これもこのままです。
ウィンドウズの64ビット版でしか動きません。それから、標準モジュールというところにコピペしないと動かないと思います。エクセルファイルを新規で作っていただきまして、マクロの「標準モジュール」というのを挿入していただき、そこに貼り付けてください。
以下に最新版のコードをさらしますね。
Option Explicit
Declare PtrSafe Function GetAsyncKeyState Lib "User32.dll" (ByVal vKey As Long) As Integer
Sub テトリス()
Dim shurui As Integer
Dim ochigyou(1 To 4), ochiretu(1 To 4) As Integer
Dim hayasa, hayaokuri, hayasas As Integer
Dim tate, yoko As Integer
Dim px As Double
tate = 30
yoko = 15
Dim sude(1 To 100, 1 To 100, 1 To 3) As Integer
Dim i, j, k, n, x, p, q As Integer
Dim a(1 To 4), b(1 To 4) As Integer
Dim iro(1 To 7, 1 To 3) As Integer
Dim PressNumber(1 To 5) As Integer
Dim narabi, kaisuu As Integer
Dim tuyosa As Integer
Dim tuyosastr As String
Dim keshi, keshikazu As Integer
'初期化
'何回消したらクリアか
keshikazu = 10
'色を定める
iro(1, 1) = 255
iro(1, 2) = 0
iro(1, 3) = 0
iro(2, 1) = 0
iro(2, 2) = 255
iro(2, 3) = 0
iro(3, 1) = 0
iro(3, 2) = 0
iro(3, 3) = 255
iro(4, 1) = 255
iro(4, 2) = 255
iro(4, 3) = 0
iro(5, 1) = 255
iro(5, 2) = 0
iro(5, 3) = 255
iro(6, 1) = 0
iro(6, 2) = 255
iro(6, 3) = 255
iro(7, 1) = 0
iro(7, 2) = 0
iro(7, 3) = 0
'メッセージ
MsgBox "「←」「→」のキーで左右に動きます。「z」「x」のキーで左右に回転します。「↓」で早送りできます。" & keshikazu & "回以上消したらクリアです。"
tuyosastr = InputBox("速さを選んでください。1.ゆっくり。2.ややゆっくり。3.普通。 4.やや速い。5.速い。 6.すごく速い。 ")
tuyosa = Int(Val(tuyosastr))
Select Case tuyosa
Case 1
hayasas = 60
Case 2
hayasas = 30
Case 3
hayasas = 20
Case 4
hayasas = 14
Case 5
hayasas = 10
Case 6
hayasas = 5
Case Else
hayasas = 20
End Select
'速さを定める
hayaokuri = 3
'セルを正方形にする
px = 12 '正方形の一辺の長さ[px]
' セルの高さと幅を設定
Cells.ColumnWidth = px * 0.118
Cells.RowHeight = px * 0.75
Cells.Clear
Range(Cells(1, yoko + 1), Cells(2, yoko + 2)).MergeCells = True
Cells(1, yoko + 1).Font.Size = 12
Cells(1, yoko + 1).HorizontalAlignment = xlCenter
Cells(1, yoko + 1).VerticalAlignment = xlCenter
Cells(1, yoko + 1).Value = 0
'本当のゲームスタート
'すべて白
For i = 1 To tate
For j = 1 To yoko
For k = 1 To 3
sude(i, j, k) = 255
Range(Cells(i, j), Cells(i, j)).Interior.Color = RGB(255, 255, 255)
Next
Next
Next
keshi = 0
'ゲームスタート
'上に発生する
L1:
x = 0
hayasa = hayasas
shurui = Int(Rnd * 7) + 1
Select Case shurui
Case 1
ochigyou(1) = 3
ochiretu(1) = Int(yoko / 2)
ochigyou(2) = 1
ochigyou(3) = 2
ochigyou(4) = 4
For j = 1 To 3
ochiretu(j + 1) = ochiretu(1)
Next
Case 2
ochigyou(1) = 1
ochiretu(1) = Int(yoko / 2)
ochigyou(2) = 2
ochiretu(2) = ochiretu(1)
ochigyou(3) = 1
ochiretu(3) = ochiretu(1) + 1
ochigyou(4) = 2
ochiretu(4) = ochiretu(1) + 1
Case 3
ochigyou(1) = 2
ochiretu(1) = Int(yoko / 2)
ochigyou(2) = 1
ochiretu(2) = ochiretu(1)
ochigyou(3) = 2
ochiretu(3) = ochiretu(1) - 1
ochigyou(4) = 2
ochiretu(4) = ochiretu(1) + 1
Case 4
ochigyou(1) = 1
ochiretu(1) = Int(yoko / 2)
ochigyou(2) = 2
ochiretu(2) = ochiretu(1)
ochigyou(3) = 1
ochiretu(3) = ochiretu(1) - 1
ochigyou(4) = 1
ochiretu(4) = ochiretu(1) - 2
Case 5
ochigyou(1) = 1
ochiretu(1) = Int(yoko / 2)
ochigyou(2) = 2
ochiretu(2) = ochiretu(1)
ochigyou(3) = 1
ochiretu(3) = ochiretu(1) + 1
ochigyou(4) = 1
ochiretu(4) = ochiretu(1) + 2
Case 6
ochigyou(1) = 2
ochiretu(1) = Int(yoko / 2)
ochigyou(2) = 1
ochiretu(2) = ochiretu(1)
ochigyou(3) = 2
ochiretu(3) = ochiretu(1) - 1
ochigyou(4) = 1
ochiretu(4) = ochiretu(1) + 1
Case 7
ochigyou(1) = 2
ochiretu(1) = Int(yoko / 2)
ochigyou(2) = 1
ochiretu(2) = ochiretu(1)
ochigyou(3) = 2
ochiretu(3) = ochiretu(1) + 1
ochigyou(4) = 1
ochiretu(4) = ochiretu(1) - 1
End Select
For i = 1 To 4
Range(Cells(ochigyou(i), ochiretu(i)), Cells(ochigyou(i), ochiretu(i))).Interior.Color = RGB(iro(shurui, 1), iro(shurui, 2), iro(shurui, 3))
Next
For k = 1 To 4
If sude(ochigyou(k), ochiretu(k), 1) < 255 Or sude(ochigyou(k), ochiretu(k), 2) < 255 Or sude(ochigyou(k), ochiretu(k), 3) < 255 Then
GoTo L3
End If
Next
'待つ
L4:
For i = 1 To hayasa
Application.Wait [Now()] + 0.01 / 86400
If PressLeft = True Then
PressNumber(1) = 1
End If
If PressRight = True Then
PressNumber(2) = 1
End If
If PressZ = True Then
PressNumber(3) = 1
End If
If PressX = True Then
PressNumber(4) = 1
End If
If PressDown = True Then
PressNumber(5) = 1
End If
If PressNumber(1) = 1 Then
For j = 1 To 4
If ochiretu(j) = 1 Then
PressNumber(1) = 0
ElseIf sude(ochigyou(j), ochiretu(j) - 1, 1) < 255 Or sude(ochigyou(j), ochiretu(j) - 1, 2) < 255 Or sude(ochigyou(j), ochiretu(j) - 1, 3) < 255 Then
PressNumber(1) = 0
End If
Next
If PressNumber(1) = 1 Then
For k = 1 To 4
Range(Cells(ochigyou(k), ochiretu(k)), Cells(ochigyou(k), ochiretu(k))).Interior.Color = RGB(255, 255, 255)
Next
For k = 1 To 4
ochiretu(k) = ochiretu(k) - 1
Next
For k = 1 To 4
Range(Cells(ochigyou(k), ochiretu(k)), Cells(ochigyou(k), ochiretu(k))).Interior.Color = RGB(iro(shurui, 1), iro(shurui, 2), iro(shurui, 3))
Next
PressNumber(1) = 0
End If
End If
If PressNumber(2) = 1 Then
For j = 1 To 4
If ochiretu(j) = yoko Then
PressNumber(2) = 0
ElseIf sude(ochigyou(j), ochiretu(j) + 1, 1) < 255 Or sude(ochigyou(j), ochiretu(j) + 1, 2) < 255 Or sude(ochigyou(j), ochiretu(j) + 1, 3) < 255 Then
PressNumber(2) = 0
End If
Next
If PressNumber(2) = 1 Then
For k = 1 To 4
Range(Cells(ochigyou(k), ochiretu(k)), Cells(ochigyou(k), ochiretu(k))).Interior.Color = RGB(255, 255, 255)
Next
For k = 1 To 4
ochiretu(k) = ochiretu(k) + 1
Next
For k = 1 To 4
Range(Cells(ochigyou(k), ochiretu(k)), Cells(ochigyou(k), ochiretu(k))).Interior.Color = RGB(iro(shurui, 1), iro(shurui, 2), iro(shurui, 3))
Next
PressNumber(2) = 0
End If
End If
If PressNumber(3) = 1 Then
Select Case shurui
Case 1, 3, 4, 5, 6, 7
For k = 2 To 4
a(k) = ochigyou(1) + (ochiretu(1) - ochiretu(k))
b(k) = ochiretu(1) - (ochigyou(1) - ochigyou(k))
If a(k) > tate Or a(k) < 1 Or b(k) > yoko Or b(k) < 1 Then
PressNumber(3) = 0
If PressNumber(3) = 1 Then
If sude(a(k), b(k), 1) < 255 Or sude(a(k), b(k), 2) < 255 Or sude(a(k), b(k), 3) < 255 Then
PressNumber(3) = 0
End If
End If
End If
Next
If PressNumber(3) = 1 Then
For k = 2 To 4
Range(Cells(ochigyou(k), ochiretu(k)), Cells(ochigyou(k), ochiretu(k))).Interior.Color = RGB(255, 255, 255)
Next
For k = 2 To 4
ochigyou(k) = a(k)
ochiretu(k) = b(k)
Next
For k = 2 To 4
Range(Cells(ochigyou(k), ochiretu(k)), Cells(ochigyou(k), ochiretu(k))).Interior.Color = RGB(iro(shurui, 1), iro(shurui, 2), iro(shurui, 3))
Next
PressNumber(3) = 0
End If
Case 2
PressNumber(3) = 0
End Select
End If
If PressNumber(4) = 1 Then
Select Case shurui
Case 1, 3, 4, 5, 6, 7
For k = 2 To 4
a(k) = ochigyou(1) - (ochiretu(1) - ochiretu(k))
b(k) = ochiretu(1) + (ochigyou(1) - ochigyou(k))
If a(k) > tate Or a(k) < 1 Or b(k) > yoko Or b(k) < 1 Then
PressNumber(4) = 0
If PressNumber(4) = 1 Then
If sude(a(k), b(k), 1) < 255 Or sude(a(k), b(k), 2) < 255 Or sude(a(k), b(k), 3) < 255 Then
PressNumber(4) = 0
End If
End If
End If
Next
If PressNumber(4) = 1 Then
For k = 2 To 4
Range(Cells(ochigyou(k), ochiretu(k)), Cells(ochigyou(k), ochiretu(k))).Interior.Color = RGB(255, 255, 255)
Next
For k = 2 To 4
ochigyou(k) = a(k)
ochiretu(k) = b(k)
Next
For k = 2 To 4
Range(Cells(ochigyou(k), ochiretu(k)), Cells(ochigyou(k), ochiretu(k))).Interior.Color = RGB(iro(shurui, 1), iro(shurui, 2), iro(shurui, 3))
Next
PressNumber(4) = 0
End If
Case 2
PressNumber(4) = 0
End Select
End If
If PressNumber(5) = 1 Then
hayasa = hayaokuri
PressNumber(5) = 0
Exit For
End If
Next
'落ちる
x = 0
For k = 1 To 4
If sude(ochigyou(k) + 1, ochiretu(k), 1) < 255 Or sude(ochigyou(k) + 1, ochiretu(k), 2) < 255 Or sude(ochigyou(k) + 1, ochiretu(k), 3) < 255 Or ochigyou(k) >= tate Then
x = 1
End If
Next
If x = 0 Then
For j = 1 To 4
Range(Cells(ochigyou(j), ochiretu(j)), Cells(ochigyou(j), ochiretu(j))).Interior.Color = RGB(255, 255, 255)
Next
For j = 1 To 4
ochigyou(j) = ochigyou(j) + 1
Next
For j = 1 To 4
Range(Cells(ochigyou(j), ochiretu(j)), Cells(ochigyou(j), ochiretu(j))).Interior.Color = RGB(iro(shurui, 1), iro(shurui, 2), iro(shurui, 3))
Next
GoTo L4
Else
For k = 1 To 4
For i = 1 To 3
sude(ochigyou(k), ochiretu(k), i) = iro(shurui, i)
Next
Next
For kaisuu = 1 To 4
For i = 1 To tate
narabi = 0
For j = 1 To yoko
If sude(i, j, 1) < 255 Or sude(i, j, 2) < 255 Or sude(i, j, 3) < 255 Then
narabi = narabi + 1
End If
Next
If narabi = yoko Then
keshi = keshi + 1
Cells(1, yoko + 1).Value = keshi
For k = 1 To i - 1
For p = 1 To yoko
For q = 1 To 3
sude(i + 1 - k, p, q) = sude(i - k, p, q)
Next
Next
Next
End If
Next
Next
For i = 1 To tate
For j = 1 To yoko
Range(Cells(i, j), Cells(i, j)).Interior.Color = RGB(sude(i, j, 1), sude(i, j, 2), sude(i, j, 3))
Next
Next
End If
If keshi >= keshikazu Then
MsgBox "おめでとうございます"
Exit Sub
End If
GoTo L1
L3:
MsgBox "ゲームオーバーです。"
End Sub
Function PressCtrl() As Boolean
Const KEY_PRESSED = -32767
PressCtrl = (GetAsyncKeyState(vbKeyControl) And KEY_PRESSED) = KEY_PRESSED
End Function
Function PressZ() As Boolean
Const KEY_PRESSED = -32767
PressZ = (GetAsyncKeyState(vbKeyZ) And KEY_PRESSED) = KEY_PRESSED
End Function
Function PressX() As Boolean
Const KEY_PRESSED = -32767
PressX = (GetAsyncKeyState(vbKeyX) And KEY_PRESSED) = KEY_PRESSED
End Function
Function PressC() As Boolean
Const KEY_PRESSED = -32767
PressC = (GetAsyncKeyState(vbKeyC) And KEY_PRESSED) = KEY_PRESSED
End Function
Function PressV() As Boolean
Const KEY_PRESSED = -32767
PressV = (GetAsyncKeyState(vbKeyV) And KEY_PRESSED) = KEY_PRESSED
End Function
Function PressLeft() As Boolean
Const KEY_PRESSED = -32767
PressLeft = (GetAsyncKeyState(vbKeyLeft) And KEY_PRESSED) = KEY_PRESSED
End Function
Function PressRight() As Boolean
Const KEY_PRESSED = -32767
PressRight = (GetAsyncKeyState(vbKeyRight) And KEY_PRESSED) = KEY_PRESSED
End Function
Function PressUp() As Boolean
Const KEY_PRESSED = -32767
PressUp = (GetAsyncKeyState(vbKeyUp) And KEY_PRESSED) = KEY_PRESSED
End Function
Function PressDown() As Boolean
Const KEY_PRESSED = -32767
PressDown = (GetAsyncKeyState(vbKeyDown) And KEY_PRESSED) = KEY_PRESSED
End Function