Page 1 of 1

Purebasic To MelonJS - HTML5 game engine

Posted: Mon Feb 18, 2013 12:08 am
by eddy
- This include file provide tools to build an HTML5 game. It's just the first draft. :mrgreen:
- It create local web server for your tests

:arrow: download MelonJS framework : http://www.melonjs.org/build/melonJS-0.9.5-min.js
:arrow: download tutorial package : http://www.melonjs.org/tutorial/tutorial_template.zip
:arrow: download TileEditor : http://www.mapeditor.org/

Todo
- CreateGameScreen( )
- CreateObjectEntity( )
- LoadLevel( )

MelonJS.pbi

Code: Select all

EnableExplicit

Structure WEB_RESOURCE
   ResFile.i
   UniqueName.s
   Src.s
   Type.s
   AudioChannels.i
   Preloaded.b
EndStructure 
Structure WEB_APPLICATION
   List Resources.WEB_RESOURCE()
   
   Initialized.b
   EngineHTML5.s
   
   WebServerWindow.i
   WebServer.i
   WebServerPort.i
   WebServerIP.s
   *WebBuffer.String
   WebRequest.s
   
   CanvasWidth.i
   CanvasHeight.i

   PageTitle.s
   PageColor.s

   HtmlFileName.s
   HtmlFile.i
   HtmlContent.s
   
   JsFileName.s
   JsFile.i
   JsContent.s
EndStructure
Global app.WEB_APPLICATION

;{ PB Debugger Functions
CompilerIf #PB_Compiler_Debugger
   Import ""
      PB_DEBUGGER_SendError(Message.p-ascii)
      PB_DEBUGGER_SendWarning(Message.p-ascii)
   EndImport
CompilerEndIf   
Macro SendDebuggerError(Message)   
   CompilerIf Defined(PB_DEBUGGER_SendError,#PB_Procedure) : PB_DEBUGGER_SendError(Message) : CompilerEndIf 
EndMacro
Macro SendDebuggerWarning(Message) 
   CompilerIf Defined(PB_DEBUGGER_SendWarning,#PB_Procedure) : PB_DEBUGGER_SendWarning(Message) : CompilerEndIf 
EndMacro
;} 

;{ PB Extended Functions
Procedure.s GetFilePartWithoutExtension(FileName.s)
   Protected filePart.s=GetFilePart(FileName)
   ProcedureReturn Mid(filePart,0,Len(filePart)-Len(GetExtensionPart(filePart))-1)
EndProcedure 
;}

Enumeration 
   #WebInit_None=0
   #WebInit_App
   #WebInit_Page
   #WebInit_Screen
EndEnumeration

Procedure.b InitWebApplication(EngineFileName.s="lib/melonJS-0.9.5-min.js")
   With app
      \EngineHTML5=EngineFileName       
      If Not FileSize(\EngineHTML5)>-1 : SendDebuggerError("MelonJS javascript not found!") : EndIf 
      
      Protected fileWithoutExtension.s= GetFilePartWithoutExtension(#PB_Compiler_File)
      
      \HtmlFileName=GetCurrentDirectory()+fileWithoutExtension+".html"
      \HtmlFile=CreateFile(#PB_Any,\HtmlFileName)
      
      \JsFileName=GetCurrentDirectory()+fileWithoutExtension+".js"
      \JsFile=CreateFile(#PB_Any,\JsFileName)
      
      \Initialized=#WebInit_App*Bool(\JsFile And \HtmlFile)
      ProcedureReturn \Initialized
   EndWith   
EndProcedure 

Procedure.b OpenWebPage(PageTitle.s, PageColor=#White)
   With app
      If Not \Initialized=#WebInit_App : SendDebuggerError("You didn't initialize a web application!") : EndIf 
      
      \PageTitle=PageTitle
      \PageColor="#"+RSet(Hex(Red(PageColor)), 2, "0")+RSet(Hex(Green(PageColor)), 2, "0")+RSet(Hex(Blue(PageColor)), 2, "0")            
      \Initialized=#WebInit_Page*Bool(\PageTitle)
      ProcedureReturn \Initialized
   EndWith 
EndProcedure 

Procedure.b OpenWebCanvas(Width, Height)
   With app 
      If Not \Initialized=#WebInit_Page : SendDebuggerError("You didn't open a web page!") : EndIf 
      
      \CanvasWidth=Width
      \CanvasHeight=Height
      \Initialized=#WebInit_Screen*Bool(\CanvasWidth And \CanvasHeight)
      ProcedureReturn \Initialized
   EndWith
EndProcedure

Procedure PreloadWebResource(Resource, FileName.s, UniqueName.s="", AudioChannels=1)
   With app
      If Not \Initialized=#WebInit_App : SendDebuggerError("You didn't initialize a web application!") : EndIf 
      
      Protected Result
      If Resource=#PB_Any  
         Result=ReadFile(Resource,FileName)
         Resource=Result
      Else 
         ReadFile(Resource,FileName)
      EndIf 
      If IsFile(Resource)
         AddElement(\Resources())
         \Resources()\ResFile=Resource
         If UniqueName=""
            UniqueName=GetFilePartWithoutExtension(FileName)
         EndIf 
         \Resources()\UniqueName=UniqueName
         \Resources()\Src=FileName
         \Resources()\AudioChannels=AudioChannels
         \Resources()\Preloaded=#True 
         Select LCase(GetExtensionPart(FileName))
            Case "png","jpg","gif"
               \Resources()\Type="image"
            Case "tmx"
               \Resources()\Type="tmx"
            Case "mp3","ogg"
               \Resources()\Type="audio"
               \Resources()\Src=GetPathPart(\Resources()\Src)
            Default 
               \Resources()\Type="binary"
         EndSelect 
      EndIf 
   EndWith
EndProcedure 

Procedure BuildWebApplication()
   With app
      ;{/// Write HTML page
      \HtmlContent="<!DOCTYPE html>"+
                   #LF$+"<html>"+
                   #LF$+"	<head>"+
                   #LF$+"		<title>"+\PageTitle+"</title>"+
                   #LF$+"	</head>"+
                   #LF$+"	<body bgcolor='"+\PageColor+"'>"+
                   #LF$+"		<div id='info' style='width: "+\CanvasWidth+"px;'>"+
                   #LF$+"			<div id='jsapp'>"+
                   #LF$+"				<font color='#FFFFFF', style='position: absolute; font-size: 10px; font-family: Courier New'>"+
                   #LF$+"					<span id='framecounter'>(0/0 fps)</span>"+
                   #LF$+"				</font>"+
                   #LF$+"				<script type='text/javascript' src='"+\EngineHTML5+"'></script>"+
                   #LF$+"				<script type='text/javascript' src='"+GetFilePart(\JsFilename)+"'></script>"+
                   #LF$+"			</div>"+
                   #LF$+"		</div>"+
                   #LF$+"	</body>"+
                   #LF$+"</html>"
      WriteString(\HtmlFile,\HtmlContent) 
      CloseFile(\HtmlFile)
      ;} 
      
      ;{/// Write RESOURCES to preload
      Protected preloadedGlobalResources.s=""
      ForEach \Resources()
         If \Resources()\Preloaded
            If preloadedGlobalResources 
               preloadedGlobalResources + ","+#LF$
            EndIf 
            preloadedGlobalResources +#TAB$+ "{name:'"+\Resources()\UniqueName+"', type:'"+\Resources()\Type+"', src:'"+\Resources()\Src+"'}"
         EndIf 
      Next 
      ;} 
      
      ;{/// Write JS script
      \JsContent="// game resources"+
                 #LF$+"var g_resources = ["+
                 #LF$+preloadedGlobalResources+
                 #LF$+"];"+
                 #LF$+"var jsApp = {"+
                 #LF$+"    onload: function() {"+
                 #LF$+"        if (!me.video.init('jsapp', "+\CanvasWidth+", "+\CanvasHeight+", false, 1.0)) { "+
                 #LF$+"            alert('Sorry but your browser does Not support html 5 canvas.');"+
                 #LF$+"            Return;"+
                 #LF$+"        }"+
                 #LF$+"        me.audio.init('mp3,ogg');"+
                 #LF$+"        me.loader.onload = this.loaded.bind(this);"+
                 #LF$+"        me.loader.preload(g_resources);"+
                 #LF$+"        me.state.change(me.state.LOADING);"+
                 #LF$+"    },"+
                 #LF$+"    loaded: function() {"+
                 #LF$+"        // set the 'Play/Ingame' Screen Object"+
                 #LF$+"        me.state.set(me.state.PLAY, new PlayScreen());"+
                 #LF$+"        // start the game"+
                 #LF$+"        me.state.change(me.state.PLAY);"+
                 #LF$+"    }"+
                 #LF$+"};"+
                 #LF$+"var PlayScreen = me.ScreenObject.extend({"+
                 #LF$+"    onResetEvent: function() {"+
                 #LF$+"        me.levelDirector.loadLevel('"+"area01"+"');"+
                 #LF$+"    },"+
                 #LF$+"    onDestroyEvent: function() {"+
                 #LF$+"    }"+
                 #LF$+"});"+
                 #LF$+"window.onReady(function() {"+
                 #LF$+"    jsApp.onload();"+
                 #LF$+"});"
      WriteString(\JsFile,\JsContent) 
      CloseFile(\JsFile)
      ;} 
      
   EndWith
EndProcedure

Procedure SendWebFile(FileName.s)
   If FileSize(FileName)>-1
      Protected SendFile=ReadFile(#PB_Any,FileName)
      If SendFile
         Protected ContentType$ 
         Select LCase(GetExtensionPart(FileName))
            Case "gif": ContentType$ = "image/gif"
            Case "png": ContentType$ = "image/png"
            Case "jpg": ContentType$ = "image/jpeg"
            Case "txt": ContentType$ = "text/plain"
            Case "js" : ContentType$ = "text/javascript"
            Default   : ContentType$ = "text/html"
         EndSelect
         Protected FileLength = Lof(SendFile)
         Protected *FileBuffer    = AllocateMemory(FileLength+200)
         Protected *FileOffset    = *FileBuffer
         Protected Length
         *FileOffset+PokeS(*FileOffset, "HTTP/1.1 200 OK"+#CRLF$)                    
         *FileOffset+PokeS(*FileOffset, "Date: Wed, 07 Aug 1996 11:15:43 GMT"+#CRLF$)
         *FileOffset+PokeS(*FileOffset, "Server: Atomic Web Server 0.2b"+#CRLF$)     
         *FileOffset+PokeS(*FileOffset, "Content-Length: "+FileLength+#CRLF$)
         *FileOffset+PokeS(*FileOffset, "Content-Type: "+ContentType$+#CRLF$)        
         *FileOffset+PokeS(*FileOffset, #CRLF$)                                      
         ReadData(SendFile, *FileOffset, FileLength)                             
         CloseFile(SendFile)
         SendNetworkData(EventClient(), *FileBuffer, *FileOffset-*FileBuffer+FileLength)
         FreeMemory(*FileBuffer)
      EndIf 
   EndIf  
EndProcedure

Procedure StartWebApplication(ServerIP.s="127.0.0.1",ServerPort=80)
   With app
      If InitNetwork()
         \WebServerPort=ServerPort
         \WebServerIP=ServerIP
         \WebServer=CreateNetworkServer(#PB_Any ,\WebServerPort, #PB_Network_IPv4,\WebServerIP)
         If \WebServer
            \WebServerWindow=OpenWindow(#PB_Any, 0, 0, 400, 100,
                                        "Purebasic Web Server - "+\WebServerIP+":"+\WebServerPort,
                                        #PB_Window_ScreenCentered|
                                        #PB_Window_SystemMenu|
                                        #PB_Window_TitleBar)
            
            Protected RequestTextbox=EditorGadget(#PB_Any,5,5,WindowWidth(\WebServerWindow)-10,80,#PB_Editor_WordWrap)
            Protected RequestFileNameRegex=CreateRegularExpression(#PB_Any,"get\s[^\s]+\s",#PB_RegularExpression_NoCase)
            Protected Dim RequestFileName.s(0)
            
            RunProgram("http://"+\WebServerIP+"/"+GetFilePart(\HtmlFileName))
            
            If \WebServerWindow
               \WebBuffer = AllocateMemory(10000)
               Repeat
                  Select NetworkServerEvent()
                     Case #PB_NetworkEvent_Connect
                     Case #PB_NetworkEvent_Disconnect
                     Case #PB_NetworkEvent_Data
                        ReceiveNetworkData(EventClient(), \WebBuffer, 2000)
                        \WebRequest=PeekS(\WebBuffer)
                        SetGadgetText(RequestTextbox,\WebRequest)
                        If ExtractRegularExpression(RequestFileNameRegex,\WebRequest,RequestFileName())
                           RequestFileName(0)=Mid(StringField(RequestFileName(0),2," "),2)
                           RequestFileName(0)=GetCurrentDirectory()+ReplaceString(RequestFileName(0),"/","\")
                           SendWebFile(RequestFileName(0))
                        EndIf 
                  EndSelect 
               Until WaitWindowEvent(10) = #PB_Event_CloseWindow
            EndIf 
            CloseNetworkServer(\WebServer)
         EndIf 
      EndIf
   EndWith 
EndProcedure

Re: Purebasic To MelonJS - HTML5 game engine

Posted: Mon Feb 18, 2013 12:15 am
by eddy

Code: Select all

; ***********************
; HTML5 GAME TEMPLATE
; ***********************
DisableExplicit

If InitWebApplication()
   LevelBackground0=PreloadWebResource(#PB_Any,"data/area01_parallax/area01_bkg0.png")
   LevelBackground1=PreloadWebResource(#PB_Any,"data/area01_parallax/area01_bkg1.png")
   LevelTiles=PreloadWebResource(#PB_Any,"data/area01_tileset/area01_level_tiles.png")
   LevelMap=PreloadWebResource(#PB_Any,"data/area01.tmx")
   
   If OpenWebPage("Purebasic Game - HTML5 & MelonJS",RGB(169, 195, 249))
      If OpenWebCanvas(640,480) 
         ;GameScreen()
         ;GameEntity()
         ;GameCollectable()
         ;GameHUD()
      EndIf 
   EndIf 
EndIf 
BuildWebApplication()
StartWebApplication()
Image

Re: Purebasic To MelonJS - HTML5 game engine

Posted: Mon Feb 18, 2013 12:45 am
by RichAlgeni
Eddy, that looks great! Is your game anything like Crystal Caves? I loved that game!

Re: Purebasic To MelonJS - HTML5 game engine

Posted: Wed Feb 20, 2013 9:08 am
by eddy
RichAlgeni wrote:Eddy, that looks great! Is your game anything like Crystal Caves?
I don't know.
It's the default project template provided by MelonJS.