moving intances of type with entityX?

Blitz3D Forums/Blitz3D Beginners Area/moving intances of type with entityX?

timmport(Posted 2006) [#1]
I have been developing(hacking script) a factory type scene where I have a machine that makes balls that fall onto a conveyor belt. These balls then move down the convyor belt. What I am trying to figure out now is how to have each individual Ball moved from the first conveyor to another conveyor by a mechanical arm. Each ball is a type Ball with various fields for positioning and movement the ball instances. When instances of my type ball collides with specific surafces (e.g. the conveyor) the ball instance moves in a new direction. To get instances of the ball to move in synch with the grabbing "hand" of the mechanical arm I thought I would get the EntityX(),EntityY(),EntityZ() and apply it to the x,y,z fields of the each Ball instances. However when I set this up and run it as soon as the Ball entity makes contact with the hand of the mechanical arm I get a memory access violation error. As I am new to Blitz script (epeecially fields and instances) could someone tell me if I am thinking about this right here are the relvent code snippets muh of which I hackd togther from Blitz samples:


Const CT_BALL = 1
Const CT_PLANE = 2
Const CT_ARM = 5

;I have changed the response to see if that did anything 
;and did not
Collisions CT_BALL , CT_PLANE , 2 , 2
Collisions CT_BALL , CT_ARM , 2 , 0


Type Ball
	Field Entity
	Field x# , y# , z#
	Field xs# , ys# , zs#
End Type



;-----------------------------
;----  conveyor belt ---------
;-----------------------------
conv1=LoadMesh("conveyor1.b3d")
EntityType(conv1 , CT_PLANE)




;-------------------------------
;---------- ARM STUFF ----------
;-------------------------------
base2=LoadMesh("arm_base.b3d")
ScaleEntity base2,.33,.33,.33
;MoveEntity base2,6.5,26,80
PositionEntity base2,-5,26,94
;RotateMesh base2,-30,0,0

RotateEntity base2,0,90,30 

arm2=LoadMesh("arm_part.b3d",base2)
MoveEntity arm2,0,3,0
ScaleEntity arm2,.5,.5,.5

for_arm2=LoadMesh("arm_part.b3d",arm2)
MoveEntity for_arm2,0,40,0

catcher = CreateCube(for_arm2)
ScaleEntity catcher,10,30,30
PositionEntity catcher,0,40,0
EntityType(catcher , CT_ARM)





Repeat

;------------------------------------------
;------------- arm animation stuff---------
;------------------------------------------
Angle = Angle + 2
negAngle = negAngle - 2
If Angle > 359 Then Angle = 0 : negAngle = 0

RotateEntity arm,Sin(angle) * 60,0,0
RotateEntity for_arm,Sin(angle) * 60,0,0

RotateEntity arm2,Sin(negAngle) * 60,0,0
RotateEntity for_arm2,Sin(negAngle) * 60,0,0

RotateEntity arm3,Sin(angle) * 60,0,0
RotateEntity for_arm3,Sin(angle) * 60,0,0


	
;------------------------------------------
;-----  the next lines of code create 
;-----  and updates instances of Type Ball
;------------------------------------------

	frame=MilliSecs()/100 Mod 7 
	frame2=MilliSecs()/100 Mod 9 
	
	UpdateBalls(0.025)



;-----  Everytime the timer ticks at 1 or less create a ball ----

	frame=MilliSecs()/.1 Mod 200
	If (frame <1)
		CreateBall()	
	EndIf




	UpdateWorld
	RenderWorld
	Flip


Until KeyHit (1)

End



Function UpdateBalls(Gravity#)

	For instance.Ball = Each Ball

		If Not instance = Null

			instance\x# = instance\x# + instance\xs#
			instance\z# = instance\z# + instance\zs#

			instance\ys# = instance\ys# - Gravity#
			instance\y# = instance\y# + instance\ys#
	
			;If the ball collides with he conveyour move down the conveyor
			If EntityCollided(instance\Entity , CT_PLANE)
				instance\ys# = Abs(instance\ys# / 1.08)
				instance\zs# = .15
				EndIf
			

;------------------------------------------------------------------------
;----------  when the mechanical arm/hand touches        ----------------
;----------  the ball move the ball with the hand        ----------------
;----------  THIS IS THE PART THAT DOES NOT WANT TO WORK ----------------
;------------------------------------------------------------------------			
			If EntityCollided(instance\Entity , CT_ARM)
			instance\ys# = EntityX( entity, globalFlag )
			EndIf


			PositionEntity(instance\Entity , instance\x# , instance\y# , instance\z#)
            ;this deletes the instances when it has reached y = -10
			If instance\y# < -10
				FreeEntity instance\Entity
				Delete instance
			EndIf

		EndIf

	Next
	

End Function



Function CreateBall()

	Ball.Ball = New Ball


		Ball\Entity = LoadMesh("glob.3DS")
		EntityType(Ball\Entity , CT_BALL)
		ScaleEntity(Ball\Entity , .1 , .1 , .1)
		EntityRadius(Ball\Entity , .15)

		;initial position of the Balls
		Ball\x# = 6.1
		Ball\y# = 4.8
		Ball\z# = 44.9
	Repeat
		;direction and speed the Balls move
		Ball\xs# = 0
		Ball\ys# = 0
		Ball\zs# = .011

	Until (Ball\zs# > 0.01 Or Ball\zs# < -0.01)
	
End Function



Sir Gak(Posted 2006) [#2]
As I was reading the sample code, I noticed you use ball for both the type and the type variable instance. While Blitz can distinguish between them, no problemo, human eyes are not as discerning,. Maybe you could rename the type declaration as T-Ball ("t" for type) for human readability, as follows:

Type T-Ball
Field Entity
Field x# , y# , z#
Field xs# , ys# , zs#
End Type

The memory access error is telling you the variable or object being accessed doesn't exist. It often occurs, for instance, when someone tries to use a graphic image that they did not successfully load (i.e. a "tree" image is un-successfully NOT loaded, and then the program tries to draw the tree.)


Stevie G(Posted 2006) [#3]
Here is the issue ( I think )

This ...
If EntityCollided(instance\Entity , CT_ARM)
			instance\ys# = EntityX( entity, globalFlag )
			EndIf


Should be this ..

If EntityCollided(instance\Entity , CT_ARM)
			instance\ys# = EntityX( instance\entity, globalFlag )
			EndIf


BTW, no need to use the condition "If not instance = null" as when deleted the instance should no longer be in the list at all.

Stevie


Sir Gak(Posted 2006) [#4]
I agree. Definitely fits the bill for a graphic object trying to be accessed, which was not loaded. The handle for the entity is in "instance\entity", not "entity". Since "entity" (by itself) was not loaded with a value, its default value is a zero (0), which is not a valid handle for an object, graphic or otherwise.


timmport(Posted 2006) [#5]
Changing instance\ys# = EntityX( entity, globalFlag )
to
instance\ys# = EntityX( instance\entity, globalFlag )
worked. But how do I get the EntityY data to my instance so that the ball will be atached to the hand.

When I do this
instance\ys# = EntityX( cacther, globalFlag )


I get that same error. Yet catcher exists.


Stevie G(Posted 2006) [#6]
Yes, but does 'cacther'? You must make the 'catcher' global as it's being referred to within a function.

Stevie


timmport(Posted 2006) [#7]
I did not reaslise that entity handles can be global. My mec arm this is somewhat working.

The balls that are "grabbed" go in unaticipated directions. I am looking to see if all parenting that went into making the "mech arm" is causing the balls to move strangley.


Sir Gak(Posted 2006) [#8]
Stevie G's point is that "catcher" is mispelled "cacther". Blitz is great, but it can't catch spelling errors. LOL. Or rather, it catches them, but thinks they are a new instance of some new variable, not the one you really wanted.

But, more seriously, I don't generally like using Functions for that very reason, that variable instances inside a function don't match what's on the outside, unless you pass them through to the function, or make them global.

But, one man's trash is another man's treasure, as the saying goes.


timmport(Posted 2006) [#9]
Sorry about the spelling error -it happened when I transcribed the code. However in the code that I execute the handle names are consistent. If anyone has any ideas about how to attach an instance I would be appreciative if you would share them.


b32(Posted 2006) [#10]
Have you tried using EntityParent ?
If collided .. etc
EntityParent instance\mesh, CollidedEntity()

And then:
instance\x = entityx(instance\mesh)
instance\y = entityy(etc..)

instead of PositionEntity instance\mesh, instance\x etc.


Sir Gak(Posted 2006) [#11]
However, if recall correctly (hey, I've been wrong before!), once you attach an entity to a parent, you can't un-attach it.

Maybe when the collision is detected, read the existing coords of the arm catcher and the ball. Calculate the difference between them, then make the ball's coords the same as the arm, but with the +/- differences determined above, meaning the ball is now "relative" to the arm catcher's coords. That way, wherever the arm moves, the ball moves with it, relative to it. When you want to release the ball, read its coords, and make them absolute, rather than relative, and then the ball can resume movement independently of the arm catcher.

You may want to create in the type for the ball two sets of fields for coords, plus a binary field that is a switch to tell you whether you are using relative coords, or absolute coords, as below (incorporating my earlier suggestion to rename the type so as to be more readable to the human eye, as I find ball.ball a bit confusing):

Type T-Ball
Field Entity
Field x# , y# , z# ;absolute coords
Field rx#, ry#, rz# ;i,e, relative coords
Field xs# , ys# , zs#
Field switch ;0=absolute, 1=relative
End Type

Anyway, that's my thought on tackling the problem. Hope this helps.

One later thought: maybe you would want also to include the arm catcher's entity handle inside your ball type, so that you know which ball is attached to (and positioned relative to) which arm catcher, like maybe this:

Type T-Ball
Field Entity
Field which_catcher_entity_handle
Field x# , y# , z# ;absolute coords
Field rx#, ry#, rz# ;i,e, relative coords
Field xs# , ys# , zs#
Field switch ;0=absolute, 1=relative
End Type


Stevie G(Posted 2006) [#12]
However, if recall correctly (hey, I've been wrong before!), once you attach an entity to a parent, you can't un-attach it.



.. and you're wrong again ;) Just use EntityParent MyMesh, 0 to unparent a mesh ;)

Storing local and global coords is overkill. After all entityy( mesh,0 ) will give you local and entityy( mesh, 1 ) will give you the global ypos. Why not simply use a Parent field in the ball type. Set it to the arm mesh if attached, set it to 0 if not and handle accordingly.

Stevie


Sir Gak(Posted 2006) [#13]
Oh, well. Thanks for the correction. I missed the fine print. Given that, your solution is more efficient, and better.


timmport(Posted 2006) [#14]
Thanks for the sugestions. I made a parent field in my type. When my CreateBall function is called the Ball\parent is set to 0. However I am not sure what specific syntax to use to this field to parent in the following section of my update function.

If EntityCollided(instance\Entity , CT_GRAB)

EndIf

I have tried to put lines of code like:

EntityParent instance\entity, catcher,1

and a lot of other variations but to no avail.
Here is a stripped down version of my script
Graphics3D 640, 480, 0, 2

SeedRnd MilliSecs()

Const CT_BALL = 1
Const CT_CONVEYOR = 2
Const CT_GRAB = 3


Collisions CT_BALL , CT_CONVEYOR , 2 , 2
Collisions CT_BALL , CT_GRAB , 2 , 0




Type Ball
	Field Entity
	Field x# , y# , z#
	Field xs# , ys# , zs# 
	Field r , g , b
End Type



FrameTimer = CreateTimer(60)
StartTime = MilliSecs()


cam = CreateCamera()
PositionEntity cam,25.5,15.3,-1.5


TurnEntity cam,18.75,0,0
lite = CreateLight()





;---------  "conveyor belt" -----------------
conveyor = CreateCube()
PositionEntity conveyor,6,11, 70 
ScaleEntity conveyor,2,2,40
RotateEntity conveyor,-30,0,0
EntityType  conveyor,CT_CONVEYOR
EntityColor conveyor , 225 , 225 , 0

;--------- the "mechachincal arm" the ------------
;--------- real version is made of meshes --------
armbase =CreateCube()
PositionEntity armbase,-6,20,94
ScaleEntity armbase,4,1,4
RotateEntity armbase,0,90,0

armPivot_low = CreatePivot()
PositionEntity armPivot_low,-6,20,94
arm_lower =CreateCube(armPivot_low)
ScaleEntity arm_lower,.5,6,.5
PositionEntity arm_lower,0,7,0


;--- this is the part of the arm that "Grabs" the balls-------
Global catcher = CreateCube(arm_lower)
ScaleEntity catcher,10,1,1
PositionEntity catcher,0,1,0
EntityType catcher,CT_GRAB
EntityAlpha catcher,.5







;=========================================
;------------MY "MAIN" LOOP---------------
;=========================================

Repeat



;------------- arm animation stuff---------

Angle = Angle + 2
negAngle = negAngle - 2

If Angle > 359 Then Angle = 0 : negAngle = 0
RotateEntity armPivot_low,0,0,Sin(negAngle) * 60


entity = CameraPick (cam, MouseX (), MouseY ())

		

;----------- Ball Stuff ---------------------------------	
	
	UpdateBalls(0.025)

;--------- Everytime the timer ticks at 1 or less create a ball -----------

	frame=MilliSecs()/.1 Mod 200
	If (frame <1)
	CreateBall()	
		EndIf




;----------------START OF CAM CONTROLS----------------
;--------- I can move the camera using the arrow keys-
;-------------- and the "e" and "d" keys -------------
vert#=0 
horz#=0 
zoom#=0 

If KeyDown( 208 )=True Then vert#=-.25 
If KeyDown( 200 )=True Then vert#=.25 
If KeyDown( 203 )=True Then horz#=-.25 
If KeyDown( 205 )=True Then horz#=.25 
If KeyDown( 32 )=True Then zoom#=-.25 
If KeyDown( 18 )=True Then zoom#=.25 

MoveEntity cam,horz#,vert#,zoom#

	
	UpdateWorld
	RenderWorld
	
	;--------- keeps the FPS rate ----------
	sysFpsTimer2# = MilliSecs()
	sysFps = 1.0 / ( (sysFpsTimer2 - sysFpsTimer1 ) / 1000.0)
	sysFpsTimer1 = sysFpsTimer2
	WaitTimer(FrameTimer)
			
	Flip

Until KeyHit (1)

End



;====================================================
Function UpdateBalls(Gravity#)

	For instance.Ball = Each Ball

		If Not instance = Null

			instance\x# = instance\x# + instance\xs#
			instance\z# = instance\z# + instance\zs#

			instance\ys# = instance\ys# - Gravity#
			instance\y# = instance\y# + instance\ys#

		
		   ;----------- When the Ball Collides with the -------------------
		   ;----------- coveyor stop falling and move in-------------------
		   ;----------- the -z direction                -------------------
		
			If EntityCollided(instance\Entity ,CT_CONVEYOR) ;Not EntityCollided(instance\Entity , CT_ARM)

				instance\ys# = Abs(instance\ys# / 1.08)
				instance\zs# = .15

			EndIf
			
			;----------  !!! HELP THIS PART IS NOT WORKING  !!!      ---------------
			;----------  if the catcher makes collides with the ball  ---------------
			;----------  the catcher becomes parent to the ball      ---------------
			If EntityCollided(instance\Entity , CT_GRAB)
			
				EntityParent instance\entity, catcher,1
				
				instance\xs# = 0
				instance\x# = instance\x# + instance\xs#	

				instance\ys# = 0
				instance\y# = instance\y# + instance\ys#
				
				instance\zs# = 0
				instance\z# = instance\z# + instance\zs#
			EndIf


			PositionEntity(instance\Entity , instance\x# , instance\y# , instance\z#)
			If instance\y# < -10
				FreeEntity instance\Entity
				Delete instance
			EndIf

		EndIf

	Next
	

End Function

;====================================================
Function CreateBall()

	Ball.Ball = New Ball

			Ball\Entity = CreateSphere()
			EntityType(Ball\Entity , CT_BALL)
			ScaleEntity(Ball\Entity , 1.5 , 1.5 , 1.5)
			EntityRadius(Ball\Entity , 1.5)
			EntityShininess(Ball\Entity , 5.0)
		
       
		;origin position of the Balls
		Ball\x# = 6.1
		Ball\y# = 4.8
		Ball\z# = 44.9
	Repeat
		;direction and speed of the Balls move
		Ball\xs# = 0
		Ball\ys# = 0
		Ball\zs# = .011


	Until (Ball\zs# > 0.01 Or Ball\zs# < -0.01)

		;randomize the color of the Balls
		Ball\r = Rnd(255)
		Ball\g = Rnd(255)
		Ball\b = Rnd(255)

		EntityColor(Ball\Entity , Ball\r , Ball\g , Ball\b)

End Function

;====================================================



b32(Posted 2006) [#15]
That looks very nice! In the part that doesn't work, use
instance\x# = 0
instance\y# = 0
instance\z# = 0
because, when the object is parented to another object, the 'connection point' is (0, 0, 0) for the connected object.
If you need the actual coordinates, use EntityX(mesh, 1) <- with a ,1