TooTing The OOP Horn Again

Blitz3D Forums/Blitz3D Programming/TooTing The OOP Horn Again

Red Ocktober(Posted 2006) [#1]
man i am really luvin working in Blitz3D now since i got this OO engine up and running... once the basic underpinnings of the engine were coded in place, 'classes could be created and objects instantiated from those classes...

it's amazing to see the results of implementing a new 'class' and adding an instance of that class into the game... just yesterday i was fitting out one of the submarine 'classes' i created... adding the diveplanes, rudders, the periscopes, and the propellors... and it was really facinating to see these things appear on each of the subs (there were two sitting around on top of the ocean) as i ran the test app...

and since the basic functionality of the submarine has already been implemented and tested, it only took a line or two of code to tie that functionality in to the new parts (rudder rotates in the right direction, dive planes tilt and rise)...

i don't see any way i could've gotten this far in the time i did without resorting to this object oriented style of coding... so far, everything is hanging in there, and the engine seems to be able to handle everything i throw at it...

actually, it's Blitz3D that seems to be handling everything in stride... the OO Engine itself is a series of loops that should, by all rights, have killed Blitz a long time ago :)

but i'm getting a lil bit ahead of myself... first a lil about this marvelous creation :)

OOBlitz3D is a source code engine that provides a means of creating objects from classes, by using Blitz TYPEs to create a defacto object oriented coding environment... all the developer has to do to create a minimal 3d game is...

1- add a global declaration for a .tGame object (yes, even the game itself is an object) like this...
Global theGame.tGame=createGame(1024,768,32,WINDOWED_ALWAYS)
2- add an include statement for engine.bb
Include "../samples/OBGameEngine.bb"

3- and code an empty function called theGame, like so...
Function theGame(this.tObject)

End Function

End


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

a 3D window will open with a default tPLAYER instantiated, looking thru the default tVIEW object, at the default tSKY object...

now to dispell a common misconception most people make right off the bat... the player is not the lil guy you see running around in the game, the PLAYER is the person outside the game who is actually playing it... the default PLAYER object has a tVIEW object attached to itself, so it can see into the 3D world it is in, and a generic movearound functionality (arrow keys) in order to look around the new 3D world...

in order for a character to appear you'd have to do a few things...
1- create an tActor class, or a tFPSChar class (call it anything)...
2- 'register' the new class with the engine...
3- instatiate the new whatever you called it, with CreateObject()...
4- call the engine's ATTACHPLAYER TO OBJECT() method...

now, the PLAYER will move in the whatever way the object it's attached to has been coded to move... and since the VIEW is attached to the PLAYER by default, it will follow the PLAYER around... this object an be anything... a person, a car, a plane... whatever...

cool eh... but hey, not everything in a game using the OO Engine has to be an object... some entities can exist on their own, especially if they don't do anything... or they may merely be properties of a class... in which they are controlled by the objects instantiated by that class...

properties... yeah, that was a kicker in the beginning... but, i got it worked out... say suppose i had a tCar class, and i wanted to have every car object of that class to have headlights... in the class definition i would DIM carHeadlight(maxCars), and reference it in code as carHeadLight(this\objID)... so now if i was in the second of 5 cars, i could turn the headlights for that car only, on or off...

everything is done like this... and it is all in the class implementation... this way, i could give the car class code to someone, and they could instantly add a car to their game by including the file, and doing what was outlined above... the only thing they would need to was what exposed properties did what... headlights on/off, brake pressed, accelerator pressed, etc... ideally, you would design your class so that manipulating these properties would be straightforward and lend themselves to keyboard, mouseclick, or joystick, depending on what it did... and your models associated with the property would give visual feedback to the player...

planning... as mentioned before, that is a biggeee in OO development...

ok... that's enough harrassment for now... when i get time i'll whip up a few docs and post up the code for anyone who is interested... it's really kinda cool once you start working with it... if i do say so myself :)

--Mike


Beaker(Posted 2006) [#2]
Red - I love you man, but I wish you would post in the correct forum!

Looking forward to seeing how you implemented OO style in Blitz3D.

(Expect this thread to be moved to Blitz3D Programming when you look again.)


Red Ocktober(Posted 2006) [#3]
ooops... sorry :)

--Mike


Grey Alien(Posted 2006) [#4]
and the OOP Horn on the bus goes toot toot toot.


Paolo(Posted 2006) [#5]
Hi Mike,

can you give us a few words about the gameplay concerning
your programming?
I mean, for example,
playing against the PC means having an AI,
and AI means keeping track of what each element is doing
in the scene,... how do you make (in your code) each
element to interact with the others? and what is they belong to
different types? ... what are you using to retrieve
the information you need? functions()? labels?


Damien Sturdy(Posted 2006) [#6]
Hi Red,

Have you managed to implement the clipages yet?


Kuron(Posted 2006) [#7]
and the OOP Horn on the bus goes toot toot toot.
ROFLMAO


Grey Alien(Posted 2006) [#8]
haha, someone got it then. My youngest boy sings that song (minus the oop bit)


Red Ocktober(Posted 2006) [#9]
@ Cyg... not yet, been too busy getting the sub class and it's controls finished and tested... i've looked at your stuff though,and a lot of what you're doing seems similar to what i have implemented already so it shouldn't be too hard to do once i'm ready to focus on that again... i'll let you know how it goes... should be in a few days...

@ Eurythmia... hey there Paolo... what's the latest on Tecno, any new news...

as far as my lil thing goes... the engine is basically a big main loop that contains a few nested loops that continuously calls the update functions for each 'class' of objects in the game...

when you create a class, you give it the a classname, then you write up one function which you register with the game engine... like this...
	For  obj.tObject=Each tObject
	  Select obj\subClass
	    ;------------------------------ default player updating     - DO NOT ALTER
	    Case "PLAYER"
		      UpdatePlayer(obj)
		;------------------------------ default sky updating        - DO NOT ALTER
		Case "SKY"
	      UpdateSky(obj)
	
	    ;------------------------------ default game logic updating - DO NOT ALTER
		Case this\Title
	      TheGame(obj)

	
.YOUR_UPDATE_FUNCTIONS
	    ;------------------------- ADD YOUR NEW UPDATE FUNCTION REFERENCES BELOW AS A CASE CLAUSE
        ;                          THESE POINT TO YOUR NEW SUBCLASS'S UPDATE FUNCTIONS 
	    
	   Case "ACTOR"
	      UpdateActors(obj)	    
	    Case "OCEAN"
	      UpdateOcean(obj)	
	    Case "BOUYANTBOX"
	      UpdateBouyantBoxes(obj)	
	    Case "GATOCLASSSUB"
	      UpdateGatoClassSubs(obj)	
	    Case "REFLECTION"
	      UpdateReflections(obj)	
	    ;
	    ;----------------------------- COMMENT OUT OR REMOVE UNUSED FUNCTION REFERENCES
	
      End Select
	Next

this is the only place where you have to edit the engine code...

this function will contain all the functionality for that 'class', and any object instatiate from the class will behave according to what is coded in this function...

as you can see, each instance of a particular class is passed to the classes update function so that each one can be treated as an individual... they all share the same update function, naturally, right, because they are all of the same class and share the same basic functionality... so you write this once, and it applies to all object created from that class...

an important point when coding objects... i don't think in terms of playing against the PC... the PC is an abstraction to the game engine, and it is only aware of the PC in the game.system class, where it is necessary to know certain things about the hardware and the directory structure... otherwise, the PC doesn't exist as far as the game engine knows...

the player is also an abstraction... it does not exist as part of the actual game, but only an entity outside of the game... merely as an interface for the user to interact with the game...

the OOP way of approaching this is to think in terms of one class of objects playing against another class of objects...

for example... if i wanted to have two groups of soldiers playing against each other i would implement 2 classes of soldiers... a redTeamSoldier class and a blueTeamSoldier class... then i would code each teams functionality based on what i want them to do... the one function, as mentioned before, which is continuously called by the engine's mainloop...

a simple ai example would be to have both classes search for members of the other class, and keep track of the distance from each one it finds... here's what the BlueTEAMSOLDIER class logic might look like...
;---------- search for enemies
for enemy.tObject=each tObject
    if obj\className="REDTEAMSOLDIER"
        ...code to add  the obj and it's distance to a list (an array of foundEnemy types could be used)
    endif
next
;--------- determine closest 
for x=0 to 5 (only search for 5 candidates)
  if  foundEnemy(x)\distance < selectedTargetDistance 
    selectedTarget=foundEnemy(x)\obj
    selectedTargetDistance=foundEnemy(x)\distance
  endif
next
;---------- track towards
pointentity... blah, blah, blah


and so on...

when the game starts up, the Player can choose which side he/she wants to be on, and the player object is attached to one of the object from either the RED or BLUE team classes... this dictates that each class has a provision for detecting whether or not an instance has a parent of the tObject type, and is of the PLAYER class, and would then not follow the ai portion of the code, but would run the segment of code that allows the player to control the object...

is any of this making any sense Paolo... i know it can be a lil convoluted...

in short, there is only one function that implements what each instance of a class can do... this is the classes update function. it can be written so that each class can detect members of another class... properties are merely DIMmmed variables that are linked to the objectID (each object of a certain class automatically gets a unique objID when created) and are available globally...

doing things this way simplifies the coding process in that all the functionality is coded once, and in one place... then, once the games objects are implemented, all you have to do is code your game like i mentioned in the top post... you can add as many soldiers from each class as you like... attach the player to one of em... and sit back and watch em all run around the place...

it's just a surface layer implementation of OO, and a loose one at that... but it helps keep my code, as well as my thinking organized...

i'll whip up a simple demo soon...

good hearing from you by the way... been a while...

--Mike


octothorpe(Posted 2006) [#10]
Hooray, you've discovered encapsulation. Let's throw a party.


Red Ocktober(Posted 2006) [#11]
actually... i've implemented a loose form of encapsulation in a procedural language not really designed for it... you yourself have done something similar... so have a few others here...

so, yeah... lets throw that party!!!

--Mike


Rook Zimbabwe(Posted 2006) [#12]
Octo was being snotty!!! I like it Red... I like it but can't quite get in to how each registered object is linked to a model or placed in a map etc.

What would determine interaction? If I made an object "WINDOW" and and object "BULLET" could I easily get the bullet to break the window?


Grey Alien(Posted 2006) [#13]
It is worth going OOP as far as possible in Blitz3D, I did it for my Blitz2D games and it was useful but still a pain in the ass that it wasn't "proper". Like no generic "Update" function due to polymorphism etc.


Red Ocktober(Posted 2006) [#14]
@GA....
yeah... it was a bit of a pain until i got the generic engine working... then i saw how i could actually do something with it, and it was actually quite easy and more organized once i got the hang of using it...


@Rook...
how each registered object is linked to a model

take a quick look at the engine's tObject declaration...
Type tObject
  Field status
  Field subClass$
  Field hEntity
  Field objId
  Field maxAllowed
  Field controlObject.tObject
  Field name$
End Type

now, say for instance you wanted to create a WINDOW object... first you would create a WINDOW class... this is simply a matter of editing a new file something like this...
;------------------------------------------------------------------------------------------------------
;
;								WINDOW Class Globals Declarations 
;
;  declare a global specifying the maximum number of instances for this  subtype here, and dimension 
;  each property to this global limit...  this gives each new instance of the subclass the capability  
;  of being manipulated as an individual object via its \objId Field in the subclass Update method
;  
;  the property names should be unique as to avoid conflicts with other variables in your program
;
;------------------------------------------------------------------------------------------------------

    Global MaxNumOfWindows=44

Function UpdateWindows(this.tObject)

End Function

notice the classes update function... this is the single function that is continuously called by the engine while it's main loop is spinning... you can leave this function empty for now, a placeholder where you will add all of the WINDOW classes functionality in later...

save this file as WindowClass.bb

next, you would register it with the engine, as described in the above posts (the only time you have to edit the engine code, but it is simple to do)...

once this is done, you could add a new WINDOW object to your game... you would do this in your code using the engine's CreateObject() function... like so...
aWindow.tObject=createObject("WINDOW", theGame\System\HomeDir +"media\house\windows.b3d")

the CreateObject() function is like a lil gameobject factory, where the fields in the TYPE declaration for tObject are filled in...

the subClass$ field gets the first arg, "WINDOW", which is the name of the class...

CreateObject() is also smart enough to check to see if the next arg is a blank string or not, and if not, then load in the model it references and return a Blitz3D entity to the hEntity field... this is what associates the object with a particular model...

finally, CreateObject() will also assign an objID to the new object, fill in that field, and will assign subsequent objIDs to all new objects added to the game that are of this particular subClass...

btw, you should now have 3 files open in your editor... OOEngine.bb, WindowClass.bb, and MyGame.bb...
the OOGameEngine is in OOEngine.bb, the WindowClass.bb is the one you just created, and MyGame is where the actual code for the game is gonna go...

lets go backa step or two, and look at the tObject declaration again... notice the status field... each new object has one and upon creation of the object it is equal to 0... you would use this field in your class implementation to do whatever you need to do during the first time the classes update function is run for a new object... then it is your responsibility to bump it up to 1...
Function UpdateWindows(this.tObject)
    ; ----------------------------------------------- initialization
    ;
    if this\status=0
          ;position it
          ;do whatever else you need to do to initialize each instance
         this\status=1
    endif

    ....
    ....
    ; now do everything else a window does... continuously
End Function


ok, so there you have it... those are the key fields of interest for now... you are now ready to run your game... just remember to include WindowClass.bb and OOEngine.bb... you will see a model of a window appear in your game... and that's about it...

by default you'll be able to move the players view around, but not much else... remember, the window doesn't have any functionality at all, so it just sits there... now you can start adding functionality to your window, and test it as you go along, all of your window class functionality will be in one place, that UpdateWindows function in WindowClass.bb...

you would do the same thing when creating a BULLET class...

now that you have a lil insight to what's going on with the engine, where would the ability to make a window and a bullet object interact go?

well, seeing as the window is going to display the most effect of the interaction, i would put this functionality in WindowClass.bb... one way would be to check for collision between any object that has the subClass "BULLET", and the object of WINDOW class, then play a windows breaking sound, run a particle anim for breaking glass or whatever... and replace the mesh texture with a broken window texture, or have it disappear entirely... whatever you want your windows to do when hit by a slug...

ok... does this sorta explain what's happening... i've tried to keep it simple and straight forward... in actuality, the WINDOW object would wind up being created in the initialization part of a HOUSE or BUILDING class implementation... this way, once you've 'built one window, any new class of object can contain one... or tow, or fifty of em... the same goes for the bullet objects... it would be create by the GUN class object, and be controlled by it (fired)...

... but ya gotta walk before you can run, so a simple implementation just to get your feet wet was all we went into for now.

is anyone really interested in this... if so, i'lll take some time and post it and a lil doc thingee...

--Mike


DH(Posted 2006) [#15]
So did Frank Taylor turn into Red Ocktober?


Red Ocktober(Posted 2006) [#16]
hahahah :) ... actually, Frank's examples and tuts were extremely helpful... his implementation went a lot further than mine and came a lot closer to OOP coding than mine does...

but i found that using his implementation required too much of a departure from both the Blitz3D procedural thinking as well as the c++ OOP way of thinking...

in short, it was too much work to code using his method... i found myself thinking more about how to do it, than about the objects and the game i was trying to create...

my lil implementation is a lot less intrusive to the natural flow of thought... although it does require that you think objects instead of functions and procedures...

--Mike


Paolo(Posted 2006) [#17]
Thanks for those comments Mike,

in some way, I'm doing similar OO things for Tecno,
although I couldn't find a way to do generic-code for some
of the level's culling routines and therefore there is some individual
code for each level that took time to do...

but, I really did all of my simple enemies in a OO way,
after settinp up some pahtfinding nodes along each level,
I can create an enemy in any place, then automatically the enemy
knows where he is, how to patrol, how to attack you (if he detects you),
how to follow you if you escape and how to "interact" with others enemies
in the scene.... and since they are TYPES I can create as many as I want,
but a medium-PC won't handle more that 6 enemies at a time so I must have
this in mind ...
... my god... it was such a "pain" to do this AI, actually I have been coding it
for the last 6 months and I still haven't finished it ...
At the end, it is not state-of-the-art AI but I'm pretty happy about how
the enemies behave in the scene, specially having in mind that there's
walking-flying enemies and so far the code is not having too much bugs ...

... now I have to code the AI for the 3 individual bosses you find along the game,
... arrrggghh, damn it, still some months to go ... :)

Paolo.


Paolo(Posted 2006) [#18]
One more thing,
some people I know, have seen the B3d language and they didn't
like it because they said it is procedural,

I don't know much about programming, but I belive b3d is not
"so procedural", actually, for example, B3d talking, if you
take time, What things exactly could NOT be done in a pseudo-OO way
because of the language limitation?

Paolo.


octothorpe(Posted 2006) [#19]
So did Frank Taylor turn into Red Ocktober?


Oh man, this cracked me up.


Red Ocktober(Posted 2006) [#20]
@ Paolo...

I couldn't find a way to do generic-code for some
of the level's culling routines and therefore there is some individual
code for each level that took time to do...

that's because you didn't approach the game from the beginning as OO development... if you had, each element in the game would've been based on a generic bit of code and would derive from a TYPE of GameObject, which would automatically have that sort of behavior built in...

this is one of my biggest problems with the older BASIC languages, of which Blitz is one... it really is procedural, and it sort of encourages procedural thinking... doing things as they come along, and starting in a direction, with no firm idea of where you're gonna wind up...

OO development requires a least a plan... and you aim towards that... one of your requirements would've been level culling... you would've written that as a behavior for all level object 'classes' (TYPEs) if you were coding it in a different language... that's why BMax 3D is gonna rock...

a lot of people here consider Blitz3D to be an engine... that is why they won't make anything more than a small demo... before you can develop a game, you must develop the 'engine' for that game... best to develop one that you can use for a few games...
it was such a "pain" to do this AI, actually I have been coding it
for the last 6 months and I still haven't finished it ...

yeah, i can imagine what a pain the ai is... the lil ai i've got in place for the enemy ships is working... but...
What things exactly could NOT be done in a pseudo-OO way
because of the language limitation?

ignoring what is consider to be the main OOP commandments, the lack of function pointers is what makes my implementation a real hack... all the functionality for a 'class' is contained in one big function... lots of unnecessary if or case checks...

next... i would like to have an available event or message que for Blitz3D.

hey Paolo... one question...
since they are TYPES I can create as many as I want,
but a medium-PC won't handle more that 6 enemies at a time
why only 6...

i've got a mission level in which there are 4 ships and 3 planes that are acting independently and on their own...

why the limit of 6?

--Mike


Paolo(Posted 2006) [#21]
that's because you didn't approach the game from the beginning as OO development...

...exactly, that was a big fault of mine,... as you know, I first
started this game with 3DRad, then when I jumped into B3d I began to
port all the game-code without thinking in OO way,
the level culling system was the first I did in B3d without
even knowing good enough the language, therefore
it is not generic at all but since it is already done and working good, I'm not
going to re-code it :)

why the limit of 6?

I is not that I have a limit, I could create a hundred if I
wanted to ... the problem is the fps of course ... I mean,
a medium range PC won't handle more than 6 at a time, there
can be many more in the level but if more than ~6 detects
you and start fighting against you then the code for the AI
takes too much time ... and so on ...

... I'm NOT using LinePicks at all, I'm using a kind of "detection-bullets" system which
is also coding in my not perfect OO style :)
... each enemy shoots 2 types of these bullets,
one detects the walls and the other detects grates and glass,
this way the enemies can see you through transparent and semitransparent materials,
when an enemy detects you, he start fighting with some logic,
he shoots you the real bullets, he follows you with a pathfinding code (A* in 3D), sometimes
he will detect a wall to crouch behind it, if you go out-of-sight the enemy will remember
the last position where he saw you and he will go to that place and if doesn't see you again
then he "jumps" to patrol mode again ...
... also when there are more than one enemy fighting with you, another simple logic-code
is scanned so that the enemies won't try to attack you from the same place so that they will
be distributed around the scene and so on ...
... at the same time if you kill an enemy a ragdoll version of that enemy is created ...
... and all of this being done for 6 enemies start asking for too much processor power and
my intention is making a game for medium-PCs or above ... :)

Paolo.

ps... arrgh , "pointers", "pointers", ... I hear about them
from time to time and don't know any idea about what they are ??? :)


DH(Posted 2006) [#22]
ignoring what is consider to be the main OOP commandments, the lack of function pointers is what makes my implementation a real hack... all the functionality for a 'class' is contained in one big function... lots of unnecessary if or case checks...


very true.

The major problem with keeping close OO techniques in a procedural language is the overhead.

I find that when I attempt to keep things to classes, I do alot of overhead (be it by calling unneeded functions, or doing cases or ifs) just to keep it OO in operation.

When Max3D comes out, I will be switching over permenantly as it gets tiring to try and keep everything as OO as possible in Blitz3d without the language features to help me. TBH I dont mind typeing more, its just the amount of cpu ticks wasted just to keep the procedural at an OO operation, ticks that can be better used in other areas.