Page 1 of 1

Use Database instead of list

Posted: Fri Oct 16, 2015 7:36 am
by microdevweb
My idea come this http://www.purebasic.fr/french/viewtopi ... =1&t=15535 falsam show than use a database in memorys.
As you know, we can sort a list but not a map. However, we can not filter this.
With sql we can make this to easily.

In this sample asteroid game i show you wen use database instead of list.

(Ps: to shorten the code i don't manage the collisions)

Code: Select all

EnableExplicit
UseSQLiteDatabase()
Enumeration 
      #MainForm
      #Ship
      #Bulet
      #Asteroid
      #Db
EndEnumeration
; La structure pour le joueur
Structure player
      X.i
      Y.i
EndStructure
Global myPlayer.player

InitSprite()
InitKeyboard()
OpenWindow(#MainForm,0,0,800,600,"Teste Db",#PB_Window_ScreenCentered|#PB_Window_SystemMenu)
OpenWindowedScreen(WindowID(#MainForm),0,0,800,600)
; Creation des sprites
;{ Le sprite pour le vaiseau un simple réctangle vert
CreateSprite(#Ship,50,80)
StartDrawing(SpriteOutput(#Ship))
Box(0,0,SpriteWidth(#Ship),SpriteHeight(#Ship),$00FF00)
StopDrawing()
; On place le joueur au centre de l'écran
myPlayer\X=400-(SpriteWidth(#Ship)/2)
myPlayer\Y=580-SpriteHeight(#Ship)
;}
;{ Le sprite pour les bales un simple cercle rouge
Define W=5
CreateSprite(#Bulet,W*2,W*2,#PB_Sprite_AlphaBlending|#PB_Sprite_PixelCollision)
StartDrawing(SpriteOutput(#Bulet))
Circle(W,W,W,$0000FF)
StopDrawing()
;}
;{ Le sprite pour les astéroides un simple cercle bleu
W=15
CreateSprite(#Asteroid,W*2,W*2,#PB_Sprite_AlphaBlending|#PB_Sprite_PixelCollision)
StartDrawing(SpriteOutput(#Asteroid))
Circle(W,W,W,$FFFF00)
StopDrawing()
;}
;{ Création de la base de données en mémoire qui va remplocer nos listes ou nos maps
If OpenDatabase(#Db,":memory:","","")=0
      MessageRequester("DataBase Error","Can not create DataBase")
      End
EndIf
; Création de la table pour nos bales
Define query$
query$="CREATE TABLE bulet ("
query$+"X INTEGER,"
query$+"Y INTEGER"
query$+")"
If DatabaseUpdate(#Db,query$)=0
      MessageRequester("DataBase Error",DatabaseError())
      End
EndIf
; Création de la table pour nos astéroides
Define query$
query$="CREATE TABLE asteroid ("
query$+"X INTEGER,"
query$+"Y INTEGER"
query$+")"
If DatabaseUpdate(#Db,query$)=0
      MessageRequester("DataBase Error",DatabaseError())
      End
EndIf
;}
;{ Ajout de plusieurs astéroides dans la table
Define N
For N=1 To 20
      query$="INSERT INTO asteroid (X,Y) VALUES ("
      query$+Str(Random(800,0))+"," ; La position X dans l'écran
      query$+Str(0-Random(800,0))+")"
      If DatabaseUpdate(#Db,query$)=0
            MessageRequester("DataBase Error",DatabaseError())
            End
      EndIf
Next
;}
Define Event
Define TireOn.b=#True
Define TimeElapset
Repeat
      Repeat
            Event=WindowEvent()
            If Event=#PB_Event_CloseWindow :End :EndIf
      Until Event=0
      ; On fait descendre les asteroide
      query$="UPDATE asteroid SET Y=Y+1"
      If DatabaseUpdate(#Db,query$)=0
            MessageRequester("DataBase Error",DatabaseError())
            End
      EndIf
      ClearScreen(RGB(0,0,0))
      ; On affiche les astéroides uniquement les visibles
      query$="SELECT * FROM asteroid WHERE Y>=-50"
      If DatabaseQuery(#Db,query$)=0
            MessageRequester("DataBase Error",DatabaseError())
            End
      EndIf
      While NextDatabaseRow(#Db)
            DisplayTransparentSprite(#Asteroid,GetDatabaseLong(#Db,0),GetDatabaseLong(#Db,1))
      Wend      
      FinishDatabaseQuery(#Db)
      ; On supprime les astéroides hors écran
      query$="DELETE FROM asteroid WHERE Y>650"
      If DatabaseUpdate(#Db,query$)=0
            MessageRequester("DataBase Error",DatabaseError())
            End
      EndIf
      ; On affiche le vaiseau
      DisplaySprite(#Ship,myPlayer\X,myPlayer\Y)
      ; Déplacement du vaiseau
      ExamineKeyboard()
      If KeyboardPushed(#PB_Key_Left) And myPlayer\X>5
            myPlayer\X-5
      EndIf
      If KeyboardPushed(#PB_Key_Right) And myPlayer\X<(795-SpriteWidth(#Ship))
            myPlayer\X+5
      EndIf
      ; Gestion du tir
      If KeyboardPushed(#PB_Key_Space) And  TireOn
            TireOn=#False ;Decative le tir
            TimeElapset=ElapsedMilliseconds(); pour lancer le chrone
            ; On ajoute la bale à la table
            query$="INSERT INTO bulet (X,Y) VALUES ("+Str(myPlayer\X+20)+","
            query$+Str(myPlayer\Y-10)+")"
            If DatabaseUpdate(#Db,query$)=0
                  MessageRequester("DataBase Error",DatabaseError())
                  End
      EndIf
      EndIf
      ; Gestion du chrone
      If Not TireOn
            If (ElapsedMilliseconds()-TimeElapset)>100
                  TireOn=#True
            EndIf
      EndIf
      ; Affichage des bales
      query$="SELECT X,Y FROM bulet ORDER BY Y DESC"
      If DatabaseQuery(#Db,query$)=0
            MessageRequester("DataBase Error",DatabaseError())
            End
      EndIf
      While NextDatabaseRow(#Db)
            DisplayTransparentSprite(#Bulet,GetDatabaseLong(#Db,0),GetDatabaseLong(#Db,1))
      Wend  
      FinishDatabaseQuery(#Db)
      ; On fait avancer les bales
       query$="UPDATE bulet SET Y=Y-6"
      If DatabaseUpdate(#Db,query$)=0
            MessageRequester("DataBase Error",DatabaseError())
            End
      EndIf
      ; On supprime les bale hors ecran
      query$="DELETE FROM bulet WHERE Y<-10"
      If DatabaseUpdate(#Db,query$)=0
            MessageRequester("DataBase Error",DatabaseError())
            End
      EndIf
      FlipBuffers()
ForEver

Re: Use Database instead of list

Posted: Fri Oct 16, 2015 9:20 am
by IdeasVacuum

Code: Select all

OpenDatabase(#Db,":memory:","","")
That's a great tip, I had no idea it could be so simple. 8)

Re: Use Database instead of list

Posted: Fri Oct 16, 2015 11:37 am
by microdevweb
for complete this post i'm create a procedure for saving the memory Db in file Db

Code: Select all

Procedure SaveDb(IdDb,FileName$)
      Structure column
            Index$
            name$
            type$
            not_nul$
            default_value$
            primaryKey$
      EndStructure
      Structure Table
            name$
            List myColumn.column()
      EndStructure
      Protected NewList myTable.Table()
      Protected query$="Select * From sqlite_master order by type Desc, name Asc"
      Protected Db,IdFile,N
      If DatabaseQuery(IdDb,query$)=0
            MessageRequester("DataBase Error",DatabaseError())
            ProcedureReturn #False
      EndIf
      ; Sauvegarde des tables
      While NextDatabaseRow(IdDb)
            If GetDatabaseString(IdDb,0)="table"
                  AddElement(myTable())
                  With myTable()
                        \name$=GetDatabaseString(IdDb,1)
                  EndWith
            EndIf
      Wend
      FinishDatabaseQuery(IdDb)
      ForEach myTable()
            With myTable()
                  ; Relevé des infos des colonnes des tables
                  query$="PRAGMA table_info('"+\name$+"')"
                  If DatabaseQuery(IdDb,query$)=0
                        MessageRequester("DataBase Error",DatabaseError())
                        ProcedureReturn #False
                  EndIf
                  While NextDatabaseRow(IdDb)
                        AddElement(\myColumn())
                        \myColumn()\Index$=GetDatabaseString(IdDb,0)
                        \myColumn()\name$=GetDatabaseString(IdDb,1)
                        \myColumn()\type$=GetDatabaseString(IdDb,2)
                        \myColumn()\not_nul$=GetDatabaseString(IdDb,3)
                        \myColumn()\default_value$=GetDatabaseString(IdDb,4)
                        \myColumn()\primaryKey$=GetDatabaseString(IdDb,5)
                  Wend
                  FinishDatabaseQuery(IdDb)
            EndWith
      Next
      ; La nouvelle base de donnée
      IdFile=CreateFile(#PB_Any,FileName$)
      If IdFile=0
            MessageRequester("File Error","Can not create file "+FileName$)
            ProcedureReturn #False
      EndIf
      CloseFile(IdFile)
      Db=OpenDatabase(#PB_Any,FileName$,"","")
      If Db=0
            MessageRequester("DataBase Error","Can not open DataBase")
            ProcedureReturn #False
      EndIf
      ; Transfert des donnée
      ForEach myTable()
            With myTable()
                  query$="CREATE TABLE "+\name$+"("
                  N=0
                  ForEach \myColumn()
                        N+1
                        If N>1
                              query$+","
                        EndIf
                        query$+\myColumn()\name$+" "
                        query$+\myColumn()\type$+" "
                        If \myColumn()\not_nul$<>"0"
                              query$+" NOT NULL "
                        EndIf
                        If \myColumn()\primaryKey$="1"
                              query$+ "PRIMARY KEY"
                        EndIf
                  Next
                  query$+")"
                  If DatabaseUpdate(Db,query$)=0
                        MessageRequester("DataBase Error",DatabaseError())
                        ProcedureReturn #False
                  EndIf
            EndWith
      Next
      ForEach myTable()
            With myTable()
                  query$=" SELECT * FROM "+\name$
                  If DatabaseQuery(IdDb,query$)=0
                        MessageRequester("Database Error",DatabaseError())
                        ProcedureReturn #False
                  EndIf
                  While NextDatabaseRow(IdDb)
                        query$="INSERT INTO "+\name$+"("
                        N=0
                        ForEach \myColumn()
                              N+1
                              If N>1
                                    query$+","
                              EndIf
                              query$+\myColumn()\name$
                        Next
                        query$+") VALUES ("
                        For N=0 To DatabaseColumns(IdDb)-1
                              If N>0
                                    query$+","
                              EndIf
                              Select DatabaseColumnType(IdDb,N)
                                    Case #PB_Database_String
                                          query$+"'"+GetDatabaseString(IdDb,N)+"'"
                                    Case #PB_Database_Long
                                          query$+Str(GetDatabaseLong(IdDb,N))
                                    Case #PB_Database_Float
                                          query$+StrF(GetDatabaseFloat(IdDb,N))
                                    Case #PB_Database_Double
                                          query$+StrD(GetDatabaseDouble(IdDb,N))
                                    Case #PB_Database_Quad
                                          query$+Str(GetDatabaseQuad(IdDb,N))
                              EndSelect
                        Next
                        query$+")"
                        If DatabaseUpdate(Db,query$)=0
                              MessageRequester("Database Error",DatabaseError())
                              ProcedureReturn #False
                        EndIf
                  Wend  
            EndWith
      Next
      ProcedureReturn #True
EndProcedure

Re: Use Database instead of list

Posted: Fri Oct 16, 2015 12:10 pm
by Kiffi
microdevweb wrote:for complete this post i'm create a procedure for saving the memory Db in file Db [...]
You can use this code to save a :memory:-Database to disk: http://www.purebasic.fr/english/viewtop ... 43#p368143

Greetings ... Peter

Re: Use Database instead of list

Posted: Sat Oct 17, 2015 6:53 am
by microdevweb
Thank's Kiffi,

It's vey nice and really more easy, but i'm modified this code look at her

Code: Select all

Procedure.i SQLite_BackupSqliteDatabase(sourceDB, FileName$)
      Protected result, backUp,IdFile,destinationDB
      IdFile=CreateFile(#PB_Any,FileName$)
      If IdFile=0
            MessageRequester("Acces file Error","Can not create this file "+FileName$)
            ProcedureReturn #False
      EndIf
      CloseFile(IdFile)
      destinationDB=OpenDatabase(#PB_Any,FileName$,"","")
      If destinationDB=0
            MessageRequester("DataBase Error","Can not open this DataBase "+FileName$)
            ProcedureReturn #False
      EndIf
      If IsDatabase(sourceDB) And IsDatabase(destinationDB)
            backUp = sqlite3_backup_init(DatabaseID(destinationDB), "main", DatabaseID(sourceDB), "main")
            If backUp
                  sqlite3_backup_step(backUp, -1)
                  If sqlite3_backup_finish(backUp) = 0 ;#SQLITE_OK
                        result = #True   
                  EndIf
            EndIf
      EndIf
      ProcedureReturn result
EndProcedure

Re: Use Database instead of list

Posted: Sat Oct 17, 2015 11:17 pm
by Andre
The theme and so the example seems to have the potential to become very useful for me.

Unfortunately it doesn't run properly on my MacOS 10.6.8 - I can only move the green sprite to left/right, but don't see anything else!?

Re: Use Database instead of list

Posted: Sun Oct 18, 2015 6:03 am
by wilbert
Andre wrote:Unfortunately it doesn't run properly on my MacOS 10.6.8 - I can only move the green sprite to left/right, but don't see anything else!?
I can confirm this on OSX 10.11 .
I have the impression that there's a bug with the combination of #PB_Sprite_AlphaBlending and DisplayTransparentSprite but am not very familiar with this.
If you are familiar with it, maybe you can check if it really is caused by this and post a bug report if it is.

Re: Use Database instead of list

Posted: Sun Oct 18, 2015 7:06 am
by microdevweb
Hello Andre, wilbert,

Id don't no know why this code don't run with macOs, perhaps macOs don't manage the memorys database, you can try with debuger for see if your variable it's right. But i don't have Mac so i don't try that.

Re: Use Database instead of list

Posted: Sun Oct 18, 2015 7:27 am
by wilbert
microdevweb wrote:perhaps macOs don't manage the memorys database
That was my initial thought but the database works fine and the coordinates to display the sprites are retrieved properly.
It's just that the sprites aren't visible.

Re: Use Database instead of list

Posted: Sun Oct 18, 2015 5:58 pm
by microdevweb
it's amazing... I don't know what for. But the interest of this message it's not for the sprite management, it's main for use the memory Database for another aplication.