Small Basic Game Programming - Vertical Scrolling Game

I wrote an article about Vertical Scrolling Game.  That was one of challenges of the month - May 2014.  At that time, I made a vertical scrolling game named Turtle Dodger.  Today, I'd like to introduce the new version of this program (QZN342-4).

Main

The main part of this program calls four subroutines.  Window title is changed for every versions, so the setting is placed out of Init().  A variable debug is set as "True" if we need to show debugging information.

1.``' Turtle Dodger 0.6b

2.``' Copyright (c) 2014 Nonki Takahashi. The MIT License.

3.``'

4.``' History:

5.``' 0.6b 2014-07-30 Changed image and sorted subroutines. (QZN342-4)

6.``' 0.5b 2014-04-17 Changed to detect collision. (QZN342-3)

7.``' 0.4a 2014-04-17 Added opening. (QZN342-2)

8.``' 0.3a 2014-04-02 Avoided to hold while Turtle moving. (QZN342-1)

9.``' 0.2a 2014-04-02 Changed for Silverlight. (QZN342-0)

10.``' 0.1a 2014-04-02 Created. (QZN342)

11.``'

12.`` title `` = ``"Turtle Dodger 0.6b"

13.``GraphicsWindow``.`` Title `` = ``title

14.`` debug `` = ``"False"

15.``Init``(``)

16.``Opening``(``)

17.``Game``(``)

18.``Closing``(``)

Adding Obstacles

This time, I sorted subroutines in alphabetical order. Because, when a program becomes longer, it becomes little harder to find subroutines. So, I will introduce this subroutine which starts with A at the first. AddObject() adds one obstacle by calling Shapes.AddRectangle(). And calls Math.GetRandomNumber() three times for changing the color, position and angle of the obstacle.

19.`` Sub ``AddObject

20.``  `` iMax `` = ``obj``[``"iMax"`` ] `` + ``1

21.``  ``obj``[``"iMax"`` ] `` = ``iMax

22.``  ``GraphicsWindow``.`` PenWidth `` = ``1

23.``  `` type `` = ``Math``.``GetRandomNumber``(``3``)

24.``  ``obj``[``iMax``]``[``"type"`` ] `` = ``type

25.``  ``GraphicsWindow``.`` BrushColor `` = ``color``[``type``]

26.``  `` sz `` = ``size``[``type``]

27.``  ``obj``[``iMax``]``[``"obj"`` ] `` = ``Shapes``.``AddRectangle``(``sz`` , ``sz``)

28.``  `` x `` = ``Math``.``GetRandomNumber``(`` gw `` - ``20`` ) `` + ``10

29.``  `` y `` = ``-``20

30.``  ``obj``[``iMax``]``[``"x"`` ] `` = ``x

31.``  ``obj``[``iMax``]``[``"y"`` ] `` = ``y

32.``  ``Shapes``.``Move``(``obj``[``iMax``]``[``"obj"``]`` , ``x`` , ``y``)

33.``  ``Shapes``.``Rotate``(``obj``[``iMax``]``[``"obj"``]`` , ``Math``.``GetRandomNumber``(``360``)``)

34.``EndSub

Procedure for Closing

This subroutine rotates the Turtle three times and displays "GAME OVER".  This position of the text is calculated to be centered horizontally.  The detail about centering text is described here.

35.`` Sub ``Closing

36.``  ``Timer``.``Pause``(``)

37.``  ``Turtle``.``Turn``(``720``)

38.``  ``GraphicsWindow``.`` BrushColor `` = ``"White"

39.``  ``GraphicsWindow``.`` FontName `` = ``"Trebuchet MS"

40.``  ``GraphicsWindow``.`` FontSize `` = ``40

41.``  `` x `` = ``(`` gw `` - ``217`` ) `` / ``2

42.``  `` y `` = ``100

43.``  ``GraphicsWindow``.``DrawText``(``x`` , ``y`` , ``"GAME OVER"``)

44.``  ``Program``.``Delay``(``3000``)

45.``EndSub

Essential Part of Game

Subroutine Game() is the essential part of this game.  I decided that the main character of this game is Turtle.  May be many games uses Shapes objects.  But I thought Turtle is easier to operate in the program code.

In vertical scrolling game, main character and obstacles must be moved simultaneously.  A Mouse or keyboard event handler can move main character.  And a timer event handler can move obstacles.  That will be an event driven program.  But since this program uses Turtle for main character, I gave up to move Turtle in a event handler because of an known issue in Small Basic v1.0.

While loop continues unless there happens collision between Turtle and an obstacle.

46.`` Sub ``Game

47.``  ``Turtle``.`` Speed `` = ``7

48.``  ``Turtle``.``PenUp``(``)

49.``  `` x `` = `` gw `` / ``2

50.``  `` y `` = `` gh `` - ``40

51.``  ``GraphicsWindow``.`` BrushColor `` = ``"White"

52.``  ``GraphicsWindow``.`` FontSize `` = ``18

53.``  `` score `` = ``Shapes``.``AddText``(``"0"``)

54.``  ``Shapes``.``Move``(``score`` , ``20`` , ``20``)

55.``  `` If `` debug ``Then

56.``    ``GraphicsWindow``.`` BrushColor `` = ``"White"

57.``    ``GraphicsWindow``.`` FontSize `` = ``12

58.``    `` pos `` = ``Shapes``.``AddText``(`` "(" `` + `` x `` + `` "," `` + `` y `` + ``")"``)

59.``    ``GraphicsWindow``.`` PenWidth `` = ``1

60.``    `` cross1 `` = ``Shapes``.``AddLine``(``0`` , ``-``8`` , ``0`` , ``8``)

61.``    `` cross2 `` = ``Shapes``.``AddLine``(``-``8`` , ``0`` , ``8`` , ``0``)

62.``    ``Shapes``.``Move``(``cross1`` , ``x`` , ``y``)

63.``    ``Shapes``.``Move``(``cross2`` , ``x`` , ``y``)

64.``    ``Shapes``.``Move``(``pos`` , `` gw `` - ``100`` , ``20``)

65.``  ``EndIf

66.``  ``Turtle``.``MoveTo``(``x`` , ``y``)

67.``  ``Turtle``.`` Angle `` = ``0

68.``  `` Not `` = ``"False=True;True=False;"

69.``  `` moving `` = ``"False"

70.``  `` scrolling `` = ``"False"

71.``  ``Ready``(``)

72.``  ``GraphicsWindow``.`` KeyDown `` = ``OnKeyDown

73.``  `` tick `` = ``"False"

74.``  ``Timer``.`` Interval `` = `` 1000 `` / ``24

75.``  ``Timer``.`` Tick `` = ``OnTick

76.``  `` lastems `` = ``Clock``.``ElapsedMilliseconds

77.``  ``obj``[``"iMin"`` ] `` = ``1

78.``  `` While ``Not``[``cd``]

79.``    `` If `` moving ``Then

80.``      `` If `` key `` = `` "Left" ``Then

81.``        ``Turtle``.``TurnLeft``(``)

82.``        ``Turtle``.``Move``(``30``)

83.``        ``Turtle``.``TurnRight``(``)

84.``      `` ElseIf `` key `` = `` "Right" ``Then

85.``        ``Turtle``.``TurnRight``(``)

86.``        ``Turtle``.``Move``(``30``)

87.``        ``Turtle``.``TurnLeft``(``)

88.``      ``EndIf

89.``      `` moving `` = ``"False"

90.``    ``Else

91.``      ``Program``.``Delay``(``100``)

92.``    ``EndIf

93.``  ``EndWhile

94.``EndSub

Initialization

This subroutine initializes window size and variables.

95.`` Sub ``Init

96.``  `` gw `` = ``598

97.``  `` gh `` = ``428

98.``  ``GraphicsWindow``.`` BackgroundColor `` = ``"DodgerBlue"

99.``  ``GraphicsWindow``.`` Width `` = ``gw

100.``  ``GraphicsWindow``.`` Height `` = ``gh

101.``  `` color `` = ``"1=Orange;2=Cyan;3=Lime;"

102.``  `` size `` = ``"1=20;2=16;3=12;"

103.``  `` passed `` = ``0

104.``  `` cd `` = ``"False"  ``' collision detected

105.``EndSub

Key Input Event Handler

I decided to use right and left arrow keys to move Turtle.  Because I thought using mouse to move Turtle might be a little difficult for players.  In this event handler, a flag moving is set to "True" and the last key is memorized.  That's it.  Then, moving Turtle will be done in the main loop of Game().

But, while the flag moving is "True", next key input will be rejected.

106.`` Sub ``OnKeyDown

107.``  `` If ``Not``[``moving`` ] ``Then

108.``    `` moving `` = ``"True"

109.``    `` key `` = ``GraphicsWindow``.``LastKey

110.``  ``EndIf

111.``EndSub

Timer Event Handler

I uses Timer for dropping obstacles.  This subroutine scrolls obstacles 24 times per second (every 41 ms).  And adds a new obstacle every 500 ms.

112.`` Sub ``OnTick

113.``  `` If ``Not``[``scrolling`` ] ``Then

114.``    `` scrolling `` = ``"True"

115.``    `` ems `` = ``Clock``.``ElapsedMilliseconds

116.``    `` If `` ems `` - `` lastems `` > `` 500 ``Then

117.``      ``AddObject``(``)

118.``      `` lastems `` = ``ems

119.``    ``EndIf

120.``    ``ScrollObject``(``)

121.``    `` scrolling `` = ``"False"

122.``  ``EndIf

123.``  `` If `` debug ``Then

124.``    `` x `` = ``Math``.``Floor``(``Turtle``.``X``)

125.``    `` y `` = ``Math``.``Floor``(``Turtle``.``Y``)

126.``    ``Shapes``.``SetText``(``pos`` , `` "(" `` + `` x `` + `` "," `` + `` y `` + ``")"``)

127.``    ``Shapes``.``Move``(``cross1`` , ``x`` , ``y``)

128.``    ``Shapes``.``Move``(``cross2`` , ``x`` , ``y``)

129.``  ``EndIf

130.``EndSub

Opening

This is not essential function of the game, but opening screen makes it more game like.  This subroutine displays the title and a big image of a turtle.  Image files used in published Small Basic program is be better to locate on the internet. In the past, I used to use my private rental server to locate images.  But someday, this kind of site will be closed.  After that, the images can't be accessed from the game programs.  So, this time, I tried to locate this turtle image on the TechNet Gallery.  I hope this image in the TechNet Gallery remains longer than my site.

One more comment.  Using GraphicsWindow.DrawImage() might be simpler because this turtle doesn't move.

131.`` Sub ``Opening

132.``  `` url `` = ``"https://gallery.technet.microsoft.com/Turtle-PNG-Bitmap-for-582b449c/file/116666/1/Turtle.png"

133.``  `` bigTurtle `` = ``Shapes``.``AddImage``(``url``)

134.``  ``Shapes``.``Move``(``bigTurtle`` , ``180`` , ``140``)

135.``  ``GraphicsWindow``.`` BrushColor `` = ``"White"

136.``  ``GraphicsWindow``.`` FontName `` = ``"Trebuchet MS"

137.``  ``GraphicsWindow``.`` FontSize `` = ``50

138.``  `` x `` = ``(`` gw `` - ``443`` ) `` / ``2

139.``  `` y `` = ``40

140.``  ``GraphicsWindow``.``DrawText``(``x`` , ``y`` , ``title``)

141.``  ``Program``.``Delay``(``3000``)

142.``  ``GraphicsWindow``.``Clear``(``)

143.``EndSub

Procedure Just before Game Start

If the game start just after opening, players may be hurried.  So I added this subroutine to display "Ready?" for about 20 seconds.

144.`` Sub ``Ready

145.``  ``GraphicsWindow``.`` FontSize `` = ``40

146.``  `` rdy `` = ``Shapes``.``AddText``(``"Ready?"``)

147.``  `` x `` = ``(`` gw `` - ``130`` ) `` / ``2

148.``  `` y `` = ``100

149.``  ``Shapes``.``Move``(``rdy`` , ``x`` , ``y``)

150.``  `` For `` opacity `` = `` 100 `` To `` 0 `` Step ``-``10

151.``    ``Shapes``.``SetOpacity``(``rdy`` , ``opacity``)

152.``    ``Program``.``Delay``(``200``)

153.``  ``EndFor

154.``  ``Shapes``.``Remove``(``rdy``)

155.``EndSub

Scrolling Obstacles

This subroutine scrolls all obstacles 5 pixels (dots) downward.  This subroutine is called from the timer event handler.  That is no problem.  Because Shapes operations work well in event handlers.

Obstacles that come below the bottom of the window are deleted here.  This makes the program faster.

And in this subroutine, collision between the Turtle and an obstacle is detected by checking every distance between them.

156.`` Sub ``ScrollObject

157.``  `` iMin `` = ``obj``[``"iMin"``]

158.``  `` iMax `` = ``obj``[``"iMax"``]

159.``  `` For `` i `` = `` iMin `` To ``iMax

160.``    `` x `` = ``obj``[``i``]``[``"x"``]

161.``    `` y `` = ``obj``[``i``]``[``"y"`` ] `` + ``5

162.``    `` tx `` = ``Math``.``Floor``(``Turtle``.``X``)

163.``    `` ty `` = ``Math``.``Floor``(``Turtle``.``Y``)

164.``    `` d `` = ``Math``.``SquareRoot``(``Math``.``Power``(`` tx `` - ``x`` , ``2`` ) `` + ``Math``.``Power``(`` ty `` - ``y`` , ``2``)``)

165.``    `` If `` d `` < ``(``size``[``obj``[``i``]``[``"type"``]`` ] `` + ``16`` ) `` / `` 2 ``Then

166.``      `` cd `` = ``"True"      ``' collision detected

167.``      `` Goto ``break

168.``    ``EndIf

169.``    `` If `` y `` > `` gh ``Then

170.``      `` passed `` = `` passed `` + ``1

171.``      ``Shapes``.``SetText``(``score`` , ``passed``)

172.``      ``Shapes``.``Remove``(``obj``[``i``]``[``"obj"``]``)

173.``      ``obj``[``i`` ] `` = ``""

174.``      ``obj``[``"iMin"`` ] `` = `` i `` + ``1

175.``    ``Else

176.``      ``Shapes``.``Move``(``obj``[``i``]``[``"obj"``]`` , ``x`` , ``y``)

177.``      ``obj``[``i``]``[``"x"`` ] `` = ``x

178.``      ``obj``[``i``]``[``"y"`` ] `` = ``y

179.``    ``EndIf

180.``  ``EndFor

181.``  ``break``:

182.``EndSub

This program size is 182 lines.  That is not so big.  I recommend you to challenge this kind of vertical scrolling game if it is your first graphical game.