'good' or 'really really bad' idea?
BlitzMax Forums/BlitzMax Programming/'good' or 'really really bad' idea?
| ||
well I had an idea, here it is, I basicly thought, what if my physics engine was very dynamic, flexible, easy to make addons for, and more oo... so heres how it works, you add whatever vars you need to be 'global' in each instance of a physics world to the fields, then you use the addproperty with pointers to the functions to initalize and update itRem This is the physics world type EndRem Rem Instructions for adding/removing custom properties to the physicsworld type: 1. add a field with all variables and lists your type will need. 2. After you create a physicsworld (assuming you call your world myworld:physicsworld) call the myworld.addperoperty( function pointer ) with a function pointer pointing to the update function of your new "property" This function must have a single parameter as follows myfunction(p:physicsworld) The physics world type will call the function passing itself as a parameter giving that function access to the lists and variables of that world 3. Now all you have to do is call myworld.update() and it will call all of your update functions. Call myworld.init and it will call all of your initiation functions you set using the myworld.addpropertyinit( function pointer ) This function must also have a single parameter of p:physicsworld EndRem Private Global fplist:TList = New TList Function getfp:functionptr(func(p:physicsworld)) For Local p:functionptr = EachIn fplist If p.func = func Then Return P:functionptr EndIf Next End Function Public Type PhysicsWorld Global PWorldList:TList = New TList 'list of all physics worlds Field Width#,Height# 'width and height of the physics world. Field VerletList:TList 'verlets in the physics world Field ConstraintList:TList 'constraints in the physics world Field ForceList:TList 'forces in the physics world Field PhysicsBodies:TList 'physics bodies in the physics world Field gravityx:Float 'gravity x velocity Field gravityy:Float 'and gravity y velocity Field PropertiesInit:TList 'list of functions that initiate the properties Field Properties:TList 'list of functions called every physics update. Function Create:PhysicsWorld(Width#,Height#,Property_Flag:Int = 1) Local p:physicsworld = New physicsworld p.width = width p.height = height p.propertiesInit:TList = New TList p.properties:TList = New TList pworldlist.addlast(p:physicsworld) Return p:physicsworld End Function Method AddProperty(prop(p:physicsworld)) Local f:functionptr = New functionptr f.func = prop fplist.addlast(f:functionptr) properties.addlast(f:functionptr) End Method Method RemoveProperty(prop(p:physicsworld)) properties.remove(getfp:functionptr(prop)) End Method Method AddPropertyInit(prop(p:physicsworld)) Local f:functionptr = New functionptr f.func = prop fplist.addlast(f:functionptr) propertiesinit.addlast(f:functionptr) End Method Method RemovePropertyInit(prop(p:physicsworld)) propertiesinit.remove(getfp:functionptr(prop)) End Method Method Update() For Local p:functionptr = EachIn properties p.func(Self) Next End Method Method Init() For Local p:functionptr = EachIn propertiesinit p.func(Self) Next End Method End Type Type FunctionPtr Field func(p:physicsworld) End Type idk if this is the best idea ive had or a bad idea doomed to failure. anyone tried this approach before? |
| ||
You're looking at a variation of the entirely legitimate Strategy pattern. It's not a stupid idea, and in fact is very probably a good one for what you're doing -- although I think that "Property" is a pretty vague name for it. I would recommend the use of functors / function objects over function pointers here -- something like: Type IPhysicsFunctor Method Apply(physics:PhysicsWorld) Abstract End Type Type FunctionPtr Extends IPhysicsFunctor Field func(p:PhysicsWorld) Method Apply(physics:PhysicsWorld) func(physics) End Method End Type and then using p.Apply(Self) instead of p.func(Self). The reason for this is that then you can do something like this: Type MoveAllBy Extends IPhysicsFunctor Field xSpeed:Float, ySpeed:Float Method Apply(physics:PhysicsWorld) ' move everything by xSpeed and ySpeed End Method End Type That is to say, your functors can encapsulate additional information (here, x/y speed) that a simple function pointer cannot (without extra work). You may want to consider allowing individual objects to have update strategies, as well. |
| ||
hmm I dont exactly get what you are saying but it sounds like a better idea than mine... what exactly is a functor? lol |
| ||
It's basically just a type that you use for one of its methods, in lieu of a function pointer. Here we have a functor type that takes a string and returns a string: ' Basic functor Type IFunctorWithString Method Apply:String(s:String) Abstract End Type And here are some concrete implementations: ' Upper functor Type UpperFunctor Extends IFunctorWithString Method Apply:String(s:String) Return Upper(s) End Method End Type ' Lower functor Type LowerFunctor Extends IFunctorWithString Method Apply:String(s:String) Return Lower(s) End Method End Type ' This function tests a functor Function TestFunctor(func:IFunctorWithString) Local s:String = "Hello world!" Print func.Apply(s) End Function TestFunctor(New UpperFunctor) TestFunctor(New LowerFunctor) The advantage over just a function pointer is that it can encapsulate additional information: ' This functor appends the value of 'toAppend' to the given string. Type AppendFunctor Extends IFunctorWithString ' We couldn't include this as easily with a function pointer. Field toAppend:String Method Apply:String(s:String) Return s + toAppend End Method End Type Local appendCapybara:AppendFunctor = New AppendFunctor appendCapybara.toAppend = "Capybara" TestFunctor(appendCapybara) |
| ||
thanks but if I want my users to be able to 'set and forget' so to speak how would this functor structure allow them to do that? Is it possible to look through all extended types? I think I might go with what I originally planned because I dont quite get functors lol |
| ||
its basically an abstract method |
| ||
There is an abstract method but that's definitely not the main point to pull out of that. The functor structure would allow set and forget -- something like passing in a New AppendFunctor.WithString("bob") instead of a pointer to AppendStringBob. That having been said, the function pointer route is still perfectly fine and a good idea if you don't want to overcomplicate things at the moment. :) |
| ||
What I'd give for closures... |