ho aggiornato il codice, ora supporta anche i file .X
Original:
Ciao ragazzi,
XNA usarlo in C# o in VB.Net è la stessa cosa, non cambia nulla. Ma come tutti sanno problema vero è proprio sono le risorse.
in C# vengono convertite in .xnb automaticamente dal Content Manager, mentre in VB no. E per caricarle occorrono altre strategie (per esempio utilizzare il LoadFromFile)
Ed è qui che vi offro la soluzione al problema
Ho cercato taaaaaaantissimo in internet ma non ho trovato soluzioni decenti, se non una vecchia per la versione 2.0 beta di xna.
Ho rivisitato il codice, l'ho testato e funziona tutto perfettamente. Ed è con piacere che lo pubblico in primis qui su xnaitalia
REQUISITI:
FrameWork 3.5 (sp1)
XNA 3.1
PROCEDURA:
al vostro progetto aggiungete una nuova classe e chiamatela VBContentManager.vb
incollate questo codice
- Codice: Seleziona tutto
'Content Manager for XNA Studio 3.1 and FrameWork 3.5 (sp1)
'Class recoded by Predator
'The original class came from www.xnamachine.com
Imports Microsoft.Xna.Framework.Content
Imports Microsoft.Xna.Framework.Graphics
Imports Microsoft.Xna.Framework.Audio
Imports Microsoft.Xna.Framework
Public Class VBContentManager
Inherits ContentManager
Public Fonts As Hashtable(Of SpriteFont)
Public Textures As Hashtable(Of Texture2D)
Public SubTextures As Hashtable(Of Hashtable(Of Rectangle))
Public Sounds As Hashtable(Of SoundBank)
Public Effects As Hashtable(Of Effect)
Private strContentprojFile, strProjectFolder, strExecutingFolder, strContentFolder As String
Private objContent As List(Of ContentFile)
Private intDupeSound, intDupeTexture, intDupeFont, intDupeEffect, intDupeModel As Integer
Public Enum Platform
Windows
XBox360
End Enum
Public Enum ContentTypes
Textures = 0
Fonts = 1
Sounds = 2
Effects = 3
Model = 4
End Enum
Private Enum ImporterName
TextureImporter = 0
FontDescriptionImporter = 1
XactImporter = 2
EffectImporter = 3
XImporter = 4
End Enum
Private Enum ProcessorName
TextureProcessor = 0
FontDescriptionProcessor = 1
XactProcessor = 2
EffectProcessor = 3
ModelProcessor = 4
End Enum
Public Structure ContentFile
Public ContentType As ContentTypes
Public File As System.IO.FileInfo
Public Name As String
Public Sub New(ByVal ContentType As ContentTypes, ByVal ContentFile As System.IO.FileInfo, ByVal Name As String)
Me.ContentType = ContentType
Me.File = ContentFile
Me.Name = Name
End Sub
End Structure
''' <summary>
''' Creates a new ContentManager which has been extended with functionality to support a Visual Basic (or other non-C#) project
''' </summary>
''' <param name="ServiceProvider">Your game has a .Services property; send that in here.</param>
''' <param name="ContentFolder">Your content folder (a relative path, from your game's Project node as it appears in the Solution Explorer)</param>
''' <remarks></remarks>
Public Sub New(ByVal ServiceProvider As IServiceProvider, ByVal ContentFolder As String)
MyBase.New(ServiceProvider)
With System.Reflection.Assembly.GetEntryAssembly.Location
Me.strExecutingFolder = .Substring(0, .LastIndexOf("\"))
End With
With Me.strExecutingFolder
With .Substring(0, .LastIndexOf("\") - 1)
Me.strProjectFolder = .Substring(0, .LastIndexOf("\"))
End With
End With
Me.strContentFolder = Me.strProjectFolder & "\" & ContentFolder
Me.Fonts = New Hashtable(Of SpriteFont)
Me.Textures = New Hashtable(Of Texture2D)
Me.SubTextures = New Hashtable(Of Hashtable(Of Rectangle))
Me.Sounds = New Hashtable(Of SoundBank)
Me.Effects = New Hashtable(Of Effect)
End Sub
''' <summary>
''' Attempts to load all assets which have been compiled by the Content Pipeline. Assets are placed into the respective Hash table (Fonts, Textures, et al)
''' </summary>
''' <remarks></remarks>
Public Sub LoadAllContent()
Dim objCompiledContent As New List(Of IO.FileInfo)
Dim strUnknownFiles As String = ""
For Each file As IO.FileInfo In New IO.DirectoryInfo(Me.strExecutingFolder).GetFiles("*.xnb", IO.SearchOption.AllDirectories)
Try
'Font?
With file.FullName.ToLower
Me.Fonts.Add(file.Name.Replace(file.Extension, ""), Me.Load(Of SpriteFont)(.Replace(Me.strExecutingFolder & "\", "").Replace(file.Extension, "")))
End With
Catch notAFont As Exception
Try
'Texture2D?
With file.FullName
Me.Textures.Add(file.Name.Replace(file.Extension, ""), Me.Load(Of Texture2D)(.Replace(Me.strExecutingFolder & "\", "").Replace(file.Extension, "")))
End With
'Is this a sheet w/ a rectangle map? If so, load the rectangle map
If IO.File.Exists(file.FullName.Replace(file.Extension, ".map")) Then
Me.LoadMap(file.Name.Replace(file.Extension, ""), file.FullName.Replace(file.Extension, ".map"))
End If
Catch notATexture2D As Exception
Try
'Sound?
With file.FullName.ToLower
Me.Sounds.Add(file.Name.Replace(file.Extension, ""), Me.Load(Of SoundBank)(.Replace(Me.strExecutingFolder & "\", "").Replace(file.Extension, "")))
End With
Catch notASoundBank As Exception
Try
'Effect?
With file.FullName.ToLower
Me.Effects.Add(file.Name.Replace(file.Extension, ""), Me.Load(Of Effect)(.Replace(Me.strExecutingFolder & "\", "").Replace(file.Extension, "")))
End With
Catch unknown As Exception
strUnknownFiles &= vbCrLf & file.FullName
End Try
End Try
End Try
End Try
Next
If strUnknownFiles <> "" Then
MsgBox("The VBContentManager was unable to determine the correct loader for:" & vbCrLf & _
strUnknownFiles & vbCrLf & vbCrLf & _
"Unless loaded by something else, the above content won't be available at runtime." & vbCrLf & vbCrLf & _
"This application may become unstable as a result.")
End If
End Sub
Private Sub LoadMap(ByVal strTextureNameName As String, ByVal strMapFile As String)
Dim objReader As IO.StreamReader
Dim strMapData As String
Dim strLine() As String
Dim strItem() As String
objReader = New IO.StreamReader(strMapFile)
Me.SubTextures.Add(strTextureNameName, New Hashtable(Of Rectangle))
strMapData = objReader.ReadToEnd
objReader.Close()
objReader.Dispose()
strLine = strMapData.Split(vbCrLf.ToCharArray, System.StringSplitOptions.RemoveEmptyEntries)
For Each strMapItem As String In strLine
strItem = strMapItem.Split(",".ToCharArray, System.StringSplitOptions.RemoveEmptyEntries)
Me.SubTextures(strTextureNameName).Add(strItem(0), New Rectangle(CInt(strItem(1)), CInt(strItem(2)), CInt(strItem(3)), CInt(strItem(4))))
Next
End Sub
''' <summary>
''' Compiles the VB Content Pipeline
''' </summary>
''' <param name="stealth">Hide/Show the MSBuild window during the compile process</param>
''' <param name="platform">If there's a way the Xbox360 will work with VB, you could pass in the Xbox parameter as a target platform to MSBuild. But it's Windows by default.</param>
''' <remarks></remarks>
Public Sub CompileContent(ByVal stealth As Boolean, Optional ByVal platform As Platform = VBContentManager.Platform.Windows)
Dim objProcess As Process
Dim objPSI As New Diagnostics.ProcessStartInfo
Me.objContent = New List(Of ContentFile)
Me.HarvestContent()
If Me.objContent.Count > 0 Then
Me.BuildContentProj(platform)
Try 'to write the content project file to disk
Using TempStreamWriter As System.IO.StreamWriter = New System.IO.StreamWriter(Me.strProjectFolder & "\Content.contentproj", False)
With TempStreamWriter
.Write(Me.strContentprojFile)
.Close()
End With
End Using
Try
With objPSI
.FileName = Environment.GetEnvironmentVariable("Windir") & "\Microsoft.NET\Framework\v3.5\MSBuild.exe"
.Arguments = """" & Me.strProjectFolder & "\Content.contentproj""" & _
" /verbosity:normal" & _
" /l:FileLogger,Microsoft.Build.Engine;logfile=""" & Me.strProjectFolder & "\Content.log"""
If stealth Then
.Arguments &= " /noconsolelogger"
.WindowStyle = ProcessWindowStyle.Hidden
End If
End With
'give the .contentproj file to MSBuild
objProcess = System.Diagnostics.Process.Start(objPSI)
While Not objProcess.HasExited
Threading.Thread.Sleep(100)
End While
Catch ex As Exception
MsgBox("When building the pipeline, trying to run MSBuild.exe resulted in: " & ex.Message)
End Try
Catch ex As Exception
MsgBox("When building the pipeline, trying to create the Content.contentproj file """ & Me.strProjectFolder & "\Content.contentproj"" resulted in: " & ex.Message)
End Try
End If
End Sub
Private Sub HarvestContent()
Dim objRoot As System.IO.DirectoryInfo = New System.IO.DirectoryInfo(Me.strContentFolder)
For Each sound As System.IO.FileInfo In objRoot.GetFiles("*.xab", IO.SearchOption.AllDirectories)
If Me.objContent.Contains(New ContentFile(ContentTypes.Sounds, sound, sound.Name.Replace(sound.Extension, ""))) Then
Me.intDupeSound += 1
Me.objContent.Add(New ContentFile(ContentTypes.Sounds, sound, sound.Name.Replace(sound.Extension, "") & Me.intDupeSound.ToString))
Else
Me.objContent.Add(New ContentFile(ContentTypes.Sounds, sound, sound.Name.Replace(sound.Extension, "")))
End If
Next
For Each texture As System.IO.FileInfo In objRoot.GetFiles("*.png", IO.SearchOption.AllDirectories)
If Me.objContent.Contains(New ContentFile(ContentTypes.Textures, texture, texture.Name.Replace(texture.Extension, ""))) Then
Me.intDupeTexture += 1
Me.objContent.Add(New ContentFile(ContentTypes.Textures, texture, texture.Name.Replace(texture.Extension, "") & Me.intDupeTexture.ToString))
Else
Me.objContent.Add(New ContentFile(ContentTypes.Textures, texture, texture.Name.Replace(texture.Extension, "")))
End If
Next
For Each texture As System.IO.FileInfo In objRoot.GetFiles("*.jpg", IO.SearchOption.AllDirectories)
If Me.objContent.Contains(New ContentFile(ContentTypes.Textures, texture, texture.Name.Replace(texture.Extension, ""))) Then
Me.intDupeTexture += 1
Me.objContent.Add(New ContentFile(ContentTypes.Textures, texture, texture.Name.Replace(texture.Extension, "") & Me.intDupeTexture.ToString))
Else
Me.objContent.Add(New ContentFile(ContentTypes.Textures, texture, texture.Name.Replace(texture.Extension, "")))
End If
Next
For Each texture As System.IO.FileInfo In objRoot.GetFiles("*.gif", IO.SearchOption.AllDirectories)
If Me.objContent.Contains(New ContentFile(ContentTypes.Textures, texture, texture.Name.Replace(texture.Extension, ""))) Then
Me.intDupeTexture += 1
Me.objContent.Add(New ContentFile(ContentTypes.Textures, texture, texture.Name.Replace(texture.Extension, "") & Me.intDupeTexture.ToString))
Else
Me.objContent.Add(New ContentFile(ContentTypes.Textures, texture, texture.Name.Replace(texture.Extension, "")))
End If
Next
For Each font As System.IO.FileInfo In objRoot.GetFiles("*.spritefont", IO.SearchOption.AllDirectories)
If Me.objContent.Contains(New ContentFile(ContentTypes.Fonts, font, font.Name.Replace(font.Extension, ""))) Then
Me.intDupeFont += 1
Me.objContent.Add(New ContentFile(ContentTypes.Fonts, font, font.Name.Replace(font.Extension, "") & Me.intDupeFont.ToString))
Else
Me.objContent.Add(New ContentFile(ContentTypes.Fonts, font, font.Name.Replace(font.Extension, "")))
End If
Next
For Each effect As System.IO.FileInfo In objRoot.GetFiles("*.fx", IO.SearchOption.AllDirectories)
If Me.objContent.Contains(New ContentFile(ContentTypes.Effects, effect, effect.Name.Replace(effect.Extension, ""))) Then
Me.intDupeEffect += 1
Me.objContent.Add(New ContentFile(ContentTypes.Effects, effect, effect.Name.Replace(effect.Extension, "") & Me.intDupeEffect.ToString))
Else
Me.objContent.Add(New ContentFile(ContentTypes.Effects, effect, effect.Name.Replace(effect.Extension, "")))
End If
Next
For Each effect As System.IO.FileInfo In objRoot.GetFiles("*.x", IO.SearchOption.AllDirectories)
If Me.objContent.Contains(New ContentFile(ContentTypes.Model, effect, effect.Name.Replace(effect.Extension, ""))) Then
Me.intDupeModel += 1
Me.objContent.Add(New ContentFile(ContentTypes.Model, effect, effect.Name.Replace(effect.Extension, "") & Me.intDupeModel.ToString))
Else
Me.objContent.Add(New ContentFile(ContentTypes.Model, effect, effect.Name.Replace(effect.Extension, "")))
End If
Next
End Sub
Private Sub BuildContentProj(ByVal platform As Platform)
Dim strPlatform As String
Select Case platform
Case VBContentManager.Platform.XBox360
strPlatform = "Xbox 360"
Case Else
strPlatform = "Windows"
End Select
Me.strContentprojFile = _
"<Project xmlns=""http://schemas.microsoft.com/developer/msbuild/2003"">" & vbCrLf & _
vbTab & "<Import Project=""$(MSBuildExtensionsPath)\Microsoft\XNA Game Studio\v3.1\Microsoft.Xna.GameStudio.ContentPipeline.targets"" />" & vbCrLf & _
vbTab & "<PropertyGroup>" & vbCrLf & _
vbTab & vbTab & "<OutputType>Library</OutputType>" & vbCrLf & _
vbTab & vbTab & "<XnaFrameworkVersion>v3.1</XnaFrameworkVersion>" & vbCrLf & _
vbTab & vbTab & "<ProjectDir>" & Me.strProjectFolder & "\</ProjectDir>" & vbCrLf & _
vbTab & vbTab & "<ParentOutputDir>" & Me.strExecutingFolder & "</ParentOutputDir>" & vbCrLf & _
vbTab & vbTab & "<ContentRootDirectory>\</ContentRootDirectory>" & vbCrLf & _
vbTab & vbTab & "<XNAContentPipelineTargetPlatform>" & strPlatform & "</XNAContentPipelineTargetPlatform>" & vbCrLf & _
vbTab & vbTab & "<OutputPath>" & Me.strExecutingFolder & "\</OutputPath>" & vbCrLf & _
vbTab & vbTab & "<OutputDirectory>" & Me.strExecutingFolder & "\</OutputDirectory>" & vbCrLf & _
vbTab & "</PropertyGroup>" & vbCrLf & _
vbTab & "<ItemGroup>" & vbCrLf & _
vbTab & vbTab & "<Reference Include=""Microsoft.Xna.Framework.Content.Pipeline.EffectImporter, Version=3.1.0.0, Culture=neutral, PublicKeyToken=6d5c3888ef60e27d, processorArchitecture=MSIL"" />" & vbCrLf & _
vbTab & vbTab & "<Reference Include=""Microsoft.Xna.Framework.Content.Pipeline.FBXImporter, Version=3.1.0.0, Culture=neutral, PublicKeyToken=6d5c3888ef60e27d, processorArchitecture=MSIL"" />" & vbCrLf & _
vbTab & vbTab & "<Reference Include=""Microsoft.Xna.Framework.Content.Pipeline.TextureImporter, Version=3.1.0.0, Culture=neutral, PublicKeyToken=6d5c3888ef60e27d, processorArchitecture=MSIL"" />" & vbCrLf & _
vbTab & vbTab & "<Reference Include=""Microsoft.Xna.Framework.Content.Pipeline.XImporter, Version=3.1.0.0, Culture=neutral, PublicKeyToken=6d5c3888ef60e27d, processorArchitecture=MSIL"" />" & vbCrLf & _
vbTab & "</ItemGroup>"
For Each content As ContentFile In Me.objContent
Me.strContentprojFile &= vbCrLf & _
vbTab & "<ItemGroup>" & vbCrLf & _
vbTab & vbTab & "<Compile Include=""" & content.File.FullName & """>" & vbCrLf & _
vbTab & vbTab & vbTab & "<Name>" & content.Name & "</Name>" & vbCrLf & _
vbTab & vbTab & vbTab & "<Importer>" & CType(content.ContentType, ImporterName).ToString & "</Importer>" & vbCrLf & _
vbTab & vbTab & vbTab & "<Processor>" & CType(content.ContentType, ProcessorName).ToString & "</Processor>" & vbCrLf & _
vbTab & vbTab & "</Compile>" & vbCrLf & _
vbTab & "</ItemGroup>"
If content.ContentType = ContentTypes.Textures Then
'If this texture is a sheet w/ a map, copy it's map out in the executable area
'along side the existing or eventual compiled texture
If IO.File.Exists(content.File.FullName.Replace(content.File.Extension, ".map")) Then
Try
IO.File.Copy(content.File.FullName.Replace(content.File.Extension, ".map"), _
Me.strExecutingFolder & content.File.FullName.Replace(Me.strProjectFolder, "").Replace(content.File.Extension, ".map"), True)
Catch ex As Exception
'I'm going to be optimistic and assume that if I can't copy
'it's because the file is already there, and life is just fine
End Try
End If
End If
Next
Me.strContentprojFile &= vbCrLf & vbTab & "<!-- To modify your build process, add your task inside one of the targets below and uncomment it. " & vbCrLf & _
vbTab & " Other similar extension points exist, see Microsoft.Common.targets." & vbCrLf & _
vbTab & "<Target Name=""BeforeBuild"">" & vbCrLf & _
vbTab & "</Target>" & vbCrLf & _
vbTab & "<Target Name=""AfterBuild"">" & vbCrLf & _
vbTab & "</Target>" & vbCrLf & _
vbTab & "-->" & vbCrLf & _
"</Project>"
End Sub
End Class
Public Class Hashtable(Of Type)
Inherits DictionaryBase
Public ReadOnly Property Keys() As ICollection
Get
Return MyBase.Dictionary.Keys
End Get
End Property
Default Public Property Item(ByVal key As String) As Type
Get
Return CType(MyBase.Dictionary(key), Type)
End Get
Set(ByVal value As Type)
MyBase.Dictionary(key) = value
End Set
End Property
Public Overloads Sub Add(ByVal key As String, ByVal obj As Type)
MyBase.Dictionary.Add(key, obj)
End Sub
Public ReadOnly Property Values() As ICollection
Get
Return Dictionary.Values
End Get
End Property
Public Function Contains(ByVal key As String) As Boolean
Return Dictionary.Contains(key)
End Function
Public Sub Remove(ByVal key As String)
Dictionary.Remove(key)
End Sub
End Class
UTILIZZO:
semplicissimo, nella vostra classe principale (di solito Game.vb) aggiungete la seguente riga tra i riferimenti globali,
cioè subito dopo Public Class Game
Protected objCM As VBContentManager
sotto New aggiungete questo per inizializzare il percorso:
Sub New()
Me.objCM = New VBContentManager(Me.Services, "Content")
per usarla basta aggiungere la seguente riga nel LoadContent
Protected Overrides Sub LoadContent()
objCM.CompileContent(True, VBContentManager.Platform.Windows)
finito
ovviamente potete scegliere tra windows o xbox.
Se non aggiungete nuove risorse basta commetare la riga. E comunque se le risorse sono state modificate, i file xnb verranno ricreati altrimenti verranno creati una sola volta
COME FUNZIONA:
Create una cartella Content dentro il percorso del vostro progetto (per capirci nella stessa cartella dove c'è il file NomeGioco.vbproj)
tutto cio' che mettete il dentro (comprese sottocartelle) verrà automaticamente processato, convertito in .xnb e messo nell'apposito percorso bin
Bhe dopo tutte le ricerche e richieste che ho letto in internet spero sia utile a molti.
se qualcuno vuole anche tradurre/sistemare quanto ho scritto tanto meglio
Ciauz
Predator




