Microsoft Small Basic

Program Listing: KLB414-2
' Air Hockey 0.3a
' Copyright (c) 2013-2014 Nonki Takahashi. MIT License.
'
' History:
' 0.3a 2014-07-03 Added mallet control. (KLB414-2)
' 0.2a 2013-07-30 Changed field design. (KLB414-1)
' 0.11a 2013-07-29 Modified for Silverlight. (KLB414-0)
' 0.1a 2013-07-29 Created as alpha version. (KLB414)
'
GraphicsWindow.Title = "Air Hockey 0.3a - W,S for P1; O,L for P2"
gw = 598
gh = 428
GraphicsWindow.Width = gw
GraphicsWindow.Height = gh
GraphicsWindow.BackgroundColor = "DimGray"
Field_Init()
continue = "True"
While continue
Game_Init()
Game_Start()
Game_End()
EndWhile
Sub Field_Init
fh = 30 ' font height
GraphicsWindow.BrushColor = "White"
GraphicsWindow.FontSize = fh
score[1]["obj"] = Shapes.AddText(0)
Shapes.Move(score[1]["obj"], gw / 2 - 100, 10)
score[2]["obj"] = Shapes.AddText(0)
Shapes.Move(score[2]["obj"], gw / 2 + 100, 10)
field["width"] = 580
field["height"] = 360
field["x"] = (gw - field["width"]) / 2
field["y"] = (gh - field["height"] + fh) / 2
field["x2"] = field["x"] + field["width"]
field["y2"] = field["y"] + field["height"]
param["x"] = field["x"] - 10
param["y"] = (field["y"] + field["y2"]) / 2 - 70
param["width"] = 20
param["height"] = 140
param["border-radius"] = 10
goal["y"] = param["y"]
goal["y2"] = param["y"] + param["height"]
GraphicsWindow.BrushColor = "Black"
FillRoundRectangle()
param["x"] = field["x2"] - 10
FillRoundRectangle()
GraphicsWindow.BrushColor = "Blue"
GraphicsWindow.FillRectangle(field["x"], field["y"], field["width"], field["height"])
GraphicsWindow.PenWidth = 5
GraphicsWindow.PenColor = "LightGray"
param["x"] = field["x"] + 20
param["y"] = field["y"] + 20
param["width"] = field["width"] - 40
param["height"] = field["height"] - 40
param["border-radius"] = 100
DrawRoundRectangle()
x = param["x"] + param["width"] / 2
GraphicsWindow.DrawLine(x, param["y"], x, param["y"] + param["height"])
GraphicsWindow.BrushColor = "Black"
GraphicsWindow.PenWidth = 0
For y = field["y"] + 20 To field["y"] + field["height"] - 20 Step 20
For x = field["x"] + 20 To field["x"] + field["width"] - 20 Step 20
GraphicsWindow.FillEllipse(x - 1, y - 1, 2, 2)
EndFor
EndFor
GraphicsWindow.BrushColor = "White"
mallet[1]["size"] = 34
mallet[1]["r"] = mallet[1]["size"] / 2
mallet[1]["obj"] = Shapes.AddEllipse(mallet[1]["size"], mallet[1]["size"])
mallet[2]["size"] = 34
mallet[2]["r"] = mallet[2]["size"] / 2
mallet[2]["obj"] = Shapes.AddEllipse(mallet[2]["size"], mallet[2]["size"])
GraphicsWindow.BrushColor = "Yellow"
puck["size"] = 34
puck["r"] = puck["size"] / 2
puck["obj"] = Shapes.AddEllipse(puck["size"], puck["size"])
EndSub
Sub Game_Init
x = field["x"]
y = field["y"] + field["height"] / 2
mallet[1]["cx"] = x + 20
mallet[1]["cy"] = y
Shapes.Move(mallet[1]["obj"], mallet[1]["cx"] - mallet[1]["r"], mallet[1]["cy"] - mallet[1]["r"])
mallet[2]["cx"] = x + field["width"] - 20
mallet[2]["cy"] = y
Shapes.Move(mallet[2]["obj"], mallet[2]["cx"] - mallet[2]["r"], mallet[2]["cy"] - mallet[2]["r"])
puck["cx"] = x + (field["width"] / 2)
puck["cy"] = y
Shapes.Move(puck["obj"], puck["cx"] - puck["r"], puck["cy"] - puck["r"])
puck["vx"] = 400
puck["vy"] = 400
dy = puck["size"]
GraphicsWindow.KeyDown = OnKeyDown
EndSub
Sub Game_Start
inGame = "True"
dt = 1 / 24 ' [second]
Timer.Interval = dt * 1000
Timer.Tick = OnTick
While inGame
Program.Delay(dt * 500) ' for Silverlight
EndWhile
EndSub
Sub Game_End
EndSub
Sub OnKeyDown
key = GraphicsWindow.LastKey
If key = "W" Then ' player 1 up
If goal["y"] <= mallet[1]["cy"] - dy Then
mallet[1]["cy"] = mallet[1]["cy"] - dy
Shapes.Move(mallet[1]["obj"], mallet[1]["cx"] - mallet[1]["r"], mallet[1]["cy"] - mallet[1]["r"])
EndIf
ElseIf key = "S" Then ' player 1 down
If mallet[1]["cy"] + dy <= goal["y2"] Then
mallet[1]["cy"] = mallet[1]["cy"] + dy
Shapes.Move(mallet[1]["obj"], mallet[1]["cx"] - mallet[1]["r"], mallet[1]["cy"] - mallet[1]["r"])
EndIf
ElseIf key = "O" Then ' player 2 up
If goal["y"] <= mallet[2]["cy"] - dy Then
mallet[2]["cy"] = mallet[2]["cy"] - dy
Shapes.Move(mallet[2]["obj"], mallet[2]["cx"] - mallet[2]["r"], mallet[2]["cy"] - mallet[2]["r"])
EndIf
ElseIf key = "L" Then ' player 2 down
If mallet[2]["cy"] + dy <= goal["y2"] Then
mallet[2]["cy"] = mallet[2]["cy"] + dy
Shapes.Move(mallet[2]["obj"], mallet[2]["cx"] - mallet[2]["r"], mallet[2]["cy"] - mallet[2]["r"])
EndIf
EndIf
EndSub
Sub OnTick
Timer.Pause()
isGoal = "False"
x = puck["cx"] + dt * puck["vx"]
' TODO to detect collision between puck and mallet
If x < field["x"] + puck["r"] Then
y = puck["cy"] + dt * (field["x"] - puck["cx"]) * puck["vy"] / puck["vx"]
If (goal["y"] < y) And (y < goal["y2"]) Then
score[2]["value"] = score[2]["value"] + 1
Shapes.SetText(score[2]["obj"], score[2]["value"])
isGoal = "True"
Else
puck["cx"] = field["x"] + puck["r"] + (field["x"] + puck["r"] - x)
puck["vx"] = -puck["vx"]
Sound.PlayClick()
EndIf
ElseIf field["x2"] - puck["r"] < x Then
y = puck["cy"] + dt * (field["x2"] - puck["cx"]) * puck["vy"] / puck["vx"]
If (goal["y"] < y) And (y < goal["y2"]) Then
score[1]["value"] = score[1]["value"] + 1
Shapes.SetText(score[1]["obj"], score[1]["value"])
isGoal = "True"
Else
puck["cx"] = field["x2"] - puck["r"] - (x - (field["x2"] - puck["r"]))
puck["vx"] = -puck["vx"]
Sound.PlayClick()
EndIf
Else
puck["cx"] = x
EndIf
If isGoal Then
If y < goal ["y"] + puck["r"] Then
y = goal["y"] + puck["r"]
ElseIf goal["y2"] - puck["r"] < y Then
y = goal["y2"] - puck["r"]
EndIf
Shapes.Move(puck["obj"], x - puck["r"], y - puck["r"])
Sound.PlayChimeAndWait()
puck["cx"] = gw / 2
puck["cy"] = (field["y"] + field["y2"]) / 2
Else
y = puck["cy"] + dt * puck["vy"]
If y < field["y"] + puck["r"] Then
puck["cy"] = field["y"] + puck["r"] + (field["y"] + puck["r"] - y)
puck["vy"] = -puck["vy"]
Sound.PlayClick()
ElseIf field["y2"] - puck["r"] < y Then
puck["cy"] = field["y2"] - puck["r"] - (y - (field["y2"] - puck["r"]))
puck["vy"] = -puck["vy"]
Sound.PlayClick()
Else
puck["cy"] = y
EndIf
Shapes.Move(puck["obj"], puck["cx"] - puck["r"], puck["cy"] - puck["r"])
EndIf
Timer.Resume()
EndSub
Sub DrawRoundRectangle
Stack.PushValue("local", param)
Stack.PushValue("local", local)
local = param
param = ""
param["r"] = local["border-radius"]
If (local["width"] / 2 < param["r"]) Or (local["height"] / 2 < param["r"]) Then
param["r"] = Math.Min(local["width"] / 2, local["height"] / 2)
EndIf
param["da"] = 5
param["x"] = local["x"] + param["r"]
param["y"] = local["y"] + param["r"]
param["a1"] = 180
param["a2"] = 270
DrawArc()
GraphicsWindow.DrawLine(local["x"] + param["r"], local["y"], local["x"] + local["width"] - param["r"], local["y"])
param["x"] = local["x"] + local["width"] - param["r"]
param["y"] = local["y"] + param["r"]
param["a1"] = 270
param["a2"] = 360
DrawArc()
GraphicsWindow.DrawLine(local["x"] + local["width"], local["y"] + param["r"], local["x"] + local["width"], local["y"] + local["height"] - param["r"])
param["x"] = local["x"] + local["width"] - param["r"]
param["y"] = local["y"] + local["height"] - param["r"]
param["a1"] = 0
param["a2"] = 90
DrawArc()
GraphicsWindow.DrawLine(local["x"] + param["r"], local["y"] + local["height"], local["x"] + local["width"] - param["r"], local["y"] + local["height"])
param["x"] = local["x"] + param["r"]
param["y"] = local["y"] + local["height"] - param["r"]
param["a1"] = 90
param["a2"] = 180
DrawArc()
GraphicsWindow.DrawLine(local["x"], local["y"] + param["r"], local["x"], local["y"] + local["height"] - param["r"])
local = Stack.PopValue("local")
param = Stack.PopValue("local")
EndSub
Sub FillRoundRectangle
Stack.PushValue("local", param)
If (param["width"] / 2 < param["border-radius"]) Or (param["height"] / 2 < param["border-radius"]) Then
param["border-radius"] = Math.Min(param["width"] / 2, param["height"] / 2)
EndIf
GraphicsWindow.FillEllipse(param["x"], param["y"], param["border-radius"] * 2, param["border-radius"] * 2)
GraphicsWindow.FillRectangle(param["x"] + param["border-radius"], param["y"], param["width"] - param["border-radius"] * 2, param["height"])
GraphicsWindow.FillEllipse(param["x"] + param["width"] - param["border-radius"] * 2, param["y"], param["border-radius"] * 2, param["border-radius"] * 2)
GraphicsWindow.FillRectangle(param["x"], param["y"] + param["border-radius"], param["width"], param["height"] - param["border-radius"] * 2)
GraphicsWindow.FillEllipse(param["x"], param["y"] + param["height"] - param["border-radius"] * 2, param["border-radius"] * 2, param["border-radius"] * 2)
GraphicsWindow.FillEllipse(param["x"] + param["width"] - param["border-radius"] * 2, param["y"] + param["height"] - param["border-radius"] * 2, param["border-radius"] * 2, param["border-radius"] * 2)
param = Stack.PopValue("local")
EndSub
Sub DrawArc
Stack.PushValue("local", param)
Stack.PushValue("local", local)
Stack.PushValue("local", a)
local = param
param = ""
local["pw"] = GraphicsWindow.PenWidth
local["pc"] = GraphicsWindow.PenColor
local["bc"] = GraphicsWindow.BrushColor
GraphicsWindow.BrushColor = local["pc"]
local["r1"] = local["r"] - local["pw"] / 2
local["r2"] = local["r"] + local["pw"] / 2
For a = local["a1"] To local["a2"] Step local["da"]
local["rad"] = Math.GetRadians(a)
param["x1"] = local["x"] + local["r1"] * Math.Cos(local["rad"])
param["y1"] = local["y"] + local["r1"] * Math.Sin(local["rad"])
param["x2"] = local["x"] + local["r2"] * Math.Cos(local["rad"])
param["y2"] = local["y"] + local["r2"] * Math.Sin(local["rad"])
If local["a1"] < a Then
FillQuadrangle()
EndIf
param["x4"] = param["x1"]
param["y4"] = param["y1"]
param["x3"] = param["x2"]
param["y3"] = param["y2"]
EndFor
GraphicsWindow.BrushColor = local["bc"]
a = Stack.PopValue("local")
local = Stack.PopValue("local")
param = Stack.PopValue("local")
EndSub
Sub FillQuadrangle
GraphicsWindow.FillTriangle(param["x1"], param["y1"], param["x2"], param["y2"], param["x3"], param["y3"])
GraphicsWindow.FillTriangle(param["x3"], param["y3"], param["x4"], param["y4"], param["x1"], param["y1"])
EndSub