Code archives/3D Graphics - Misc/Blitz3D Game Framework
This code has been declared by its author to be Public Domain code.
Download source code
| |||||
Yet another game framework - This time for Blitz3D. Similar to the framework I posted for the Blitz3DSDK + Blitzmax, this example provides a basic game object and functions that handle game initialisation and running of the main loop (including built in render tweening). The slick thing about this example is the use of the FastPointer library to make the framework as modular as possible. The example includes a GameComponent type that simply holds a set of function pointers to be called in the main loop - Want something to happen? simply instantiate a new GameComponent object, provide the functions that do the actual work, provide the function pointers and the framework will do the rest. The example does not contain any comments but should still be fairly easy to understand - The code is fairly straight forward and I have declared all variables using descriptive names. Please post any constructive criticism - I would appreciate any help in making this better - In particular if anyone has any ideas how to implement a system for controlling GameComponent state e.g. The ability to make one component active/inactive from another. I'm not sure how to handle this at the moment due to the way Blitz3D types work. I'm probably overlooking something simple. ## Important Requires the (free) FastPointer library to implement the function callback mechanism. the FastPointer library can be downloaded from http://fastlibs.com/ If you do not have this userlib installed you will get the famous "userlib not found" error message when attempting to run this example. ## Important | |||||
Type TGame Field Timer.TGameTime Field FramesPerSecond% Field AnimationSpeed# Field Components.TGameComponent Field IsRunning% Field GraphicsMode.TGraphicsMode Field WindowMode% End Type Const GFXMODE_FULLSCREEN = 1 Const GFXMODE_WINDOWED = 2 Function CreateGame.TGame(gfx.TGraphicsMode,title$,windowMode=GFXMODE_WINDOWED,FPS%=60) AppTitle title HidePointer() Graphics3D(gfx\Width,gfx\Height,gfx\Depth,windowMode) SetBuffer(BackBuffer()) Local G.TGame = New TGame G\GraphicsMode = gfx G\WindowMode = windowMode G\FramesPerSecond = FPS G\AnimationSpeed = 1 G\Timer = CreateGameTime(FPS) Return G End Function Function RunGame(game.TGame) Local i ; Initialise game components -------------------------------------- For game\Components = Each TGameComponent CallFunction(game\Components\Initialise) Next ; Start the main game loop ---------------------------------------- game\IsRunning = True While game\IsRunning = True UpdateGameTime(game\Timer) For i=1 To game\Timer\Ticks UpdateFrameTime(game\Timer) If i=game\Timer\Ticks Then CaptureWorld() End If For game\Components = Each TGameComponent CallFunction(game\Components\Update) Next UpdateWorld(game\AnimationSpeed) Next RenderWorld(game\Timer\Tween) UpdateRemainingTime(game\Timer) If game\Timer\RemainingTime > 1 Then Delay (game\Timer\RemainingTime-1) End If For game\Components = Each TGameComponent CallFunction(game\Components\Draw) Next VWait Flip(False) Wend ; Dispose game components ---------------------------------------- For game\Components = Each TGameComponent CallFunction(game\Components\Dispose) Next End Function Function DisposeGame(game.TGame) Delete(game\Timer) For game\Components = Each TGameComponent Delete game\Components Next Delete(game) ClearWorld() End End Function ;------------------------------------------------------------------------- Type TGameTime Field Period% Field FrameTime% Field StartTime% Field ElapsedTime% Field Ticks% Field Tween# Field RemainingTime% End Type Function CreateGameTime.TGameTime(FPS%=60) Local t.TGameTime = New TGameTime t\Period = 1000 / FPS t\FrameTime = MilliSecs() - t\Period Return t End Function Function UpdateGameTime(GT.TGameTime) GT\StartTime = MilliSecs() GT\ElapsedTime = MilliSecs() - GT\FrameTime GT\Ticks = (GT\ElapsedTime) / (GT\Period) GT\Tween = Float(GT\ElapsedTime Mod GT\Period) / Float(GT\Period) End Function Function UpdateFrameTime(GT.TGameTime) GT\FrameTime = GT\FrameTime + GT\Period End Function Function UpdateRemainingTime(GT.TGameTime) GT\RemainingTime = GT\Period - (MilliSecs() - GT\StartTime) End Function ;------------------------------------------------------------------------- Type TGameComponent Field Initialise Field Update Field Draw Field Dispose End Type ;------------------------------------------------------------------------- Type TGraphicsMode Field Width Field Height Field Depth End Type ;------------------------------------------------------------------------- ; Main program Const KEY_ESCAPE = 1 Const KEY_ENTER = 28 Global gfxMode.TGraphicsMode = New TGraphicsMode gfxMode\Width = 800 gfxMode\Height = 600 gfxMode\Depth = 32 Global ExampleGame.TGame = CreateGame(gfxMode,"Game Framework Demo") Global cam = CreateCamera() Global Cube = CreateCube() Global Light = CreateLight() CreateSpinningCubeComponent(ExampleGame) CreatecolorChangerComponent(ExampleGame) RunGame(ExampleGame) DisposeGame(ExampleGame) ;------------------------------------------------------------------------- ; Spinning cube component Function CreateSpinningCubeComponent(g.TGame) g\Components = New TGameComponent g\Components\Initialise = FunctionPointer() Goto skipInitialise initialiseSpinningCube() .skipInitialise g\Components\Update = FunctionPointer() Goto skipUpdate UpdateSpinningCube() .skipUpdate g\Components\Draw = FunctionPointer() Goto skipDraw DrawSpinningCube() .skipDraw g\Components\Dispose = FunctionPointer() Goto SkipDispose DisposeSpinningCube() .SkipDispose End Function Function initialiseSpinningCube() CameraClsColor(cam,100,149,237) PositionEntity(Cube,0,0,5) End Function Function UpdateSpinningCube() If KeyHit(KEY_ESCAPE) Then ExampleGame\IsRunning = False TurnEntity(Cube,0.1,0.2,0.3) End Function Function DrawSpinningCube() Text(10,10,"Cube Spinner Component Loaded.") End Function Function DisposeSpinningCube() FreeEntity(Cube) FreeEntity(Light) End Function ;------------------------------------------------------------------------- ; Color changer component. Function CreatecolorChangerComponent(g.TGame) Local C.TGameComponent = New TGameComponent C\Initialise = FunctionPointer() Goto skipInitialise initialiseColorChanger() .skipInitialise C\Update = FunctionPointer() Goto skipUpdate UpdateColorChanger() .skipUpdate C\Draw = FunctionPointer() Goto skipDraw DrawColorChanger() .skipDraw g\Components = C End Function Function initialiseColorChanger() SeedRnd(MilliSecs()) EntityColor(Cube,Rand(0,255),Rand(0,255),Rand(0,255)) End Function Function UpdateColorChanger() If KeyHit(KEY_ENTER) EntityColor(Cube,Rand(0,255),Rand(0,255),Rand(0,255)) End Function Function DrawColorChanger() Text(10,20,"Cube color changer component loaded") End Function |
Comments
| ||
interesting! i've thinking a way to improve the clasic Case struct we tend to use to implement a state machine for the "Components" behavior, but till FuntionPoninter apear to life i didn't found a good way to implement it. The idea is at first the same your are using. A simple call to a function via pointer no mather wich funtion is in fact called. So as the call uses a variable, the same call can call diferents functions, in my planning : a case with out cases: when a component's state is to be moved to another state it simply change the pointer to a function that defines the new state, in place to change the variable that controls the case struct. i know that my post dont answer your request but seems to me that a framework to implement a case using poninter should complement your work. to control a Component from another one in a general way there should be a general function to search for a particular kind of Component and for that component a do a call to a Particular function Behavior or StateChange or Control (the name is not relvant). So only certain Components (ID, Group or all of them) receive the command. I should add a field ID and a field Group when created, the ID field should be initialized: g\ID = Handle(g) ;and returned by the function g\Group = group (should be a parameter pased to the fun that creates the component) function CreateComponentBla(g.TGame, Group=0) g.TGameComponent = new TGameComponent g\ID = Handle(g) g\Group = Group ;rest of creation code return g\ID end function global C1 = CreateComponentBla(ExampleGame,1) ; Group=1 having C1 equals a handle, then you could: c.TGameComponent = Object.TGameComponent(C1) (Both Handle and Object are vastly used but Undocumented!) in this way you get the instance of the object with out to do a search for each object in the list! I use a general Control(Type, ID, Action, Value) function Type says the kind of object to act on (in this case always TGameComponent), ID should be 0 for all, a negative number (the minus Group) to act on a group and a positive one to go stright to the object. When I reach the one or the ones i do a call to a function based on Action and pas Value to that function. some thing like: function Control(ID, Action, Value) if sgn(ID) then c.TGameComponent = Object.TGameComponent(ID) Select Action Case 1 call c\Wathever(Value) Case 2 .... End Select else for c.TGameComponent = each TGameComponent If ID=0 Or ((Sgn(ID)=-1) And (c\Group = Abs(ID)) )Then ;call all if ID=0 or only who's group is indicated ;you have to pass a -Group to act on a group! Select Action Case 1 call c\Wathever(Value) Case 2 .... End Select end if next end if end function so if you do Control(0,1,5) ;you call Function Case 1 with value 5 to all the components. Control(-2,3,True) ; you call to all the components of the group 2, with the function case 3 with value True but if you call: Control(C1,2,-3) : you only control one component: the component ho's ID you have stored in C1 hope i expresed my self, my english is not so good! sorry Juan |
Code Archives Forum