We'll need a form, a picturebox, called picDisp and a button called btnStart (see pic):
First of all we'll need a game field and its contents:
Now, let's create our snake:Code:Public Enum SquareContents Empty = 0 Food = 1 Obstacle = 2 Body = 3 End Enum Public Const FIELD_WIDTH As Integer = 30 Public Const FIELD_HEIGHT As Integer = 30 Public Shared GameField(0 To FIELD_WIDTH - 1, 0 To FIELD_HEIGHT - 1) As SquareContents Public Enum Directions Left Right Up Down End Enum
vb.net Code:
Public Class Snake ' His body is simply a queue of points ' A queue works by the FIFO principle - First In - First Out Public BodyCells As New Queue(Of Point) ' The direction of his movement Public Direction As Directions ' The location of his head Public HeadLocation As Point ' We'll need two events Public Event PainfulDeath() ' Game over Public Event YumYum() ' Snake eats Public Sub New() HeadLocation = New Point(FIELD_WIDTH \ 2, FIELD_HEIGHT \ 2) ' We place him in the center BodyCells.Enqueue(HeadLocation) ' We add his only cell to his body Direction = Directions.Right ' ... and make him look to the right End Sub ' Now, what will our snake do with each heatbeat? Public Sub Tick() Dim NextCell As Point = HeadLocation ' Where is the next cell Select Case Direction Case Directions.Up NextCell.Y -= 1 If NextCell.Y < 0 Then RaiseEvent PainfulDeath() ' ... kill the poor beast. Exit Sub End If Case Directions.Down NextCell.Y += 1 If NextCell.Y = FIELD_HEIGHT Then RaiseEvent PainfulDeath() Exit Sub End If Case Directions.Left NextCell.X -= 1 If NextCell.X < 0 Then RaiseEvent PainfulDeath() Exit Sub End If Case Directions.Right NextCell.X += 1 If NextCell.X = FIELD_WIDTH Then RaiseEvent PainfulDeath() Exit Sub End If End Select ' What do we have in this cell Select Case GameField(NextCell.X, NextCell.Y) Case SquareContents.Body, SquareContents.Obstacle ' bumped into an obstacle RaiseEvent PainfulDeath() Exit Sub Case SquareContents.Food ' some food here BodyCells.Enqueue(NextCell) ' add another cell to body HeadLocation = NextCell GameField(NextCell.X, NextCell.Y) = SquareContents.Body ' Delete eaten food RaiseEvent YumYum() ' Gimme more food Case SquareContents.Empty BodyCells.Enqueue(NextCell) ' The tricky part - we add a body cell here.. HeadLocation = NextCell Dim Tail As Point = BodyCells.Dequeue() ' ... and cut off his tail GameField(Tail.X, Tail.Y) = SquareContents.Empty GameField(NextCell.X, NextCell.Y) = SquareContents.Body End Select End Sub End Class
Something that would drive our game - a timer and some other helpers at the class level:
vb.net Code:
Public TICKS_FOR_FOOD As Integer Public Bob As Snake ' Here's our Bob Public CellSize As Size ' This is a size in pixels of one field cell (we'll determine it later) Public tmr As Timer ' Main timer Public FoodAt As Point ' Where the food is Public KeepFood As Integer = 0 ' Ticks remaining before the food is spoiled ' Colors: Public pGrass As Color Public pFood As Color Public pBody As Color Public pObstacle As Color Public GameOver As Boolean = False
A few preparations:
vb.net Code:
Private Sub frmSnake_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load Me.KeyPreview = True tmr = New Timer tmr.Interval = 100 ' Setting timer interval (this value actually controls the speed of the game) ' the less it is the faster the game tmr.Enabled = False ' Colors: pGrass = Color.DarkGreen pFood = Color.Red pBody = Color.Yellow pObstacle = Color.White AddHandler tmr.Tick, AddressOf tmr_Tick ' Making timer work End Sub ' Update the size of the game field cell in pixels: Private Sub frmSnake_Resize(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Resize CellSize.Width = CInt(picDisp.Width / FIELD_WIDTH) CellSize.Height = CInt(picDisp.Height / FIELD_HEIGHT) End Sub
Clicking the start button:
vb.net Code:
Private Sub btnStart_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnStart.Click Bob = New Snake ReDim GameField(0 To FIELD_WIDTH - 1, 0 To FIELD_HEIGHT - 1) ' Clear the game field AddHandler Bob.PainfulDeath, AddressOf EndGame ' Show 'Game Over' if snake dies AddHandler Bob.YumYum, AddressOf PlaceNewFood ' For placing food tmr.Enabled = True btnStart.Enabled = False GameOver = False End Sub ' Tell Bob where to go: Private Sub frmSnake_KeyDown(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyEventArgs) Handles Me.KeyDown Select Case e.KeyCode Case Keys.Left If Bob.Direction = Directions.Right Then Exit Sub Bob.Direction = Directions.Left Case Keys.Right If Bob.Direction = Directions.Left Then Exit Sub Bob.Direction = Directions.Right Case Keys.Up If Bob.Direction = Directions.Down Then Exit Sub Bob.Direction = Directions.Up Case Keys.Down If Bob.Direction = Directions.Up Then Exit Sub Bob.Direction = Directions.Down End Select End Sub ' Bob dies: Public Sub EndGame() GameOver = True tmr.Stop() btnStart.Enabled = True picDisp.Invalidate() End Sub ' Game tick: Public Sub tmr_Tick(ByVal sender As Object, ByVal e As EventArgs) If KeepFood = 0 Then PlaceNewFood(EmptyCell:=True) ' We need to remove the old food and place a new one Dim rng As New Random TICKS_FOR_FOOD = rng.Next(10, 40) End If KeepFood += 1 If KeepFood > TICKS_FOR_FOOD Then KeepFood = 0 ' Food is spolied if KeepFood = 0 Bob.Tick() ' Kick Bob to move picDisp.Invalidate() ' Redraw screen End Sub
Providing food is an important business:
vb.net Code:
Public Sub PlaceNewFood(Optional ByVal EmptyCell As Boolean = False) Dim rng As New Random Dim fx, fy As Integer Do fx = rng.Next(0, FIELD_WIDTH) fy = rng.Next(0, FIELD_HEIGHT) Loop While GameField(fx, fy) <> SquareContents.Empty If EmptyCell Then ' If we need to remove the old food we do that: GameField(FoodAt.X, FoodAt.Y) = SquareContents.Empty End If GameField(fx, fy) = SquareContents.Food ' New food is placed FoodAt.X = fx ' We should remember where it is to remove it later FoodAt.Y = fy End Sub ' Drawing the game screen: Private Sub DrawGameField(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles picDisp.Paint If GameOver Then Dim fnt As New Font(Me.Font.FontFamily, 42, FontStyle.Bold, GraphicsUnit.Pixel) Dim txt As String = "GAME OVER" Dim TextSize As SizeF = e.Graphics.MeasureString(txt, fnt, New SizeF(picDisp.Width, fnt.Height)) e.Graphics.DrawString(txt, fnt, Brushes.Red, _ CSng(picDisp.Width / 2 - TextSize.Width / 2), _ CSng(picDisp.Height / 2 - TextSize.Height / 2)) Exit Sub End If Dim x, y As Integer ' Draw each game square them: For y = 0 To FIELD_HEIGHT - 1 For x = 0 To FIELD_WIDTH - 1 Dim cellRect As New Rectangle(x * CellSize.Width, y * CellSize.Height, CellSize.Width, CellSize.Height) Select Case GameField(x, y) Case SquareContents.Empty e.Graphics.FillRectangle(New SolidBrush(pGrass), cellRect) Case SquareContents.Body e.Graphics.FillRectangle(New SolidBrush(pGrass), cellRect) e.Graphics.FillEllipse(New SolidBrush(pBody), cellRect) Case SquareContents.Food e.Graphics.FillRectangle(New SolidBrush(pGrass), cellRect) e.Graphics.FillEllipse(New SolidBrush(pFood), cellRect) Case SquareContents.Obstacle e.Graphics.FillRectangle(New SolidBrush(pObstacle), cellRect) End Select Next Next End Sub
That's all. Complete source code is attached.





Reply With Quote