SHOOTER

At this lesson the exercice will be the creation of a "shooter" that will be our usual customizeable "legoic", now having a gun. But, using a similar technique, a "shooter" can be any "false avatar" - a tank, a cannon etc.

The more important "part" of the "ODE piece" that will be the "shooter" is: the bullet. Like we have the "logo" in the ColumnLogo piece , or the "door" in the WallDoor piece, here we have, defined, inside the 3ds max: the bullet, a little sphere inside the barrel of the weapon.

To do our exercice you need to download:

legoicMGunODE.ase - in the folder legoicMGunODE

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

Let's go to explain how the gun works.

And how we code this application?

Easy...

First, to define the Class LegoicMGunODE:

TGroup subclass: #LegoicMGunODE
	instanceVariableNames: 'inControl tframe body geom pickDelta bullet '
	classVariableNames: ''
	poolDictionaries: 'OpenGLConstants '
	category: 'MyCroquet'

New here is the instance variable bullet, defined in:

initialize

super initialize.
tframe := (TLoad3DSMax new initializeWithFileName: 
	   (FileDirectory pathFrom:
            {FileDirectory default pathName.  'Content'.   'legoicMGunODE'. 'legoicMGunODE.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: 100.
self body:body.

geom:= ODEBox new extent: 6@6@6 .
	geom body: self body.

bullet := (tframe find:[:frm | frm objectName = 'bullet']) at: 1.
inControl := false.

Like we will use bullet in the Class Private (Smaltalk doesn't have properties...) we need to create the method:

bullet

^bullet.

The other methods of this Class are the same of the usual "false avatar".

We will use the same Class Private of the previous lesson, but we need to add some new instance variables:

TeapotMorph subclass: #Private
	instanceVariableNames: 'tframe cworld sceneObjects floor world space contacts prevTime
         rnd  wD12x7x1a wD12x7x1abody ahead   cL4x6x4a cL4x6x4abody on 
          cL4x6x4afly lG shot bulletInitT bulletInitO shotS expS recS '
	classVariableNames: ''
	poolDictionaries: 'OpenGLConstants '
	category: 'MyCroquet' 

This new variables, in bold, are defined in:

initializeDefaultSpace
	 
| base|
 on:=0. 
cL4x6x4afly:=0.

shot:=0.

"loading the sound files" 
shotS:=StreamingMP3Sound onFileNamed:  
 (FileDirectory pathFrom:
           {FileDirectory default pathName.  'Content'. 'legoicMGunODE' .'gunshot2.mp3'}) . 
expS:=StreamingMP3Sound onFileNamed:  
 (FileDirectory pathFrom:
           {FileDirectory default pathName.  'Content'. 'legoicMGunODE' .'explosion2.mp3'}) . 
recS:=StreamingMP3Sound onFileNamed:  
 (FileDirectory pathFrom:
           {FileDirectory default pathName.  'Content'. 'legoicMGunODE' .'gunrecharging.mp3'}) . 

cworld := TSpace new.
self makeLight: cworld.
	 
base :=BasePlateA70x3x70 new.
base translationX: 0 y: -6.3  z: 0.
cworld addChild: base.
 
prevTime := Time millisecondClockValue.
world := ODEWorld new.
space := ODESpace new.
world add: (contacts := ODEContactGroup new).
sceneObjects := Dictionary new.
rnd := Random new.
	
lG := LegoicMGunODE  new.
lG translationX: 0 y: -2  z: 0.
cworld addChild: lG.
world add: (lG body).
space add: (lG geom).
sceneObjects at:lG body id put: {lG. lG body.  lG geom}.

bulletInitT:= lG bullet translation.
bulletInitO:= lG bullet orientation.

self addCube.  "required"
self transferCam: lG.
^ cworld 

CODE COMMENTS

We have something new also, here:

 
keyStroke: anEvent

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

kv = 30 ifTrue:[ 
 ahead:=true.
 lG   translation: lG translation + (lG localTransform column3*-0.5).
 lG body position: lG globalPosition.  
]. 

kv = 31 ifTrue:[ 
 ahead:=false.
 lG   translation: lG translation + (lG localTransform column3*0.5).   
 lG body position:lG globalPosition. 
]. 

kv = 28 ifTrue:[ 
 lG addRotationAroundY:2.
 lG body quaternion: lG quaternion.
].    
  
kv = 29 ifTrue:[ 
 lG addRotationAroundY:-2.
 lG body quaternion: lG quaternion.
].

kc = $o ifTrue:[ 
 on:=1.
]. 
 
kv = 5 ifTrue:[ "Insert"
  self addWallDoor12x7x1a.
 self addColumnLogo4x6x4a. 
].

kc = $b ifTrue:[ 
 shot=0 ifTrue:[
  shot:=1.
  bulletInitT:= lG bullet translation.
  bulletInitO:= lG bullet orientation.
  shotS play.
 ].
].
  

(#(28 29 30 31) includes: kv) ifTrue: [^self]. 
kv = 27 ifTrue:[ "Esc  "
^self transferCam:lG].
super keyStroke: anEvent.

CODE COMMENTS

The action is really here:

stepAt: currentTime

| dur nCollision|
super step.

 cL4x6x4a ifNotNil:[
 cL4x6x4a logo addRotationAroundY: 1.
 (cL4x6x4afly=1)ifTrue:[
   cL4x6x4abody linearVel:  5@ 5@ -5.
   cL4x6x4abody angularVel:  5@ 0.5@ -5. 
 ]
]. 
	
 wD12x7x1a ifNotNil:[
 wD12x7x1abody  position:28.0@0.50@-26.0.
 wD12x7x1abody rotationAroundZ:0.
]. 

(shot=1) ifTrue:[
 lG  bullet translation: lG  bullet translation + (lG  bullet localTransform column3*-2). " A good velocity..."

 ((lG bullet distanceTo: lG)>20) ifTrue:[
   lG bullet translation: bulletInitT .
   lG bullet orientation: bulletInitO.
   recS play.
   shot:=0.
  ].
  (cL4x6x4a)ifNotNil:[
   ((lG bullet distanceTo: cL4x6x4a)<4) ifTrue:[ "What to do in the collision"
     cL4x6x4abody linearVel:  5@ 5@ -5.
     cL4x6x4abody angularVel:  5@ 0.5@ -5. 
     expS play.
     lG bullet translation: bulletInitT .
     lG bullet orientation: bulletInitO.
     recS play.
     shot:=0.
   ].
  ].
].	
	
 
space ifNil: [^self  ].
world connect.
space connect.
dur := ((currentTime asFloat) - (prevTime asFloat)) / 1000.
prevTime := currentTime.
sceneObjects do:[:id|
  | each body |
  each := id at:1. 
  body := id at:2.
  each isStepping not ifTrue:[
  each localTransform: body transform transposed.
 ]
 ifFalse:[ 
  body linearVel:  each globalPosition - (body position) * 10.	
  body position: each globalPosition.
  body quaternion: (each quaternion)
 ]
].
space collideDo: [:geom1 :geom2 |  
 nCollision := contacts
 addContact: geom1
 with: geom2
 bounce: 0.1 
 bounceVel: 0.1
 softCFM: 0.1.
 nCollision > 0 ifTrue: [
  wD12x7x1a ifNotNil:[ 
  
  self verifycL4x6x4a. 
 
  (ahead=true & on=0 ) ifTrue:[
   lG translationX: 0 y: -2  z: 0.
  ].
  (ahead=false & on=0 ) ifTrue:[
    lG translationX: 0 y: -2  z: 0.
   ].	
  (ahead=true  & on=1) ifTrue:[
    lG  translation:lG translation + (lG localTransform column3*0.5). 
  ].
  (ahead=false  & on=1 ) ifTrue:[
    lG  translation: lG translation - (lG localTransform column3*0.5). 
  ]. 	 
 
]].
].

world quickStep: dur.  
contacts empty.

CODE COMMENTS

The other methods of the Class Private are the same of the previous lesson.

I would like to remember, at the end of this important lesson, that Croquet is not a game engine. But it's possible to create some funny interactive sceneries for the Croquet spaces.


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.