Parent Child..
BlitzMax Forums/BlitzMax Programming/Parent Child..
| ||
don't think I have ever tried this before so will ask here before I do. I need to code or have the ability in a game to parent an object to another, essentially little guy walks around and picks stuff up, I want to parent the stuff to his hands/claws/jaws so that when I move guy, the stuff goes with and I dont need to worry about it until I drop it on the ground again. thoughts? |
| ||
This is quite easy if you're using an object based structure. Your guy object should have the fields to define him (position, image reference, whatever else) and an array/list/dictionary/etc. to hold references to the stuff he's carrying (if he can just cary one thing then you just need a field for that rather than a list obviously). The guy then has a draw method that draws him and loops through anything he's carrying and draws that offset by his position. When he picks something up it should be removed from your list of stuff on the ground, or however else you're referencing that stuff to draw it when it's not being carried. If you're not using OOP, you will want a list (or other grouping) of stuff being carried by your guy to serve a similar purpose. Hope that helps get you started. |
| ||
I hadd'nt thought of it like that. I did it like that last time, although my ant type didnt have a field for stuff it was holding, instead I had a field in my food type called holder which I set to the instance of ant which picked it up, when drawing the food being held I then just did a loop to draw all food, and when one was found during that loop to be held I did a second look to find the ant, get its position and then draw the food. I'm not sure which way is better, my method kept all food in a single list so stuff was not being copied or moved from list to list all the time, but I can see some benefit to having all food thats being held in its own list of objects, what do you think would be faster I wonder, there could be a lot of food on the ground and a lot of ants picking it up regularly. Also what I really had trouble with last time and what prompted this post is the specifics on positioning of the held object. in my b3d code I just draw the food on the ant, but this time around I want to actually put the food in the ants mouth, then when I rotate the ant I want the food to stay in its mouth, its the math behind this that has me stumped all that sin and cos stuff hurts my brain. So.. type ant field x,y..... field holding : true or false end type ants=list of all ants. type food field x,y.... field heldby end type food = list of all food. where as soon as an ant picks up a bit of food, I set that foods heldby=ants.ant and I set ant holding to true. or would I be faster having a seperete list of items being held and whos holding them. Last edited 2011 |
| ||
the b3d code I wrote was more of an AI simulation with 4 queens which spawned workers who got food, and then when enough food was gathered spawned soldiers which looked for other ants to kill, there were after about 30 minutes hundreds of ants, on screen picking up lots of food and fighter so which ever way is fastest I'll use. |
| ||
I would suggest a different approach. Not necesarily better than the ima747 one:Class ParentableObj Field _x:Float Field Parent:ParentableObj Method DrawPosX:Float() If Parent <> Null then Return Parent.DrawPosX()+_x Else Return _x EndIf End Method End Class You could do the same for the _y coordinate, rotation, etc. This way, you can handle complex chains of objects and they will be always related to their parents (wich will be related to the parents of the parents, etc.) EDIT: The only problem of this design, is that you'll have to be careful to prevent cyclic parenting. If you do, you'll run out of stack, but it would be a bug in the code anyway. Last edited 2011 |
| ||
You could handle it any way that makes sense to you: MOB->Things it's holding or Thing->Being held by I generally prefer objects having a list of stuff they hold for the reason that it's easier to figure out what an object is holding (just look, rather than loop through ALL objects looking for the one it's holding on to). Also it helps with off screen optimizations (if the MOB is not drawn you can skip looking at all the things it's holding too) but it's really down to what makes the most sense given the structure of your game... you can of course have both. An object can have a list of things it's holding, and something being held can have a reference to the thing it's holding... Ziggy's example is easily applied as an extension of either method to further simplify drawing and your class structures. In practice I would use something along those lines, but if you're not into sub-classing, or your game is structurally simple enough that you don't want to go that extra step then you could skip it... again, whatever makes the most sense to you. Last edited 2011 |
| ||
First of all I haddnt thought of stuff being out of screen and being held, old code was single screen but the new code will have much bigger play area, so thats a major plus for creating or keep a list of all objects being held. As for the parenting I only ever at least at this point need to parent 1 object to 1 ant, and only worker ants, picking up a bit of food,water,egg,etc. so I should only ever need to parent one object to one ant. ziggy, your code Return Parent.DrawPosX()+_x, I get it your grabbing the x from its parent and adding its own x but how would that be done with rotation ? for example say my ant is facing north walks up and grabs a bit of food, then it turns 1 degree at a time to face south and walks off with the food in its mouth, how would you get the foods position relative to the ants head or a spot just in front of the ants head. I know there should be a simple sin cos routine to get the local position relative to the ants x,y but my math stinks. |
| ||
I would have the ant refering to the food and the food also refering to the ant. If you do this you need to be aware it's a circular reference. This means when you want to delete an object, it must have a remove method which sets anything which could be circular to null. |
| ||
Yeah thats why I was just having the ant with a true or false boolean to say if its holding something or not, and the food type manages whos holding what. but I might flip that around and have the ant manage what its holding and the food or object type just have the boolean to say its being held or not which I would use to push and pop those objects off the main list and onto the holding list. im gona use this little bit of test code to sort out the parenting of a leaf object to the mouth of an ant. ![]() ![]() Strict Framework brl.glmax2d Import brl.freeaudioaudio Import brl.linkedlist Import brl.math Import brl.random Import brl.wavloader Import brl.bmploader Import brl.pngloader Import brl.tgaloader Import brl.jpgloader Import brl.oggloader SetGraphicsDriver GLMax2DDriver() Global GFX_Width :Int = 1024 Global GFX_Height :Int = 768 Graphics GFX_Width , GFX_Height , 0 SetBlend MASKBLEND | ALPHABLEND 'HideMouse Global antSpriteSheet:TImage = LoadAnimImage("ants.png" , 35 , 35 , 0 , 4) SetImageHandle antSpriteSheet , 17 , 17 Global leafSprite:TImage = LoadImage("leaf.png") SetImageHandle leafSprite,7,5 Global Time:Int=0 Global AnimationRate:Int=100 Global AnimationFrame : Int =0 Global Rot:Int Const Walking:Int = 1 Const Still:Int = 2 Global Ants:TList = CreateList() Type TAnt Field x:Float Field y:Float Field angle:Float Field x_vel:Float Field y_vel:Float Field speed:Float Field state:Int End Type For Local looper:Int = 1 To 1 Local newant:TAnt = New TAnt newant.x = 500+Rand(-500,500) newant.y = 500+Rand(-500,500) newant.angle = 12 newant.x_vel = 0 newant.y_vel = 0 newant.speed = 3 newant.state = still ListAddLast(Ants,newant) Next Repeat Cls If MilliSecs() - time => AnimationRate AnimationFrame:+ 1 If AnimationFrame => 4 Then AnimationFrame = 0 time=MilliSecs() End If If MouseHit(2) For Local rant:Tant = EachIn Ants rant.x = 500+Rand(-500,500) rant.y = 500 + Rand( - 500 , 500) Next End If For Local myant:Tant = EachIn Ants If MouseDown(1) myant.state=walking Else myant.state=still End If Select myant.state Case still rot = -ATan2(MouseX()-myant.x,MouseY()-myant.y) myant.angle = rot myant.x_vel = Cos(rot) * myant.speed myant.y_vel = Sin(rot) * myant.speed Case walking rot = -ATan2(MouseX()-myant.x,MouseY()-myant.y) myant.angle = rot myant.x_vel = Sin(rot) * myant.speed myant.y_vel = Cos(rot) * myant.speed myant.x :- myant.x_vel myant.y :+ myant.y_vel End Select SetRotation myant.angle DrawImage(antSpriteSheet,myant.x,myant.y,AnimationFrame) SetRotation 1 Next Flip Until KeyHit(KEY_SPACE) Or AppTerminate() |