ASSEMBLING AN ODE CAR

The exercice of this lesson is very funny:

Your first work is to download these new pieces for the car:

baseCar10x2x8.ase - in the folder baseCar10x2x8

frontCar10x2x8.ase - in the folder frontCar10x2x8

frontCar10x2x8.jpg - in the subfolder Textures

backCar10x2x8.ase - in the folder backCar10x2x8

backCar10x2x8.jpg - in the subfolder Textures

seatCar10x2x8.ase - in the folder seatCar10x2x8

arms.jpg - in the subfolder Textures

body.jpg - in the subfolder Textures

chest.jpg - in the subfolder Textures

hair.jpg - in the subfolder Textures

theFace.jpg - in the subfolder Textures

VERY IMPORTANT:We have 3 types of pieces:

Each one of these objects has a different Class definition, having different methods.

We will mix pieces of different types for the creation of our car. Its base will be a "kicker" but having "normal pieces" assembled to it.

The first thing you need to do is the creation of 3 new Classes: FrontCar10x2x8, BackCar10x2x8, SeatCar10x2x8. They are "normal pieces".

So, they will have the methods:handlesKeyboard, handlesPointerDown, isComponent, initialize, keyDown.

Remember to use the new formulas for "initialize" and "KeyDown". By example, for BackCar10x2x8:

initialize

| url |	 
 
super initialize.
url := 'http://www.dmu.com/TeaLand/spaces/backCar10x2x8.tea'.
tframe := (TLoad3DSMax new initializeWithFileName: 
	   (FileDirectory pathFrom:
           {FileDirectory default pathName.  'Content'.   'backCar10x2x8'. 'backCar10x2x8.ase'}) 
	   scale: 0.1 shadeAngle: 90.1 textureMode: GLReplace) frame.
tframe collapse.
tframe boundsDepth: 3.
tframe initBounds.
self addChild: tframe.
tframe objectOwner: self.
 
TExporter export: tframe asBinary:url.
inControl := false.

The keyDown for these "normal pieces" will be:

keyDown: pointer

| c |
c := pointer event2D keyCharacter.
"To move X+" 
c = $w ifTrue:[ 
 tframe translation:  tframe translation+( tframe localTransform column1*0.5).			 
 inControl := true.
].
"To move X-" 
c = $s ifTrue:[  
  tframe translation:  tframe translation-( tframe localTransform column1*0.5).	
 inControl := true.
].
"To turn left"
c = $a ifTrue:[  
  tframe addRotationAroundY:-90.
 inControl := true.
].
"To turn right"
c = $d ifTrue:[  
   tframe addRotationAroundY: 90.			 
 inControl :=true.
].
"To go up:Y+"
c = $z ifTrue:[ 
 tframe translation:  tframe translation+( tframe localTransform column2*0.5).		 
 inControl := true.
].
"To go down (oops!):Y-"
c = $x ifTrue:[  
 tframe translation:  tframe translation-( tframe localTransform column2*0.5).		 
inControl := true.
].
"To move Z+"
c = $c ifTrue:[  
  tframe translation: tframe translation+( tframe localTransform column3*0.5).		 
 inControl:= true.
].
"To move Z-"
c = $v ifTrue:[ "Z-" 
  tframe translation:  tframe translation-( tframe localTransform column3*0.5).		 
 inControl := true.
].
 

c = $l ifTrue:[ "Localization" 
 Transcript show: tframe globalPosition.	 
 inControl := true.
]. 

Different will be the Class BaseCar10x2x8. It will be a "kicker". Like we saw in the previous lesson it will have the methods: body, body:,geom, geom:, handlesPointerDown, isComponent, pick, pointerDown, pointerUp, step , that are the same for every ODE piece.

You need to pay attention to this method:

initialize

| fC bC sC |
super initialize.
tframe := (TLoad3DSMax new initializeWithFileName: 
	   (FileDirectory pathFrom:
            {FileDirectory default pathName.  'Content'.   'baseCar10x2x8'. 'baseCar10x2x8.ase'}) 
	   scale: 0.1  shadeAngle: 90.1 textureMode: GLReplace) frame.
tframe collapse.
tframe boundsDepth: 3.
tframe initBounds.
self addChild: tframe.
tframe objectOwner: self.
body:=ODEBody new.
body position: self globalPosition.
body massSphere: 500.
self body:body.

geom:= ODEBox new extent: 10@10@8 .
geom body: self body.

fC := FrontCar10x2x8  new.
fC translationX: 2 y: 3 z: 2.
fC addRotationAroundY:0.	 
self addChild: fC.

bC := BackCar10x2x8  new.
bC translationX: 2 y: 5 z: -2.
bC addRotationAroundY:0.	 
self addChild: bC.

sC := SeatCar10x2x8  new.
sC translationX: 4 y: 7 z: -5.
sC addRotationAroundY:0.	 
self addChild: sC.

inControl := false.

CODE COMMENTS

For the MyODE (or Private) Class: you need to change some variables of the class because the name of the "false avatar' will be different, like you can see at the initializeDefaultSpace, method similar of that of the previous lesson:

 
initializeDefaultSpace
	 
cworld := TSpace new.
 
self makeLight: cworld.
floor := self makeFloor: cworld fileName:  'lawn.BMP'  .
floor translationX: 0 y: -3 z: 0.
prevTime := Time millisecondClockValue.
world := ODEWorld new.
space := ODESpace new.
world add: (contacts := ODEContactGroup new).
world gravity: #(0 -30 0 ).
sceneObjects := Dictionary new.
rnd : Random new.
	
space add: (ODEPlane new planeA: 1 b:0 c:0 d:-40).	
space add: (ODEPlane new planeA: 0 b:0 c:1 d:-40).	
space add: (ODEPlane new planeA:-1 b:0 c:0 d:-40).	
space add: (ODEPlane new planeA: 0 b:0 c:-1 d:-40).	
space add: (ODEPlane new planeA: 0 b:1 c:0 d: (floor globalPosition y + (floor extent y / 2))).

"Adding the "kicker"
bC := BaseCar10x2x8 new.
bC translationX: 0 y: -2 z: 0.
cworld addChild: bC.
world add: (bC body).
space add: (bC geom).
	 
sceneObjects at: bC body id put: {bC. bC body.  bC geom}.
 
self addCube. "required!!!!"
self transferCam: bC.
^ cworld

This Class will have the same methods of the previous lesson: addCube , addBall2, stepAt, transferCam,wantsSteps

The method keyStroke , by example, is the same:

 
keyStroke: anEvent
	
| kv kc bb |
kc := anEvent keyCharacter asLowercase.
kv := anEvent keyValue.

bb:= bc .
  
"The codes for arrow keys are: 28, 29, 30, 31" 
kv = 30 ifTrue:[ 
 bb   translation: bb translation+( bb localTransform column3*-0.5). 
 bb body position: bb globalPosition.  
]. 
kv = 31 ifTrue:[ 
 bb   translation: bb translation+( bb localTransform column3*0.5).   	 
 bb body position:bb globalPosition. 
]. 
kv = 28 ifTrue:[ 
 bb addRotationAroundY:2.
 bb body quaternion: bb quaternion.
].    
kv = 29 ifTrue:[ 
 bb addRotationAroundY:-2.
 bb body quaternion: bb quaternion.
].

"To create ODE objects, press P"
kc = $p ifTrue:[ 
self addBall2.
self addBall2.
self addBall2. 
].

(#(28 29 30 31) includes: kv) ifTrue: [^self]. 

"To change the camera legoic/avatar use Esc key"	
kv = 27 ifTrue:[
^self transferCam:bb].
	
super keyStroke: anEvent.

Change the size of the Balls in the method addBall2 - radius: 3.

IMPORTANT: Remember that you can use the "normal avatar" - better for the assembling of the pieces - but to revert to the "false avatar" - the car! - the "normal" needs to be in its initial position. Or the movements will be not correct.

TIP: After the car assembled: use the key:"L" to find the ultimate positions of the pieces. Change the values in the "initialize" of the BaseCar10x2x8 Class, and redo the MyODE space. After the load, use only the arrow-keys.

VERY IMPORTANT: Add 2 units to the Y position of the pieces (because the Base is at -2, to be in the usual Croquet floor standard position - a Croquet bug?).

USUAL ERROR: If you put the "front" not in the "right position" the car will "look" to you and the arrow keys will work in the contrary... YOUR ERROR! Sorry...

Look some figures of our exercice:




PREVIOUS LESSON NEXT LESSON
T. CONTENTS HOMEPAGE

DISCLAIMER: This material can be translated for any language, and reproduced total or partially by anybody using any type of media. But, please, don't put your name like author. And let me know if it was useful (americo@dmu.com).The use of any code, 3D model or technique published is free and doesn't need to have any reference about this source.The author is not responsible for any damage that the material can cause to your professional or sexual life.