Parent Child..

BlitzMax Forums/BlitzMax Programming/Parent Child..

Paul "Taiphoz"(Posted 2011) [#1]
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?


ima747(Posted 2011) [#2]
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.


Paul "Taiphoz"(Posted 2011) [#3]
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


Paul "Taiphoz"(Posted 2011) [#4]
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.


ziggy(Posted 2011) [#5]
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


ima747(Posted 2011) [#6]
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


Paul "Taiphoz"(Posted 2011) [#7]
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.


Czar Flavius(Posted 2011) [#8]
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.


Paul "Taiphoz"(Posted 2011) [#9]
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()