
Imagine that you are creating a little game for your space (Croquet is not a game engine but it's viable for the creation of simple minigames).
In the game, a "shooter" try to kill many "monsters" (HalfLife3?). And you would like to create an score, showing how many "monsters" are dead.
TIP: There are more "serious" applications for this convergence 3D-2D, like, by example: a virtual galery of sculptures. When the avatar is near (use of "distance") an sculpture, appears a description about it. Different ambient sounds for each sculpture... Etc. Etc. Use your imagination!
In this lessons you will learn how to do it.
IMPORTANT: I hope that you understood all the concepts of the "Basic Tutorial for Beginners because they are pre-requirements for these lessons.
Until now we have created "instances variable" of a Class. But for our application we need to create a: Class variable.
When we change the value of a Class variable in any instance of the Class, this value will be changed at all the instances .
We will do an exercice using some of the resources we have created at previous lessons. So, the new definition of the Class Private will be:
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: 'Score'
poolDictionaries: 'OpenGLConstants '
category: 'MyCroquet'
A Class variable is always "capitalized" (first letter in upper case).
Like Smalltalk doesn't have the usual concept of properties (like Java, C++ etc.) we need to create 2 new methods to access this Class variable. To "read" and "write":
score ^ Score.
And to "write":
score:aScore. Score:= aScore.
In the initializeDefaultSpace method we initialize the variable with: zero (in red).
initializeDefaultSpace
| base|
on:=0.
cL4x6x4afly:=0.
shot:=0.
Score := 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
Our exercice will be very simple. At this lesson we will create a Text-border and to do an script glued to it, where we will create an instance of the Class Private, whose name will be: pr. Look the figure:
IMPORTANT: If you are not understanding nothing that you are seeing it's because you need to read again the: "Basic Tutorial for Beginners.
The code of the script1 is:
| pr | pr:=Private new. self setCharacters: pr score.
This script will run when the user "mouseEnter" the Text-border, actualizing the value of the score.
We would like that: when the shooter do a "good shot" against the column, the score is increased by 1.
We need to code this (in red) at the stepAt method:
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.
Score := Score+1.
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.
Only this... Very easy.
PREVIOUS LESSON NEXT LESSON T. CONTENTS HOMEPAGE
