返回介绍

Nibbles

发布于 2025-02-22 22:19:43 字数 11083 浏览 0 评论 0 收藏 0

In this part of the Visual Basic GTK# programming tutorial, we will create a Nibbles game clone.

Nibbles is an older classic video game. It was first created in late 70s. Later it was brought to PCs. In this game the player controls a snake. The objective is to eat as many apples as possible. Each time the snake eats an apple, its body grows. The snake must avoid the walls and its own body.

Development

The size of each of the joints of a snake is 10px. The snake is controlled with the cursor keys. Initially, the snake has three joints. The game starts immediately. When the game is finished, we display "Game Over" message in the center of the window.

board.vb

Imports Gtk
Imports Cairo

NameSpace BoardSpace

Public Class Board 
  Inherits DrawingArea 

  Const WIDTH As Integer = 300
  Const HEIGHT As Integer = 300
  Const DOT_SIZE As Integer = 10
  Const ALL_DOTS As Integer = 900
  Const RAND_POS As Integer = 30
  Const DELAY As Integer = 140

  Dim x(ALL_DOTS) As Integer 
  Dim y(ALL_DOTS) As Integer 

  Dim dots As Integer
  Dim apple_x As Integer
  Dim apple_y As Integer

  Dim left As Boolean = False
  Dim right As Boolean = True

  Dim up As Boolean = False
  Dim down As Boolean = False
  Dim inGame As Boolean = True

  Dim dot As ImageSurface
  Dim apple As ImageSurface
  Dim head As ImageSurface


  Public Sub New
    
    MyBase.New

    ModifyBg(StateType.Normal, New Gdk.Color(0, 0, 0))
     
    Me.InitGame
    
  End Sub


  Private Sub InitGame

    dots = 3
    
    For z As Integer = 0 To dots-1 
      x(z) = 50 - z*10
      y(z) = 50
    Next
    
    Try 
      dot = New ImageSurface("dot.png")
      head = New ImageSurface("head.png")
      apple = New ImageSurface("apple.png")
    Catch 
      Console.WriteLine("Images not found")
      Environment.Exit(1)
    End Try

    Me.LocateApple

    Dim timer As New GLib.TimeoutHandler(AddressOf Me.OnTimer)

    GLib.Timeout.Add(100, timer)
    AddHandler Me.ExposeEvent, AddressOf Me.OnExpose
    
  End Sub


  Protected Sub OnExpose(ByVal sender As Object, ByVal e As ExposeEventArgs) 

    Dim cc As Cairo.Context = Gdk.CairoHelper.Create(sender.GdkWindow)

    If inGame
      Me.DrawObjects(cc)
    Else 
      Me.GameOver(cc)
    End If
     
    Dim disposeTarget As IDisposable = CType(cc.Target, IDisposable)
    disposeTarget.Dispose
    
    Dim disposeContext As IDisposable = CType(cc, IDisposable)
    disposeContext.Dispose
    
  End Sub

  Private Sub DrawObjects(ByVal cc As Cairo.Context) 

    cc.SetSourceSurface(apple, apple_x, apple_y)
    cc.Paint

    For z As Integer = 0 to dots - 1
      If z = 0
        cc.SetSourceSurface(head, x(z), y(z))
        cc.Paint
      Else 
        cc.SetSourceSurface(dot, x(z), y(z))
        cc.Paint
      End If 
    Next
    
  End Sub

  Private Sub GameOver(ByVal cc As Cairo.Context) 

    Dim message As String = "Game Over"
    
    Dim x As Integer = Allocation.Width / 2
    Dim y As Integer = Allocation.Height / 2

    cc.SetSourceRGB(1, 1, 1)
    cc.SetFontSize(18)
    
    Dim extents As TextExtents = cc.TextExtents(message)
    
    cc.MoveTo(x - extents.Width/2, y)
    cc.ShowText(message)
    inGame = False
    
  End Sub


  Private Sub CheckApple

    If x(0) = apple_x And y(0) = apple_y
    
      dots += 1
      Me.LocateApple
      
    End If
    
  End Sub
 
  Private Sub Move

    For z As Integer = dots To 1 Step -1
      x(z) = x(z - 1)
      y(z) = y(z - 1)
    Next

    If left 
      x(0) -= DOT_SIZE
    End If

    If right
      x(0) += DOT_SIZE
    End If
      
    If up 
      y(0) -= DOT_SIZE
    End If

    If down 
      y(0) += DOT_SIZE
    End If
      
  End Sub


  Private Sub CheckCollision

    For z As Integer = dots To 1 Step -1
      If z > 4 And x(0) = x(z) And y(0) = y(z) 
        inGame = False
      End If
    Next   
  
    If y(0) > HEIGHT 
      inGame = False
    End If
  
    If y(0) < 0 
      inGame = False
    End If
  
    If x(0) > WIDTH 
      inGame = False
    End If

    If x(0) < 0 
      inGame = False
    End If
      
  End Sub
    
  
  Private Sub LocateApple
  
    Dim rand As New Random

    Dim r As Integer = rand.Next(RAND_POS)
    
    apple_x = r * DOT_SIZE
    r = rand.Next(RAND_POS)
    apple_y = r * DOT_SIZE
     
    
  End Sub

  Private Function OnTimer As Boolean

    If inGame
      
      Me.CheckApple
      Me.CheckCollision
      Me.Move
      Me.QueueDraw
      
      Return True
      
     Else 
      Return False
    End If
    
  End Function

  Public Sub OnKeyDown(ByVal e As Gdk.EventKey)
    
    Dim key As Integer = e.KeyValue

    If key = Gdk.Key.Left AndAlso Not right
      left = True
      up = False
      down = False
    End If

    If key = Gdk.Key.Right AndAlso Not left
      right = True
      up = False
      down = False
    End If
    
    If key = Gdk.Key.Up AndAlso Not down
      up = True
      right = False
      left = False
    End If

    If key = Gdk.Key.Down AndAlso Not up
      down = True
      right = False
      left = False
    End If

  End Sub
  
End Class

End Namespace

First we will define some globals used in our game.

The WIDTH and HEIGHT constants determine the size of the Board. The DOT_SIZE is the size of the apple and the dot of the snake. The ALL_DOTS constant defines the maximum number of possible dots on the Board. The RAND_POS constant is used to calculate a random position of an apple. The DELAY constant determines the speed of the game.

Dim x(ALL_DOTS) As Integer 
Dim y(ALL_DOTS) As Integer 

These two arrays store x, y coordinates of all possible joints of a snake.

The InitGame method initializes variables, loads images and starts a timeout function.

If inGame
  Me.DrawObjects(cc)
Else 
  Me.GameOver(cc)
End If

Inside the OnExpose method, we check the inGame variable. If it is true, we draw our objects. The apple and the snake joints. Otherwise we display "Game over" text.

Private Sub DrawObjects(ByVal cc As Cairo.Context) 

   cc.SetSourceSurface(apple, apple_x, apple_y)
   cc.Paint

   For z As Integer = 0 to dots - 1
     If z = 0
       cc.SetSourceSurface(head, x(z), y(z))
       cc.Paint
     Else 
       cc.SetSourceSurface(dot, x(z), y(z))
       cc.Paint
     End If 
   Next
  
End Sub

The DrawObjects method draws the apple and the joints of the snake. The first joint of a snake is its head, which is represented by a red circle.

Private Sub CheckApple

  If x(0) = apple_x And y(0) = apple_y
   
    dots += 1
    Me.LocateApple
     
  End If 
   
End Sub

The CheckApple method checks if the snake has hit the apple object. If so, we add another snake joint and call the LocateApple method, which randomly places a new apple object.

In the Move method we have the key algorithm of the game. To understand it, look at how the snake is moving. You control the head of the snake. You can change its direction with the cursor keys. The rest of the joints move one position up the chain. The second joint moves where the first was, the third joint where the second was etc.

For z As Integer = dots To 1 Step -1
  x(z) = x(z - 1)
  y(z) = y(z - 1)
Next

This code moves the joints up the chain.

If left
  x(0) -= DOT_SIZE
End If

Move the head to the left.

In the CheckCollision method, we determine if the snake has hit itself or one of the walls.

For z As Integer = dots To 1 Step -1
  If z > 4 And x(0) = x(z) And y(0) = y(z) 
    inGame = False
  End If
Next   

We finish the game if the snake hits one of its joints with the head.

If y(0) > HEIGHT 
  inGame = False
End If

We finish the game if the snake hits the bottom of the Board.

The LocateApple method locates an apple randomly on the board.

Dim rand As New Random

Dim r As Integer = rand.Next(RAND_POS)

We get a random number from 0 to RAND_POS - 1.

apple_x = r * DOT_SIZE
...
apple_y = r * DOT_SIZE

These line set the x, y coordinates of the apple object.

If inGame
   
  Me.CheckApple
  Me.CheckCollision
  Me.Move
  Me.QueueDraw
   
  Return True
   
Else 
  Return False
End If

Every 140 ms, the OnTimer method is called. If we are in the game, we call three methods that build the logic of the game. Otherwise we return False , which stops the timer event.

In the OnKeyDown method of the Board class, we determine the keys that were pressed.

If key = Gdk.Key.Left AndAlso Not right
  left = True
  up = False
  down = False
End If

If we hit the left cursor key, we set left variable to true. This variable is used in the Move method to change coordinates of the snake object. Notice also that when the snake is heading to the right, we cannot turn immediately to the left.

nibbles.vb

' ZetCode Mono Visual Basic GTK# tutorial
'
' In this program, we create
' a Nibbles game clone
'
' author jan bodnar
' last modified May 2009
' website www.zetcode.com

Imports Gtk
 
Public Class GtkVBApp
  Inherits Window

  Dim WIDTH As Integer = 250
  Dim HEIGHT As Integer = 150
  Dim board As BoardSpace.Board

  Public Sub New
  
    MyBase.New("Nibbles")

    board = New BoardSpace.Board
    Me.Add(board)

    AddHandler Me.DeleteEvent, AddressOf Me.OnDelete

    Me.Resize(310, 310)
    Me.Move(300, 300)
    Me.ShowAll
    
  End Sub
  
  Private Sub OnDelete(ByVal sender As Object, _
      ByVal args As DeleteEventArgs)
    Application.Quit
  End Sub

  
  Protected Overrides Function OnKeyPressEvent(ByVal e As Gdk.EventKey) As Boolean
    board.OnKeyDown(e)
    Return True
  End Function

  Public Shared Sub Main
  
    Application.Init
    Dim app As New GtkVBApp
    Application.Run
    
  End Sub

End Class

In this class, we set up the Nibbles game.

Protected Overrides Function OnKeyPressEvent(ByVal e As Gdk.EventKey) As Boolean
  board.OnKeyDown(e)
  Return True
End Function

In this class, we catch the key press events. And delegate the processing to the OnKeyDown method of the board class.

Nibbles
Figure: Nibbles

The following command compiles the game.

vbnc -r:/usr/lib/mono/gtk-sharp-2.0/gtk-sharp.dll 
  -r:/usr/lib/mono/gtk-sharp-2.0/gdk-sharp.dll -r:/usr/lib/mono/2.0/Mono.Cairo.dll 
  -r:/usr/lib/mono/gtk-sharp-2.0/glib-sharp.dll nibbles.vb board.vb

This was the Nibbles computer game programmed with the GTK# library and the Visual Basic programming language.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文