Introduction
Tutorials + Examples
Here are some tutorials and examples showing a few features of the Game Template. I will post new examples here whenever I finish them.
Dynamically Loaded Resources: Part 1 Beginner - Intermediate Tutorial
What you will need: Optional
Dark Data
Tutorial:
Mission:
My
Multi-Level File and Folder Finder can be used to find resources. I can use my
Dynamic Resources for finding indexes. All the files can be stored in a database and loaded with a few commands.
- Naming resources.
- Grouping resources.
- Naming resources and finding indexes based on a name
- Possible automatic loading of resources
First I have to find all the files and store them in a database.
This can be done two ways:
- Using Dark Data to store the data for easy and quick access
- Save/Load Array Commands.
Edit: I included those functions in Part 2.
Dark Data Example:
Type Folder
Path$
Name$
SubLevel
EndType
Type File
Path$
Folder$
Name$
EndType
SetupFile()
ScanFolder("Media")
Message "Files Found:" + Str$(Array Count(Files()))
End
Function SetupFile()
Global Dim Folders() As Folder
Global Dim Files() As File
EndFunction
` Modified To Create a Database + Store Data
Function ScanFolder(Dir$)
CurrentDir$ = Get Dir$() : Set Dir Dir$
Folder$ = "Media"
` Create Data File
DFS Create 1, Folder$ + ".dat", 1
DFS Add Field 1, "String 99 As Path"
DFS Add Field 1, "String 99 As Folder"
DFS Add Field 1, "String 99 As Name"
DFS Finish 1
KFS Create 2, Folder$ + ".kfs", 20, 0, 0
Find First
FileType = HandleFile(0)
While FileType <> -1
If FileType = 1 Then FolderCount = FolderCount + 1
Find Next
FileType = HandleFile(0)
EndWhile
Repeat
Count = FolderCount
FolderCount = 0
ArrayCount = Array Count(Folders())
For Index = 0 To ArrayCount
If Folders(Index).SubLevel = SubLevel
Set Dir Folders(Index).Path$
Find First
FileType = HandleFile(SubLevel + 1)
If FileType = 1 Then FolderCount = FolderCount + 1
While FileType <> -1
If FileType = 1 Then FolderCount = FolderCount + 1
Find Next
FileType = HandleFile(SubLevel + 1)
EndWhile
EndIf
Next Index
SubLevel = SubLevel + 1
Until FolderCount = 0
DFS Close 1
KFS Close 2
Set Dir CurrentDir$
EndFunction
Function HandleFile(SubLevel)
FileType = Get File Type()
FileName$ = Get File Name$()
If Mid$(FileName$, 1) <> "."
If FileType = 1
Add To Stack Folders()
Folders().Path$ = Get Dir$() + "\" + FileName$
Folders().Name$ = FileName$
Folders().SubLevel = SubLevel
EndIf
If FileType = 0
Add To Stack Files()
Files().Path$ = Get Dir$() + "\" + FileName$
Files().Name$ = FileName$
Files().Folder$ = Get Dir$()
CLS
Print FileName$
Record = DFS Add(1)
DFS Put 1, "Path", Files().Path$
DFS Put 1, "Folder", Files().Folder$
DFS Put 1, "Name", Files().Name$
DFS Save 1, Record
KFS Add 2, Files().Name$, Record
EndIf
EndIf
EndFunction FileType
Function GetFileName$(FilePath$)
For Index = 1 To Len(FilePath$)
If Mid$(FilePath$, Index) = "." Then Exit
FileName$ = FileName$ + Mid$(FilePath$, Index)
Next Index
EndFunction FileName$
Function GetFileFolder(Level, Path$)
Index = Len(Path$)
For Iter = 1 To Level
Repeat : Index = Index - 1 : Until Mid$(Path$, Index) = "\"
Next Iter
Index2 = Index + 1
Repeat : Index2 = Index2 + 1 : Until Mid$(Path$, Index2) = "\"
Index2 = Index2 - Index
Folder$ = Mid$(Path$, Index + 1, Index2 - 1)
EndFunction Folder$
DBP Example:
Type Folder
Path$
Name$
SubLevel
EndType
Type File
Path$
Folder$
Name$
EndType
SetupFile()
ScanFolder("Media")
Message "Files Found: " + Str$(Array Count(Files()))
End
Function SetupFile()
Global Dim Folders() As Folder
Global Dim Files() As File
EndFunction
` Modified To Create a Database + Store Data
Function ScanFolder(Dir$)
CurrentDir$ = Get Dir$() : Set Dir Dir$
Find First
FileType = HandleFile(0)
While FileType <> -1
If FileType = 1 Then FolderCount = FolderCount + 1
Find Next
FileType = HandleFile(0)
EndWhile
Repeat
Count = FolderCount
FolderCount = 0
ArrayCount = Array Count(Folders())
For Index = 0 To ArrayCount
If Folders(Index).SubLevel = SubLevel
Set Dir Folders(Index).Path$
Find First
FileType = HandleFile(SubLevel + 1)
If FileType = 1 Then FolderCount = FolderCount + 1
While FileType <> -1
If FileType = 1 Then FolderCount = FolderCount + 1
Find Next
FileType = HandleFile(SubLevel + 1)
EndWhile
EndIf
Next Index
SubLevel = SubLevel + 1
Until FolderCount = 0
Set Dir CurrentDir$
EndFunction
Function HandleFile(SubLevel)
FileType = Get File Type()
FileName$ = Get File Name$()
If Mid$(FileName$, 1) <> "."
If FileType = 1
Add To Stack Folders()
Folders().Path$ = Get Dir$() + "\" + FileName$
Folders().Name$ = FileName$
Folders().SubLevel = SubLevel
EndIf
If FileType = 0
Add To Stack Files()
Files().Path$ = Get Dir$() + "\" + FileName$
Files().Name$ = FileName$
Files().Folder$ = Get Dir$()
CLS
Print FileName$
EndIf
EndIf
EndFunction FileType
Function GetFileName$(FilePath$)
For Index = 1 To Len(FilePath$)
If Mid$(FilePath$, Index) = "." Then Exit
FileName$ = FileName$ + Mid$(FilePath$, Index)
Next Index
EndFunction FileName$
Function GetFileFolder(Level, Path$)
Index = Len(Path$)
For Iter = 1 To Level
Repeat : Index = Index - 1 : Until Mid$(Path$, Index) = "\"
Next Iter
Index2 = Index + 1
Repeat : Index2 = Index2 + 1 : Until Mid$(Path$, Index2) = "\"
Index2 = Index2 - Index
Folder$ = Mid$(Path$, Index + 1, Index2 - 1)
EndFunction Folder$
Next is to load files using my
Dynamic Resources lib. Until next time.
Dynamically Loaded Resources: Part 2
Intermediate Tutorial
What you will need:
Dark Data (Optional)
Dynamic Resources
Tutorial:
In the first part I showed an example of how to scan for media. This example I am storing the data in a database or file and load the resource based on the resources name.
DBP Example:
Type Folder
Path$
Name$
SubLevel
EndType
Type File
Path$
Folder$
Name$
EndType
Setup_DynamicResources() : SetupFile()
If File Exist("Media\Files.dat") = 0
ScanFolder("Media") : SaveFilesArray()
Message "Files Found: " + Str$(Array Count(Files()))
Else
LoadFilesArray()
EndIf
LoadObject("piano2")
Message "Object Count: " + Str$(Object Count())
Do
Loop
Function SetupFile()
Global Dim Folders() As Folder
Global Dim Files() As File
EndFunction
` Modified To Create a Database + Store Data
Function ScanFolder(Dir$)
CurrentDir$ = Get Dir$() : Set Dir Dir$
Find First
FileType = HandleFile(0)
While FileType <> -1
If FileType = 1 Then FolderCount = FolderCount + 1
Find Next
FileType = HandleFile(0)
EndWhile
Repeat
Count = FolderCount
FolderCount = 0
ArrayCount = Array Count(Folders())
For Index = 0 To ArrayCount
If Folders(Index).SubLevel = SubLevel
Set Dir Folders(Index).Path$
Find First
FileType = HandleFile(SubLevel + 1)
If FileType = 1 Then FolderCount = FolderCount + 1
While FileType <> -1
If FileType = 1 Then FolderCount = FolderCount + 1
Find Next
FileType = HandleFile(SubLevel + 1)
EndWhile
EndIf
Next Index
SubLevel = SubLevel + 1
Until FolderCount = 0
Set Dir CurrentDir$
EndFunction
Function SaveFilesArray()
Open To Write 1, "Media\Files.dat"
For Index = 0 To Array Count(Files())
Write String 1, Files(Index).Path$
Write String 1, Files(Index).Folder$
Write String 1, Files(Index).Name$
Next Index
Close File 1
EndFunction
Function LoadFilesArray()
Open To Read 1, "Media\Files.dat"
While File End(1) = 0
Add To Stack Files()
Read String 1, Path$ : Files().Path$ = Path$
Read String 1, Folder$ : Files().Folder$ = Folder$
Read String 1, Name$ : Files().Name$ = Name$
EndWhile
Close File 1
EndFunction
Function HandleFile(SubLevel)
FileType = Get File Type()
FileName$ = Get File Name$()
If Mid$(FileName$, 1) <> "."
If FileType = 1
Add To Stack Folders()
Folders().Path$ = Get Dir$() + "\" + FileName$
Folders().Name$ = FileName$
Folders().SubLevel = SubLevel
EndIf
If FileType = 0
If GetExtentionType(GetFileExtension$(Files().Path$)) <> ""
Add To Stack Files()
Files().Path$ = Get Dir$() + "\" + FileName$
Files().Name$ = GetFileName$(FileName$) ` Remove the extension
Files().Folder$ = Get Dir$()
CLS
Print FileName$
EndIf
EndIf
EndIf
EndFunction FileType
Function GetFileName$(FilePath$)
For Index = 1 To Len(FilePath$)
If Mid$(FilePath$, Index) = "." Then Exit
FileName$ = FileName$ + Mid$(FilePath$, Index)
Next Index
EndFunction FileName$
Function GetFileFolder(Level, Path$)
Index = Len(Path$)
For Iter = 1 To Level
Repeat : Index = Index - 1 : Until Mid$(Path$, Index) = "\"
Next Iter
Index2 = Index + 1
Repeat : Index2 = Index2 + 1 : Until Mid$(Path$, Index2) = "\"
Index2 = Index2 - Index
Folder$ = Mid$(Path$, Index + 1, Index2 - 1)
EndFunction Folder$
Function GetFileExtension$(FilePath$)
For Index = 1 To Len(FilePath$)
If Mid$(FilePath$, Index) = "." Then Exit
Next Index
StartIndex = Index
For Index = StartIndex To Len(FilePath$)
FileExtension$ = FileExtension$ + Mid$(FilePath$, Index)
Next Index
EndFunction FileExtension$
Function GetExtentionType(Extention$)
Extention$ = Upper$(Extention$)
Select Extention$
Case ".BMP"
Type$ = "Image"
EndCase
Case ".JPG"
Type$ = "Image"
EndCase
Case ".TGA"
Type$ = "Image"
EndCase
Case ".DDS"
Type$ = "Image"
EndCase
Case ".DIB"
Type$ = "Image"
EndCase
Case ".PNG"
Type$ = "Image"
EndCase
Case ".X"
Type$ = "Object"
EndCase
Case ".DBO"
Type$ = "Object"
EndCase
Case ".3DS"
Type$ = "Object"
EndCase
Case ".MDL"
Type$ = "Object"
EndCase
Case ".MD2"
Type$ = "Object"
EndCase
Case ".MD3"
Type$ = "Object"
EndCase
Case ".FX"
Type$ = "Effect"
EndCase
Case ".WAV"
Type$ = "Sound"
EndCase
Case ".MIDI"
Type$ = "Music"
EndCase
Case ".MP3"
Type$ = "Music"
EndCase
Case Default
Type$ = ""
EndCase
EndSelect
EndFunction Type$
DBP Load Resource Functions:
Place in the Dynamic Resources lib.
```````````````````````````
` Load Resource Functions `
````````````````````````````````````````````````````````````````````````````````````````````````
` Finds the record. If all the information is correct and the file exist then load the resource and return the index.
` I would recommend not calling the DBP function within the main loop. The Dark Data function are faster so use them instead.
Function LoadObject(Name$)
For Index = 0 To Array Count(Files())
If GetExtentionType(GetFileExtension$(Files(Index).Path$)) = "Object"
If Files(Index).Name$ = Name$
Load Object Files(Index).Path$, NextObject()
EndIf
EndIf
Next Index
EndFunction ObjectIndex
Function LoadSound(Name$)
For Index = 0 To Array Count(Files())
If GetExtentionType(GetFileExtension$(Files(Index).Path$)) = "Sound"
If Files(Index).Name$ = Name$
Load Sound Files(Index).Path$, NextSound()
EndIf
EndIf
Next Index
EndFunction SoundIndex
Function LoadMusic(Name$)
For Index = 0 To Array Count(Files())
If GetExtentionType(GetFileExtension$(Files(Index).Path$)) = "Music"
If Files(Index).Name$ = Name$
Load Music Files(Index).Path$, NextMusic()
EndIf
EndIf
Next Index
EndFunction MusicIndex
Function LoadEffect(Name$)
For Index = 0 To Array Count(Files())
If GetExtentionType(GetFileExtension$(Files(Index).Path$)) = "Effect"
If Files(Index).Name$ = Name$
Load Effect Files(Index).Path$, NextEffect(), 0
EndIf
EndIf
Next Index
EndFunction EffectIndex
Function LoadImage(Name$)
For Index = 0 To Array Count(Files())
If GetExtentionType(GetFileExtension$(Files(Index).Path$)) = "Image"
If Files(Index).Name$ = Name$
Load Image Files(Index).Path$, NextImage()
EndIf
EndIf
Next Index
EndFunction ImageIndex
Dark Data Example:
Rem ***** Main Source File *****
Type Folder
Path$
Name$
SubLevel
EndType
Type File
Path$
Folder$
Name$
EndType
Setup_DynamicResources() : SetupFile()
If File Exist("Media\Media.dat") = 0
ScanFolder("Media", "Media")
Message "Files Found: " + Str$(Array Count(Files()))
EndIf
LoadDatabase("Media", "Media") : LoadObject("piano2")
Message "Object Count: " + Str$(Object Count())
End
Function SetupFile()
Global Dim Folders() As Folder
Global Dim Files() As File
EndFunction
` Modified To Create a Database + Store Data
Function ScanFolder(Dir$, DatabaseName$)
CurrentDir$ = Get Dir$() : Set Dir Dir$
KFS Create 2, DatabaseName$ + ".kfs", 33, 0, 0
` Create Data File
DFS Create 1, DatabaseName$ + ".dat", 0
DFS Add Field 1, "String 199 As Path"
DFS Add Field 1, "String 99 As Folder"
DFS Add Field 1, "String 99 As Name"
DFS Add Field 1, "String 99 As Type"
DFS Finish 1
Find First
FileType = HandleFile(0)
While FileType <> -1
If FileType = 1 Then FolderCount = FolderCount + 1
Find Next
FileType = HandleFile(0)
EndWhile
Repeat
Count = FolderCount
FolderCount = 0
ArrayCount = Array Count(Folders())
For Index = 0 To ArrayCount
If Folders(Index).SubLevel = SubLevel
Set Dir Folders(Index).Path$
Find First
FileType = HandleFile(SubLevel + 1)
If FileType = 1 Then FolderCount = FolderCount + 1
While FileType <> -1
If FileType = 1 Then FolderCount = FolderCount + 1
Find Next
FileType = HandleFile(SubLevel + 1)
EndWhile
EndIf
Next Index
SubLevel = SubLevel + 1
Until FolderCount = 0
DFS Close 1
KFS Close 2
Set Dir CurrentDir$
EndFunction
Function HandleFile(SubLevel)
FileType = Get File Type()
FileName$ = Get File Name$()
If Mid$(FileName$, 1) <> "."
If FileType = 1
Add To Stack Folders()
Folders().Path$ = Get Dir$() + "\" + FileName$
Folders().Name$ = FileName$
Folders().SubLevel = SubLevel
EndIf
If FileType = 0
Add To Stack Files()
Files().Path$ = Get Dir$() + "\" + FileName$
Files().Name$ = FileName$
Files().Folder$ = Get Dir$()
CLS
Print FileName$
` It will only work if it finds an extention DBP uses.
If GetExtentionType(GetFileExtension$(Files().Path$)) <> ""
Record = DFS Add(1)
DFS Put 1, "Path", Files().Path$
DFS Put 1, "Folder", Files().Folder$
DFS Put 1, "Name", GetFileName$(FileName$)
DFS Put 1, "Type", GetExtentionType(GetFileExtension$(Files().Path$))
DFS Save 1, Record
KFS Add 2, Lower$(GetFileName$(FileName$)), Record
EndIf
EndIf
EndIf
EndFunction FileType
Function GetFileName$(FilePath$)
For Index = 1 To Len(FilePath$)
If Mid$(FilePath$, Index) = "." Then Exit
FileName$ = FileName$ + Mid$(FilePath$, Index)
Next Index
EndFunction FileName$
Function GetFileExtension$(FilePath$)
For Index = 1 To Len(FilePath$)
If Mid$(FilePath$, Index) = "." Then Exit
Next Index
StartIndex = Index
For Index = StartIndex To Len(FilePath$)
FileExtension$ = FileExtension$ + Mid$(FilePath$, Index)
Next Index
EndFunction FileExtension$
Function GetExtentionType(Extention$)
Extention$ = Upper$(Extention$)
Select Extention$
Case ".BMP"
Type$ = "Image"
EndCase
Case ".JPG"
Type$ = "Image"
EndCase
Case ".TGA"
Type$ = "Image"
EndCase
Case ".DDS"
Type$ = "Image"
EndCase
Case ".DIB"
Type$ = "Image"
EndCase
Case ".PNG"
Type$ = "Image"
EndCase
Case ".X"
Type$ = "Object"
EndCase
Case ".DBO"
Type$ = "Object"
EndCase
Case ".3DS"
Type$ = "Object"
EndCase
Case ".MDL"
Type$ = "Object"
EndCase
Case ".MD2"
Type$ = "Object"
EndCase
Case ".MD3"
Type$ = "Object"
EndCase
Case ".FX"
Type$ = "Effect"
EndCase
Case ".WAV"
Type$ = "Sound"
EndCase
Case ".MIDI"
Type$ = "Music"
EndCase
Case ".MP3"
Type$ = "Music"
EndCase
Case Default
Type$ = ""
EndCase
EndSelect
EndFunction Type$
Dark Data Load Resource Functions:
I have found errors in the code. Some of the errors required a complete rewrite of the framework. I added all the updates and class rewrites into the Game Template.
How it works:
Using the scan function I wrote it will scan for the files and write all of them to an array. The files that DBP doesn't recognize are not added to the array. The file array is written to a database or an array file. The load resource functions will search for a resource based on the name given. If it is found it will load it and return the resource index. If it isn't found then it will report an error.
Dynamically Loaded Resources: Part 3
Naming Resources: Part 1
Intermediate Tutorial
What you will need:
Dark Data
Dynamic Resources
You will need Dark Data!
Tutorial:
I noticed that DBP's "GetIndex" function would be very slow so it would be un-needed. A good alternative would be to use lua. I will give an example using lua in the next tutorial.
Dark Data has a Find function making it easier and faster then searching manually though an array.
In order to make things easier for me I am posting the full source code here. Just download the example from the previous post or create your own media folder to test this example.
Here is the example:
Type Folder
Path$
Name$
SubLevel
EndType
Type File
Path$
Folder$
Name$
EndType
Setup_DynamicResources() : SetupFile()
If File Exist("Media\Media.dat") = 0
ScanFolder("Media", "Media")
EndIf
LoadFileDatabase("Media", "Media")
` Load/Create Name Database
If File Exist("Names.dat") = 0
CreateNameDatabase()
Else
KFS Open 4, "Names.kfs"
DFS Open 3, "Names.dat"
EndIf
LoadObject("piano2")
Message "Object Count: " + Str$(Object Count())
Message "Object Index: " + Str$(GetIndex("piano2"))
CloseDatabases()
End
Function SetupFile()
Global Dim Folders() As Folder
Global Dim Files() As File
EndFunction
` Modified To Create a Database + Store Data
Function ScanFolder(Dir$, DatabaseName$)
CurrentDir$ = Get Dir$() : Set Dir Dir$
KFS Create 2, DatabaseName$ + ".kfs", 33, 0, 0
` Create Data File
DFS Create 1, DatabaseName$ + ".dat", 0
DFS Add Field 1, "String 199 As Path"
DFS Add Field 1, "String 99 As Folder"
DFS Add Field 1, "String 99 As Name"
DFS Add Field 1, "String 99 As Type"
DFS Finish 1
Find First
FileType = HandleFile(0)
While FileType <> -1
If FileType = 1 Then FolderCount = FolderCount + 1
Find Next
FileType = HandleFile(0)
EndWhile
Repeat
Count = FolderCount
FolderCount = 0
ArrayCount = Array Count(Folders())
For Index = 0 To ArrayCount
If Folders(Index).SubLevel = SubLevel
Set Dir Folders(Index).Path$
Find First
FileType = HandleFile(SubLevel + 1)
If FileType = 1 Then FolderCount = FolderCount + 1
While FileType <> -1
If FileType = 1 Then FolderCount = FolderCount + 1
Find Next
FileType = HandleFile(SubLevel + 1)
EndWhile
EndIf
Next Index
SubLevel = SubLevel + 1
Until FolderCount = 0
DFS Close 1
KFS Close 2
Set Dir CurrentDir$
EndFunction
Function HandleFile(SubLevel)
FileType = Get File Type()
FileName$ = Get File Name$()
If Mid$(FileName$, 1) <> "."
If FileType = 1
Add To Stack Folders()
Folders().Path$ = Get Dir$() + "\" + FileName$
Folders().Name$ = FileName$
Folders().SubLevel = SubLevel
EndIf
If FileType = 0
Add To Stack Files()
Files().Path$ = Get Dir$() + "\" + FileName$
Files().Name$ = FileName$
Files().Folder$ = Get Dir$()
CLS
Print FileName$
` It will only work if it finds an extention DBP uses.
If GetExtentionType(GetFileExtension$(Files().Path$)) <> ""
Record = DFS Add(1)
DFS Put 1, "Path", Files().Path$
DFS Put 1, "Folder", Files().Folder$
DFS Put 1, "Name", GetFileName$(FileName$)
DFS Put 1, "Type", GetExtentionType(GetFileExtension$(Files().Path$))
DFS Save 1, Record
KFS Add 2, Lower$(GetFileName$(FileName$)), Record
EndIf
EndIf
EndIf
EndFunction FileType
Function GetFileName$(FilePath$)
For Index = 1 To Len(FilePath$)
If Mid$(FilePath$, Index) = "." Then Exit
FileName$ = FileName$ + Mid$(FilePath$, Index)
Next Index
EndFunction FileName$
Function GetFileExtension$(FilePath$)
For Index = 1 To Len(FilePath$)
If Mid$(FilePath$, Index) = "." Then Exit
Next Index
StartIndex = Index
For Index = StartIndex To Len(FilePath$)
FileExtension$ = FileExtension$ + Mid$(FilePath$, Index)
Next Index
EndFunction FileExtension$
Function GetExtentionType(Extention$)
Extention$ = Upper$(Extention$)
Select Extention$
Case ".BMP"
Type$ = "Image"
EndCase
Case ".JPG"
Type$ = "Image"
EndCase
Case ".TGA"
Type$ = "Image"
EndCase
Case ".DDS"
Type$ = "Image"
EndCase
Case ".DIB"
Type$ = "Image"
EndCase
Case ".PNG"
Type$ = "Image"
EndCase
Case ".X"
Type$ = "Object"
EndCase
Case ".DBO"
Type$ = "Object"
EndCase
Case ".3DS"
Type$ = "Object"
EndCase
Case ".MDL"
Type$ = "Object"
EndCase
Case ".MD2"
Type$ = "Object"
EndCase
Case ".MD3"
Type$ = "Object"
EndCase
Case ".FX"
Type$ = "Effect"
EndCase
Case ".WAV"
Type$ = "Sound"
EndCase
Case ".MIDI"
Type$ = "Music"
EndCase
Case ".MP3"
Type$ = "Music"
EndCase
Case Default
Type$ = ""
EndCase
EndSelect
EndFunction Type$
Dynamic Resources Function Additions:
Copy and paste
Dynamic Resources and this snippet.
```````````````````````````
` Load Resource Functions `
````````````````````````````````````````````````````````````````````````````````````````````````
` Finds the record. If all the information is correct and the file exist then load the resource and return the index.
` I would recommend not calling the DBP function within the main loop. The Dark Data function are faster so use them instead.
remstart
Function LoadObject(Name$)
For Index = 0 To Array Count(Files())
If GetExtentionType(GetFileExtension$(Files(Index).Path$)) = "Object"
If Files(Index).Name$ = Name$
Load Object Files(Index).Path$, NextObject()
EndIf
EndIf
Next Index
EndFunction ObjectIndex
Function LoadSound(Name$)
For Index = 0 To Array Count(Files())
If GetExtentionType(GetFileExtension$(Files(Index).Path$)) = "Sound"
If Files(Index).Name$ = Name$
Load Sound Files(Index).Path$, NextSound()
EndIf
EndIf
Next Index
EndFunction SoundIndex
Function LoadMusic(Name$)
For Index = 0 To Array Count(Files())
If GetExtentionType(GetFileExtension$(Files(Index).Path$)) = "Music"
If Files(Index).Name$ = Name$
Load Music Files(Index).Path$, NextMusic()
EndIf
EndIf
Next Index
EndFunction MusicIndex
Function LoadEffect(Name$)
For Index = 0 To Array Count(Files())
If GetExtentionType(GetFileExtension$(Files(Index).Path$)) = "Effect"
If Files(Index).Name$ = Name$
Load Effect Files(Index).Path$, NextEffect(), 0
EndIf
EndIf
Next Index
EndFunction EffectIndex
Function LoadImage(Name$)
For Index = 0 To Array Count(Files())
If GetExtentionType(GetFileExtension$(Files(Index).Path$)) = "Image"
If Files(Index).Name$ = Name$
Load Image Files(Index).Path$, NextImage()
EndIf
EndIf
Next Index
EndFunction ImageIndex
remend
` Dark Data Required
Function LoadFileDatabase(Dir$, Folder$)
LastDir$ = Get Dir$() : Set Dir Dir$
KFS Open 2, Folder$ + ".kfs"
DFS Open 1, Folder$ + ".dat"
Set Dir LastDir$
EndFunction
Function LoadObject(Name$)
KFS Reset 2
Record = KFS Find(2, Lower$(Name$))
If Record > 0 ` Negitive/Zero = Not Found
DFS Load 1, Record
If DFS Get$(1, "Type") = "Object"
If DFS Get$(1, "Name") = Name$
If File Exist(DFS Get$(1, "Path")) = 1
Load Object DFS Get$(1, "Path"), NextObject()
Record = DFS Add(3)
DFS Put 3, "Path", DFS Get$(1, "Path")
DFS Put 3, "Folder", DFS Get$(1, "Folder")
DFS Put 3, "Name", DFS Get$(1, "Name")
DFS Put 3, "Type", DFS Get$(1, "Type")
DFS Put 3, "Index", ObjectIndex
DFS Save 3, Record
KFS Add 4, DFS Get$(1, "Name"), Record
Else
Message "File Error: File " + DFS Get$(1, "Path") + " doesn't exist!"
Endif
Else
Message "Name Error:" + DFS Get$(1, "Name")
EndIf
Else
Message "Type Error:" + DFS Get$(1, "Type")
EndIf
Else
Message "Record with the name: " + Name$ + " Doesn't Exist."
EndIf
EndFunction ObjectIndex
Function LoadSound(Name$)
KFS Reset 2
Record = KFS Find(2, Lower$(Name$))
If Record > 0 ` Negitive/Zero = Not Found
DFS Load 1, Record
If DFS Get$(1, "Type") = "Sound"
If DFS Get$(1, "Name") = Name$
If File Exist(DFS Get$(1, "Path")) = 1
Load Sound DFS Get$(1, "Path"), NextSound()
Record = DFS Add(3)
DFS Put 3, "Path", DFS Get$(1, "Path")
DFS Put 3, "Folder", DFS Get$(1, "Folder")
DFS Put 3, "Name", DFS Get$(1, "Name")
DFS Put 3, "Type", DFS Get$(1, "Type")
DFS Put 3, "Index", SoundIndex
DFS Save 3, Record
KFS Add 4, DFS Get$(1, "Name"), Record
Else
Message "File Error: File " + DFS Get$(1, "Path") + " doesn't exist!"
Endif
Else
Message "Name Error:" + DFS Get$(1, "Name")
EndIf
Else
Message "Type Error:" + DFS Get$(1, "Type")
EndIf
Else
Message "Record with the name: " + Name$ + " Doesn't Exist."
EndIf
EndFunction SoundIndex
Function LoadMusic(Name$)
KFS Reset 2
Record = KFS Find(2, Lower$(Name$))
If Record > 0 ` Negitive/Zero = Not Found
DFS Load 1, Record
If DFS Get$(1, "Type") = "Sound"
If DFS Get$(1, "Name") = Name$
If File Exist(DFS Get$(1, "Path")) = 1
Load Music DFS Get$(1, "Path"), NextMusic()
Record = DFS Add(3)
DFS Put 3, "Path", DFS Get$(1, "Path")
DFS Put 3, "Folder", DFS Get$(1, "Folder")
DFS Put 3, "Name", DFS Get$(1, "Name")
DFS Put 3, "Type", DFS Get$(1, "Type")
DFS Put 3, "Index", MusicIndex
DFS Save 3, Record
KFS Add 4, DFS Get$(1, "Name"), Record
Else
Message "File Error: File " + DFS Get$(1, "Path") + " doesn't exist!"
Endif
Else
Message "Name Error:" + DFS Get$(1, "Name")
EndIf
Else
Message "Type Error:" + DFS Get$(1, "Type")
EndIf
Else
Message "Record with the name: " + Name$ + " Doesn't Exist."
EndIf
EndFunction MusicIndex
Function LoadEffect(Name$)
KFS Reset 2
Record = KFS Find(2, Lower$(Name$))
If Record > 0 ` Negitive/Zero = Not Found
DFS Load 1, Record
If DFS Get$(1, "Type") = "Sound"
If DFS Get$(1, "Name") = Name$
If File Exist(DFS Get$(1, "Path")) = 1
Load Effect DFS Get$(1, "Path"), NextEffect(), 0
Record = DFS Add(3)
DFS Put 3, "Path", DFS Get$(1, "Path")
DFS Put 3, "Folder", DFS Get$(1, "Folder")
DFS Put 3, "Name", DFS Get$(1, "Name")
DFS Put 3, "Type", DFS Get$(1, "Type")
DFS Put 3, "Index", EffectIndex
DFS Save 3, Record
KFS Add 4, DFS Get$(1, "Name"), Record
Else
Message "File Error: File " + DFS Get$(1, "Path") + " doesn't exist!"
Endif
Else
Message "Name Error:" + DFS Get$(1, "Name")
EndIf
Else
Message "Type Error:" + DFS Get$(1, "Type")
EndIf
Else
Message "Record with the name: " + Name$ + " Doesn't Exist."
EndIf
EndFunction EffectIndex
Function LoadImage(Name$)
KFS Reset 2
Record = KFS Find(2, Lower$(Name$))
If Record > 0 ` Negitive/Zero = Not Found
DFS Load 1, Record
If DFS Get$(1, "Type") = "Sound"
If DFS Get$(1, "Name") = Name$
If File Exist(DFS Get$(1, "Path")) = 1
Load Image DFS Get$(1, "Path"), NextImage()
Record = DFS Add(3)
DFS Put 3, "Path", DFS Get$(1, "Path")
DFS Put 3, "Folder", DFS Get$(1, "Folder")
DFS Put 3, "Name", DFS Get$(1, "Name")
DFS Put 3, "Type", DFS Get$(1, "Type")
DFS Put 3, "Index", ImageIndex
DFS Save 3, Record
KFS Add 4, DFS Get$(1, "Name"), Record
Else
Message "File Error: File " + DFS Get$(1, "Path") + " doesn't exist!"
Endif
Else
Message "Name Error:" + DFS Get$(1, "Name")
EndIf
Else
Message "Type Error:" + DFS Get$(1, "Type")
EndIf
Else
Message "Record with the name: " + Name$ + " Doesn't Exist."
EndIf
EndFunction ImageIndex
Function CreateNameDatabase()
DatabaseName$ = "Names"
KFS Create 4, DatabaseName$ + ".kfs", 33, 0, 0
` Create Data File
DFS Create 3, DatabaseName$ + ".dat", 0
DFS Add Field 3, "String 199 As Path"
DFS Add Field 3, "String 99 As Folder"
DFS Add Field 3, "String 99 As Name"
DFS Add Field 3, "String 99 As Type"
DFS Add Field 3, "Integer As Index"
DFS Finish 3
EndFunction
` Instead of creating many functions like GetObjectIndex I just have one.
Function GetIndex(Name$)
KFS Reset 4
Record = KFS Find(4, Lower$(Name$))
If Record > 0 ` Negitive/Zero = Not Found
Index = DFS Get(3, "Index")
If Index = 0
Message "Error: Index not set."
End
EndIf
Else
Message "Record with the name: " + Name$ + " Doesn't Exist."
EndIf
EndFunction Index
Function CloseDatabases()
DFS Close 1
KFS Close 2
DFS Close 3
KFS Close 4
EndFunction
How it works:
I created a separate database containing the names of the objects that are loaded. Every time a Load resource function is called it will add that name to the database. To quickly get the index of a resource just use the "GetIndex" function providing a name.
Side Note: I don't search for redundant names yet. Every time the example runs it will add piano2 to the name database. I will add a redundancy check in future examples.
Dynamically Loaded Resources: Part 3
Naming Resources: Part 2
Beginner - Intermediate Tutorial
What you will need:
Dark Data
Dynamic Resources
Tutorial:
I said I would give a tutorial on using Lua as an alternative to a Dark Data database. Well, here it is:
I think Lua might be faster then using Dark Data to store names. Using Lua the names are temporarily stored.
"Why not just use an array for naming resources?"
You would have to search though each index of the array. This would reduce the performance. Just read what I wrote about performance.
Lua Script:
Items = {}
function AddNamedItem(index, name)
Items[name] = index
end
function GetIndex(name)
return Items[name]
end
How it works:
It will create an array called Items. The name is used instead of an index in the arrays parentheses. AddNamedItem will add a new item to the Items array. GetIndex will return that item. Very simple yet effective script!
An addition to the Load resource functions:
Lua_NameItem(EffectIndex, DFS Get$(1, "Name")) ` Use instead of "Add Named Item To Database"
How it works:
When the load resource function is called it will create a named item using lua. The name just like the name database is
and the index is the index of the newly created resource.
Lua Naming Functions:
Function Lua_LoadNameScript()
Success = Load Lua("Name Item.lua")
EndFunction
Function Lua_GetIndex(Name$)
Lua Set Function "GetIndex", 1, 1
Lua Push String Name$
Lua Call
Index = Lua Return Int()
EndFunction Index
Function Lua_NameItem(Index, Name$)
Lua Set Function "AddNamedItem", 2, 0
Lua Push Int Index
Lua Push String Name$
Lua Call
EndFunction
How it works:
- Lua_LoadNameScript: Loads the script
- Lua_GetIndex: calls lua the function GetIndex and returns the index.
- Lua_NameItem: Calls the lua function AddNamedItem and passes the name as a parameter.
Dynamically Loaded Resources: Part 3
Naming Groups
Beginner - Intermediate Tutorial
What you will need:
Dark Data
Dynamic Resources
Matrix1Util
Download from previous post!
Tutorial:
Using these functions if you are using the database method:
- GetIndex
- Database_NameGroup:
Function Database_NameGroup(Name$, GroupIndex)
` Add Named Item To Database
Record = DFS Add(3)
DFS Put 3, "Path", ""
DFS Put 3, "Folder", ""
DFS Put 3, "Name", DFS Get$(1, "Name")
DFS Put 3, "Type", "Group"
DFS Put 3, "Index", GroupIndex
DFS Save 3, Record
KFS Add 4, Name$, Record
EndFunction
By assigning a group with a name it makes it easy to keep track of. No more variables to remember the indexes.
Just call Database_NameGroup and enter your GroupIndex and Name$ for a group.
In Matrix1Util it is #19 - "List and group objects". Learn how to use groups and assign objects to groups. Use Database_NameGroup to name the group and GetIndex to get the index of group Name$.
If you are using the Lua method then:
Just enter in the group index and group name in:
Lua_NameItem(GroupIndex, GroupName$)
Use:
to get the group index.
That's it for the "Dynamic Resources" tutorials for now. I plan on giving a tutorial on something more practical. It most likely will be a 3D demo.
Coroutines
Beginner - Tutorial
Google Doc: Click Here To View
Example:
Disable EscapeKey
Global MyFunction : MyFunction = 1
Create Coroutine MyFunction, Get Ptr To Function("MyFunction")
Set Coroutine End State MyFunction, 1
While EscapeKey() = 0
Wait 2000
Print "Main Coroutine:" + Str$(RND(1000))
Next Coroutine
EndWhile
Delete Coroutine MyFunction
End
Function MyFunction()
Print "MyFunction Coroutine:" + Str$(RND(1000))
Next Coroutine
EndFunction
Example 2:
Disable EscapeKey
Global CoroutineIndex
Global MyFunction : MyFunction = CreateCoroutine("MyFunction")
While EscapeKey() = 0
Print "Main Coroutine:" + Str$(RND(1000))
Update_Coroutines()
EndWhile
Close_DeleteCoroutines()
Function MyFunction()
Print "MyFunction Coroutine:" + Str$(RND(1000))
Update_Coroutines()
EndFunction
Function NextCoroutine()
CoroutineIndex = CoroutineIndex + 1
Index = CoroutineIndex
EndFunction Index
```````````````````````
` Coroutine Functions `
````````````````````````````````````````````````````````````````````````````````````````````````
Function CreateCoroutine(FunctionName$)
Pointer = Get Ptr To Function(FunctionName$)
Coroutine = NextCoroutine()
If Function Ptr Is Valid(Pointer) = 1
Create Coroutine Coroutine, Pointer
Set Coroutine End State Coroutine, 1
EndIf
EndFunction Coroutine
` If Co-Routines are used then it will goto the next co-routine in the list
Function Update_Coroutines()
If CoroutineIndex > 0 Then Next Coroutine
EndFunction
Function Close_DeleteCoroutines()
If CoroutineIndex > 0
For Index = 1 To CoroutineIndex
Delete Coroutine Index
Next Index
EndIf
EndFunction
Multi-Threading
Intermediate - Advanced Tutorial
Google Docs: Click Here To View
Example:
Type Thread
MemoryID
MemorySize
Handle
DllPtr
FunctionPtr
FunctionName$
EndType
Disable EscapeKey
Global Kernel32 : Kernel32 = Load Dll("Kernel32.dll")
Global FunctionThread As Thread
CreateThread("MyFunction") : MyThread As Thread = FunctionThread
Repeat
Sync
Until EscapeKey() = 1
Sleep 1000 ` Wait enough time for the thread to end
CloseThread(MyThread)
End
Function MyFunction()
Sleep 250 ` Required to sleep a bit to get the multi-threading to work.
Repeat
` Do some processing
For Index = 0 To 10000
Next Index
Until EscapeKey() = 1
EndFunction
Function CreateThread(FunctionName$)
FunctionThread.MemorySize = 4
FunctionThread.MemoryID = Make Memory(FunctionThread.MemorySize)
FunctionThread.FunctionName$ = FunctionName$
FunctionThread.DllPtr = Get Ptr To Dll Function(Kernel32, "CreateThread")
FunctionThread.FunctionPtr = Get Ptr To Function(FunctionName$)
If Function Ptr Is Valid(FunctionThread.FunctionPtr) = 1
If Function Ptr Is Valid(FunctionThread.DllPtr) = 1
FunctionThread.Handle = Call Function Ptr(FunctionThread.DllPtr, 0, FunctionThread.MemorySize, FunctionThread.FunctionPtr, 0, FunctionThread.MemoryID)
Else
Message "CreateThread: Function Pointer is Invalid!"
EndIf
Else
Message FunctionThread.FunctionName$ + ": Function Pointer is Invalid!"
EndIf
EndFunction
Function CloseThread(FunctionThread As Thread)
ClosePtr = Get Ptr To Dll Function(Kernel32, "CloseHandle")
If Function Ptr Is Valid(ClosePtr) = 1
Call Function Ptr ClosePtr, FunctionThread.Handle
Delete Memory FunctionThread.MemoryID
Else
Message "CloseHandle: Function Pointer is Invalid!"
Delete Memory FunctionThread.MemoryID
EndIf
EndFunction
Performance: Loops Per Second
Beginner Tutorial
I was doing some research in performance and I needed to determine a way to measure performance. FPS isn't a good way to measure for performance. What really matters is how many commands are being executed and the time it takes to execute those commands.
The best way to determine performance is loops per second. An accurate timer is needed.
Here is an accurate timer example:
Freq# = GetFreq()
OldTime# = PerfTimer()
Do
ElapsedTime# = (PerfTimer() - OldTime#) / Freq#
CLS : Print ElapsedTime#
Loop
Function GetFreq()
Load DLL "kernel32.dll", 1 : Kernel32 = 1
Memory = Make Memory(16)
Call Dll Kernel32, "QueryPerformanceFrequency", Memory
Freq# = *Memory
Delete DLL Kernel32 : Delete Memory Memory
EndFunction Freq#
Here is an example to calculate loops per second:
LoopCount = 0
Freq# = GetFreq()
OldTime# = PerfTimer()
Do
Inc LoopCount, 1
ElapsedTime# = (PerfTimer() - OldTime#) / Freq#
LPS = LoopCount / ElapsedTime#
CLS
Print ElapsedTime#
Print LPS
Loop
Function GetFreq()
Load DLL "kernel32.dll", 1 : Kernel32 = 1
Memory = Make Memory(16)
Call Dll Kernel32, "QueryPerformanceFrequency", Memory
Freq# = *Memory
Delete DLL Kernel32 : Delete Memory Memory
EndFunction Freq#
With that you should be able to approx. performance in loops per second.
Performance: Running the Main Loop at the Same Rate
Beginner Tutorial
I did some experimentation with the sync command and that sync doesn't always run at a constant loops per second.
Here is an example illustrating that fact:
Sync On : Sync Rate 30
Set Display Mode Screen Width(), Screen Height(), Screen Depth(), 1
LoopCount = 0
Freq# = GetFreq()
OldTime# = PerfTimer()
Do
ElapsedTime# = (PerfTimer() - OldTime#) / Freq#
LPS = LoopCount / ElapsedTime#
If SpaceKey() = 1
Nice Wait 1000
EndIf
CLS
Print ElapsedTime#
Print LPS
Sync : Inc LoopCount, 1
Loop
Function GetFreq()
Load DLL "kernel32.dll", 1 : Kernel32 = 1
Memory = Make Memory(16)
Call Dll Kernel32, "QueryPerformanceFrequency", Memory
Freq# = *Memory
Delete DLL Kernel32 : Delete Memory Memory
EndFunction Freq#
Hold the space key to return time back to the system for 1 second. Notice how the loops per second decreases and than slowly increases.
This slowly trys to correct, but stays around 26-27 for a while.
What does this mean?
It is not running at a constant rate!! If this was on a server then there would be lagging or a delay! Constant speed between clients is essential when you play multi-player games.
This example corrects the flaws with Sync:
Sync On : Sync Rate 0
Set Display Mode Screen Width(), Screen Height(), Screen Depth(), 1
LoopCount = 0
Freq# = GetFreq()
OldTime# = PerfTimer()
Do
ElapsedTime# = (PerfTimer() - OldTime#) / Freq#
LPS = LoopCount / ElapsedTime#
` Cap it at 30 Loops Per Second
If LPS <= 30
GoSub MainLoop
EndIf
Sync
Loop
MainLoop:
CLS
Print ElapsedTime#
Print LPS
Inc LoopCount, 1
Return
Function GetFreq()
Load DLL "kernel32.dll", 1 : Kernel32 = 1
Memory = Make Memory(16)
Call Dll Kernel32, "QueryPerformanceFrequency", Memory
Freq# = *Memory
Delete DLL Kernel32 : Delete Memory Memory
EndFunction Freq#
No matter how fast your computer is it will run a constant 30 Loops per Second.
I did notice that KISTech wrote a tutorial on "Decouple the Display Loop for Better Performance.". I need to look into how it works.
What I have figured out so far from KISTech's tutorial: The display loop should need to be run in the main loop. The display loop can be run 1/4 the amount of times the main loop is running.
Performance: Part 2
Control the LPS of the Display Loop and Main Loop
Beginner Tutorial
Performance Example:
` Performance
Global Display_LoopCount : Display_LoopCount = 0
Global Main_LoopCount : Main_LoopCount = 0
Global Freq# : Freq# = GetFreq()
Global OldTime# : OldTime# = PerfTimer()
Global ElapsedTime#
Global Display_LPS
Global Main_LPS
While EscapeKey() = 0
Update_Performance()
EndWhile
End
MainLoop:
Return
DisplayLoop:
CLS
Print Screen FPS()
Print Main_LPS
Print Display_LPS
Sync
Return
Function Update_Performance()
ElapsedTime# = (PerfTimer() - OldTime#) / Freq#
` Calculate LPS
Display_LPS = Display_LoopCount / ElapsedTime#
Main_LPS = Main_LoopCount / ElapsedTime#
` Cap it at GlobalLPS Loops Per Second
If Display_LPS <= GlobalLPS
GoSub DisplayLoop : Inc Display_LoopCount, 1
EndIf
` Cap it at 4 x GlobalLPS Loops Per Second
If Main_LPS <= (GlobalLPS * 4)
GoSub MainLoop : Inc Main_LoopCount, 1
EndIf
` Need to calculate the wait time. Will post in next version/update.
`Nice Wait 1 ` Return time back to the system
EndFunction
` Gets the Processor Freq for making a Hi-Resolution Timer
Function GetFreq()
Load DLL "Kernel32.dll", 1
Memory = Make Memory(16)
Call Dll 1, "QueryPerformanceFrequency", Memory
Freq# = *Memory
Delete DLL 1 : Delete Memory Memory
EndFunction Freq#
How it works:
The display loop runs at a constant LPS. Instead of running the main loop as fast as possible taking up CPU time I am just going to run it 4x the the GlobalLPS.
This will calculate the Loops Per Second for both loops:
Display_LPS = Display_LoopCount / ElapsedTime#
Main_LPS = Main_LoopCount / ElapsedTime#
The display loop is capped at GlobalLPS using this line:
If Display_LPS <= GlobalLPS
The main loop is capped at GlobalLPS x 4 using this line:
If Main_LPS <= (GlobalLPS * 4)
Next Tutorial:
Performance: When the main loop and the display loop isn't running then return the CPU time back to the CPU.
Timers
Count-Downs
Beginner Tutorial
Here is the example:
Freq# : Freq# = GetFreq() ` Used to increase accuracy of the timer
Global OldTime# : OldTime# = PerfTimer()
Global StartTime#
Setup_CountDown(10.0)
Do
CurrentTime# = Update_CountDown("Seconds")
If CurrentTime# <= 0
Reset_CountDown()
EndIf
CLS ` Clear the screen
Print "Current Time: " + Str$(CurrentTime#)
Loop
Function Setup_CountDown(Start#)
StartTime# = Start#
EndFunction
Function Reset_CountDown()
ResetTimer()
EndFunction
Function Update_CountDown(Units$)
Select Units$
Case "Hours"
CurrentTime# = StartTime# - GetHours() ` Subtract minutes elapsed
EndCase
Case "Minutes"
CurrentTime# = StartTime# - GetMinutes() ` Subtract minutes elapsed
EndCase
Case "Seconds"
CurrentTime# = StartTime# - GetSeconds() ` Subtract minutes elapsed
EndCase
Case "MiliSeconds"
CurrentTime# = StartTime# - GetMiliSeconds() ` Subtract minutes elapsed
EndCase
EndSelect
EndFunction CurrentTime#
Function GetHours()
Minutes# = (((PerfTimer() - OldTime#) / Freq#) / 60.0) / 60.0
EndFunction Minutes#
Function GetMinutes()
Minutes# = ((PerfTimer() - OldTime#) / Freq#) / 60.0
EndFunction Minutes#
Function GetSeconds()
Seconds# = (PerfTimer() - OldTime#) / Freq#
EndFunction Seconds#
Function GetMiliSeconds()
MiliSeconds# = ((PerfTimer() - OldTime#) / Freq#) * 1000
EndFunction MiliSeconds#
Function ResetTimer()
OldTime# = PerfTimer()
EndFunction
Function GetFreq()
Load DLL "Kernel32.dll", 1
Memory = Make Memory(16)
Call Dll 1, "QueryPerformanceFrequency", Memory
Freq# = *Memory
Delete DLL 1 : Delete Memory Memory
EndFunction Freq#
How it works:
Variables handled by the functions
GetFreq() - For better accuracy then the DBP commands.
OldTime# - Stores PerfTimer
PerfTimer - Gets the time since the computer was turned on. This is the raw time.
between the time now and the start time you get the current time.
StartTime# - The start time of the count down.
Time
Will reset the timer by setting old time to PerfTimer(). This means the difference will be 0. PerfTimer() - PerfTimer() = 0
By getting the difference it will calculate the raw time.
To get the time in seconds divide by the Freq.
((PerfTimer() - OldTime#) / Freq#)
Functions
Setup_CountDown(Start#):
- Start#: Sets the Start Time of the count down
Update_CountDown(Units$):
- This function you feed in the units: ("Hours", "Minutes", "Seconds", "MiliSeconds")
- It will subtract the time from the start time and return the current time left.
Reset_CountDown()
- It will reset the timer
Timers: Part 2
Multiple Count-Down Timers
Beginner Tutorial
Here is the example:
Global Freq# : Freq# = GetFreq() ` Used to increase accuracy of the timer
Type CountDown
StartTime#
OldTime#
Units$
CurrentTime#
EndType
Global Dim CountDown() As CountDown
Create_CountDown(1.35, "Minutes")
Create_CountDown(0.63, "Minutes")
Create_CountDown(1.84, "Minutes")
Create_CountDown(0.13, "Minutes")
Do
Update_CountDown()
` Output Results
CLS
Size = Array Count(CountDown())
For Index = 0 To Size
Print CountDown(Index).CurrentTime#
Next Index
Loop
Function Create_CountDown(StartTime#, Units$)
Add To Stack CountDown()
CountDown().StartTime# = StartTime#
CountDown().OldTime# = PerfTimer()
CountDown().Units$ = Units$
EndFunction
Function Update_CountDown()
Size = Array Count(CountDown())
For Index = 0 To Size
Select CountDown(Index).Units$
Case "Hours"
CountDown(Index).CurrentTime# = CountDown(Index).StartTime# - GetHours(Index) ` Subtract minutes elapsed
EndCase
Case "Minutes"
CountDown(Index).CurrentTime# = CountDown(Index).StartTime# - GetMinutes(Index) ` Subtract minutes elapsed
EndCase
Case "Seconds"
CountDown(Index).CurrentTime# = CountDown(Index).StartTime# - GetSeconds(Index) ` Subtract minutes elapsed
EndCase
Case "MiliSeconds"
CountDown(Index).CurrentTime# = CountDown(Index).StartTime# - GetMiliSeconds(Index) ` Subtract minutes elapsed
EndCase
EndSelect
If CountDown(Index).CurrentTime# <= 0.0
` Execute Event. Next tutorial
Reset_CountDown(Index)
EndIf
Next Index
EndFunction
Function Reset_CountDown(Index)
CountDown(Index).OldTime# = PerfTimer()
EndFunction
Function GetHours(Index)
Minutes# = (((PerfTimer() - CountDown(Index).OldTime#) / Freq#) / 60.0) / 60.0
EndFunction Minutes#
Function GetMinutes(Index)
Minutes# = ((PerfTimer() - CountDown(Index).OldTime#) / Freq#) / 60.0
EndFunction Minutes#
Function GetSeconds(Index)
Seconds# = (PerfTimer() - CountDown(Index).OldTime#) / Freq#
EndFunction Seconds#
Function GetMiliSeconds(Index)
MiliSeconds# = ((PerfTimer() - CountDown(Index).OldTime#) / Freq#) * 1000
EndFunction MiliSeconds#
Function GetFreq()
Load DLL "Kernel32.dll", 1
Memory = Make Memory(16)
Call Dll 1, "QueryPerformanceFrequency", Memory
Freq# = *Memory
Delete DLL 1 : Delete Memory Memory
EndFunction Freq#
How it works:
I have an array of count-down timer. I use the same variables as the previous tutorial "StartTime#" + "OldTime#".
Count-Down Type:
StartTime# - The start time of the count down.
OldTime# - Stores perftimer() (The raw time since the computer was turned on)
Units$ - The units of the timer. ("Hours", "Minutes", "Seconds", "MiliSeconds")
CurrentTime# - Is the current time set by the Update_CountDown function.
Functions
Create_CountDown:
- Sets the StartTime
- Sets the OldTime# to pertimer()
- Sets the Units of the timer
Update_CountDown:
- Checks the units
- Sets current time to the time minus the start time
- If the current time equal 0 then reset the timer
The rest of the functions are explained in the previous tutorial. They don't need to be called because everything is handled automatically!
Timers: Part 3
Multiple Count-Down Timers with Events
Beginner Tutorial
Example:
Global Freq# : Freq# = GetFreq() ` Used to increase accuracy of the timer
Type CountDown
OldStartTime#
StartTime#
OldTime#
Units$
CurrentTime#
Event
EndType
Global Dim CountDown() As CountDown
Create_CountDown(1.35, "Minutes")
Create_CountDown(0.63, "Minutes")
Create_CountDown(1.84, "Minutes")
Create_CountDown(0.13, "Minutes")
Set_Event(3, "MyEvent")
Do
Update_CountDown()
` Output Results
CLS
Size = Array Count(CountDown())
For Index = 0 To Size
Print CountDown(Index).CurrentTime#
Next Index
Loop
Function Create_CountDown(StartTime#, Units$)
Add To Stack CountDown()
CountDown().StartTime# = StartTime#
CountDown().OldStartTime# = StartTime#
CountDown().OldTime# = PerfTimer()
CountDown().Units$ = Units$
EndFunction
Function Set_Event(Index, FunctionName$)
CountDown(Index).Event = Get Ptr To Function(FunctionName$)
EndFunction
Function Update_CountDown()
Size = Array Count(CountDown())
For Index = 0 To Size
Select CountDown(Index).Units$
Case "Hours"
CountDown(Index).CurrentTime# = CountDown(Index).StartTime# - GetHours(Index) ` Subtract minutes elapsed
EndCase
Case "Minutes"
CountDown(Index).CurrentTime# = CountDown(Index).StartTime# - GetMinutes(Index) ` Subtract minutes elapsed
EndCase
Case "Seconds"
CountDown(Index).CurrentTime# = CountDown(Index).StartTime# - GetSeconds(Index) ` Subtract minutes elapsed
EndCase
Case "MiliSeconds"
CountDown(Index).CurrentTime# = CountDown(Index).StartTime# - GetMiliSeconds(Index) ` Subtract minutes elapsed
EndCase
EndSelect
If CountDown(Index).CurrentTime# <= 0.0
If Function Ptr Is Valid(CountDown(Index).Event) = 1
Call Function Ptr CountDown(Index).Event
EndIf
Reset_CountDown(Index)
EndIf
Next Index
EndFunction
Function Reset_CountDown(Index)
CountDown(Index).OldTime# = PerfTimer()
EndFunction
Function GetHours(Index)
Minutes# = (((PerfTimer() - CountDown(Index).OldTime#) / Freq#) / 60.0) / 60.0
EndFunction Minutes#
Function GetMinutes(Index)
Minutes# = ((PerfTimer() - CountDown(Index).OldTime#) / Freq#) / 60.0
EndFunction Minutes#
Function GetSeconds(Index)
Seconds# = (PerfTimer() - CountDown(Index).OldTime#) / Freq#
EndFunction Seconds#
Function GetMiliSeconds(Index)
MiliSeconds# = ((PerfTimer() - CountDown(Index).OldTime#) / Freq#) * 1000
EndFunction MiliSeconds#
Function GetFreq()
Load DLL "Kernel32.dll", 1
Memory = Make Memory(16)
Call Dll 1, "QueryPerformanceFrequency", Memory
Freq# = *Memory
Delete DLL 1 : Delete Memory Memory
EndFunction Freq#
` ----------
` - Events -
` ----------------------------------------------------------------------------------------------------------------------------------
Function MyEvent()
CLS
Print "Hello World"
Wait Key
EndFunction
How it works:
- Added event to the type CountDown. This will store the function pointer.
If Function Ptr Is Valid(CountDown(Index).Event.Pointer) = 1
Call Function Ptr CountDown(Index).Event.Pointer
EndIf
- If the function pointer is valid then call the function.
Set_Event(Index, Event As Event):
- Sets the Event of the CountDown at Index
Shoot Object Tutorial
Requirements:
- Dark Physics
- Trig.
Example:
For X = 1 To 256
For Y = 1 To 256
Dot X, Y, RGB(RND(255), RND(255), RND(255))
Next Y
Next X
Get Image 1, 1, 1, 256, 256
Phy Start
AutoCam Off
Sync On : Sync Rate 60
Set Ambient Light 100
Make Object Box 1, 100, 10, 100
Texture Object 1, 1
Set Object Cull 1, 0
Move Object Down 1, 20
Move Object 1, 50
Move Object Right 1, 50
Phy Make Rigid Body Static Box 1
Move Camera - 40 : Move Camera Right 50
For Index = 2 To 12
Make Object Sphere Index, 10
Position Object Index, RND(100), 0, RND(100)
Texture Object Index, 1
Phy Make Rigid Body Dynamic Sphere Index
Next Index
Do
Control Camera Using ArrowKeys 0, 1, 1
Object = Pick Object(MouseX(), MouseY(), 1, Object Count())
If Object <> 0 And MouseClick() = 1 Then ShootObject(Object, 100.0)
Text 0, 0, "Object Picked: " + Str$(Object)
Phy Update
Sync
Loop
Shoot Object Function:
Function ShootObject(Object, Force#)
ForceX# = Force# * (Sin(Camera Angle Y()) * Cos(-Camera Angle X()))
ForceY# = Force# * Sin(-Camera Angle X())
ForceZ# = Force# * (Cos(Camera Angle Y()) * Cos(-Camera Angle X()))
Phy Set Rigid Body Linear Velocity Object, ForceX#, ForceY#, ForceZ#
EndFunction
How it works:
Use these formulas:
X = Distance# * Sin(Y Axis) * Cos(X Axis)
Y = Distance# * Sin(X Axis)
Z = Distance# * Cos(Y Axis) * Cos(X Axis)
Mini Tutorial: Eyes Follow Cursor
What you need:
- The image attached to this post
How it works:
ATanFull will return an angle by using distances. The distance from the eye to the mouse is used to get an angle. From that angle you can get the center position of the circle or eye.
Using this formula:
X = Sin(Angle) * Distance
Y = Cos(Angle) * Distance
The distance is the distance from the center point of the circle. In this case being the distance from (Eye1_X, Eye1_Y) or (Eye2_X, Eye2_Y). This explains the circle or orbit of the center point movement.
Example:
Eye1_X = 150
Eye1_Y = 192
Eye2_X = 265
Eye2_Y = 192
Load Image "Ha.png", 1
Do
CLS RGB(255, 0, 0)
` Paste Image
Paste Image 1, 100, 100
` Eye 1
Angle = GetAngle(Eye1_X, Eye1_Y, MouseX(), MouseY())
X = Sin(Angle) * 8
Y = Cos(Angle) * 8
Ink RGB(0, 0, 0), RGB(0, 0, 0)
Circle Eye1_X + X, Eye1_Y + Y, 8
` Eye 2
Angle = GetAngle(Eye2_X, Eye2_Y, MouseX(), MouseY())
X = Sin(Angle) * 8
Y = Cos(Angle) * 8
Ink RGB(0, 0, 0), RGB(0, 0, 0)
Circle Eye2_X + X, Eye2_Y + Y, 8
Loop
Function GetAngle(X1, Y1, X2, Y2)
Angle = ATanFull(X1 - X2, Y1 - Y2) + 180
EndFunction Angle
How it works:
Equation:
X = X + Distance# * Sin(WrapValue(Angle# + 180))
Y = Y + Distance# * Cos(WrapValue(Angle# + 180))
When orbitting on a certain axis the only thing to remember is that one axis will have Sin() and the other Cos().
The distance is the distance from the X, Y, Z which is the center point it is orbiting around.
Example:
AutoCam Off
Sync On : Sync Rate 60
Move Camera - 200
Make Object Cube 1, 10
Make Object Sphere 2, 10
Speed# = 1.0
Do
If InKey$() = "x"
Inc AngleX#, Speed# : AngleY# = 0 : AngleZ# = 0
XOrbitObject(1, 0, 0, 0, 100.0, AngleX#)
EndIf
If InKey$() = "y"
Inc AngleY#, Speed# : AngleZ# = 0 : AngleX# = 0
YOrbitObject(1, 0, 0, 0, 100.0, AngleY#)
EndIf
If InKey$() = "z"
Inc AngleZ#, Speed# : AngleY# = 0 : AngleX# = 0
ZOrbitObject(1, 0, 0, 0, 100.0, AngleZ#)
EndIf
Sync
Loop
Function ZOrbitObject(Object, X#, Y#, Z#, Distance#, Angle#)
Position Object Object, X# + Distance# * Sin(WrapValue(Angle# + 180)), Y# + Distance# * Cos(WrapValue(Angle#)), Z#
EndFunction
Function YOrbitObject(Object, X#, Y#, Z#, Distance#, Angle#)
Position Object Object, X# + Distance# * Sin(WrapValue(Angle#)), Y#, Z# + Distance# * Cos(WrapValue(Angle# + 180))
EndFunction
Function XOrbitObject(Object, X#, Y#, Z#, Distance#, Angle#)
Position Object Object, X#, Y# + Distance# * Cos(WrapValue(Angle#)), Z# + Distance# * Sin(WrapValue(Angle# + 180))
EndFunction
Pulse Gun: Part 1
Click to create a pulse to push the objects around the camera.
How it works:
This code snippet is fairly basic. To create a pulse I go though each object and if it is within a certain range then it will shoot the object.
Example:
For X = 1 To 256
For Y = 1 To 256
Dot X, Y, RGB(RND(255), RND(255), RND(255))
Next Y
Next X
Get Image 1, 1, 1, 256, 256
Phy Start : D3D_Init
AutoCam Off
Sync On : Sync Rate 60
Set Ambient Light 100
Make Object Box 1, 100, 10, 1000
Texture Object 1, 1
Set Object Cull 1, 0
Move Object Down 1, 20
Move Object 1, 500
Move Object Right 1, 50
Phy Make Rigid Body Static Box 1
Move Camera Right 50 : Move Camera Up 50 : Move Camera -100
For Index = 2 To 50
Make Object Sphere Index, 10
Position Object Index, RND(100), 0, RND(1000)
Phy Make Rigid Body Dynamic Sphere Index
Next Index
Do
Control Camera Using ArrowKeys 0, 1, 1
If MouseClick() = 1
Size = Object Count()
For Index = 1 To Object Count()
Dist# = ObjectToCamera(Index)
If Dist# < 400.0
ShootObject(Index, 400.0 - Dist#)
EndIf
Next Index
EndIf
Text 0, 0, "Click To Shoot The Pulse Gun"
Phy Update
Sync
Loop
Function ShootObject(Object, Force#)
ForceX# = Force# * (Sin(Camera Angle Y()) * Cos(-Camera Angle X()))
ForceY# = Force# * Sin(-Camera Angle X())
ForceZ# = Force# * (Cos(Camera Angle Y()) * Cos(-Camera Angle X()))
Phy Set Rigid Body Linear Velocity Object, ForceX#, ForceY#, ForceZ#
EndFunction
Function ObjectToCamera(Object)
Null3D = Make Vector3(1)
X# = Object Position X(Object)
Y# = Object Position Y(Object)
Z# = Object Position Z(Object)
Set Vector3 1, X# - Camera Position X(), Y# - Camera Position Y(), Z# - Camera Position Z() : Result# = Length Vector3(1)
Null3D = Delete Vector3(1)
EndFunction Result#
Game Template: Standard Game Library of classes. Makes it easy to focus on your game and less on your code.