ESC / Ctrl+Shft+Q / Alt+F4 / Close = quit the game engine
Ctrl+Shft+R = restart
F3 = display FPS
F11 = switch to full screen or back to window
F12 = screen capture
Please make any suggestions for how I am using PB and especially variables etc
Updates:
2017-01-05: fixed up FPS calculation and removed keyboard and mouse detection variables
2017-01-06: lots of fixes and added menu controls
2017-01-09: going to make this my last update, added windowed full screen and sprites. Quake 3 engine is ~64,000 lines of code, so I'm not going to keep updating this. It's a good framework for getting the game started.
2017-01-10: some bug fixes
2017-12-09: minor update
Code: Select all
; Universal Game Engine
EnableExplicit
; Do compiler checks
CompilerSelect #PB_Compiler_OS
CompilerCase #PB_OS_Windows
CompilerCase #PB_OS_Linux
CompilerCase #PB_OS_MacOS
CompilerDefault
CompilerError "OS not supported"
CompilerEndSelect
;- Enumerations
; Layer 1 - Operating System and universal controls
Enumeration Render_Engine3D
#Render_Engine3D_None
#Render_Engine3D_Builtin ; custom built 3D engine
EndEnumeration
Enumeration Game_Window
#Game_Window_Main
#Game_Window_Full_Screen_Minimised ; this is special window opened when classic full screen mode is switched back to the OS
EndEnumeration
Enumeration Full_Screen_Type
#Full_Screen_Classic
#Full_Screen_Windowed ; recommended, allows multiple monitor support
EndEnumeration
Enumeration Data_Source
#Data_Source_None
#Data_Source_Internal_Memory
#Data_Source_File
#Data_Source_Database
EndEnumeration
Enumeration Simulated_Resolution_Stretch_Type
; Used for simulating a low resolution game
#Simulated_Resolution_Stretch_Smallest ; recommended
#Simulated_Resolution_Stretch_H
#Simulated_Resolution_Stretch_V
#Simulated_Resolution_Stretch_Both
EndEnumeration
; Layer 2 - Menus and controls
Enumeration Control_Hardware
#Control_Hardware_Keyboard
#Control_Hardware_Mouse
EndEnumeration
Enumeration Menu_System ; specifies how the menu will be navigated
#Menu_System_Menuless ; uses buttons only to start and reset the game
#Menu_System_Simple ; like most console and some PC games (uses arrow keys/controller to navigate)
#Menu_System_Pointer ; like most PC games
EndEnumeration
Enumeration Menu_Action
; specifies different actions a menu will take
#Menu_Action_None
; menuless
#Menu_Action_Start ; starts the game
#Menu_Action_Select ; selects which mode of the game to play
#Menu_Action_Reset ; resets the game
; simple
#Menu_Action_Confirm
#Menu_Action_Back
#Menu_Action_Up
#Menu_Action_Down
#Menu_Action_Left
#Menu_Action_Right
; pointer based menu controls
#Menu_Action_Click
EndEnumeration
Enumeration Menu_Background
#Menu_Background_None ; displays a solid colour
#Menu_Background_Vector
#Menu_Background_Image
EndEnumeration
;- Globals
Global Restart.i=0 ; restarts the game engine
;- Constants
; System
#Max_Monitors_Supported = 3
#Max_Sprite_Resources = 256 ; total amount of individual sprites supported
; Menu
#Max_Menu_Controls = 12
; Game
#Max_Sprite_Instances = 2048 ; all sprites used by the game
;- Structures
; System
Structure Desktop_Structure ; structure to store parametres for each available display
Name.s
Width.i
Height.i
Depth.i
Frequency.i
EndStructure
Structure Sprite_Resource_Structure
; Source collection of sprites
Width.i
Height.i
Mode.i ; #PB_Sprite_PixelCollision and #PB_Sprite_AlphaBlending
Transparent.i ; set if the sprite uses transparency
Data_Source.i ; See Data_Source enumeration
Memory_Location.i ; use one of these
File_Location.s
Database_Location.i
EndStructure
; Menu
Structure Menu_Control_Structure
Menu_Control_Type.i ; specifies the type of the menu control system, see Enumeration Menu_System
Menu_Control_Action.i ; this is the action the control will take, see Enumeration Menu_Control_Actions
Menu_Control_Hardware_Type.i ; see Enumeration Control_Hardware
Menu_Control_ID.i ; this is the ID of the actual control, for example a keyboard key
EndStructure
; Game
Structure Sprite_Instance_Structure
Sprite_Resource.i
X.i
Y.i
Intensity.i ; only works for transparent sprites
Colour.i ; only works for transparent sprites, not yet implemented
Layer.i ; used to sort the sprite instance array for drawing order, 0 is background
Visible.i
EndStructure
;- Parametres
Structure Game_Parametres_Structure
;***************************************************
; System
;***************************************************
Allow_AltF4_Full_Screen.i ; allows full screen to be quit using Alt+F4
Allow_Restart.i ; allows the game engine to be restarted
Allow_Screen_Capture.i ; allows a screenshot to be taken
Allow_Switch_to_Window.i ; to allow switching between window and full screen
Allow_Window.i ; prevents window mode completely
Allow_Window_Resize.i ; to allow the game window to be resized or maximised (doesn't apply to full screen mode)
Background_Colour.i ; background colour used when clearing the screen. This is set depending on what layer the system is running in
Config_File.i ; set to 1 if config file exists, used for when there's no config file
Config_Loaded.i ; set to 1 once the config is loaded. Cannot save until loaded
Current_Directory.s
Desktop.Desktop_Structure[#Max_Monitors_Supported] ; Array to hold information about all monitors
Fatal_Error_Message.s ; when the game encounters a fatal error this is the error which will be displayed immediately and the program ended with an error code
Flip_Mode.i ; Video flip mode: 0 = no sync, 1 = sync, 2 = smart sync
FPS.i ; current FPS
FPS_Frame_Count.i ; counts how many frames have been drawn within one second
FPS_Last_Time.i ; stores the last time in milliseconds that FPS will be calculated from
FPS_Limit.i ; maximum FPS for unsynced mode
Full_Screen.i ; 0 = windowed, 1 = full screen
Full_Screen_Inactive.i ; set when the user switches from the full screen to the desktop
Full_Screen_Type.i ; see enumeration Full_Screen_Types, classic or windowed
Game_Config_File.s ; filename of the confg file
Game_Database_Location.s ; location of the database
Game_Loop_Start_Time.i ; records the time in milliseconds when the main loop started
Game_Resource_Location.s ; location of files
Game_Title.s ; Name of the game
Initialisation_Error.i ; will be set when there's an error. Helps track down the first error causing an issue
Initialise_Error_Message.s ; special string for giving an initialisation error message. Only set this using SetInitialiseError()
Initialised.i
Last_Screen_Capture_File.s ; last file used by screen capture
Last_Screen_Capture_Number.i ; used for capturing more than one frame per second
Main_Loop_Time.i ; time in milliseconds for a game loop based on maximum FPS setting
Min_Window_Width.i ; minimum width you can set a window to
Min_Window_Height.i
Mouse_Button_Left.i ; gives the actual mouse button state, only works in ExamineMouse() mode
Mouse_Button_Middle.i
Mouse_Button_Right.i
Mouse_Control.i ; mouse is controlling the player
Mouse_Left_Click.i ; set when the mouse is clicked while in window mode
Mouse_Right_Click.i
Mouse_Offset_X.i ; offset of the mouse sprite displayed
Mouse_Offset_Y.i ; usually 0
Mouse_Save_X.i ; saves the position of the mouse when switching back to desktop (alt+tab)
Mouse_Save_Y.i
Mouse_Sensitivity_X.f
Mouse_Sensitivity_Y.f
Mouse_Sprite_Index.i ; index of the sprite to use for the mouse
Mouse_Wheel_Movement.i ; movement of the mouse wheel since the last ExamineMouse()
Mouse_X.f ; location of the mouse pointer when it is over the window
Mouse_Y.f
MutexError.i ;
MutexID.i ; used to check if more than one instance of the game is running
Num_Monitors.i ; number of monitors detected
Quit.i ; flag to quit game 1 = quit. To restart the game use the global Restart variable
Render_Engine3D.i ; select which 3D rendering engine to use, select none for 2D only
Reset_Window.i ; triggers a move back to the main monitor, useful if a monitor is unplugged
Screen_Active.i ; set when the screen is active (including the windowed screen)
Screen_Open.i ; flag set when screen successfuly open (window or full screen)
Screen_W.i ; size of the full screen mode
Screen_H.i
Show_Debug_Info.i ; when set this will show things like FPS etc on screen
Show_Loading_Screen.i ; will show the loading screen during LoadConfig
Show_Mouse.i ; shows the mouse
Simulate_Res.i ; zooms sprites to simulate a low res game
Simulate_Res_W.i ; width of simulated resolution
Simulate_Res_H.i
Simulate_Res_Stretch.i ; how to stretch the simulated resolution (see enumeration Simulated_Resolution_Stretch_Types)
Sprite_List_Data_Source.i ; The source for the sprite resource list (see enumeration Data_Source)
Sprite_Resource_Count.i ; number of sprite resources loaded
Sprite_Resource.Sprite_Resource_Structure[#Max_Sprite_Resources] ; hold all sprite resources (the actual sprite image data)
Sprite_Zoom_X.i ; zoom factor for displaying sprites to the current screen
Sprite_Zoom_Y.i
Take_Screen_Capture.i ; flag to take a screen capture
Total_Desktop_Width.i ; used for checking if the window is displayed off screen
Window_Flags.i ; holds flags for game window
Window_Maximised.i ; set when window is maximised
Window_Minimised.i ; set when window is minimised
Window_Moved.i ; triggers whenever the window in normal mode moves
Window_Open.i ; flag is set when window successfully open
Window_W.i ; size of the window when in window mode
Window_H.i
Window_X.i ; position of window
Window_Y.i
Window_Ratio.f ; ratio of Window_W and Window_H
Window_Ratio_Enable.i ; set to enforce keeping the ratio when resizing the window
;***********************************************
; Menu
;***********************************************
Menu_Action.i ; which menu action to take
Menu_Active.i ; when true means that the menu system is active and has control
Menu_Background.i ; see enumeration Menu_Background
Menu_Background_Colour.i; background colour for the menu
Menu_Background_Data_Source.i ; see enumeration Data_Source
Menu_Control.Menu_Control_Structure[#Max_Menu_Controls] ; array that holds menu controls
Menu_Controls_Count.i ; total number of menu controls loaded
Menu_System_Type.i ; the type of menu system
;***********************************************
; Game
;***********************************************
; The game layer includes all the game mechanics as well as the display mechanism for the levels
Game_Active.i ; game is active
Sprite_Instance.Sprite_Instance_Structure[#Max_Sprite_Instances]
Sprite_Instance_Count.i
EndStructure
Procedure SetDefaults(*P.Game_Parametres_Structure)
; System
*P\Allow_AltF4_Full_Screen = 0
*P\Allow_Restart = 1
*P\Allow_Screen_Capture = 1
*P\Allow_Switch_to_Window = 1
*P\Allow_Window_Resize = 1
*P\Background_Colour = #Black ; this is the background for the system
*P\Config_File = 0 ; assume no config file
*P\Config_Loaded = 0 ; config not yet loaded
*P\Current_Directory = GetCurrentDirectory()
*P\Fatal_Error_Message = "none"
*P\Flip_Mode = #PB_Screen_WaitSynchronization
*P\FPS = 0
*P\FPS_Frame_Count = 1
*P\FPS_Last_Time = ElapsedMilliseconds() ; start the timer for calculating the FPS
*P\FPS_Limit = 60 ; used for unsynced mode
*P\Full_Screen = 0
*P\Full_Screen_Type = #Full_Screen_Windowed
*P\Full_Screen_Inactive = 0
*P\Game_Config_File = "settings.cfg"
*P\Game_Database_Location = ""
*P\Game_Resource_Location = "data"
*P\Game_Title = "Universal Game Engine"
*P\Initialisation_Error = 0
*P\Initialise_Error_Message = "none"
*P\Initialised = 0
*P\Last_Screen_Capture_File = ""
*P\Last_Screen_Capture_Number = 0 ; reset the screen capture counter for more than one per second
*P\Main_Loop_Time = 1000 / *P\FPS_Limit ; the time it should take for the main loop to complete
*P\Min_Window_Width = 320
*P\Min_Window_Height = 200
*P\Mouse_Control = 0 ; set when the mouse is controlling the player
*P\Mouse_Offset_X = 0
*P\Mouse_Offset_Y = 0
*P\Mouse_Sprite_Index = 1
*P\Mouse_Sensitivity_X = 1
*P\Mouse_Sensitivity_Y = 1
*P\Mouse_Wheel_Movement = 0
*P\Num_Monitors = 0
*P\Quit = 0
*P\Render_Engine3D = #Render_Engine3D_Builtin
*P\Reset_Window = 0
*P\Screen_Active = 0
*P\Screen_Open = 0
*P\Show_Debug_Info = 0
*P\Show_Loading_Screen = 1
*P\Show_Mouse = 1
*P\Simulate_Res = 1 ; simulate a low resolution game
*P\Simulate_Res_W = 320
*P\Simulate_Res_H = 200
*P\Simulate_Res_Stretch = #Simulated_Resolution_Stretch_Both
*P\Sprite_List_Data_Source = #Data_Source_Internal_Memory
*P\Sprite_Resource_Count = 0
*P\Take_Screen_Capture = 0
*P\Total_Desktop_Width = 0
*P\Window_Minimised = 0
*P\Window_Moved = 0
*P\Window_W = 640
*P\Window_H = 400
*P\Window_Ratio = *P\Window_H / *P\Window_W
*P\Window_Ratio_Enable = 1
; Menu
*P\Menu_Active = 0 ; game starts in system mode, when initialise finishes the menu becomes active
*P\Menu_Action = #Menu_Action_None ; make sure nothing has been pressed for the menu controls
*P\Menu_Background = #Menu_Background_None
*P\Menu_Background_Colour = #Black ; this will be changed when the menu is loaded
*P\Menu_Background_Data_Source = #Data_Source_Internal_Memory
*P\Menu_System_Type = #Menu_System_Menuless
EndProcedure
;- Error Handler
Procedure Fatal_Error(*P.Game_Parametres_Structure)
Debug "FATAL ERROR: " + *P\Fatal_Error_Message
CloseScreen() ; drop back to desktop
MessageRequester (*P\Game_Title + " Fatal Error", "FATAL ERROR!" + #CRLF$ + *P\Fatal_Error_Message, #PB_MessageRequester_Error)
End 1 ; 1 means there was an error
EndProcedure
;- Graphics
Procedure InitDesktop(*P.Game_Parametres_Structure)
; used to check which monitors are connected and how to display the game by default
Protected c.i, t.i
*P\Num_Monitors = ExamineDesktops()
Debug "InitDesktop: " + *P\Num_Monitors + " monitors detected"
If *P\Num_Monitors > 0
t = *P\Num_Monitors
If t > #Max_Monitors_Supported : t = #Max_Monitors_Supported : EndIf
*P\Total_Desktop_Width = 0
For c = 0 To *P\Num_Monitors - 1
*P\Desktop[c]\Name = DesktopName(c)
*P\Desktop[c]\Width = DesktopWidth(c)
*P\Desktop[c]\Height = DesktopHeight(c)
*P\Desktop[c]\Depth = DesktopDepth(c)
*P\Desktop[c]\Frequency = DesktopFrequency(c)
*P\Total_Desktop_Width = *P\Total_Desktop_Width + *P\Desktop[c]\Width
Next
; Full screen mode is always on monitor 0, this is a limitation of PureBasic
*P\Screen_W = DesktopWidth(0)
*P\Screen_H = DesktopHeight(0)
Else
Debug "InitDesktop: could not initialise desktop"
ProcedureReturn 0
EndIf
ProcedureReturn 1
EndProcedure
Procedure SetWindowFlags(*P.Game_Parametres_Structure)
; used to set the flags for how the windowed application will be displayed
If *P\Full_Screen
; Set window flags for windowed full screen
*P\Window_Flags = #PB_Window_Maximize | #PB_Window_BorderLess
Else
*P\Window_Flags = #PB_Window_MinimizeGadget
If *P\Allow_Window_Resize
*P\Window_Flags = *P\Window_Flags | #PB_Window_SizeGadget | #PB_Window_MaximizeGadget
EndIf
If *P\Reset_Window ; windows has been reset back to main display, centre it
*P\Window_Flags = *P\Window_Flags | #PB_Window_ScreenCentered
EndIf
If *P\Window_Maximised
*P\Window_Flags = *P\Window_Flags | #PB_Window_Maximize
EndIf
EndIf
EndProcedure
Procedure GetScreenWidth(*P.Game_Parametres_Structure)
; Returns the screen width whether it's a window or full screen
If *P\Full_Screen
ProcedureReturn *P\Screen_W
Else
ProcedureReturn WindowWidth(#Game_Window_Main)
EndIf
EndProcedure
Procedure GetScreenHeight(*P.Game_Parametres_Structure)
If *P\Full_Screen
ProcedureReturn *P\Screen_H
Else
ProcedureReturn WindowHeight(#Game_Window_Main)
EndIf
EndProcedure
Procedure LoadSpriteResources(*P.Game_Parametres_Structure)
; Can be called anytime as it handles freeing all existing sprites
Protected c.i, f.s
Protected x.i, y.i, col.l
Protected r.i ; this is used as a variable for reading data to be discarded
Debug "LoadSprites: loading sprite resource list"
Select *P\Sprite_List_Data_Source
Case #Data_Source_None
*P\Sprite_Resource_Count = 0
Debug "LoadSprites: no sprite resources to load"
Case #Data_Source_Internal_Memory
Restore Sprite_Resource_Data
Read *P\Sprite_Resource_Count
If *P\Sprite_Resource_Count > #Max_Sprite_Resources
*P\Fatal_Error_Message = "#Max_Sprite_Resources too small to load all sprite resources"
Fatal_Error(*P)
EndIf
; Read complete sprite resource list first
; That way sprites can be loaded from the DataSection
For c = 0 To *P\Sprite_Resource_Count - 1
Read.i *P\Sprite_Resource[c]\Width
Read.i *P\Sprite_Resource[c]\Height
Read.i *P\Sprite_Resource[c]\Mode
Read.i *P\Sprite_Resource[c]\Transparent
Read.i *P\Sprite_Resource[c]\Data_Source
Select *P\Sprite_Resource[c]\Data_Source
; Have to specify which variable we read the next data in to
Case #Data_Source_None
Read.i r
Case #Data_Source_Internal_Memory
Read.i *P\Sprite_Resource[c]\Memory_Location
Case #Data_Source_File
Read.s *P\Sprite_Resource[c]\File_Location
Case #Data_Source_Database
Read.i *P\Sprite_Resource[c]\Database_Location
EndSelect
Next
Case #Data_Source_File
Case #Data_Source_Database
EndSelect
; Now that the resource list has been stored, load the sprites.
; This is necessary so that sprites can be stored in the DataSection
If *P\Sprite_Resource_Count > 0
Debug "LoadSprites: loading sprites"
Restore Sprite_Data
For c = 0 To *P\Sprite_Resource_Count - 1
Select *P\Sprite_Resource[c]\Data_Source
Case #Data_Source_None
; Nothing to do, empty sprite
Case #Data_Source_Internal_Memory
If Not CreateSprite(c, *P\Sprite_Resource[c]\Width, *P\Sprite_Resource[c]\Height, *P\Sprite_Resource[c]\Mode)
*P\Fatal_Error_Message = "Unable to create sprite " + c
Fatal_Error(*P)
EndIf
StartDrawing(SpriteOutput(c))
DrawingMode(#PB_2DDrawing_AllChannels)
For y = 0 To *P\Sprite_Resource[c]\Height - 1
For x = 0 To *P\Sprite_Resource[c]\Width - 1
Read.l col
Plot(x,y,col)
Next
Next
StopDrawing()
Case #Data_Source_File
f = *P\Game_Resource_Location + "\" + *P\Sprite_Resource[c]\File_Location
If Not LoadSprite(c, f, *P\Sprite_Resource[c]\Mode)
*P\Fatal_Error_Message = "Unable to load sprite " + f
Fatal_Error(*P)
EndIf
Case #Data_Source_Database
*P\Fatal_Error_Message = "Loading sprites from a database not yet supported"
Fatal_Error(*P)
EndSelect
Next
EndIf
Debug "LoadSprites: " + *P\Sprite_Resource_Count + " sprite resource(s) loaded"
EndProcedure
Procedure SetWindowScreen(*P.Game_Parametres_Structure)
; Sets the window screen closing the old one if necessary
If *P\Screen_Open
CloseScreen()
*P\Screen_Open = 0
EndIf
If OpenWindowedScreen(WindowID(#Game_Window_Main), 0, 0, WindowWidth(#Game_Window_Main), WindowHeight(#Game_Window_Main), #False, 0, 0, *P\Flip_Mode)
*P\Screen_Open = 1
*P\Screen_Active = 1
Debug "SetWindowScreen: set new window screen dimensions: " + WindowWidth(#Game_Window_Main) + " x " + WindowHeight(#Game_Window_Main)
Else
Debug "SetWindowScreen: could not initialise windowed screen"
ProcedureReturn 0
EndIf
ProcedureReturn 1
EndProcedure
Procedure SetScreen(*P.Game_Parametres_Structure)
; Sets (or resets) the screen. In fullscreen mode it opens a fullscreen.
; In window mode it opens a window then opens a window screen inside it.
; When used mid game-loop check if it failed and generate a fatal error.
Protected Result.i
If *P\Screen_Open
Debug "SetScreen: closing screen"
CloseScreen()
*P\Screen_Open = 0
EndIf
If *P\Window_Open
; Only used if switching to full screen from a window
Debug "SetScreen: closing window"
CloseWindow(0)
*P\Window_Open = 0
EndIf
If *P\Full_Screen And *P\Full_Screen_Type = #Full_Screen_Classic
Debug "SetScreen: opening full screen"
If OpenScreen(*P\Screen_W, *P\Screen_H, 32, *P\Game_Title, *P\Flip_Mode)
*P\Screen_Open = 1
*P\Screen_Active = 1
Else
Debug "SetScreen: could not intialise full screen"
ProcedureReturn 0
EndIf
Else
; check the window is visible, useful if you unplug a monitor
If *P\Window_X > *P\Total_Desktop_Width And Not *P\Full_Screen
; Only reset the window if it's not in windowed full screen mode
Debug "SetScreen: window is not visible"
*P\Reset_Window = 1
*P\Window_X = 0
*P\Window_Y = 0
*P\Window_Maximised = 0 ; need to demaximise window so it can get new coordinates
EndIf
SetWindowFlags(*P)
Debug "SetScreen: opening window"
If OpenWindow(#Game_Window_Main, *P\Window_X, *P\Window_Y, *P\Window_W, *P\Window_H, *P\Game_Title, *P\Window_Flags)
*P\Window_Open = 1
WindowBounds(#Game_Window_Main, *P\Min_Window_Width, *P\Min_Window_Height, #PB_Default, #PB_Default)
; Sets the limit of how small a window can be resized
If Not *P\Config_File Or *P\Reset_Window ; update window coordinates because there was no config file
*P\Window_X = WindowX(#Game_Window_Main)
*P\Window_Y = WindowY(#Game_Window_Main)
*P\Window_W = WindowWidth(#Game_Window_Main)
*P\Window_H = WindowHeight(#Game_Window_Main)
*P\Reset_Window = 0
EndIf
Else
Debug "SetScreen: could not initialise window"
ProcedureReturn 0
EndIf
Debug "SetScreen: opening window screen"
If OpenWindowedScreen(WindowID(#Game_Window_Main), 0, 0, WindowWidth(#Game_Window_Main), WindowHeight(#Game_Window_Main), #False, 0, 0, *P\Flip_Mode)
*P\Screen_Open = 1
*P\Screen_Active = 1
Else
Debug "SetScreen: could not initialise windowed screen"
ProcedureReturn 0
EndIf
EndIf
ProcedureReturn 1
EndProcedure
Procedure SwitchFullScreen(*P.Game_Parametres_Structure)
; Handles reloading of resources
*P\Full_Screen = 1 - *P\Full_Screen ; toggle full screen
If Not SetScreen(*P)
*P\Fatal_Error_Message = "SetScreen failed"
Fatal_Error(*P)
EndIf
LoadSpriteResources(*P) ; need to reload sprites anytime SetScreen is called
EndProcedure
Procedure SaveScreen(*P.Game_Parametres_Structure)
Protected s.i, d.s, n.s, f.s
s = GrabSprite(#PB_Any, 0, 0, ScreenWidth(), ScreenHeight())
d = FormatDate("%yyyy%mm%dd-%hh%ii%ss", Date())
n = ""
If *P\Last_Screen_Capture_File = d
; add counter to end of date
*P\Last_Screen_Capture_Number = *P\Last_Screen_Capture_Number + 1
n = "-" + Str(*P\Last_Screen_Capture_Number)
Else
; reset the counter because the time has incremented to the next second
*P\Last_Screen_Capture_Number = 0
EndIf
f = *P\Current_Directory + "screen_capture_" + d + n + ".png"
*P\Last_Screen_Capture_File = d
If SaveSprite(s, f, #PB_ImagePlugin_PNG)
Debug "SaveScreen: saved screen_capture_" + d + n + ".png"
Else
Debug "SaveScreen: failed"
EndIf
FreeSprite(s)
EndProcedure
Procedure DoClearScreen(*P.Game_Parametres_Structure)
If Not *P\Full_Screen_Inactive
ClearScreen(*P\Background_Colour)
EndIf
EndProcedure
Procedure DoFlipBuffer(*P.Game_Parametres_Structure)
If Not *P\Full_Screen_Inactive
; don't try and flip an inactive full screen
FlipBuffers()
EndIf
EndProcedure
Procedure Draw3DWorld(*P.Game_Parametres_Structure)
If *P\Render_Engine3D <> #Render_Engine3D_None
Select *P\Render_Engine3D
Case #Render_Engine3D_Builtin
; not written yet
EndSelect
EndIf
EndProcedure
Procedure DisplaySpriteInstance(*P.Game_Parametres_Structure, i.i)
; Sprite instances are all the copies of sprites displayed in a level
; The only limit to how big a level can be is available memory
If *P\Sprite_Resource[*P\Sprite_Instance[i]\Sprite_Resource]\Transparent
DisplayTransparentSprite(*P\Sprite_Instance[i]\Sprite_Resource, *P\Sprite_Instance[i]\X, *P\Sprite_Instance[i]\Y, *P\Sprite_Instance[i]\Intensity)
Else
DisplaySprite(*P\Sprite_Instance[i]\Sprite_Resource, *P\Sprite_Instance[i]\X, *P\Sprite_Instance[i]\Y)
EndIf
EndProcedure
Procedure DisplaySpriteResource(*P.Game_Parametres_Structure, s.i, x.i, y.i, Intensity.i=255)
; Used for manually displaying a sprite
If *P\Sprite_Resource[s]\Transparent
DisplayTransparentSprite(s, x, y, Intensity)
Else
DisplaySprite(s, x, y)
EndIf
EndProcedure
Procedure DrawDebugInfo(*P.Game_Parametres_Structure)
Protected f.s
If *P\Show_Debug_Info
f = "FPS: " + Str(*P\FPS)
DrawingMode(#PB_2DDrawing_Transparent)
DrawText(0, 0, f)
EndIf
EndProcedure
Procedure Draw2DGraphics(*P.Game_Parametres_Structure)
Protected c.i
If Not *P\Full_Screen_Inactive ; don't draw anything if full screen has been alt+tabbed
; *************************************
; menu
; *************************************
StartDrawing(ScreenOutput())
If *P\Menu_Active
; Only draw background and menus when active
; Draw menu background
Select *P\Menu_Background
Case #Menu_Background_None
; nothing to do
Case #Menu_Background_Vector
Case #Menu_Background_Image
EndSelect
EndIf
StopDrawing()
; *************************************
; system
; *************************************
EndIf
EndProcedure
Procedure DrawSprites(*P.Game_Parametres_Structure)
If *P\Sprite_Resource_Count > 0
; Display sprites
StartDrawing(ScreenOutput())
StopDrawing()
EndIf
EndProcedure
Procedure DrawMouse(*P.Game_Parametres_Structure)
If *P\Show_Mouse
If *P\Mouse_Control
; dont show mouse when it's in control (ie first person mouse control)
Else
If *P\Full_Screen
; show the mouse sprite
; no need to show the mouse sprite in window mode when it's not in control of the player
DisplaySpriteResource(*P, *P\Mouse_Sprite_Index, *P\Mouse_X - *P\Mouse_Offset_X, *P\Mouse_Y - *P\Mouse_Offset_Y)
EndIf
EndIf
EndIf
EndProcedure
Procedure DoPostProcessing(*P.Game_Parametres_Structure)
If *P\Take_Screen_Capture
SaveScreen(*P)
*P\Take_Screen_Capture = 0
EndIf
EndProcedure
Procedure CheckFullScreen(*P.Game_Parametres_Structure)
; Manages the full screen in case the user switches back
; to the operating system (ie using alt+tab)
Protected e.i
If *P\Full_Screen_Type = #Full_Screen_Classic
If *P\Full_Screen_Inactive
; process window events for the minimised window
e = WaitWindowEvent(10)
If e = #PB_Event_ActivateWindow
; User has switched back to full screen
Debug "CheckFullScreen: returned to full screen"
CloseWindow(#Game_Window_Full_Screen_Minimised)
; this closes the dummy minimised window that gets
; created to hide the full screen
If Not SetScreen(*P)
*P\Fatal_Error_Message = "SetScreen failed"
Fatal_Error(*P)
EndIf
MouseLocate(*P\Mouse_Save_X, *P\Mouse_Save_Y) ; move the mouse back to the saved location
LoadSpriteResources(*P)
*P\Full_Screen_Inactive = 0
EndIf
Else
; Check if the screen has gone inactive
*P\Screen_Active = IsScreenActive()
If Not *P\Screen_Active And *P\Full_Screen And *P\Full_Screen_Type = #Full_Screen_Classic
; only process IsScreenActive if in full screen
*P\Mouse_Save_X = *P\Mouse_X ; Save the mouse position
*P\Mouse_Save_Y = *P\Mouse_Y
ReleaseMouse(1) ; release the mouse to the OS
CloseScreen()
*P\Screen_Open = 0
*P\Full_Screen_Inactive = 1
OpenWindow(#Game_Window_Full_Screen_Minimised, 1, 1, 1, 1, *P\Game_Title, #PB_Window_Minimize)
Debug "CheckFullScreen: screen inactive, waiting for user to switch back"
EndIf
EndIf
EndIf
EndProcedure
;- Input
Procedure ProcessKeyboard(*P.Game_Parametres_Structure)
Protected c.i
If Not *P\Full_Screen_Inactive
; Disable keyboard when classic full screen inactive
ExamineKeyboard()
; Always process CTRL, SHIFT and ALT pushed commands first
; Process alt commands
If KeyboardPushed(#PB_Key_LeftAlt) Or KeyboardPushed(#PB_Key_RightAlt)
If KeyboardReleased(#PB_Key_Return)
SwitchFullScreen(*P)
EndIf
EndIf
; Process control commands
If KeyboardPushed(#PB_Key_LeftControl) Or KeyboardPushed(#PB_Key_RightControl)
; Process control+shift commands
If KeyboardPushed(#PB_Key_LeftShift) Or KeyboardPushed(#PB_Key_RightShift)
If KeyboardReleased(#PB_Key_R)
If *P\Allow_Restart
Debug "ProcessKeyboard: restarting"
Restart = 1
Else
Debug "ProcessKeyboard: not allowed to restart"
EndIf
EndIf
If KeyboardReleased(#PB_Key_Q)
Debug "ProcessKeyboard: quit"
*P\Quit = 1
EndIf
EndIf
EndIf
; *************************************
; menu
; *************************************
If *P\Menu_Active
; only process menu controls when the menu is active
*P\Menu_Action = #Menu_Action_None
For c = 0 To #Max_Menu_Controls - 1
If *P\Menu_Control[c]\Menu_Control_Hardware_Type = #Control_Hardware_Keyboard
; only check keyboard controls since this is the keyboard handler
If KeyboardReleased(*P\Menu_Control[c]\Menu_Control_ID)
Debug "ProcessKeyboard: menu control " + *P\Menu_Control[c]\Menu_Control_ID + " pressed"
*P\Menu_Action = *P\Menu_Control[c]\Menu_Control_Action
EndIf
EndIf
If *P\Menu_Action <> #Menu_Action_None : Break : EndIf
Next
EndIf
; *************************************
; system
; *************************************
; Process full screen only key commands
; *************************************
If *P\Full_Screen
If KeyboardPushed(#PB_Key_LeftAlt) Or KeyboardPushed(#PB_Key_RightAlt)
If KeyboardReleased(#PB_Key_F4)
If *P\Allow_AltF4_Full_Screen
Debug "ProcessKeyboard: quit by Alt+F4 in fullscreen"
*P\Quit = 1
Else
Debug "ProcessKeyboard: not allowed to quit by Alt+F4 in fullscreen"
EndIf
EndIf
EndIf
Else
; Remove F10 and Alt
CompilerIf #PB_Compiler_OS = #PB_OS_Windows
If KeyboardPushed(#PB_Key_F10) Or KeyboardPushed(#PB_Key_LeftAlt) Or KeyboardPushed(#PB_Key_RightAlt)
keybd_event_(#PB_Key_F9, 0, #KEYEVENTF_KEYUP, 0)
Debug "ProcessKeyboard: F10/Alt key pushed while in Window mode"
EndIf
CompilerEndIf
EndIf
; ************************************************
; Process both full screen and window key commands
; ************************************************
If KeyboardReleased(#PB_Key_F11)
If *P\Allow_Switch_to_Window
; switch between window or full screen
SwitchFullScreen(*P)
Else
Debug "ProcessKeyboard: not allowed to switch between full screen and window"
EndIf
EndIf
If KeyboardReleased(#PB_Key_F12)
If *P\Allow_Screen_Capture
*P\Take_Screen_Capture = 1
Else
Debug "ProcessKeyboard: not allowed to screen capture"
EndIf
EndIf
If KeyboardReleased(#PB_Key_Escape)
Debug "ProcessKeyboard: quit"
*P\Quit = 1
EndIf
EndIf
EndProcedure
Procedure ProcessMouse(*P.Game_Parametres_Structure)
Protected c.i
If Not *P\Full_Screen_Inactive
; only process is there has been a change
If *P\Full_Screen Or *P\Mouse_Control
; Mouse is contained within the screen
ExamineMouse()
*P\Mouse_X = MouseX() * *P\Mouse_Sensitivity_X
*P\Mouse_Y = MouseY() * *P\Mouse_Sensitivity_Y
*P\Mouse_Button_Left = MouseButton(#PB_MouseButton_Left)
*P\Mouse_Button_Middle = MouseButton(#PB_MouseButton_Middle)
*P\Mouse_Button_Right = MouseButton(#PB_MouseButton_Right)
*P\Mouse_Wheel_Movement = MouseWheel()
Else
*P\Mouse_X = WindowMouseX(#Game_Window_Main)
*P\Mouse_Y = WindowMouseY(#Game_Window_Main)
; Window mouse clicks are handled by ProcessWindowEvents
EndIf
EndIf
EndProcedure
;- Events
Procedure ProcessWindowEvents(*P.Game_Parametres_Structure)
Protected Event.i
If Not *P\Full_Screen Or *P\Full_Screen_Type = #Full_Screen_Windowed
; only process window events in a window mode
*P\Mouse_Left_Click = 0 ; Reset the mouse clicks
*P\Mouse_Right_Click = 0
Repeat ; process all events
Event = WindowEvent()
Select Event
Case #PB_Event_Menu
Debug "ProcessWindowEvents: menu event"
Case #PB_Event_DeactivateWindow
Debug "ProcessWindowEvents: window deactivated"
Case #PB_Event_ActivateWindow
Debug "ProcessWindowEvents: window activated"
Case #PB_Event_CloseWindow
*P\Quit = 1
Case #PB_Event_SizeWindow
If GetWindowState(#Game_Window_Main) = #PB_Window_Normal
; ****************************************************
; Only update window variables if it's a normal window
; This is needed for maximise etc to work
If *P\Window_W <> WindowWidth(#Game_Window_Main) Or *P\Window_H <> WindowHeight(#Game_Window_Main)
; Window has actually been resized and not just minimised
*P\Window_W = WindowWidth(#Game_Window_Main)
*P\Window_H = WindowHeight(#Game_Window_Main)
If *P\Window_Ratio_Enable
; Calculate the window height based on the width
*P\Window_H = Round(*P\Window_W * *P\Window_Ratio, #PB_Round_Up)
ResizeWindow(#Game_Window_Main, *P\Window_X, *P\Window_Y, *P\Window_W, *P\Window_H)
EndIf
Debug "ProcessWindowEvents: window resized to " + *P\Window_W + " x " + *P\Window_H
*P\Window_Moved = 1
; Don't close the window and reopen (SetScreen), just reset the window screen
SetWindowScreen(*P)
LoadSpriteResources(*P) ; have to reload sprites after setting a new Window Screen
EndIf
EndIf
Case #PB_Event_MoveWindow
If GetWindowState(#Game_Window_Main) = #PB_Window_Normal ; only change the coordinates if it's a normal window
Debug "ProcessWindowEvents: window moved"
*P\Window_Moved = 1
*P\Window_X = WindowX(#Game_Window_Main)
*P\Window_Y = WindowY(#Game_Window_Main)
EndIf
Case #PB_Event_MaximizeWindow
Debug "ProcessWindowEvents: window maximised"
*P\Window_Maximised = 1
*P\Window_Minimised = 0
SetWindowScreen(*P)
LoadSpriteResources(*P) ; have to reload sprites after setting a new Window Screen
Case #PB_Event_RestoreWindow
*P\Window_Maximised = 0
*P\Window_Minimised = 0
Case #PB_Event_MinimizeWindow
*P\Window_Maximised = 0
*P\Window_Minimised = 1
Case #PB_Event_LeftClick
Debug "ProcessWindowEvents: primary mouse button clicked"
*P\Mouse_Left_Click = 1
Case #PB_Event_RightClick
Debug "ProcessWindowEvents: secondary mouse button clicked"
*P\Mouse_Right_Click = 1
EndSelect
Until Event = 0
EndIf
EndProcedure
;- System
Procedure DoCPUWait(*P.Game_Parametres_Structure)
Protected t.i, d.i
If *P\Flip_Mode = #PB_Screen_NoSynchronization
; Only no sync mode needs CPU wait time
t = ElapsedMilliseconds() - *P\Game_Loop_Start_Time ; length of time the main loop took
d = *P\Main_Loop_Time - t ; Main loop time is usually a fixed frame rate like 60
If d>=0 : Delay(d) : EndIf
EndIf
EndProcedure
Procedure ProcessFPS(*P.Game_Parametres_Structure)
Protected t.i
t = ElapsedMilliseconds() - *P\FPS_Last_Time
If t >= 1000
*P\FPS = *P\FPS_Frame_Count
; reset the timer
*P\FPS_Frame_Count = 0
*P\FPS_Last_Time = ElapsedMilliseconds()
Else
*P\FPS_Frame_Count = *P\FPS_Frame_Count + 1
EndIf
EndProcedure
Procedure ProcessSystem(*P.Game_Parametres_Structure)
*P\Game_Loop_Start_Time = ElapsedMilliseconds()
ProcessFPS(*P)
EndProcedure
Procedure SaveConfig(*P.Game_Parametres_Structure, Level.i=1)
; Never call SaveConfig before LoadConfig
; Save levels: 1 - window settings, 2 - game settings
Protected f.s
f = GetCurrentDirectory() + *P\Game_Config_File
If *P\Config_Loaded ; only save if the config has been loaded
If Level = 1 Or Level = 2
; Create or open the config file
If Not *P\Config_File
; Need to create a new file
Debug "SaveConfig: creating new config file"
If Not CreatePreferences(f)
Debug "SaveConfig: ERROR - unable to create config file"
ProcedureReturn 0
EndIf
*P\Reset_Window = 1 ; reset the window so that it's centred
*P\Config_File = 1 ; config file exists now
Else
; Open the existing config file
If Not OpenPreferences(f)
Debug "SaveConfig: ERROR - unable to open existing config file"
ProcedureReturn 0
EndIf
EndIf
; Window settings are automatically saved when closing the game
; or changing the window (while in window mode)
Debug "SaveConfig: writing window preferences"
PreferenceGroup("Window")
WritePreferenceInteger("Full_Screen", *P\Full_Screen)
WritePreferenceInteger("Window_X", *P\Window_X)
WritePreferenceInteger("Window_Y", *P\Window_Y)
WritePreferenceInteger("Window_W", *P\Window_W)
WritePreferenceInteger("Window_H", *P\Window_H)
WritePreferenceInteger("Window_Maximised", *P\Window_Maximised)
If Level = 2
; write the level 2 settings
; this is usually only run in-game
Debug "SaveConfig: writing graphics preferences"
PreferenceGroup("Graphics")
; WritePreferenceInteger("Flip_Mode", *P\Flip_Mode)
EndIf
ClosePreferences()
ProcedureReturn 1
Else ; invalid config level specified
Debug "SaveConfig: ERROR - invalid config level specified: " + Level
ProcedureReturn 0
EndIf
Else
Debug "SaveConfig: ERROR - cannot save config if it hasn't been loaded yet"
ProcedureReturn 0
EndIf
EndProcedure
Procedure LoadConfig(*P.Game_Parametres_Structure)
; Loads configuration if available and sets defaults when no config is available
; If there is no config file then SaveConfig will be called
Protected f.s
; Layer 1
f = *P\Game_Config_File
If FileSize(f)>0
*P\Config_File = 1 ; config file found
EndIf
Debug "LoadConfig: opening " + *P\Game_Config_File
OpenPreferences(f)
Debug "LoadConfig: loading window preferences from disk storage"
PreferenceGroup("Window")
*P\Full_Screen = ReadPreferenceInteger("Full_Screen", *P\Full_Screen)
*P\Window_X = ReadPreferenceInteger("Window_X", 0)
*P\Window_Y = ReadPreferenceInteger("Window_Y", 0)
*P\Window_W = ReadPreferenceInteger("Window_W", *P\Window_W)
*P\Window_H = ReadPreferenceInteger("Window_H", *P\Window_H)
*P\Window_Maximised = ReadPreferenceInteger("Window_Maximised", 0)
PreferenceGroup("Grapics")
; *P\Flip_Mode = ReadPreferenceInteger("Flip_Mode", #Default_Flip_Mode)
*P\Config_Loaded = 1 ; set this so that SaveConfig can run. It's important to load config before saving
ClosePreferences()
ProcedureReturn 1
EndProcedure
Procedure SetInitialiseError(*P.Game_Parametres_Structure, Message.s)
; Sets a special error message on the first initialisation error encountered, to help troubleshooting
If Not *P\Initialisation_Error
; Only set the error message if there has been no error yet, this helps with troubleshooting so you can see the first error
*P\Initialisation_Error = 1
*P\Initialise_Error_Message = Message
EndIf
EndProcedure
Procedure Initialise(*P.Game_Parametres_Structure)
; Initialises the environment
Protected o.i, Result.i, c.i
Debug "Initialise: starting"
SetDefaults(*P)
CompilerIf #PB_Compiler_OS = #PB_OS_Windows
; Check if game is already running
*P\MutexID = CreateMutex_(0, 1, *P\Game_Title)
*P\MutexError = GetLastError_()
If *P\MutexID = 0 Or *P\MutexError <> 0
ReleaseMutex_(*P\MutexID)
CloseHandle_(*P\MutexID)
Debug "Initialise: " + *P\Game_Title + " is already running, cannot run more than one instance"
SetInitialiseError(*P, *P\Game_Title + " is already running, cannot run more than one instance")
ProcedureReturn 0
EndIf
CompilerEndIf
InitKeyboard()
InitMouse()
UsePNGImageEncoder() ; enable PNG encoding for saving screen captures
UsePNGImageDecoder()
If Not InitDesktop(*P)
Debug "Initialise: could not initialise desktop"
SetInitialiseError(*P, "could not initialise desktop (the operating system graphical display)")
ProcedureReturn 0
EndIf
If *P\Desktop[0]\Depth <> 32
Debug "Initialise: only 32 bit desktop colour depth is supported)"
SetInitialiseError(*P, "only 32 bit desktop colour depth is supported")
ProcedureReturn 0
EndIf
If Not InitSprite()
Debug "Initialise: could not initialise sprite environment"
SetInitialiseError(*P, "could not initialise sprite environment (usually this is a DirectX problem)")
ProcedureReturn 0
EndIf
If Not LoadConfig(*P)
Debug "Initialise: could not load config"
SetInitialiseError(*P, "could not load config")
ProcedureReturn 0
EndIf
SaveConfig(*P, 2) ; always save config on start incase of corrupt file
If Not SetScreen(*P)
Debug "Initialise: could not set screen"
SetInitialiseError(*P, "could not set screen")
ProcedureReturn 0
EndIf
;*****************************************
; Loading screen begin
;*****************************************
ClearScreen(*P\Background_Colour)
FlipBuffers()
If *P\Show_Loading_Screen
ClearScreen(*P\Background_Colour)
StartDrawing(ScreenOutput())
DrawingMode(#PB_2DDrawing_Transparent)
DrawText(0, 0, "Loading...")
StopDrawing()
FlipBuffers()
EndIf
If *P\Render_Engine3D <> #Render_Engine3D_None
; Don't initialise 3D if it is not enabled
Debug "Initialise: 3D engine"
Select *P\Render_Engine3D ; Initialise render engine
Case #Render_Engine3D_Builtin
; not written yet
EndSelect
EndIf
Debug "Initialise: loading menu controls"
Select *P\Menu_System_Type
Case #Menu_System_Menuless
Restore Menu_Controls_MenuLess_Data
Case #Menu_System_Simple
Restore Menu_Controls_Simple_Data
Case #Menu_System_Pointer
Restore Menu_Controls_Pointer_Data
EndSelect
Read.i *P\Menu_Controls_Count
If *P\Menu_Controls_Count > #Max_Menu_Controls
*P\Fatal_Error_Message = "#Max_Menu_Controls too small to load all menu controls"
Fatal_Error(*P)
EndIf
For c = 0 To *P\Menu_Controls_Count - 1
Read.i *P\Menu_Control[c]\Menu_Control_Type
Read.i *P\Menu_Control[c]\Menu_Control_Action
Read.i *P\Menu_Control[c]\Menu_Control_Hardware_Type
Read.i *P\Menu_Control[c]\Menu_Control_ID
Next
LoadSpriteResources(*P)
; Load Menu Background
Select *P\Menu_Background_Data_Source
Case #Data_Source_Internal_Memory
Restore Menu_Background_None_Data
Read.i *P\Menu_Background_Colour
EndSelect
; Elevate control to layer 2 (menu)
*P\Background_Colour = *P\Menu_Background_Colour
*P\Menu_Active = 1
Debug "Initialise: completed"
*P\Initialised = 1
ProcedureReturn 1 ; Initialise successful
EndProcedure
Procedure Shutdown(*P.Game_Parametres_Structure)
If *P\Screen_Open
CloseScreen()
*P\Screen_Open = 0
EndIf
If *P\Window_Open
CloseWindow(0)
*P\Window_Open = 0
EndIf
SaveConfig(*P) ; only need to save screen/window variables
CompilerIf #PB_Compiler_OS = #PB_OS_Windows : CloseHandle_(*P\MutexID) : CompilerEndIf
FreeMemory(*P)
EndProcedure
;- Main loop
Repeat ; used for restarting the game
If Restart : Debug "System: restarting..." : EndIf
Restart = 0 ; game has started so don't restart again
Define *P.Game_Parametres_Structure
*P = AllocateMemory(SizeOf(Game_Parametres_Structure)) ; Allocate game memory
If *P And Initialise(*P)
; Game memory allocated and game initialised
Debug "System: starting main loop"
Repeat
; main game loop
ProcessSystem(*P) ; must be first in the main loop
ProcessWindowEvents(*P)
ProcessMouse(*P)
ProcessKeyboard(*P)
DoFlipBuffer(*P)
DoClearScreen(*P)
Draw3DWorld(*P)
DrawSprites(*P) ; draws all sprites
Draw2DGraphics(*P)
DrawMouse(*P)
DoPostProcessing(*P) ; eg screen capture
CheckFullScreen(*P) ; check for switching back to main window system (alt+tab), must be after FlipBuffers
DoCPUWait(*P) ; limit the CPU usage
Until *P\Quit Or Restart
Debug "System: shutting down..."
Shutdown(*P)
Else
MessageRequester ("Unable to start " + *P\Game_Title, "Could not initialise." + #CRLF$ + *P\Initialise_Error_Message, #PB_MessageRequester_Error)
EndIf
Until Not Restart
Debug "System: game ended"
End 0
;- Data section
DataSection
Menu_Controls_Data:
; First record is the number of records (make sure #Max_Menu_Controls is higher than the largest)
; Data is in the format of the Structure Menu_Control_Type
; menuless system
Menu_Controls_Menuless_Data:
; This menu control system is like the Atari 2600 and is only included for making very simple games
Data.i 3
Data.i #Menu_System_Menuless, #Menu_Action_Start, #Control_Hardware_Keyboard, #PB_Key_Space
Data.i #Menu_System_Menuless, #Menu_Action_Select, #Control_Hardware_Keyboard, #PB_Key_F1
Data.i #Menu_System_Menuless, #Menu_Action_Reset, #Control_Hardware_Keyboard, #PB_Key_F2
; simple menu system
Menu_Controls_Simple_Data:
; This menu system is for making console type games where the menu is controlled by up/down/left/right etc
Data.i 6
Data.i #Menu_System_Simple, #Menu_Action_Confirm, #Control_Hardware_Keyboard, #PB_Key_Return
Data.i #Menu_System_Simple, #Menu_Action_Back, #Control_Hardware_Keyboard, #PB_Key_Escape
Data.i #Menu_System_Simple, #Menu_Action_Up, #Control_Hardware_Keyboard, #PB_Key_Up
Data.i #Menu_System_Simple, #Menu_Action_Down, #Control_Hardware_Keyboard, #PB_Key_Down
Data.i #Menu_System_Simple, #Menu_Action_Left, #Control_Hardware_Keyboard, #PB_Key_Left
Data.i #Menu_System_Simple, #Menu_Action_Right, #Control_Hardware_Keyboard, #PB_Key_Right
; pointer menu system
Menu_Controls_Pointer_Data:
; This menu system is the most common for PC games
Data.i 3
Data.i #Menu_System_Pointer, #Menu_Action_Click, #Control_Hardware_Keyboard, #PB_Key_Return
Data.i #Menu_System_Pointer, #Menu_Action_Click, #Control_Hardware_Keyboard, #PB_Key_Space
Data.i #Menu_System_Pointer, #Menu_Action_Click, #Control_Hardware_Mouse, #PB_MouseButton_Left
Image_Data:
; These are all the 2D images loaded by the system available to the game
Data.i 0 ; Number of records
Sprite_Resource_Data:
; Provides a list of sprite resources to be loaded
; Examples:
; Loading a sprite from internal memory is not yet supported
; Format: Width, Height, Mode, Transparent, Source, Index/file
; From DataSection: Data.i 30, 30, #PB_Sprite_AlphaBlending, #Data_Source_Internal_Memory, 0
; From a file: Data.i 30, 30, 0, #Data_Source_File : Data.s "test.bmp"
; From a database: Data.i 30, 30, 0, #Data_Source_Database, 100
Data.i 2
; Number of records
;Data.i 12, 19, #PB_Sprite_AlphaBlending, #True, #Data_Source_File : Data.s "mouse.png"
Data.i 8, 8, #PB_Sprite_AlphaBlending, #True, #Data_Source_None, 0
; This is the scratch sprite, used for zooming 2D drawing operations when simulating low resolution
Data.i 12, 19, #PB_Sprite_AlphaBlending, #True, #Data_Source_Internal_Memory, 0
; Mouse sprite
Sprite_Data:
; Provides actual sprites in the DataSection
; This can be ignored if necessary but leave the label above as the code needs it to work
Data.l $FF000000,$00000000,$00000000,$00000000,$00000000,$00000000,$00000000,$00000000,$00000000,$00000000,$00000000,$0000F2FF
Data.l $FF000000,$FF000000,$00000000,$00000000,$00000000,$00000000,$00000000,$00000000,$00000000,$00000000,$00000000,$0000F2FF
Data.l $FF000000,$FFFFFFFF,$FF000000,$00000000,$00000000,$00000000,$00000000,$00000000,$00000000,$00000000,$00000000,$0000F2FF
Data.l $FF000000,$FFFFFFFF,$FFFFFFFF,$FF000000,$00000000,$00000000,$00000000,$00000000,$00000000,$00000000,$00000000,$0000F2FF
Data.l $FF000000,$FFFFFFFF,$FFFFFFFF,$FFFFFFFF,$FF000000,$00000000,$00000000,$00000000,$00000000,$00000000,$00000000,$0000F2FF
Data.l $FF000000,$FFFFFFFF,$FFFFFFFF,$FFFFFFFF,$FFFFFFFF,$FF000000,$00000000,$00000000,$00000000,$00000000,$00000000,$0000F2FF
Data.l $FF000000,$FFFFFFFF,$FFFFFFFF,$FFFFFFFF,$FFFFFFFF,$FFFFFFFF,$FF000000,$00000000,$00000000,$00000000,$00000000,$0000F2FF
Data.l $FF000000,$FFFFFFFF,$FFFFFFFF,$FFFFFFFF,$FFFFFFFF,$FFFFFFFF,$FFFFFFFF,$FF000000,$00000000,$00000000,$00000000,$00000000
Data.l $FF000000,$FFFFFFFF,$FFFFFFFF,$FFFFFFFF,$FFFFFFFF,$FFFFFFFF,$FFFFFFFF,$FFFFFFFF,$FF000000,$00000000,$00000000,$00000000
Data.l $FF000000,$FFFFFFFF,$FFFFFFFF,$FFFFFFFF,$FFFFFFFF,$FFFFFFFF,$FFFFFFFF,$FFFFFFFF,$FFFFFFFF,$FF000000,$00000000,$00000000
Data.l $FF000000,$FFFFFFFF,$FFFFFFFF,$FFFFFFFF,$FFFFFFFF,$FFFFFFFF,$FFFFFFFF,$FFFFFFFF,$FFFFFFFF,$FFFFFFFF,$FF000000,$00000000
Data.l $FF000000,$FFFFFFFF,$FFFFFFFF,$FFFFFFFF,$FFFFFFFF,$FFFFFFFF,$FFFFFFFF,$FFFFFFFF,$FFFFFFFF,$FFFFFFFF,$FFFFFFFF,$FF000000
Data.l $FF000000,$FFFFFFFF,$FFFFFFFF,$FFFFFFFF,$FFFFFFFF,$FFFFFFFF,$FFFFFFFF,$FF000000,$FF000000,$FF000000,$FF000000,$FF000000
Data.l $FF000000,$FFFFFFFF,$FFFFFFFF,$FFFFFFFF,$FF000000,$FFFFFFFF,$FFFFFFFF,$FF000000,$00000000,$00000000,$00000000,$00000000
Data.l $FF000000,$FFFFFFFF,$FFFFFFFF,$FF000000,$00000000,$FF000000,$FFFFFFFF,$FFFFFFFF,$FF000000,$00000000,$00000000,$00000000
Data.l $FF000000,$FFFFFFFF,$FF000000,$00000000,$00000000,$FF000000,$FFFFFFFF,$FFFFFFFF,$FF000000,$00000000,$00000000,$00000000
Data.l $FF000000,$FF000000,$00000000,$00000000,$00000000,$00000000,$FF000000,$FFFFFFFF,$FFFFFFFF,$FF000000,$00000000,$0000F2FF
Data.l $00000000,$00000000,$00000000,$00000000,$00000000,$00000000,$FF000000,$FFFFFFFF,$FFFFFFFF,$FF000000,$00000000,$0000F2FF
Data.l $00000000,$00000000,$00000000,$00000000,$00000000,$00000000,$00000000,$FF000000,$FF000000,$00000000,$00000000,$0000F2FF
Menu_Background_Data:
; Data for displaying the menu background
Menu_Background_None_Data:
Data.i 8723235 ; colour to be displayed as background
Menu_Background_Vector_Data:
Menu_Background_Image_Data:
EndDataSection