Generic OO Blitz Game Engine Core...

Miscellaneous Forums/General Discussion/Generic OO Blitz Game Engine Core...

ok... the other thread was getting a lil long in the tooth... so here we go, as tasked by a few in the last discussion, lets do what some think is the impossible...


lets make a core Blitz3D OO game engine from scratch... in a day or two... and lets talk about it as we do it... sort of a prep for the real 3D OOP thinking that is ahead for many of us with BMAX3D...

this is gonna be short... or it should be, anyway... with the goals here being...

1- to show how simple an Object Oriented methodlogy, while not fully OO compliant, can be implemented in a non OO language such as Blitz...

2- to demonstrate how it will make planning and organizing, as well as maintainence (even though we are gonna keep it simple and not implement any sort of inheritance) of project code a much more streamlined endeavor, by affording the developer a means of modularizing his/her code into objects and their related methods...

3- implement a generic kind of encapsulation methodology, where all of an objects data resides in the class definition and is used inside the scope of the member functions, as an further step in code modularization...

4- attempt to implement some sort of polymorphism, no promises though...

5- KISS... keep it simple... if it starts getting to obtuse, if it starts requiring that you put more into it to enforce its OOness, well, then i've failed...

ok... that's it... lets move to step one... the thinking about it all... this is where most projects fail without ever realizing it... this is more true when coding OO...

just what is a game engine anyway... well, contrary to what some people here, who shall remain nameless think (octothorpe being one of em), Blitz3D despite its entity system does not qualify as one... by itself, there is no initial setup, nor is there a graphics rendering or logic processing pipeline... this is the barest definiton of a game engine as far as i see it... so this is what i'm gonna shoot for...

the core of this lil OO game engine will initialize itself, with awareness of the environment it is running in, and then spin off into a main loop to provide the pipeline for graphics and logic rendering... period... nothing more, nothing less (hopefully)...

and, for this to be of any real use though, there must be a methodology for extending it so that it can accept additional functionality (other than just sitting there spinning its main loop)... so i will make it so that it is extendable... some way or the other... so that any sort of 3D game can be made with it... this will be able to serve as the foundation for your next game... maybe :)

ok... goals defined... thought completed... comments and/or suggestions welcome and accepted while i hack this thing out... better be quick though... i type slow when putting thoughts to paper, but i type fast when laying down code logic :)


--Mike

I'll be interested to see the final thing. Get to it.

ok... here's the first part... it is based on all the design goals mentioned above...
the key class (TYPE) is the tGame class, which is the heart of the game engine...

it contains members from a few additional classes, tSystemSettings, tDisplaySettings,
and tGameObject... additional classes which are closely related to, and are essential to
the functioning of tGame...

;---------------------------------------------------------------------------------------------------
;
;                				Blitz3D Object Oriented Game Engine 
;	
;				a simple, easy to implement, generic framework for developing games in Blitz3D
;				         utilizing an Object Oriented development methodology 
;			     		
;            
;		                   				by Michael Hense 
;---------------------------------------------------------------------------------------------------
;

;---------------------------------------------------------------------------------------------------
;
;									tGame Global Declarations 
;
;           	 tGame and all the classes directly related to tGame are declared here
;
;---------------------------------------------------------------------------------------------------
;
;
;												some globals and constants
Const WINDOWED=0
Const FULLSCREEN_ALWAYS=1
Const WINDOWED_ALWAYS=2
Const WINDOWED_SCALED_ALWAYS=3

Const YES=1
Const NO=0


;												the tGame engine class 
Type tGame
  Field title$
  Field display.tDisplaySettings
  Field system.tSystemSettings
  Field player.tGameObject
  Field view.tGameObject
  Field objCount
End Type


;												the system settings class
Type tSystemSettings
  Field FrameRate
  Field HomeDir$
  Field WinDir$
  Field TempDir$
  Field Time$
  Field Date$
End Type

;												the display settings class
Type tDisplaySettings
  Field Mode
  Field Width
  Field Height
  Field Depth
End Type

;												the Game Object class
Type tGameObject
  Field objID
  Field class$
  Field hEntity
  Field name$
End Type


for brevity sake, tSystemSettings and tDisplaySettings don't do much at this point, but if this thing works,
i will move the code for these to their own source files (which should be done for all classes) and add methods to them
that will allow the game engine to query the environment for information and to initially set the
optimum graphic mode for the engine to start out in...

so far each class (TYPE) has members for all that i see right now that a game engine might need... and right
now, this should be enough to represent a usefull OO game engine...

the tGameObject class is worth taking note of... this and the tGame class comprise the real core of the
engine, as i see it... more on this later...

also, look at the tGame class... you'll see that there exists two tGameObjects as members of the class... i
reason that every 3d game must have a player and a view into the 3D world, so i made these directly linked
to the core of the engine... i dunno, right now it sounds logical :)

the implementation code for these classes will follow shortly... i think i'll make a Create() method (Function)
for each class as their constructor first... then the player and game object classes need to be
implemented, so that a quick validation of the concept can be made with a running example...

if that works, then i move on... if not, then the naysayers are right and they win... more in a few
minutes as i flesh out this thing in my head...

in the meantime... comments and or suggestions... and make it fast... the next bit of code is being typed as you
read this...

--Mike

T + 30 minutes or so...

you guys are taking too long to comment... either noone is really interested, or you're all on tea break or something :)

anyways... here's the constructor method and the run method for tGame... just add it below the code above
(everything is copy and paste ready to run in Blitz3D)


;----------------------------------------------------------------------------------------------------
;
;										tGame Implementation 
;
;							all the methods to support tGame class go here
;
;----------------------------------------------------------------------------------------------------


;--------------------------------------------------------------------------- tGame CreateGame method
;
Function CreateGame.tGame(title$)
  this.tGame=New tGame
  this\title$=title$
  this\system.tSystemSettings=New tSystemSettings
  this\display.tDisplaySettings=New tDisplaySettings
  this\display\Width=1024
  this\display\Height=768
  this\display\Depth=32
  this\display\Mode=WINDOWED
  this\system\frameRate=70
  Return this
End Function 



;--------------------------------------------------------------------------------- tGame Run method
;
Function Run.tGame(this.tGame)
   Graphics3D this\Display\Width,this\Display\Height,this\Display\Depth,this\Display\mode

level=LoadMesh("c:\program files\gile[s]\lightmaps\cathedral\cathedral.b3d")

   SetBuffer BackBuffer()
   WBuffer enable

   Dither enable
   AntiAlias enable
   ;------------------------------------------------- create the game timer 
   ;
   GameTimer=CreateTimer(this\System\frameRate)		
   AntiAlias True
   AppTitle this\title,"Are You Sure?"
   ;------------------------------------------------- create default game PLAYER object
   ;
   newPlayer.tGameObject=CreateGameObject(this,"PLAYER","")

   ;------------------------------------------------- create default game VIEW object
   ;
   newView.tGameObject=CreateGameObject(this,"VIEW","")

   attachViewToPlayer(this)


  ;----------------------------------- main loop starts here
  ;      
  ;                    				   the game timer controls the speed of the logic
  ;                   				   and is separate from the video refresh timing
  ;
  Repeat
    FPS=WaitTimer(GameTimer)			
    For k=1 To FPS

   ;------------------------------------ continually call each objects update() method here
   ;
   ;														[[[ NOTE ]]]
   ;
   ;							         add a new case select for each new class in the game
   ;									 so that its update() method can be called by the main
   ;									 loop
   ;
	For  obj.tGameObject=Each tGameObject
	  Select obj\class
	    Case "PLAYER"
	      UpdatePlayer(obj)

      End Select
	
	Next

  Next

  ;------------------------------------ keyboard handler code goes here 
  ;             
  ;          				   the game  must contain a HandleKeyboardInput() function to 
  ;                			   handle any keyboard input while the game is running
  ;          
  ;;;;;;;;HandleKeyboardInput()

  ;------------------------------------------ update the scene
  ;                                               
  UpdateWorld
  RenderWorld

  ;---------------------------- any text displays and all non game logic goes here 
  ;          
  ;;;;;;;;;;updateTextDisplay()
  ;

  ;----------------------------------------- video refresh   
  ;
   VWait:Flip False
  ;
  ;

Until KeyHit(1) 
End Function


ok, what we've got here is the Create() method for tGame... which initializes the game engine and instantiates the
system and display members (instances of SystemSettings and tDisplaySettings)... these will be responsible for providing
queries as to get info about the users system and logic which uses that info to set preliminary directory layout to the engine, and to set
the initial graphics mode... for brevity sake, these are hard coded right now, so i can get a test up and running...

we also have the Run() method for tGame coded... it will actually start the game running and provide a game loop...
as you can see, the default view and player are instantiated here... plus, i've cheated a lil... i've added a line of code to load a mesh so that there will be something to see for the test... this you won't do when the engine is up and completed...

seems a lil verbose right now, as we are coding the very workings of the game engine... and some of it seems useless
and might not make sense... but, as we progress, the workload will be come less intensive, and the design logic behind it will become a lot clearer...

after all, that's the whole point of this excercise... right...



--Mike

This article might interest you Red:
Faked Object-Oriented Programming (B3D Tutorial)

T + 60 minutes since inception... and where is octothorpe or halo :)

ok... almost at the point where i can test this out to see if i'm really crazy, or just a lil nuts... i've added a few more methods that are essential to the game engine operation... the core of the engine is almost basically done... or at least i think it is...

;-------------------------------------------------------------------- tGame AttachViewToPlayer method
;
Function AttachViewToPlayer(this.tGame)
	EntityParent this\View\hEntity, this\Player\hEntity
End Function

;-------------------------------------------------------------------------- tGame UpdatePlayer method
;
Function UpdatePlayer(this.tGameObject)
   If GetParent(this\hEntity)=0
     If KeyDown(200) 
       MoveEntity this\hEntity,0,0,1
     End If
     If KeyDown(208) 
       MoveEntity this\hEntity,0,0,-1
     End If 
   EndIf     

End Function


;----------------------------------------------------------------------------------------------------
;
;										tGameObject Implementation 
;
;							all the methods to support tGameObject class 
;
;----------------------------------------------------------------------------------------------------


;---------------------------------------------------------------- tGameObject CreateGameObject method
;
Function createGameObject.tGameObject(theGame.tGame, Class$, FileName$)
    this.tGameObject=New tGameObject
	this\Class=class$
	this\objID=theGame\objCount
	theGame\objCount=theGame\objCount+1
	If FileName$<>"" Then this\hEntity=LoadAnimMesh(FileName$)
	If class="PLAYER" 
	  this\hEntity=CreateCube()
	  ;--------------------------------- link to default game player
	  ;
	  theGame\Player=this
	EndIf
	If class="VIEW" 
	  this\hEntity=CreateCamera()
	  ;--------------------------------- link to default game view
	  ;
	  theGame\View=this
	EndIf
	Return this
End Function


the most important method implemented here is the CreateGameObject() method... in my vision, every 'object' that the game engine will manage needs to have certain member properties (fields) to identify it properly to the engine... this is where the power of the engine lies... the Class$ and hEntity fields are gonna serve to determine the which update function is called in the run main loop... thus providing a mechanism to have your objects, and thus, the game actually do something...

again, View and Player are directly linked to tGame... so special coding is provided to 'force' this association... it will not be necessary to do this for all subsequent class instances... at least i hope not :)

even though View and Player are special objects, they are still tGameObject types, and will require the all important Update() function, as will as future classes that you implement... i've added a very generic update method to the player class... just to get this up and running...

and i also added an AttachViewToPlayer method... a concept that considers the View a game object that always has a parent... either the player or another game object...

while we're on this topic, lets talk a bit more about the Player... some people will think of the player as being the little gnome that you see running around the level of a game... IT IS NOT... the Player is a sort of abstract object, as it has no physical presence in the game itself... the Player needs to have a control object which represents it in a game... either a lil character actor, a car, a ship, whatever... more on this later as well, as i'm sorta anxious to see if all this stuff is gonna work or not...

just copy and past this code to the bottom of what's above... and save it all as whatever you wanna call your engine... B3DOOGameEngine.bb is fine...

now we can test...

--Mike

Just making sure you noticed my post squeezed between your gigantic posts.

     If KeyDown(<b>200</b>) 
       MoveEntity this\hEntity,0,0,1
     End If
     If KeyDown(<b>208</b>) 
       MoveEntity this\hEntity,0,0,-1
     End If 


Say uhm, I don't want to drop a tirt in your swimmingpool but what about 2-player-games-on-one-keyboard where player2 uses A D W S (or any config'ed keys!) to move his player? :P

T plus two hours from incept...

and i'm starting to feel like i'm talking to myself... no comments or snide remarks from the naysayers yet... i'm dissapointed... anyways, i ran it and it looks like it works... the concept appears valid, so far...


ok, you try... lets say i'm Joe Blow developer... and i wanna use this game engine source as a jump start to my next game... which i wanna code in a OO manner...

first thing i do is open a new file in the Blitz ide and the first line of code includes B3DOOGameEngine.bb...

next i create an instance of the tGame

then i run it... like this...

Include "../samples/OBGameEngine.bb"


myGame.tGame=createGame("Invaders")

run(myGame)


whew... it actually works... the only thing that the player can do now is move forward and backwards with the arrow keys... a default behavior for the player, that will be expanded upon, if the player has no control object associated to it... but this does show that something like this is doable... and easily so...

now, even at this point you can add new classes and create new objects and define their behaviors... and have it all work in this minimal OO engine...

and you never have to touch the engine code again... with the key exception of adding a select clause for each class you need the game to update in the tGame Run method... all you need to concentrate on now is your objects... design the classes, implement the behaviors in the Update() method, and they will magically do what they're supposed to in the game...

i'll expound on this a bit more later... after i've looked over the code... maybe add it to the archives for anyone interested... if it can actually do something more than simply open a 3D window and put up a camera...

hey... try adding your own classes and objects the way i just did, and lemme know if this is really viable... or just some wierdness i cooked up from having to much caffeine and sugar pastries this morning...

comments and suggestions welcome...

thanks for your consideration...

--Mike

@ CS...
Say uhm, I don't want to drop a tirt in your swimmingpool but what about 2-player-games-on-one-keyboard where player2 uses A D W S (or any config'ed keys!) to move his player? :P

no tirts allowed in my pool CS... simply instantiate a new tGameObject instance and name it's class as anything but PLAYER... name it PLAYER2 class... ( i guess i should've called the class field subclass... easy enough to change)...

then give it the functionality player2 requires... there should be no problemos... i even envision network clients being added in much the same way farther down the line...

you can even expand the functionality of the view 'subclass' to have each player own half the screen...

hey thanks for asking this... subClass does seem like a better field description, as each tGameObject will have an entry in the subClass field to identify it's actually functional class...



--Mike

uh w8 w8, are you saying you'll create a new playerclass just for player 2 ?

I'd stick to one class for the 'generic' player, and attach a controls-field to it, some link to some bank or whatever where you can readout the key-config for any player-instance.

Said simpler: each player has a link to some look-up table with key-config.

no... that's not what i'm saying...

that would be the immediate approach, and not really OO compliant thinking... remember what i said in the old
thread about thinking out a solution in OO terms before rushing to code it...

hear me out for a second...

first, the point you brought was better than i first thought... the concept of each new object being an instance of tGameObject
didn't go far enough... while it is still valid, it needs to take into acount that each new tGameObject will also be a sort of sub class,
identified by the class member field (which i will change the name to subClass) in TGameObject...

so you would simply add a new a new tGameObject, and then in its Create() method, i would assign the sub class name... "PLAYER2"
to it's class field (the second arg)...

now it can live in the engine as a tGameObject:PLAYER2 object...

wait a second... lemme see if this works...


*** added***

ok... it works... again for each 'subclass' of tGameObject you need to...

1- write an update method (function) for it
2- add a select clause that points to it's update method via its class field, so that the engine is aware of it...

look at the new code for myGame that adds this second player...
Include "../samples/OBGameEngine.bb"

myGame.tGame=createGame("Invaders")
player2.tGameObject=createGameObject(myGame,"PLAYER2","")
run(myGame)

and the added code to implement the new subclasses update functionality (right now all it does is initialize it)...
;----------------------------------------------------------------------tGameObject Player2 Update method
;
Function UpdatePlayer2(this.tGameObject)
     ;-------------------------------------- initialize the new subclass object here
     If begin=0
      this\hEntity=CreateCube()
      HideEntity this\hEntity
      begin=1
     Else
                ;--------------------------- normal game logic processing goes  here...
     EndIf
    
End Function

as you can start to see, all the functionality for Player2 is in one spot and can be coded and maintain all in one spot...
and the engine will make sure it is taken care of...

and the only revision needed to the core game engine code would be the addition of the new select clause in the run method... as is mentioned in the code comments for that section... and removing that select clause if the function is not defined in the next game you make... this is a must do for all new subclasses of tGameObject...

ok... it looks like this...
	Case "PLAYER2"
	      UpdatePlayer2(obj)


now that whole update section of code looks like this...
   ;------------------------------------ continually call each objects update() method here
   ;
   ;														[[[ NOTE ]]]
   ;
   ;							         add a new case select for each new class in the game
   ;									 so that its update() method can be called by the main
   ;									 loop
   ;
	For  obj.tGameObject=Each tGameObject
	  Select obj\class
	    Case "PLAYER"
	      UpdatePlayer(obj)
		Case "PLAYER2"
	      UpdatePlayer2(obj)

      End Select
	
	Next


so, now to sum things up... we've created a new subclass for tGameObject, added its update function, and made teh engine aware of it...

this is the simple process that will be repeated when a new object is added to the game...

simple eh... well organized, everything is right where you expect it to be... encapsulated, with no globals all over the place...
the beginnings of an object oriented framework...

yes... no...



--Mike

@ GoSsE...

sorry... i was on a roll there :) yeah, i saw your post, i'll take a look at it now...

i read through Frank Taylor's tutorial a while back, and while elegant and more complete than this lil thing i just whipped up, i had to agree a bit with halo's assessment of it being more trouble than it's worth...

... just enforcing the OO doctrines laid out there would cause a migrane... i'm primarily looking at an interim solution until BMax3 comes out for encapsulation and organizing code functionality for when projects start growing beyond a single page of source... this allows me to modularize the code into discrete source modules that only deal with a specific functionality, thereby making it easier to code, debug, and maintain.

*** added***

hey, this is cool... i took a slightly different approach, with no globals and no hard coded constants as far as the objects are concerned... i think this allows a more free form OO implementation, as there are only a few rules to remember... every new object is a tGameObject, and its functionality is implemented by the mechanism that links its class (soon to be subClass) field to its update function... of which all subclasses of tGameObject must have...

and that's all there is to it... from this, anybody could simply include the game engine source at the top of their project, and start making a game using objects in a lightweight, but still OO way...

i envision new subclasses like GAMELOGIC, MULTIPLAYERCLIENT, ACTOR, AI ACTOR, AI ENEMY, etc being added and working within this lil framework thingee...

i'm gonna take a break right now, but later i'll expand the tSystemSetings and tDisplaySettings classes, and do a general clean up... please comment and add suggestions...

oh... i almost forgot... octothorpe, are you still convinced that this wouldn't work... are you still convinced that i don't know what i'm talking about :P


--Mike

well I only use Blitz PLus so I can't comment properly on the 3D aspects, but the fake OOP is how I had to make my games. I prefer real oop anyway, so I'll be moving to Max soon.

there is no such thing as fake OOP GA... you either think and code in OO terms or you don't...

some languages either promote strict adherence to the OO paradigm, or they don't...

it's how you approach your development that counts in the end... OO is merely the goal...

... or not.

--Mike

I'd contribute, but there's no way to use true OO code in Blitz3D, so, basically, this has already failed.

there is no such thing as fake OOP GA
Well I mean because you can't have object.method you have to have a function called ObjectMethod. And you can't inherit so polymorphism has to be hacked. You end up having to make very similar functions to handle similar objects instead of having one function that handles a variety of objects. Or you make one SUPER object with all possible fields you'd want to use and make everything in your game one of these. Only inevitably you'll end up having to put some Select Case statements in your "generic" functions to handle the different behaviours OR call different "generic" functions depending on the sub-type of your SUPER object. That's a bit rubbish really imho. I had to do all that in BPlus.

Hm dunno about all that special player2 stuff. I wouldn't ever do it like that. When assuming that player 1 and player 2 are essentially the same players (technically), just different gamers controlling it, I'd stick to one playerclass forever.
The select-case thing could work to divide between:
- players
- enemy
- npc
- boss
- map-event

etc. (tho I would do it differently anyway :P)

Sofar, I still don't see any harm in using a lookup to make the differences between player 1 and player 2. The simple reason is: perhaps we'll do more players? Whatyagonnado then? Add UpdatePlayer3(), UpdatePlayer4() etc. ? What if the number of players is dynamic? What if suddenly 48 players are playing? UpdatePlayer48() ?

My idea of an RPG setup:

Game object
- maps
- entities

map object
- map reference
- location
- list or array with maps
- imagedata reference
- event-data reference
- action-data reference

entity object
- name
- controller (user|computer)
- xy location
- keyboardshortcuts reference
- text-data reference
- image-data reference
- event-data reference
- action-data reference


Something like this. The *only* thing you ever need to do is (1) create a core game object, (2) add maps and entities, (3) add scripts/data to maps and entities. The rest runs automagically. For this you don't even need OO perse, other than for datahiding.
I'm more affraid of the amount of data in a project than of not being able to inherit orso. Like I said in the other big topic: Inheritence is *imho* slightly overrated. Again the modular-synth refernce: I prefer to connect flat objects to eachother. But that's all a style o' coding.. plenty o' ppz wouldn't agree. :)

@ CS...
When assuming that player 1 and player 2 are essentially the same players (technically), just different gamers controlling it, I'd stick to one playerclass forever.

this assumption is faulty... and based on incorrect premises...

1- player2 is not from the same subclaass as the default player, and thus does not share the linkage to tGame that the initial player does... the implications of this will become apparent further down the line... a tGame has one and only one default player... and one and only one default view... due to what was stated previously, every game will most likely have at least one player and one view... so it is included as part of the engine... but that doesn't restrict you from adding additional players... just give them a different subclass name...

2- the Player is not a separate class from Player2... all objects in a game belong to the tGameObject class... the PLAYER is a separate subClass from Player2, and they need to be for the reasons just given... that is the only reason to make an additional player subclass, to accomodate another player in the same game...

your idea of a rpg game above is fine, but it is not OO in nature... as i see it you've got the game engine tied to closely to the type of game you are making... in your design, how would i make a game with no map...

do you see any hard references to a map in irrlicht, or any generic game engine... the game engine only needs to know what is necessary to get itself instatiated... and at is basic form, this only requires it to be able to know where on the users hard drive it is, what type of video is there, how much memory is available, and possibly where the win and temp directories are located...

the Map and others stuff are best implemented as separate subclasses classes... and generic enough to allow you to reuse the subclasses in subsequent games...

Something like this. The *only* thing you ever need to do is (1) create a core game object,

you're not looking at the big picture... you're trying to cram too much in at once... and this will bite you in the long run... KISS is the rule here... keep each functional component discrete... your approach would have you creating a new game engine for each new game you make... you can make a rpg with my engine design, as well as a fps, a simulation, a chess game, even a racing game... i'm not saying that my idea is the only solution... i am saying though, that yours is only a partial attempt at an OO design... there no real encapsulation, and no real code reuse...

perhaps we'll do more players? Whatyagonnado then? Add UpdatePlayer3(), UpdatePlayer4() etc. ?

of course not... PLAYER2 is just the name i gave to the subclass... i could've easily called it AUXPLAYER, and thus could have as many as memory allows... and each one could have different keyboard assignments via the \obj instance passed in the update function...

that's the whole point of creating sub classes... the pseudo polymorphhism is implemented in this way...

you just don't see it yet...

@ GA...
And you can't inherit so polymorphism has to be hacked. You end up having to make very similar functions to handle similar objects instead of having one function that handles a variety of objects.

wrong... as stated above, there is no inheritance, per say... only a single sub layer of functionality that i would only term a rudimentary form of inheritance... all tGameObjects 'inherit' if you like, the same update function, which, can handle all instances of the same subclass of tGameObject... no matter how many you choose to instantiate... you could have 20 Player2 objects, each calling the same Player2 update function, only differentiated by their \obj arg in the Update function...

regardless of how you want to look at this, it is still OO in nature, providing a rudimentary form of inheritance like qualities, and a rudimentary form of polymorphism by what i just explained to CS directly above...

the OO nature is real... the adherance to strict OOP is lacking, but that doesn't mean it's not OO...

@ Noel...
i just saw your reply... true OO code, theres no such thing... that's just like saying you can't implement OO in c... which is already a well known falsehood... you are confusing OO with OOP, Object Oriented Programming compliant languages... where strict adherance is the goal...

and if you think it already has failed, copy and paste the code, and see how easy it is to create an object...

... or a game with the engine as it is in it's early state.

--Mike

and if you think it already has failed, copy and paste the code, and see how easy it is to create an object...


Can't. I don't have a B3D license anymore. Buy me one and I'd help ;)

ok... will do... ahhhh, wait a sec... i already spent that money on vanilla wafers... sorrrrrrrrrryyyyyy...

--Mike

I settled with the following conclusion:

-I will use BlitzMax, because it has VERY good interaction with external libs.

-I will use types, because I like the "." separator.

-I am not going to bother with this "generic class" nonsense, and will make very conservative use of inheritance and methods.

whatever works for you... as for me, i'm gonna make a game with this... just to see if it really is usefull... if i had a current BMax license, i would've whipped up the same thing in that, for 2D...

hey, tell me, how do you plan to implement your 3D stuff in BMax for your 3D engine... direct OpenGL calls?

--Mike

with the key exception of adding a select clause for each class you need the game to update in the tGame Run method


This shouldn't go in tGame. Run() should call GameObjectUpdate() which would have a Select clause for dispatching to the correct GameObject (sub)class's update function. If it has to do with GameObjects, it should be in the GameObject class!

so you would simply add a new a new tGameObject, and then in its Create() method, i would assign the sub class name... "PLAYER2"


Atrocious. You're going to have serious coupling between Player and Player2/PlayerAux. Either they will both share a lot of the same code, or they'll both call the same function (in which case it was pointless to make them two separate (sub)classes.)

Harmful architecture like this is precisely what you're going to run into when you try to create a framework that is too generic. You just don't see it yet...

as i see it you've got the game engine tied to closely to the type of game you are making... in your design, how would i make a game with no map...


In your design, how would I make a game with no player?

and if you think it already has failed, copy and paste the code, and see how easy it is to create an object...


You won't be able to see if your framework fails until it gets used in a complex project.

@ octothorpe....
This shouldn't go in tGame. Run() should call GameObjectUpdate() which would have a Select clause for dispatching to the correct GameObject (sub)class's update function. If it has to do with GameObjects, it should be in the GameObject class!

nonesense... why would i make a separate update function for tGameObjectm when you can't instatiate a tGameObject without also supplying a subclass name... besides, the Run method is part of the tGame class... your reaching :P

Atrocious. You're going to have serious coupling between Player and Player2/PlayerAux.
more nonsesne... show me...

In your design, how would I make a game with no player?
simple... just don't use the default player... ahahahahahahaa... seriously, he's only there if you need him...

You won't be able to see if your framework fails until it gets used in a complex project.
even more nonsense... it already works... try it if you don't think so...

i'm only being this straight forward with you because of the rude comments you made earlier... but still, this is what i asked for, so don't start whining just because i'm treating you with the same indfference to politeness that you treated me with... this sorta teardown is good for this lil project...

see if you can validate anything that you just said... and i will take it into consideration...

--Mike

>>> and if you think it already has failed, copy and paste the code, and see how easy it is to create an object...

>> You won't be able to see if your framework fails until it gets used in a complex project.

> even more nonsense... it already works... try it if you don't think so...

I give up. You're an idiot.

I give up. You're an idiot.
hahahahahahaaa... you're surrendering to an idiot... what does that make you...

hey, it's alright, i expected no less... and no more from you... yours is a typical response from the humiliated, and eternally confused...

i gracefully accept your surrender :) , and move on to people who are actually interested in this stuff, and have legitimate questions and points of view...


--Mike

I find it interesting, but I still don't see the point - you had to write how many lines of code just to get the player moving backwards and forwards? This kind of approach just doesn't appeal to me - you'd be forever tweaking yer damn "engine" rather than getting on with coding your game.

I think the "player" debate is a very good indication why just hard-coding what you need basically rocks. I have a player type in my current ditty, but playerOne.player, playerTwo.player and playerThree.player are all hard-coded instances. The sort of mess you two are arguing over never even arises... I can barely fathom what it is that you've got your knickers in such a twist about, in fact. Just code your game.

just what is a game engine anyway... well, contrary to what some people here, who shall remain nameless think (octothorpe being one of em), Blitz3D despite its entity system does not qualify as one...

That's true. Blitz3D does NOT qualify as a "game engine", it qualifies as a "graphics engine".

Function UpdatePlayer2(this.tGameObject)

IMHO, this is a very bad way to do this. Instead, why not make each player object, and simply assign it to a "controller". For example:
Type TGameObject
  Field Physics.TPhysics
  Field Controller.TController
  ...
  ...
End Type

The Physics field would contain an object which updated the TGameObject's position/rotation with some sort of physics, even if very simple (for example, a pac man physics would simply move the pac man in the direction specified by the TController). The TController is an object which affects the object's Physics updater (for example, a car game's Controller would provide the Physics updater with steering, acceleration, break, etc.).

This way, the TController object could direct the object based on the user's inputs from the keyboard, mouse, network, etc., or even from some AI code if you want. This way, you could make an object (a vehicle, for example) operate on AI or player input, by simply re-assigning the TGameObject's Controller field.

@ John J...
IMHO, this is a very bad way to do this. Instead, why not make each player object, and simply assign it to a "controller".
this is a mistake many people make JJ, and an understandable one...

if you really take the time to think about it, you'll realize that the Player is not the object you see on the screen running around inside the 3D world... the Player is sort of an abstraction... a representation of the person outside of the game, who is playing the game... and as such would not be the object that would be directly controlled by anything in the game...

the Player must be abstracted this way in order to allow the developer the flexibility to have the player 'associated' with various other object types... an airplane, for example, as is the case in a flight simulator...

think about it for a second... do you ever see yourself, the Player, in the flight sim... no, you don't... as in many simulations... you the Player enter the game as the type of thing you are simulating...

the concept of associating the Player with a Control Object comes into play here... it is something that i borrowed from the Torque architecture, and seems to be the perfect way to allow the coder the flexibility to associate the Player with say an airplane, or a race car, or an Actor... whatever...

this allows you to make all sorts of games without invading or even having to know much about the internals of the engine...


--Mike

ok... i just whipped up a small demo showing the concepts i just finished talking about immediately above...

a single .exe about 800k... get it here--> http://home.att.net/~mikey102/OOPBlitzDemo.zip

the code for the program is here...
Include "../samples/OBGameEngine.bb"
Include "../samples/ActorClass.bb"


Global myActor.tObject
Global AnotherActor.tObject
Global wait



Function TheGame(this.tObject)

  ;----------------------------------  initialization
  ;
  If theGame\status=0
   myActor.tObject=CreateObject("ACTOR","media/crewmen/crewman1.x")
   PositionObject(myActor,-120,2,120) 
   anotherActor.tObject=CreateObject("ACTOR","media/crewmen/crewman1.x")
   PositionObject(anotherActor,120,2,120)
   theGame\status=1
   myFont=LoadFont("Arial",21,True,True)
   SetFont myFont
  EndIf 
 
  ;---------------------------------------------------------------------------- always 
  ;  


  ;-------------------------------------------- user is awake start the clock, bump the status 
  ;  
  If KeyDown(200) Or KeyDown(208) Or KeyDown(203) Or KeyDown(205) 
     If wait=0 Then wait=MilliSecs()
     theGame\status=2
  EndIf

  ;-------------------------------------------- now its ok for user to set control object 
  ; 
  If theGame\status=2
    If KeyDown(25) 
      setControlObject(theGame\Player,myActor)
      adjustView(theGame\View,0,46,6)
    EndIf
  EndIf

  ;-------------------------------------------- set notices per condition detected 
  ; 
  If GetControlObject(theGame\Player)=Null 
   notice$="       The Player object currently has no Control Object associated with it, and uses its default move method"
   notice1$="                         Use The Arrow Keys To Move And Turn The Player Object Around Now"
   

  ;----------------------- wait a lil while for this one to pop up 
  ;
   If MilliSecs()>wait+1600 And wait>0
       notice2$="             This is the default behavior for the Player, as it is not yet associated with any other object"
       notice3$="   Since the View is Attached to the Player, it follows it around allowing a 'fly by' functionality by default"
       notice4$="    Press the P key now to set the Control Object for the Player to the Actor object standing on the left"
    EndIf
  Else
    notice$="               The Actor Object on the left is now set as the Control Object for the Player"  
   notice1$="              The W,A,S,D keys now control the movement of the player via SetControlObject() " 
   notice2$="       When the player now moves, he is using the Control Object's (Actor) walk method to move around"
   notice3$="         This allows the Player to control a multitude of object types, inheriting their methods"
   notice4$="          Right now the Actor subclass only moves, but walk animations and more can be added..."
  EndIf

  ;-------------------------------------------- the notices  
  ; 
  Text 20,40,notice$ 
  Text 20,80,notice1$ 
  Text 20,180,notice2$ 
  Text 20,220,notice3$ 
  Text 20,260,notice4$   


  ;-------------------------------------------- user is quitting app
  ; 
  If KeyDown(3) Then FreeFont myFont


End Function


the Actor 'subClass' code is here...
;------------------------------------------------------------------------------------------------------
;
;						Actor Class Globals Declarations 
;
;------------------------------------------------------------------------------------------------------

Global walkingSound,walkingSoundChannel


;------------------------------------------------------------------------------------------------------
;
;						Actor Class Implementation
;
;------------------------------------------------------------------------------------------------------


Function UpdateActors(this.tObject)

      ;----------------------------------- one time initialization
      ;
      If this\status=0
        ScaleMesh this\hEntity,20,20,20
		walkingSound=LoadSound("media/sounds/footstep.wav")
        this\status=1        
      EndIf

     ;------------------------------------------------------------------- always
     ;
   
     If GetControlObject(theGame\Player) = this

     ;---------------------------------------------  walking method
     ;
      If KeyDown(17) 
        MoveEntity this\hEntity,0,0,3
        If ChannelPlaying(walkingSoundChannel)=0 Then walkingSoundChannel=PlaySound(walkingSound)
		ChannelPitch(walkingSoundChannel,35000)
      End If
      If KeyDown(31) 
        MoveEntity this\hEntity,0,0,-3
       If ChannelPlaying(walkingSoundChannel)=0 Then WalkingSoundChannel=PlaySound(walkingSound)
	   ChannelPitch(walkingSoundChannel,35000)
      End If   
 
     ;---------------------------------------------  turning method
     ;
      If KeyDown(30) 
        TurnEntity this\hEntity,0,3,0
      End If   
      If KeyDown(32) 
        TurnEntity this\hEntity,0,-3,0
      End If  
     EndIf


End Function


i had to 'register' the Actor with the Engine by adding this
	Case "ACTOR"
	      UpdateActors(obj)
to the select clauses which allow the engine to process the different objects (this spot is clearly designated by a label in the ide lables list)...

... that's all there is to it.

this allows me to work in a modular, object oriented mindset, concetrating just on the functionality i need at the moment...

define an Actor in ActorClass.bb... add it to the game in MyGame.bb... then code the new object as i want it to behave in the game at the same spot...

if i want to have more Actors, i simply instantiate a new object of the same subclass... what could be simpler, more easy, and more organized...

--Mike

That's what I get:


... checking it now

**** ok fixed *****

try it now... it seems as if it needs to be wrapped in a zip before it'll work right over the wires...

sorry about that...

--Mike

Works now... Pretty cool! I might consider using the idea for some of my next projects...

if i find it usefull in a real app, i'll post it in the archives as a source code include lib, which you would include at the top of your main project file... and some docs on how to use it...

the current source listed above has been modified taking into account the feedback i got from several members...

--Mike

Has anyone seen my pants? I seem to have misplaced them.

look on your head... :P

--Mike

I did, they're not there.

hey Anatoly... or anyone else who looked at this...

did you just see a few characters and no building they were in, but just a black background?

i think i forgot to include the building model and the textures...

if you've got a free minute, take a quick look see at this... sorry 'bout the screwup...

http://home.att.net/~mikey102/OOPBlitzDemo.zip

--Mike