Casino online









Mercato forex






A6. Gestire i livelli


Sicuramente non possiamo pensare di inserire tutti i blocchi da codice controllando i livelli con degli If. Dobbiamo fare in modo che il processo di caricamento dei livelli venga automatizzato dal programma: ogni livello sarà salvato su un file con estensione *.lvl, letto e trasportato sul gioco. Dobbiamo, quindi, creare un engine.
Per prima cosa servono altre quattro utilissime variabili globali:
    'Il livello a cui si è arrivati
    Private Level As Int16 = 0
    'Numero di vite a disposizione del giocatore
    Private Lives As Int16 = 3
    'Determina se il livello sia completato
    Private LevelCompleted As Boolean = True
    'Determina se il gioco sia completato
    Private GameCompleted As Boolean = False 
Visto che abbiamo dichiarato Lives, aggiustiamo il codice di CollisionCheck nel caso in cui la palla vada fuori dal margine inferiore:
'Se, invece, supera il margine inferiore della finestra, allora si perde
'una vita. 
If Ball.Position.Y > Me.Graphics.GraphicsDevice.Viewport.Height Then
    Lives -= 1
    'Sposta la palla al centro e la fa muovere verso il basso
    Ball.Position = New Vector2( _
        Me.GraphicsDevice.Viewport.Width / 2, _
        Me.GraphicsDevice.Viewport.Height / 2)
    Ball.Velocity = New Vector2(0, BallSpeed)
End If 
Ora si deve pensare a come scrivere i file per comunicare la posizione di uno o più blocchi sullo schermo. Dato che in questo gioco è molto frequente avere una o più file consecutive di elementi, sarebbe utile studiare un modo per dichiarare la posizione non di un solo blocco ma di molti. Io ho pensato a questa formattazione:
[Nome blocco] = [X] > [Xmax], [Y] > [Ymax] 
Dove i caratteri ">" indicano che si debbano porre tanti blocchi quanti ne servono per riempire lo spazio tra [X] e [Xmax] (o tra [Y] e [Ymax]). Ecco alcuni esempi:


Block01 = 30, 30



Block01 = 30 > 250, 30



Block01 = 30, 30 > 250



Block01 = 30 > 250, 30 > 250

Per ottenere questo risultato, dovremo scrivere una nuova procedura AdvanceLevel, che legga un file e trasformi le dichiarazioni ivi contenute in realtà:
Imports Microsoft.Xna.Framework
Imports Microsoft.Xna.Framework.Input
Imports Microsoft.Xna.Framework.Graphics

Public Class Game
    Inherits Microsoft.Xna.Framework.Game

    Private Graphics As GraphicsDeviceManager
    Private Batch As SpriteBatch

    Private BatSpeed As Single = 3
    Private BallSpeed As Single = 3

    Private Background As GameObject

    'Il livello a cui si è arrivati
    Private Level As Int16 = 0
    'Numero di vite a disposizione del giocatore
    Private Lives As Int16 = 3
    'Determina se il livello sia completato
    Private LevelCompleted As Boolean = True
    'Determina se il gioco sia completato
    Private GameCompleted As Boolean = False

    Private Bat As GameObject
    Private Ball As GameObject
    Private Blocks As New List(Of Block)

    Private Function GetTexture(ByVal Name As String) As Texture2D
        Return Texture2D.FromFile(Me.Graphics.GraphicsDevice, _
            My.Application.Info.DirectoryPath & "\" & Name)
    End Function

    Private Function GetBounds(ByVal Obj As GameObject) As Rectangle
        Return New Rectangle( _
            Obj.Position.X - (Obj.Sprite.Width / 2), _
            Obj.Position.Y - (Obj.Sprite.Height / 2), _
            Obj.Sprite.Width, Obj.Sprite.Height)
    End Function

    Private Sub KeyboardCheck()
        Dim KeyState As KeyboardState = Keyboard.GetState

        If KeyState.IsKeyDown(Keys.Right) Then
            Bat.Position += New Vector2(BatSpeed, 0)
        End If
        If KeyState.IsKeyDown(Keys.Left) Then
            Bat.Position += New Vector2(-BatSpeed, 0)
        End If
        If KeyState.IsKeyDown(Keys.Escape) Then
            Me.Exit()
        End If
    End Sub

    Private Sub CalculateBallVelocity(ByVal Obj As GameObject)
        Dim DeltaX As Single = Ball.Position.X - Obj.Position.X
        Dim DevAngle As Single = _
            (Math.Abs(DeltaX) / (Obj.Sprite.Width / 2)) * (Math.PI / 3)
        Dim AngleOnX As Single = MathHelper.PiOver2 - Math.Abs(DevAngle)

        Dim YComponent As Single = BallSpeed * Math.Sin(AngleOnX)
        Dim XComponent As Single = BallSpeed * Math.Cos(AngleOnX)

        If DeltaX < 0 Then
            XComponent = -XComponent
        End If

        If Ball.Position.Y <= Obj.Position.Y Then
            Ball.Velocity = New Vector2(XComponent, -YComponent)
        Else
            Ball.Velocity = New Vector2(XComponent, YComponent)
        End If
    End Sub

    Private Sub CollisionCheck()
        Dim BallRect As Rectangle = GetBounds(Ball)
        Dim BatRect As Rectangle = GetBounds(Bat)
        Dim Bounced As Boolean = False

        If BallRect.Intersects(BatRect) Then
            CalculateBallVelocity(Bat)
        End If

        If ((Ball.Position.X < 5) Or _
        (Ball.Position.X > Me.GraphicsDevice.Viewport.Width - 5)) _
        And (Ball.Position.Y < Me.GraphicsDevice.Viewport.Height - 5) Then
            Ball.Velocity = _ 
                New Vector2(-Ball.Velocity.X, Ball.Velocity.Y)
        End If

        If Ball.Position.Y < 5 Then
            Ball.Velocity = _ 
                New Vector2(Ball.Velocity.X, -Ball.Velocity.Y)
        End If

        'Se, invece, supera il margine inferiore della finestra, 
        'allora si perde una vita. 
        If Ball.Position.Y > Me.GraphicsDevice.Viewport.Height Then
            Lives -= 1
            'Sposta la palla al centro e la fa muovere verso il basso
            Ball.Position = New Vector2( _
                Me.GraphicsDevice.Viewport.Width / 2, _
                Me.GraphicsDevice.Viewport.Height / 2)
            Ball.Velocity = New Vector2(0, BallSpeed)
        End If

        Dim HitBlocks As New List(Of Block)
        For Each Block As Block In Blocks
            Dim BlockRect As Rectangle = GetBounds(Block)
            If BallRect.Intersects(BlockRect) And (Not Bounced) Then
                Ball.Velocity = _ 
                    New Vector2(Ball.Velocity.X, -Ball.Velocity.Y)
                Bounced = True
                Block.Life -= 1
                If Block.Life = 0 Then
                    Block.Enabled = False
                    HitBlocks.Add(Block)
                Else
                    Block.Sprite = GetTexture("Block" & _
                        Block.Life.ToString.PadLeft(2, "0") & ".png")
                End If
            End If
        Next

        For Each Block As Block In HitBlocks
            Blocks.Remove(Block)
        Next
    End Sub

    'AdvanceLevel verrà chiamata una volta
    'verificato che Blocks non contenga più nessun blocco
    Private Sub AdvanceLevel()
        'Aumenta il livello di 1
        Level += 1
        LevelCompleted = False

        If Not IO.File.Exists( _ 
            My.Application.Info.DirectoryPath & _ 
            "\Level" & Level & ".lvl") Then
            'Se non esiste il file, significa che non ci sono più
            'livelli, quindi il gioco è finito
            GameCompleted = True
        End If

        Dim Reader As New IO.StreamReader( _ 
            My.Application.Info.DirectoryPath & _ 
            "\Level" & Level & ".lvl")
        Dim Line As String

        Do While Not Reader.EndOfStream
            'Legge la linea
            Line = Reader.ReadLine

            'Se è vuota, la salta
            If String.IsNullOrEmpty(Line) Then
                Continue Do
            End If

            'Spezza la linea in base al carattere "="
            Dim Vals() As String = Line.Split("=")
            'Il primo argomento è il nome del blocco
            Dim Name As String = Vals(0).Trim
            'Il secondo le coordinate
            Dim Arg As String = Vals(1).Trim

            If Arg.Contains(",") Then
                'Prosegue, spezzando Args in base a ","
                Dim Coords() As String = Arg.Split(",")
                'Il primo valore sarà l'ascissa
                Dim CoX As String = Coords(0).Trim
                'Il secondo l'ordinata
                Dim CoY As String = Coords(1).Trim
                'Area determina la porzione di schermo che
                'dovrà essere coperta dai blocchi
                Dim Area As New Rectangle

                'Se l'ascissa contiene >, signifca che i blocchi
                'occuperanno un'area estesa in larghezza
                If CoX.Contains(">") Then
                    'Ottiene [X] e [Xmax]
                    Dim Xs() As String = CoX.Split(">")
                    Dim MinX As Int16 = CInt(Xs(0).Trim)
                    Dim MaxX As Int16 = CInt(Xs(1).Trim)
                    'Imposta la Location dell'area su [X]
                    Area.X = MinX
                    'E la sua larghezza su [Xmax]-[X]
                    Area.Width = MaxX - MinX
                Else
                    'Altrimenti, c'è un solo blocco
                    'in larghezza
                    Area.X = CInt(CoX)
                    Area.Width = 0
                End If

                'La stessa cosa per le Y
                If CoY.Contains(">") Then
                    Dim Ys() As String = CoY.Split(">")
                    Dim MinY As Int16 = CInt(Ys(0).Trim)
                    Dim MaxY As Int16 = CInt(Ys(1).Trim)
                    Area.Y = MinY
                    Area.Height = MaxY - MinY
                Else
                    Area.Y = CInt(CoY)
                    Area.Height = 0
                End If

                'Con due cicli for, popola l'area seleazionata.
                'Su X usiamo Step 35, poichè i blocchi sono
                'larghi 32 pixel, e inseriamo 3 pixel di distanza
                'tra ognuno. E questo anche su Y
                For X As Int16 = Area.X To (Area.X + Area.Width) Step 35
                    For Y As Int16 = Area.Y To (Area.Y + Area.Height) Step 19
                        'Inizializza un nuovo blocco in base al nome
                        Dim B As New Block(GetTexture(Name & ".png"))
                        'Imposta la sua posizione
                        B.Position = New Vector2(X, Y)
                        B.Name = Name
                        'Se il nome contiene Block, ottiene la sua "vita"
                        'dal numero in fondo al nome
                        If Name.StartsWith("Block") Then
                            B.Life = CInt(Name.Remove(0, Name.Length - 2))
                        End If
                        'Lo aggiunge alla lista
                        Blocks.Add(B)
                    Next
                Next
            End If
        Loop

        Reader.Close()
    End Sub

    Sub New()
        Me.Graphics = New GraphicsDeviceManager(Me)
        Me.Content.RootDirectory = "Content"
    End Sub

    Protected Overrides Sub Initialize()
        Batch = New SpriteBatch(Me.Graphics.GraphicsDevice)
        Me.IsMouseVisible = True
        MyBase.Initialize()
    End Sub

    Protected Overrides Sub LoadContent()
        MyBase.LoadContent()

        Background = New GameObject(GetTexture("Background.png"))
        Background.Position = Background.Center

        Dim Size As New Viewport
        Size.Width = Background.Sprite.Width
        Size.Height = Background.Sprite.Height
        Size.X = 0
        Size.Y = 0
        Me.Graphics.GraphicsDevice.Viewport = Size
        Me.Graphics.PreferredBackBufferHeight = Size.Height
        Me.Graphics.PreferredBackBufferWidth = Size.Width
        Me.Graphics.ApplyChanges()

        Bat = New GameObject(GetTexture("Bat.png"))
        Bat.Position = New Vector2( _
            Me.Graphics.GraphicsDevice.Viewport.Width / 2, _
            Me.Graphics.GraphicsDevice.Viewport.Height - 40)

        Ball = New GameObject(GetTexture("Ball.png"))
        Ball.Position = New Vector2( _
            Me.Graphics.GraphicsDevice.Viewport.Width / 2, _
            Me.Graphics.GraphicsDevice.Viewport.Height / 2)
        Ball.Velocity = New Vector2(0, BallSpeed)

        'Passa al primo livello
        AdvanceLevel()
    End Sub

    Protected Overrides Sub UnloadContent()
        MyBase.UnloadContent()
    End Sub

    Protected Overrides Sub Update(ByVal GameTime As GameTime)
        KeyboardCheck()

        CollisionCheck()

        Ball.Position += Ball.Velocity

        'Se non ci sono più blocchi, passa al livello dopo
        If Blocks.Count = 0 Then
            AdvanceLevel()
        End If

        MyBase.Update(GameTime)
    End Sub

    Protected Overrides Sub Draw(ByVal gameTime As GameTime)
        Me.Graphics.GraphicsDevice.Clear(Color.White)

        Batch.Begin()

        Background.Draw(Batch)

        Bat.Draw(Batch)
        Ball.Draw(Batch)
        'Disegna tutti i blocchi
        For Each Block As GameObject In Blocks
            Block.Draw(Batch)
        Next

        Batch.End()

        MyBase.Draw(gameTime)
    End Sub
End Class 
Ora possiamo scrivere il primo livello, ad esempio:
Block01 = 100 > 200, 30 > 130
Block01 = 890 > 990, 30 > 130
Block01 = 300 > 700, 300 > 370 


Risultato






 

The Totem's Lair - Copyright (C) 2009
È vietata la riproduzione sia totale che parziale del sito.