Dynamically Creating Objects From Data Statements

Started by kevin, November 27, 2009, 07:21:29 PM

Previous topic - Next topic

kevin

 Dynamically Creating Objects From Data Statements

  This example uses the new CallFunction feature found in the more recent beta editions of PlayBasic1.64k(and above).   What this feature does, it is allows the user to call a function by name at run time.   This seems a pretty abstract thing on the surface,  but what it allows us to do, is set up more generic handler routines, in particular when handling the creation  or destruction of  objects (This example only shows creation).  

  In this example,  what we're doing is passing some information into a generic spawning routine.  This routine will call the appropriate creation function for us.    It does without us have to manually tack the function call into the spawning routine.    So the spawning routine doesn't have modified every time we add a new object type to our game..  

  One area where this is rather useful, occurs when importing information about our game characters (objects) from an external source, such as loading a level from disc.  While this example doesn't the load the object declarations  from disc, they're stored as data statements, but the process is the same.


 CallFunction Version

PlayBASIC Code: [Select]
` *=---------------------------------------------------------------------=*
`
` > Creating Objects From Data Statements V0.01 <<
`
` By Kevin Picone
`
` Built with (& requires) PlayBASIC V1.64K beta19
`
` (c) copyright 2009, By Kevin Picone, All rights reserved.
` *=---------------------------------------------------------------------=*
`
` This is example uses the new CallFUNCTION feature to dynamically call
` call the various creation functions from a list of data statements.
`
`
` *=---------------------------------------------------------------------=*


Constant ObjectClass_Circle =1
Constant ObjectClass_Box =2


Type tObject
ObjectClass
x#,y#
size
colour
EndType

Dim Object(10) as tobject


// --------------------------------------------------
// Spawn the objects from the data statements bellow
// --------------------------------------------------
repeat
obj$=readdata$()
SpawnObject(obj$)
until obj$=""


// --------------------------------------------------
// Demo loop
// --------------------------------------------------

Setfps 60

Do
cls 0


for lp=1 to getarrayelements(Object(),1)
if Object(lp)
select Object(lp).Objectclass
case ObjectClass_Circle
circlec Object(lp).x,Object(lp).y,Object(lp).size,true,Object(lp).Colour

case ObjectClass_Box
size=Object(lp).size
x1#=Object(lp).x-size
y1#=Object(lp).y-size
x2#=Object(lp).x+size
y2#=Object(lp).y+size
boxc x1#,y1#,x2#,y2#,true,Object(lp).Colour

endselect
endif
next

Sync
loop



; ---------------------------------------------------------------------
; ---------------------------------------------------------------------
; Sample object creation data..
; Parameter format. X,y,size,colour

Data "CreateBall[100,200,50,$ff0000]"
Data "CreateBox[400,400,25,$00ff00]"
Data "CreateBox[700,100,10,$ff00ff]"
Data "" ; end of list of



` *=---------------------------------------------------------------------=*
` >> Spawn Object <<
` *=---------------------------------------------------------------------=*
`
` This routine takes in the input string, the parses this into the
` function to calls name,. and it's standard parameter list.
`
` Since this generic, we can add more object types without having to
` explicitly parse them out in here. As long as the function name
` exists and the input params match, then we're golden.
`
` *=---------------------------------------------------------------------=*



Function SpawnObject(obj$)
Obj$=trim$(Obj$," "+Chr$(9))
if Len(obj$)>5

// Get the Function to Calls NAME$
pos=instring(obj$,"[",1,false)
FunctionName$=Left$(Obj$,Pos-1)

pos++
// Get the param list
params$=mid$(obj$,pos,len(obj$)-pos)


// split this list into string array
Dim Fields$(10)
Count=SplitToArray(params$,",",Fields$(),1)

// convert the fields from strings to values
x#=Val#(Fields$(1))
y#=Val#(Fields$(2))
size#=Val#(Fields$(3))
colour=Val(Fields$(4))

// Call this function by name
CallFunction FunctionName$,x#,y#,Size#,Colour
endif

EndFunction



` *=---------------------------------------------------------------------=*
` >> Create (Spawn) Ball Object <<
` *=---------------------------------------------------------------------=*


Function CreateBall(x#,y#,RAdius,Colour)
ThisBall=GetFreeCell(Object())
Object(ThisBall).ObjectClass=ObjectClass_Circle
Object(ThisBall).x=x#
Object(ThisBall).y=y#
Object(ThisBall).size=Radius
Object(ThisBall).colour=colour
EndFunction


` *=---------------------------------------------------------------------=*
Login required to view complete source code





 Manual Version


 

` *=---------------------------------------------------------------------=*
`
`              > Creating Objects From Data Statements V0.01 <<
`
`                              By Kevin Picone
`
`                    Built with PlayBASIC V1.64K beta19
`
`      (c) copyright 2009, By Kevin Picone, All rights reserved.
` *=---------------------------------------------------------------------=*
`
`     This is example uses uses a select/case to spawn objects.  So,
`  in this version new object types would have to hard coded into the spawn
`  function.
`
`
` *=---------------------------------------------------------------------=*


Constant ObjectClass_Circle =1
Constant ObjectClass_Box =2


Type tObject
ObjectClass
x#,y#
size
colour
EndType

Dim Object(10) as tobject


// --------------------------------------------------
// Spawn the objects from the data statements bellow
// --------------------------------------------------
repeat
obj$=readdata$()
SpawnObject(obj$)
until obj$=""


// --------------------------------------------------
// Demo loop
// --------------------------------------------------

Setfps 60

Do
cls 0


for lp=1 to getarrayelements(Object(),1)
if Object(lp)
select Object(lp).Objectclass
case ObjectClass_Circle
circlec Object(lp).x,Object(lp).y,Object(lp).size,true,Object(lp).Colour

case ObjectClass_Box
size=Object(lp).size
x1#=Object(lp).x-size
y1#=Object(lp).y-size
x2#=Object(lp).x+size
y2#=Object(lp).y+size
boxc x1#,y1#,x2#,y2#,true,Object(lp).Colour

endselect
endif
next

Sync
loop



; ---------------------------------------------------------------------
; ---------------------------------------------------------------------
;  Sample object creation data..  
; Parameter format.  X,y,size,colour

Data "CreateBall[100,200,50,$ff0000]"
Data "CreateBox[400,400,25,$00ff00]"
Data "CreateBox[700,100,10,$ff00ff]"
Data "" ; end of list of







` *=---------------------------------------------------------------------=*
` >> Spawn Object <<
` *=---------------------------------------------------------------------=*
`
`    This routine takes in the input string, the parses this into the
` function to calls name,. and it's standard parameter list.
`
`
`    unlike the CallFunction version, this routine is not generic.  In this
` version we have to parse out and call the functions manually..
`
` *=---------------------------------------------------------------------=*


Function SpawnObject(obj$)
Obj$=trim$(Obj$," "+Chr$(9))
if Len(obj$)>5

// Get the Function to Calls NAME$
pos=instring(obj$,"[",1,false)
FunctionName$=Left$(Obj$,Pos-1)

pos++
// Get the param list
params$=mid$(obj$,pos,len(obj$)-pos)


// split this list into string array
Dim Fields$(10)
Count=SplitToArray(params$,",",Fields$(),1)

// convert the fields from strings to values
x#=Val#(Fields$(1))
y#=Val#(Fields$(2))
size#=Val#(Fields$(3))
colour=Val(Fields$(4))


// Trap what function name this is
Select FunctionName$

; if it's a ball, then create the ball
case "CreateBall"
CreateBall(x#,y#,Size#,Colour)

; if it's a box, then create the box
Case "CreateBox"
CreateBox(x#,y#,Size#,Colour)


EndSelect

// Call this function by name
endif

EndFunction



` *=---------------------------------------------------------------------=*
` >> Create (Spawn) Ball  Object <<
` *=---------------------------------------------------------------------=*


Function CreateBall(x#,y#,RAdius,Colour)
ThisBall=GetFreeCell(Object())
Object(ThisBall).ObjectClass=ObjectClass_Circle
Object(ThisBall).x=x#
Object(ThisBall).y=y#
Object(ThisBall).size=Radius
Object(ThisBall).colour=colour
EndFunction


` *=---------------------------------------------------------------------=*
` >> Create (Spawn) BOX  Object <<
` *=---------------------------------------------------------------------=*


Function CreateBox(x#,y#,RAdius,Colour)
ThisBall=GetFreeCell(Object())
Object(ThisBall).ObjectClass=ObjectClass_Box
Object(ThisBall).x=x#
Object(ThisBall).y=y#
Object(ThisBall).size=Radius
Object(ThisBall).colour=colour
EndFunction

 







Error Missing Closing Square Bracket

kevin

#1
 Example #2
 
 This version expand the previous example.  Except this time, we're not only handling creation dynamically, but rendering also.    



PlayBASIC Code: [Select]
` *=---------------------------------------------------------------------=*
`
` > Creating Objects From Data Statements V0.02 <<
`
` By Kevin Picone
`
` Built with (& requires) PlayBASIC V1.64K beta19
`
` (c) copyright 2009, By Kevin Picone, All rights reserved.
` *=---------------------------------------------------------------------=*
`
` This version extends the previous example, except this time, we're
` using generic calling for not only object creations,but object rendering.
` This allows us to plug new object types in without have to mod the creation
` or drawing code.
`
`
` *=---------------------------------------------------------------------=*



Type tObject
ClassName$
x#,y#
size
colour
EndType

Dim Object(10) as tobject


// --------------------------------------------------
// Spawn the objects from the data statements bellow
// --------------------------------------------------
repeat
obj$=readdata$()
SpawnObject(obj$)
until obj$=""


// --------------------------------------------------
// Demo loop
// --------------------------------------------------

Setfps 60

Do
cls 0

// draw the object types
for lp=1 to getarrayelements(Object(),1)
if Object(lp)
CallFunction "Draw"+Object(lp).ClassName$,lp
endif
next

Sync
loop



; ---------------------------------------------------------------------
; ---------------------------------------------------------------------
; Sample object creation data..
; Parameter format. X,y,size,colour

Data "Ball[100,200,50,$ff0000]"
Data "Box[400,400,25,$00ff00]"
Data "Box[700,100,10,$ff00ff]"
Data "" ; end of list of



` *=---------------------------------------------------------------------=*
` >> Spawn Object <<
` *=---------------------------------------------------------------------=*
`
` This routine takes in the input string, the parses this into the
` function to calls name,. and it's standard parameter list.
`
` Since this generic, we can add more object types without having to
` explicitly parse them out in here. As long as the functionname
` exists and the input params match, then we're golden.
`
` *=---------------------------------------------------------------------=*



Function SpawnObject(obj$)
Obj$=trim$(Obj$," "+Chr$(9))
if Len(obj$)>5

// Get the Function to Calls NAME$
pos=instring(obj$,"[",1,false)
FunctionName$=Left$(Obj$,Pos-1)

pos++
// Get the param list
params$=mid$(obj$,pos,len(obj$)-pos)


// split this list into string array
Dim Fields$(10)
Count=SplitToArray(params$,",",Fields$(),1)

// convert the fields from strings to values
x#=Val#(Fields$(1))
y#=Val#(Fields$(2))
size#=Val#(Fields$(3))
colour=Val(Fields$(4))

// Call this function by name
CallFunction "Create"+FunctionName$,x#,y#,Size#,Colour
endif

EndFunction



` *=---------------------------------------------------------------------=*
` >> Create (Spawn) Ball Object <<
` *=---------------------------------------------------------------------=*


Function CreateBall(x#,y#,RAdius,Colour)
ThisBall=GetFreeCell(Object())
Object(ThisBall).ClassName = "Ball"
Object(ThisBall).x=x#
Object(ThisBall).y=y#
Object(ThisBall).size=Radius
Object(ThisBall).colour=colour
EndFunction




` *=---------------------------------------------------------------------=*
` >> DrawBall <<
` *=---------------------------------------------------------------------=*


Function DrawBall(ThisObject)
circlec Object(ThisObject).x,Object(ThisObject).y,Object(ThisObject).size,true,Object(ThisObject).colour
EndFunction


Login required to view complete source code


Error Missing Closing Square Bracket

kevin

#2
 Example #3

   This versions adds some user interaction, so this time the user can click on the object to delete it.   Each object type has it's own click function. So the central loop doesn't need to be aware of what object type is getting clicked. 





` *=---------------------------------------------------------------------=*
`
`              > Creating Objects From Data Statements V0.03 <<
`
`                              By Kevin Picone
`
`              Built with (& requires) PlayBASIC V1.64K beta19
`
`      (c) copyright 2009, By Kevin Picone, All rights reserved.
` *=---------------------------------------------------------------------=*
`
`     This version extends the previous example by adding some user
`  interaction.   in this versio theuser can click on the obejcts to
` to destory them.
`
` *=---------------------------------------------------------------------=*


Type tObject
ClassName$
x#,y#
size
colour
EndType

Dim Object(10) as tobject


// --------------------------------------------------
// Spawn the objects from the data statements bellow
// --------------------------------------------------
repeat
obj$=readdata$()
SpawnObject(obj$)
until obj$=""


// --------------------------------------------------
// Demo loop
// --------------------------------------------------

Setfps 60

Do
cls 0

// draw the object types
for lp=1 to getarrayelements(Object(),1)

; check if this object exists
if Object(lp)

; get the objects class name
Name$=Object(lp).ClassName$

; draw the object, so we see it this frame
CallFunction "Draw"+Name$,lp

; Call the mouseOver function for this obhect type
CallFunction "MouseOver"+Name$,lp

endif
next

Sync
loop



; ---------------------------------------------------------------------
; ---------------------------------------------------------------------
;  Sample object creation data..  
; Parameter format.  X,y,size,colour

Data "Ball[100,200,50,$ff0000]"
Data "Box[400,400,25,$00ff00]"
Data "Box[700,100,10,$ff00ff]"
Data "" ; end of list of



` *=---------------------------------------------------------------------=*
` >> Spawn Object <<
` *=---------------------------------------------------------------------=*
`
`    This routine takes in the input string, the parses this into the
` function to calls name,. and it's standard parameter list.
`
`     Since this generic,  we can add more object types without having to
`  explicitly parse them out in here.   As long as the functionname
`  exists and the input params match, then we're golden.
`
` *=---------------------------------------------------------------------=*



Function SpawnObject(obj$)
Obj$=trim$(Obj$," "+Chr$(9))
if Len(obj$)>5

// Get the Function to Calls NAME$
pos=instring(obj$,"[",1,false)
FunctionName$=Left$(Obj$,Pos-1)

pos++
// Get the param list
params$=mid$(obj$,pos,len(obj$)-pos)


// split this list into string array
Dim Fields$(10)
Count=SplitToArray(params$,",",Fields$(),1)

// convert the fields from strings to values
x#=Val#(Fields$(1))
y#=Val#(Fields$(2))
size#=Val#(Fields$(3))
colour=Val(Fields$(4))

// Call this function by name
CallFunction "Create"+FunctionName$,x#,y#,Size#,Colour
endif

EndFunction



` *=---------------------------------------------------------------------=*
` >> Create (Spawn) Ball  Object <<
` *=---------------------------------------------------------------------=*


Function CreateBall(x#,y#,RAdius,Colour)
ThisBall=GetFreeCell(Object())
Object(ThisBall).ClassName = "Ball"
Object(ThisBall).x=x#
Object(ThisBall).y=y#
Object(ThisBall).size=Radius
Object(ThisBall).colour=colour
EndFunction



` *=---------------------------------------------------------------------=*
` >> DrawBall <<
` *=---------------------------------------------------------------------=*


Function DrawBall(ThisObject)
circlec Object(ThisObject).x,Object(ThisObject).y,Object(ThisObject).size,true,Object(ThisObject).colour
EndFunction


Function MouseOverBall(ThisObject)
if leftmousebutton()
if pointintersectcircle(mousex(),mousey(),Object(ThisObject).x,Object(ThisObject).y,Object(ThisObject).size)
Delete(ThisObject)
endif
endif
EndFunction





` *=---------------------------------------------------------------------=*
` >> Create (Spawn) BOX  Object <<
` *=---------------------------------------------------------------------=*


Function CreateBox(x#,y#,RAdius,Colour)
ThisBall=GetFreeCell(Object())
Object(ThisBall).ClassName = "Box"
Object(ThisBall).x=x#
Object(ThisBall).y=y#
Object(ThisBall).size=Radius
Object(ThisBall).colour=colour
EndFunction


Function DrawBox(ThisObject)
size=Object(ThisObject).size
x1#=Object(ThisObject).x-size
y1#=Object(ThisObject).y-size
x2#=Object(ThisObject).x+size
y2#=Object(ThisObject).y+size
boxc x1#,y1#,x2#,y2#,true,Object(ThisObject).Colour
EndFunction




Function MouseOverBox(ThisObject)
if leftmousebutton()
size=Object(ThisObject).size
x1#=Object(ThisObject).x-size
y1#=Object(ThisObject).y-size
x2#=Object(ThisObject).x+size
y2#=Object(ThisObject).y+size
if PointInBox(MouseX(),Mousey(),x1#,y1#,x2#,y2#)
Delete(ThisObject)
endif
endif
boxc x1#,y1#,x2#,y2#,true,Object(ThisObject).Colour
EndFunction





Function Delete(ThisObject)
Object(ThisObject) = null
EndFunction

Error Missing Closing Square Bracket

LemonWizard

#3


This is AWESOME!
so basically, the object type can be linked to a specific function, and you can use callfunction to execute a function contained in a string..

damn! THIS IS GREAT



kevin


 yeah, it just lets us 'select'  a function to call at runtime, rather than at compile time.   While  it's not something that every program will benefit from, but there are occasions where this type of approach can greatly simplify user code.  

LemonWizard


Yeah.
It's too bad I can't execute a command from a string.
Would that even work?
Assuming you could execute a command from a string:

Program output:
"Enter any command" ;
User types "Dim myarray(100)"

Are arrays dimmed when the program is compiled, or are they created within the code as the code executes?

Because, I can use if statements to create a new array and resize arrays using redim so...



kevin

#6
Quote
It's too bad I can't execute a command from a string.
Would that even work?
Assuming you could execute a command from a string:

   This is a whole other rabbit hole. (ie scripting).    It's technically possible (at least to some degree),  but it's not easily implemented due to how the VM1 works.   It'd somewhat more suited to how Vm2 works.  
 

QuoteAre arrays dimmed when the program is compiled

   Dim is a multi purpose operation in BASIC.    It's first and foremost job is a compiler level declaration, but for arrays it actually an initialization method also.  

   During compilation, the compiler builds a prototype when it first sees an arrays dim statement.   Which all the stuff it needs to know about it, such as it's name and number of dimensions and it's type primarily.   The actual data though is not create during  compilation (too many unknowns!),  the actual array data is initialized when you run the Dim command.

   You can see this yourself with the following.

PlayBASIC Code: [Select]
    Goto SkipDim

Dim Table(100)

SkipDim:
Table(10) = 122345

Print Table(10)




  While, this will compile, the array creation has been skipped over, so when the runtime hits the Table(10) = 122345 line, it'll halt the program as the Table() array doesn't actually exist (have any data in it).
     

Quote

Program output:
"Enter any command" ;
User types "Dim myarray(100)"

   In order to build 'native' PB code and then execute it, means instancing the entire package.  This wouldn't really work.

   Scripting is better tackled the old fashion way..  Ie  Kyruss II ..  

   
   Also,  you can dynamically create arrays in 1.64K, Which is shown Here



LemonWizard


That's interesting. I haven't had a chance to look at your KyrusII thing yet.
I've been strongly considering how I would go about building a visual scripting system. It would be used in games and things like that for character movement, speech, and that kinda thing. Or for AI and character dialouge. (Okay now this is way off topic sorry)



kevin

       I think all too often people confused a database / action scripting with the need for script programming.    The whole point of externalizing the data/actions is to make content creation easier for creators (level/worlds designers shouldn't need to be programmers).  The user shouldn't have to painstakingly roll code to do everything

     So an action script should be a simplified down as far as possible.      In other words the script is controlling the characters actions, but the not micro managing the character on a one to one basis.. Too much overhead, and too time consuming to create content.    For example,  when the script, tells the character to talk to 'some person'.   Then the engine goes about finding this person, by moving the character so they can make this interaction.  So actions are like the characters thought process.    

      For stuff like conversation dialogs,  movement paths, animations etc etc,  then  these are just data.