Code archives/Miscellaneous/Project PLASMA FPS 2004: Level.bb
This code has been declared by its author to be Public Domain code.
Download source code
| |||||
This levelLoader is designed to load game entity data stored in *.csv (comma delimited text) files and game entity geometry stored in the *.b3d format. I choose these formats for flexibility, speed, and ease of use. With *.csv data files you can easily import and export the data into your favorite spreadsheet application and manage the data in the form of table, taking advantage of Spreadsheet Apps features. You can also use any other text editor (ie: notepad) to edit the data. Many databases are readily equip to import data in the form *.csv, not to mention PHP scripting langauge support for the *.csv format. The B3D file format is a 3D file format specifically designed for use with Blitz3D. Many game specific features are supported including vertex coloring, multitexturing, boned animations and so on. In my opinion it was the highest logical choice. The level Loader is based on a simple "Label Scheme" in which all game entities can be identified within the Level Map using a label$+id% (ie: bot01, ammo01, struct01). Basic game entity labels: Spawner{Bot, Ammo, Weapon, PowerUp}, Door, Key, Switch, and Lift. Simply load the csv data, and then b3d level map. The loader will parse the labels, create, and assign entity properties from the data. This is the easiest and most generic way to build the game level content and bind it to data. Additional labels for extra game entities and non-game entities (ie: waypoints, cameras, etc) can be added with ease. Other considerations. The B3D level geometry already provides orientation, scale, texture, and other information for 3D geometry. This information can be extracted and used to assigned these properties to both entities with and without geometry(ie: Switch, Fields, etc). All game entities can be visually represented in a Level Editor to include game entities that have no geometry at runtime. The geometry that represents game entities with no geometry can be hidden or even freed during loadtime. The Label Scheme provides a simple visual design interface mechanism in which level builders can orientate all game entities in the level map using available geometry editors. Many popular commercial game editors provide a visual interface to orientate entities and a variety of 3rd party Level Editors can be used as long as there is a means to label the entities and export the geometry to B3D. Auxillary Data (ie: precalculated data files in binary format) and media files will be required. The level *.csv file can be used to store path and filename of such files associated with a particular game entity. Modular Design is my goal. A function template can be use to create a module specific 'level loader' function. All the main level loader will have to do is call these module level loader functions to load data associated with the module. Loading Modules in a specific order will be necessary. A modular level load design will accomadate. Last Update 02/03/04 Check out the Wip Zip for demos and more code! | |||||
;============================ ;LEVEL ;============================ Const LEVEL_CSVFIELD_MAX%=255 Const LEVEL_ENTITY_MAX%=1024 Global level.level Type level Field map% ; Field configuration Field filename$ Field file% Field entities% Field entity%[LEVEL_ENTITY_MAX%] Field entitylabel$ Field entityID% Field csvfields% Field csvfield$[LEVEL_CSVFIELD_MAX%] End Type Function levelLoad.level(filename$) ;------------------------------- ;LOAD LEVEL levelcsv DATA ;Note: Loading Order is Critical ;------------------------------- this.level=New level this\filename$=filename$ this\file%=ReadFile(this\filename$+".csv") If Not this\file% RuntimeError (this\filename$+".csv File Not Found") While Not Eof(this\file%) this\csvfields%=levelCSVRead(this) Select this\csvfield$[1] ;label Case "map" Case "texture" Case "model" Case "sound" Case "action" ;load handler for action data Case "script" Case "waypoint" waypoint.waypoint=waypointNew() waypoint\id%=this\csvfield$[2] ;id waypointId.waypoint(waypoint\id%)=waypoint ;assign to id pointer waypoint\typeid%=this\csvfield$[3] ;typeid waypoint\position\x#=this\csvfield$[4] ;x waypoint\position\y#=this\csvfield$[5] ;y waypoint\position\z#=this\csvfield$[6] ;z Case "bot" Case "struct" ;load stuff for this entitytypeid% Case "door" ;load stuff For this entitytypeid% Case "platform" ;load stuff For this entitytypeid% Case "switch" ;load stuff For this entitytypeid% Case "light" ;load stuff For this entitytypeid% light.light=lightNew() light\id%=this\csvfield$[2] ;id lightId.light(light\id%)=light ;assign to id pointer light\typeid%=this\csvfield$[3] ;typeid light\entity%=this\csvfield$[4] ;modelfile: if integer id% then copy else its a this\file% If light\entity% light\entity%=CopyEntity(lightId(light\entity%)\entity%) Else light\entity%=LoadAnimMesh(this\csvfield$[4]) If Not light\entity% RuntimeError("No Entity File or Copy Found for light"+Str(light\id%)) EndIf EntityType light\entity%,1 EntityFX light\entity%,1+4+8 light\position\x#=this\csvfield$[8] ;x light\position\y#=this\csvfield$[9] ;y light\position\z#=this\csvfield$[10] ;z light\angle\x#=this\csvfield$[14] light\angle\y#=this\csvfield$[15] light\angle\z#=this\csvfield$[16] If this\csvfield$[17] ;uniformscale light\scale\x#=this\csvfield$[17] ;xscale light\scale\y#=this\csvfield$[17] ;yscale light\scale\z#=this\csvfield$[17] ;zscale Else light\scale\x#=this\csvfield$[11] ;xscale light\scale\y#=this\csvfield$[12] ;yscale light\scale\z#=this\csvfield$[13] ;zscale EndIf PositionEntity light\entity%,light\position\x#,light\position\y#,light\position\z# ScaleEntity light\entity%,light\scale\x#,light\scale\y#,light\scale\z# RotateEntity light\entity%,light\angle\x#,light\angle\y#,light\angle\z# Case "prop" prop.prop=propNew() prop\id%=this\csvfield$[2] ;id propId.prop(prop\id%)=prop ;assign to id pointer prop\typeid%=this\csvfield$[3] ;typeid prop\entity%=this\csvfield$[4] ;modelfile: if integer id% then copy else its a this\file% prop\textureid%=this\csvfield$[5];texture If prop\entity% prop\entity%=CopyEntity(propId(prop\entity%)\entity%) Else Select this\csvfield$[6] Case 2 ;animated prop\entity%=LoadAnimMesh(this\csvfield$[4]) Default ;stactic prop\entity%=LoadMesh(this\csvfield$[4]) End Select If Not prop\entity% RuntimeError("No Entity File or Copy Found for Prop"+Str(prop\id%)) EndIf If prop\textureid% prop\textureid%=propId(prop\textureid%)\textureid% Else prop\textureid%=LoadTexture(this\csvfield$[5]) ;to be change to support texture EndIf If prop\textureid% EntityTexture prop\entity%,prop\textureid% EntityType prop\entity%,1 prop\position\x#=this\csvfield$[8] ;x prop\position\y#=this\csvfield$[9] ;y prop\position\z#=this\csvfield$[10] ;z prop\angle\x#=this\csvfield$[14] prop\angle\y#=this\csvfield$[15] prop\angle\z#=this\csvfield$[16] If this\csvfield$[17] ;uniformscale prop\scale\x#=this\csvfield$[17] ;xscale prop\scale\y#=this\csvfield$[17] ;yscale prop\scale\z#=this\csvfield$[17] ;zscale Else prop\scale\x#=this\csvfield$[11] ;xscale prop\scale\y#=this\csvfield$[12] ;yscale prop\scale\z#=this\csvfield$[13] ;zscale EndIf PositionEntity prop\entity%,prop\position\x#,prop\position\y#,prop\position\z# ScaleEntity prop\entity%,prop\scale\x#,prop\scale\y#,prop\scale\z# RotateEntity prop\entity%,prop\angle\x#,prop\angle\y#,prop\angle\z# Case "soundfield" ;load stuff For this entitytypeid% Case "particle" Case "flare" Case "gadget" Case "controlmap" Case "network" End Select Wend CloseFile(this\file%) ;--------------------------- ;LOAD LEVEL GEOMETRY ;--------------------------- this\map%=LoadAnimMesh(this\filename$+".b3d") If Not this\map% RuntimeError (this\filename$+".b3d File Not Found") levelHierarchy(this,this\map%) For loop = 1 To this\entities% this\entitylabel$=EntityName$(this\entity%[loop]) ;load handler for bot geometry this\entityID%=levelEntityLabel%(this,"spawner") If this\entityID% EntityColor this\entity%[loop],0,0,255 EntityFX this\entity%[loop],1+4+8 EntityAlpha this\entity%[loop],.4 EndIf this\entityID%=levelEntityLabel%(this,"waypoint") If this\entityID% If waypointId(this\entityID%)=Null waypoint.waypoint=waypointNew() waypointId(this\entityID%)=waypoint.waypoint Else waypoint.waypoint=waypointId(this\entityID%) ;object reference EndIf waypoint\position\x#=EntityX(this\entity%[loop],True) waypoint\position\y#=EntityY(this\entity%[loop],True) waypoint\position\z#=EntityZ(this\entity%[loop],True) Select waypoint\typeid% ;start-goal testing Case 0 EntityColor this\entity%[loop],255,255,0;FreeEntity this\entity%[loop] startwaypoint.waypoint=waypoint Case 1 EntityColor this\entity%[loop],0,255,0 Case 2 goalwaypoint.waypoint=waypoint EntityColor this\entity%[loop],255,0,0 End Select ;freeEntity this\entity%[loop] EndIf this\entityID%=levelEntityLabel%(this,"portal") If this\entityID% EndIf this\entityID%=levelEntityLabel%(this,"switch") If this\entityID% EntityColor this\entity%[loop],255,0,255 EntityFX this\entity%[loop],1+4+8 EntityAlpha this\entity%[loop],.4 EndIf this\entityID%=levelEntityLabel%(this,"door") If this\entityID% EntityFX this\entity%[loop],1+4+8 EntityColor this\entity%[loop],255,0,0 EndIf this\entityID%=levelEntityLabel%(this,"platform") If this\entityID% EntityColor this\entity%[loop],255,0,127 EndIf this\entityID%=levelEntityLabel%(this,"climber") If this\entityID% EntityColor this\entity%[loop],255,255,0 EntityFX this\entity%[loop],1+4+8 EntityAlpha this\entity%[loop],.4 EndIf this\entityID%=levelEntityLabel%(this,"struct") If this\entityID% ;struct.struct=structId(this\entityID%) ;If struct\collisiontype%=1 EntityType this\entity%[loop],1;level collision EndIf this\entityID%=levelEntityLabel%(this,"soundfield") If this\entityID% If soundfieldId(this\entityID%)=Null soundfield.soundfield=soundfieldNew() soundfieldId(this\entityID%)=soundfield.soundfield Else soundfield.soundfield=soundfieldId(this\entityID%) ;object reference EndIf soundfield\position\x#=EntityX(this\entity%[loop],True) soundfield\position\y#=EntityY(this\entity%[loop],True) soundfield\position\z#=EntityZ(this\entity%[loop],True) EndIf this\entityID%=levelEntityLabel%(this,"light") If this\entityID% EntityColor this\entity%[loop],255,255,0 EntityFX this\entity%[loop],1+4+8 EndIf Next ;--------------------------- ;LOAD LEVEL AUXILLARY DATA ;--------------------------- ;WAYPOINTS this\file%=ReadFile(filename+"._markerset") If this\file% Repeat waypoint.waypoint=waypointRead(this\file%) ;replace waypoint initialized at markersetStart() waypoint\entity%=waypointId(waypoint\id)\entity% waypointDelete(waypointId(waypoint\id)) waypointId(stackPop(waypointIndex))=waypoint PositionEntity waypoint\entity%,waypoint\position\x#,waypoint\position\y#,waypoint\position\z# ;EntityColor waypoint\entity%,0,255,0 ;ShowEntity waypoint\entity% ;ScaleEntity waypoint\entity%,.05,.05,.05 waypoint\typeid%=1 waypoints%=waypoints%+1 Until Eof(this\file%) CloseFile(this\file%) ;correct WaypointAvail waypointAvail\pointer=reset For waypoint.waypoint=Each waypoint If waypoint\state%=0 stackPush(waypointAvail,waypoint\id%) Next EndIf this\file%=ReadFile(this\filename$+".waypoints") If this\file% While Not Eof(this\file%) waypoint.waypoint=waypointID(stackPop(waypointAvail)) waypoint\position\x#=ReadFloat(this\file%) waypoint\position\y#=ReadFloat(this\file%) waypoint\position\z#=ReadFloat(this\file%) waypoint\typeid=ReadInt(this\file%) PositionEntity waypoint\entity%,waypoint\position\x#,waypoint\position\y#,waypoint\position\z# ;show waypoint ;ShowEntity waypoint\entity% ;ScaleEntity waypoint\entity%,.05,.05,.05 ;If waypoint\typeid% ; EntityColor waypoint\entity%,255,0,255 ;EndIf ;EntityAlpha waypoint\entity%,.75 waypoints%=waypoints%+1 Wend EndIf Return this End Function Function levelSave(filename$) End Function Function levelClear() End Function Function levelLoadPLD(filename$) End Function Function levelcsvRead%(this.level,csvdelimiter$=",") csvrow$=ReadLine(this\file%) csvcolumn%=1 this\csvfield$[csvcolumn%]=nil$ csvquote%=False For loop=1 To Len(csvrow$) csvchar$=Mid$(csvrow$,loop,1) If csvchar$=Chr$(34) csvquote%=True-csvquote% ElseIf csvchar$=csvdelimiter$ And csvquote%=False ; end of column csvcolumn%=csvcolumn%+1 this\csvfield$[csvcolumn%]=nil$ Else this\csvfield$[csvcolumn%]=this\csvfield$[csvcolumn%]+csvchar$ End If Next Return csvcolumn% End Function Function levelEntityLabel%(this.level,label$);compare label and returns id integer If Left(this\entitylabel$,Len(label$))=label$ Return Right(this\entitylabel$,Len(this\entitylabel$)-Len(label$) ) End Function Function levelHierarchy(this.level,parent%) children%=CountChildren(parent%) For loop = 1 To children% this\entities%=this\entities%+1 child%=GetChild(parent%,loop) If child% DebugLog("levelHierarchy:child["+Str(this\entities%)+"]="+Str(child%)+"/"+EntityName(child%)+" Surfaces="+CountSurfaces(child%));testing EndIf this\entity%[this\entities%]=child% levelHierarchy(this,child%) Next End Function Function levelCollisionSet() ;Collisions src_type,dest_type,method,response Collisions 2,1,2,2 ;entity,level,sphere-to-polygon,slide Collisions 3,1,2,1 ;worker,level,sphere-to-polygon,stop End Function Function levelEntityCollide%(worker.worker,typeofentity%);perform non stop collision detection worker\collision%=EntityCollided(worker\entity%,typeofentity%) If worker\collision% ResetEntity worker\entity% entitycollisioncount%=entitycollisioncount%+1 ;testing EndIf Return worker\collision% End Function |
Comments
None.
Code Archives Forum