Вы находитесь на странице: 1из 14

11/12/13

Make a Neon Vector Shooter in jMonkeyEngine: Enemies and Sounds | Gamedevtuts+

Make a Neon Vector Shooter in jMonkeyEngine: Enemies and Sounds


Daniel Gallenberger on Nov 11th 2013 with 1 Comment

Tutorial Details
Software: jMonkeyEngine Difficulty: Intermediate Completion Time: 1 hour In the first part of this series on building a Geometry Wars-inspired game in jMonkeyEngine, we implemented the players ship and let it move and shoot. This time, well add the enemies and sound effects.

Overview
Heres what were working towards across the whole series:

gamedev.tutsplus.com/tutorials/implementation/make-a-neon-vector-shooter-in-jmonkeyengine-enemies-and-sounds/

1/14

11/12/13

Make a Neon Vector Shooter in jMonkeyEngine: Enemies and Sounds | Gamedevtuts+

and heres what well have by the end of this part:

gamedev.tutsplus.com/tutorials/implementation/make-a-neon-vector-shooter-in-jmonkeyengine-enemies-and-sounds/

2/14

11/12/13

Make a Neon Vector Shooter in jMonkeyEngine: Enemies and Sounds | Gamedevtuts+

Well need some new classes in order to implement the new features:
S e e k e r C o n t r o l : This is a behavior class for the seeker enemy. W a n d e r e r C o n t r o l : This is also

a behavior class, this time for the wanderer enemy. S o u n d : Well manage the loading and playing of sound effects and music with this. As you might have guessed, well add two types of enemies. The first one is called a seeker; it will actively chase the player until it dies. The other one, the wanderer, just roams around the screen in a random pattern.

Adding Enemies
Well spawn the enemies at random positions on the screen. In order to give the player some time to react, the enemy wont be active immediately, but rather will fade in slowly. After it has faded in completely, it will begin moving through the world. When it collides with the player, the player dies; when it collides with a bullet, it dies itself.

Spawning Enemies
First of all, we need to create some new variables in the M o n k e y B l a s t e r M a i nclass:
gamedev.tutsplus.com/tutorials/implementation/make-a-neon-vector-shooter-in-jmonkeyengine-enemies-and-sounds/ 3/14

11/12/13

Make a Neon Vector Shooter in jMonkeyEngine: Enemies and Sounds | Gamedevtuts+

1 2 3 4

p r i v a t el o n ge n e m y S p a w n C o o l d o w n ; p r i v a t ef l o a te n e m y S p a w n C h a n c e=8 0 ; p r i v a t eN o d ee n e m y N o d e ;

Well get to use the first two soon enough. Before that, we need to initialize the e n e m y N o d ein s i m p l e I n i t A p p ( ) : 1 2 3 / /s e tu pt h ee n e m y N o d e e n e m y N o d e=n e wN o d e ( " e n e m i e s " ) ; g u i N o d e . a t t a c h C h i l d ( e n e m y N o d e ) ;
?

Okay, now on to the real spawning code: well override s i m p l e U p d a t e ( f l o a tt p f ) . This method gets called by the engine over and over again, and simply keeps calling the enemy spawning function as long as the player is alive. (We already set the userdata a l i v eto t r u ein the last tutorial.) 1 2 3 4 5 6 @ O v e r r i d e p u b l i cv o i ds i m p l e U p d a t e ( f l o a tt p f ){ i f( ( B o o l e a n )p l a y e r . g e t U s e r D a t a ( " a l i v e " ) ){ s p a w n E n e m i e s ( ) ; } }
?

And this is how we actually spawn the enemies: 0 1 0 2 0 3 0 4 0 5 0 6 0 7 0 8 0 9 1 0 1 1 1 2 1 3 1 4 1 5 1 6 1 7 1 8 p r i v a t ev o i ds p a w n E n e m i e s ( ){ i f( S y s t e m . c u r r e n t T i m e M i l l i s ( )-e n e m y S p a w n C o o l d o w n> =1 7 ){ e n e m y S p a w n C o o l d o w n=S y s t e m . c u r r e n t T i m e M i l l i s ( ) ;
?

i f( e n e m y N o d e . g e t Q u a n t i t y ( )<5 0 ){ i f( n e wR a n d o m ( ) . n e x t I n t ( ( i n t )e n e m y S p a w n C h a n c e )= =0 ){ c r e a t e S e e k e r ( ) ; } i f( n e wR a n d o m ( ) . n e x t I n t ( ( i n t )e n e m y S p a w n C h a n c e )= =0 ){ c r e a t e W a n d e r e r ( ) ; } } / / i n c r e a s eS p a w nT i m e i f( e n e m y S p a w n C h a n c e> =1 . 1 f ){ e n e m y S p a w n C h a n c e=0 . 0 0 5 f ; }

Dont get confused by the e n e m y S p a w n C o o l d o w nvariable. Its not there to make enemies spawn at a decent frequency17ms would be much too short of an interval.
e n e m y S p a w n C o o l d o w nis actually there to

ensure that the quantity of new enemies is the same on every machine. On faster computers, s i m p l e U p d a t e ( f l o a tt p f )gets called much more often than on slower ones. With this variable we check about every 17ms if we should spawn new enemies. But do we want to spawn them every 17ms? We actually want them to spawn in random intervals, so we
gamedev.tutsplus.com/tutorials/implementation/make-a-neon-vector-shooter-in-jmonkeyengine-enemies-and-sounds/ 4/14

11/12/13

Make a Neon Vector Shooter in jMonkeyEngine: Enemies and Sounds | Gamedevtuts+

introduce an i fstatement: 1 i f( n e wR a n d o m ( ) . n e x t I n t ( ( i n t )e n e m y S p a w n C h a n c e )= =0 ){
?

The smaller the value of e n e m y S p a w n C h a n c e , the more probable it is that a new enemy will spawn in this 17ms interval, and so the more enemies the player will need to deal with. Thats why we subtract a little bit of e n e m y S p a w n C h a n c eevery tick: it means that the game will get more difficult over time. Creating seekers and wanderers is similar to creating any other object: 0 1 0 2 0 3 0 4 0 5 0 6 0 7 0 8 0 9 1 0 1 1 1 2 1 3 1 4 1 5 p r i v a t ev o i dc r e a t e S e e k e r ( ){ S p a t i a ls e e k e r=g e t S p a t i a l ( " S e e k e r " ) ; s e e k e r . s e t L o c a l T r a n s l a t i o n ( g e t S p a w n P o s i t i o n ( ) ) ; s e e k e r . a d d C o n t r o l ( n e wS e e k e r C o n t r o l ( p l a y e r ) ) ; s e e k e r . s e t U s e r D a t a ( " a c t i v e " , f a l s e ) ; e n e m y N o d e . a t t a c h C h i l d ( s e e k e r ) ; } p r i v a t ev o i dc r e a t e W a n d e r e r ( ){ S p a t i a lw a n d e r e r=g e t S p a t i a l ( " W a n d e r e r " ) ; w a n d e r e r . s e t L o c a l T r a n s l a t i o n ( g e t S p a w n P o s i t i o n ( ) ) ; w a n d e r e r . a d d C o n t r o l ( n e wW a n d e r e r C o n t r o l ( ) ) ; w a n d e r e r . s e t U s e r D a t a ( " a c t i v e " , f a l s e ) ; e n e m y N o d e . a t t a c h C h i l d ( w a n d e r e r ) ; }
?

We create the spatial, we move it, we add a custom control, we set it non-active, and we attach it to our e n e m y N o d e . What? Why non-active? Thats because we dont want the enemy to start chasing the player as soon as it spawns; we want to give the player some time to react. Before we get into the controls, we need to implement the method g e t S p a w n P o s i t i o n ( ) . The enemy should spawn randomly, but not right next to the player: 1 2 3 4 5 6 7
? p r i v a t eV e c t o r 3 fg e t S p a w n P o s i t i o n ( ){ V e c t o r 3 fp o s ; d o{ p o s=n e wV e c t o r 3 f ( n e wR a n d o m ( ) . n e x t I n t ( s e t t i n g s . g e t W i d t h ( ) ) , }w h i l e( p o s . d i s t a n c e S q u a r e d ( p l a y e r . g e t L o c a l T r a n s l a t i o n ( ) )<8 0 0 0 ) ; r e t u r np o s ; }

We calculate a new random position p o s . If its too close to the player, we calculate a new position, and repeat until its a decent distance away. Now we just need to make the enemies set themselves active and start moving. Well do that in their controls.

Controlling Enemy Behavior


gamedev.tutsplus.com/tutorials/implementation/make-a-neon-vector-shooter-in-jmonkeyengine-enemies-and-sounds/ 5/14

11/12/13

Make a Neon Vector Shooter in jMonkeyEngine: Enemies and Sounds | Gamedevtuts+

Well deal with the S e e k e r C o n t r o lfirst: 0 1 0 2 0 3 0 4 0 5 0 6 0 7 0 8 0 9 1 0 1 1 1 2 1 3 1 4 1 5 1 6 1 7 1 8 1 9 2 0 2 1 2 2 2 3 2 4 2 5 2 6 2 7 2 8 2 9 3 0 3 1 3 2 3 3 3 4 3 5 3 6 3 7 3 8 3 9 4 0 4 1 4 2 4 3 4 4 p u b l i cc l a s sS e e k e r C o n t r o le x t e n d sA b s t r a c t C o n t r o l{ p r i v a t eS p a t i a lp l a y e r ; p r i v a t eV e c t o r 3 fv e l o c i t y ; p r i v a t el o n gs p a w n T i m e ; p u b l i cS e e k e r C o n t r o l ( S p a t i a lp l a y e r ){ t h i s . p l a y e r=p l a y e r ; v e l o c i t y=n e wV e c t o r 3 f ( 0 , 0 , 0 ) ; s p a w n T i m e=S y s t e m . c u r r e n t T i m e M i l l i s ( ) ; }


?

@ O v e r r i d e p r o t e c t e dv o i dc o n t r o l U p d a t e ( f l o a tt p f ){ i f( ( B o o l e a n )s p a t i a l . g e t U s e r D a t a ( " a c t i v e " ) ){ / / t r a n s l a t et h es e e k e r V e c t o r 3 fp l a y e r D i r e c t i o n=p l a y e r . g e t L o c a l T r a n s l a t i o n ( ) . s u b t r a p l a y e r D i r e c t i o n . n o r m a l i z e L o c a l ( ) ; p l a y e r D i r e c t i o n . m u l t L o c a l ( 1 0 0 0 f ) ; v e l o c i t y . a d d L o c a l ( p l a y e r D i r e c t i o n ) ; v e l o c i t y . m u l t L o c a l ( 0 . 8 f ) ; s p a t i a l . m o v e ( v e l o c i t y . m u l t ( t p f * 0 . 1 f ) ) ; / /r o t a t et h es e e k e r i f( v e l o c i t y! =V e c t o r 3 f . Z E R O ){ s p a t i a l . r o t a t e U p T o ( v e l o c i t y . n o r m a l i z e ( ) ) ; s p a t i a l . r o t a t e ( 0 , 0 , F a s t M a t h . P I / 2 f ) ; } }e l s e{ / /h a n d l et h e" a c t i v e " s t a t u s l o n gd i f=S y s t e m . c u r r e n t T i m e M i l l i s ( )-s p a w n T i m e ; i f( d i f> =1 0 0 0 f ){ s p a t i a l . s e t U s e r D a t a ( " a c t i v e " , t r u e ) ; } C o l o r R G B Ac o l o r=n e wC o l o r R G B A ( 1 , 1 , 1 , d i f / 1 0 0 0 f ) ; N o d es p a t i a l N o d e=( N o d e )s p a t i a l ; P i c t u r ep i c=( P i c t u r e )s p a t i a l N o d e . g e t C h i l d ( " S e e k e r " ) ; p i c . g e t M a t e r i a l ( ) . s e t C o l o r ( " C o l o r " , c o l o r ) ;

@ O v e r r i d e p r o t e c t e dv o i dc o n t r o l R e n d e r ( R e n d e r M a n a g e rr m ,V i e w P o r tv p ){ }

Lets focus on c o n t r o l U p d a t e ( f l o a tt p f ) : First, we need to check whether the enemy is active. If its not, we need to slowly fade it in. We then check the time that has elapsed since we spawned the enemy and, if its long enough, we set it active.
gamedev.tutsplus.com/tutorials/implementation/make-a-neon-vector-shooter-in-jmonkeyengine-enemies-and-sounds/ 6/14

11/12/13

Make a Neon Vector Shooter in jMonkeyEngine: Enemies and Sounds | Gamedevtuts+

Regardless of whether weve just set it active, we need to adjust its color. The local variable s p a t i a lcontains the spatial that the control has been attached to, but you may remember that we did not attach the control to the actual picturethe picture is a child of the node we attached the control to. (If you dont know what Im talking about, take a look at the method g e t S p a t i a l ( S t r i n gn a m e )we implemented last tutorial.) So; we get the picture as a child of s p a t i a l , get its material and set its color to the appropiate value. Nothing special once youre used to the spatials, materials and nodes. Info: You may wonder why we set the material color to white. (The RGB values are all 1in our code). Dont we want a yellow and a red enemy? Its because the material mixes the material color with the texture colors, so if we want to display the texture of the enemy as it is, we need to mix it with white. Now we need to take a look at what we do when the enemy is active. This control is named S e e k e r C o n t r o l for a reason: we want enemies with this control attached to follow the player. In order to achieve that, we calculate the direction from the seeker to the player and add this value to the velocity. After that, we decrease the velocity by 80% so that it cant grow infinitely, and move the seeker accordingly. The rotation is nothing special: if the seeker is not standing still, we rotate it in the direction of the player. We then rotate it a little more because the seeker in S e e k e r . p n gis not pointing upwards, but to the right. Info: The r o t a t e U p T o ( V e c t o r 3 fd i r e c t i o n )method of S p a t i a lrotates a spatial so that its y-axis points in the given direction. So that was the first enemy. The code of the second enemy, the wanderer, is not much different: 0 1 0 2 0 3 0 4 0 5 0 6 0 7 0 8 0 9 1 0 1 1 1 2 1 3 1 4 1 5 1 6 1 7 1 8 1 9 2 0 2 1 2 2 p u b l i cc l a s sW a n d e r e r C o n t r o le x t e n d sA b s t r a c t C o n t r o l{ p r i v a t ei n ts c r e e n W i d t h ,s c r e e n H e i g h t ; p r i v a t eV e c t o r 3 fv e l o c i t y ; p r i v a t ef l o a td i r e c t i o n A n g l e ; p r i v a t el o n gs p a w n T i m e ; p u b l i cW a n d e r e r C o n t r o l ( i n ts c r e e n W i d t h ,i n ts c r e e n H e i g h t ){ t h i s . s c r e e n W i d t h=s c r e e n W i d t h ; t h i s . s c r e e n H e i g h t=s c r e e n H e i g h t ; v e l o c i t y=n e wV e c t o r 3 f ( ) ; d i r e c t i o n A n g l e=n e wR a n d o m ( ) . n e x t F l o a t ( )*F a s t M a t h . P I*2 f ; s p a w n T i m e=S y s t e m . c u r r e n t T i m e M i l l i s ( ) ;
?

@ O v e r r i d e p r o t e c t e dv o i dc o n t r o l U p d a t e ( f l o a tt p f ){ i f( ( B o o l e a n )s p a t i a l . g e t U s e r D a t a ( " a c t i v e " ) ){ / /t r a n s l a t et h ew a n d e r e r / /c h a n g et h ed i r e c t i o n A n g l eab i t


7/14

gamedev.tutsplus.com/tutorials/implementation/make-a-neon-vector-shooter-in-jmonkeyengine-enemies-and-sounds/

11/12/13

Make a Neon Vector Shooter in jMonkeyEngine: Enemies and Sounds | Gamedevtuts+

2 3 2 4 2 5 2 6 2 7 2 8 2 9 3 0 3 1 3 2 3 3 3 4 3 5 3 6 3 7 3 8 3 9 4 0 4 1 4 2 4 3 4 4 4 5 4 6 4 7 4 8 4 9 5 0 5 1 5 2 5 3 5 4 5 5 5 6 5 7 5 8

d i r e c t i o n A n g l e+ =( n e wR a n d o m ( ) . n e x t F l o a t ( )*2 0 f-1 0 f )*t p f S y s t e m . o u t . p r i n t l n ( d i r e c t i o n A n g l e ) ; V e c t o r 3 fd i r e c t i o n V e c t o r=M o n k e y B l a s t e r M a i n . g e t V e c t o r F r o m A n g l d i r e c t i o n V e c t o r . m u l t L o c a l ( 1 0 0 0 f ) ; v e l o c i t y . a d d L o c a l ( d i r e c t i o n V e c t o r ) ; / /d e c r e a s et h ev e l o c i t yab i ta n dm o v et h ew a n d e r e r v e l o c i t y . m u l t L o c a l ( 0 . 8 f ) ; s p a t i a l . m o v e ( v e l o c i t y . m u l t ( t p f * 0 . 1 f ) ) ;

/ /m a k et h ew a n d e r e rb o u n c eo f ft h es c r e e nb o r d e r s V e c t o r 3 fl o c=s p a t i a l . g e t L o c a l T r a n s l a t i o n ( ) ; i f( l o c . x s c r e e n W i d t h| |l o c . y>s c r e e n H e i g h t ){ V e c t o r 3 fn e w D i r e c t i o n V e c t o r=n e wV e c t o r 3 f ( s c r e e n W i d t h / d i r e c t i o n A n g l e=M o n k e y B l a s t e r M a i n . g e t A n g l e F r o m V e c t o r ( n e w D } / /r o t a t et h ew a n d e r e r s p a t i a l . r o t a t e ( 0 , 0 , t p f * 2 ) ; }e l s e{ / /h a n d l et h e" a c t i v e " s t a t u s l o n gd i f=S y s t e m . c u r r e n t T i m e M i l l i s ( )-s p a w n T i m e ; i f( d i f> =1 0 0 0 f ){ s p a t i a l . s e t U s e r D a t a ( " a c t i v e " , t r u e ) ; } C o l o r R G B Ac o l o r=n e wC o l o r R G B A ( 1 , 1 , 1 , d i f / 1 0 0 0 f ) ; N o d es p a t i a l N o d e=( N o d e )s p a t i a l ; P i c t u r ep i c=( P i c t u r e )s p a t i a l N o d e . g e t C h i l d ( " W a n d e r e r " ) ; p i c . g e t M a t e r i a l ( ) . s e t C o l o r ( " C o l o r " , c o l o r ) ;

@ O v e r r i d e p r o t e c t e dv o i dc o n t r o l R e n d e r ( R e n d e r M a n a g e rr m ,V i e w P o r tv p ){ }

The easy stuff first: fading the enemy in is the same as in the seeker control. In the constructor, we choose a random direction for the wanderer, in which it will fly once activated. Tip: If you have more than two enemies, or simply want to structure the game more cleanly, you could add a third control: E n e m y C o n t r o lIt would handle everything that all enemies had in common: moving the enemy, fading it in, setting it active Now to the major differences: When the enemy is active, we first change its direction a bit, so that the wanderer doesnt move in a straight line all the time. We do this by changing our d i r e c t i o n A n g l ea bit and adding the d i r e c t i o n V e c t o rto the v e l o c i t y . We then apply the velocity just like we do in the S e e k e r C o n t r o l . We need to check whether the wanderer is outside of the screen borders and, if so, we change the
gamedev.tutsplus.com/tutorials/implementation/make-a-neon-vector-shooter-in-jmonkeyengine-enemies-and-sounds/ 8/14

11/12/13

Make a Neon Vector Shooter in jMonkeyEngine: Enemies and Sounds | Gamedevtuts+

d i r e c t i o n A n g l eto

a more appropiate direction so that it gets applied in the next update.

Finally, we rotate the wanderer a bit. This is just because a spinning enemy looks cooler. Now that weve finished implementing both of the enemies, you can start the game and play a bit. It gives you a little glance at how the game will play, even though you cant kill the enemies and they cant kill you either. Lets add that next.

Collision Detection
In order to make enemies kill the player, we need to know whether they are colliding. For this, well add a new method, h a n d l e C o l l i s i o n s , called in s i m p l e U p d a t e ( f l o a tt p f ) : 1 2 3 4 5 6 7 @ O v e r r i d e p u b l i cv o i ds i m p l e U p d a t e ( f l o a tt p f ){ i f( ( B o o l e a n )p l a y e r . g e t U s e r D a t a ( " a l i v e " ) ){ s p a w n E n e m i e s ( ) ; h a n d l e C o l l i s i o n s ( ) ; } }
?

And now the actual method: 0 1 0 2 0 3 0 4 0 5 0 6 0 7 0 8 0 9 1 0


? p r i v a t ev o i dh a n d l e C o l l i s i o n s ( ){ / /s h o u l dt h ep l a y e rd i e ? f o r( i n ti = 0 ;i < e n e m y N o d e . g e t Q u a n t i t y ( ) ;i + + ){ i f( ( B o o l e a n )e n e m y N o d e . g e t C h i l d ( i ) . g e t U s e r D a t a ( " a c t i v e " ) ){ i f( c h e c k C o l l i s i o n ( p l a y e r , e n e m y N o d e . g e t C h i l d ( i ) ) ){ k i l l P l a y e r ( ) ; } } } }

We iterate through all the enemies by gettings the quantity of the children of the node and then getting each one of them. Furthermore we only need to check wether the enemy kills the player when the enemy is actually active. If it isnt, we dont need to care about it. So if he is active, we check wether the player and the enemy collide. We do that in another method, c h e c k C o l l i s o i n ( S p a t i a la ,S p a t i a lb ) : 1 2 3 4 5

? p r i v a t eb o o l e a nc h e c k C o l l i s i o n ( S p a t i a la ,S p a t i a lb ){ f l o a td i s t a n c e=a . g e t L o c a l T r a n s l a t i o n ( ) . d i s t a n c e ( b . g e t L o c a l T r a n s l a t i o n f l o a tm a x D i s t a n c e= ( F l o a t ) a . g e t U s e r D a t a ( " r a d i u s " )+( F l o a t ) b . g e t U s e r D r e t u r nd i s t a n c e< =m a x D i s t a n c e ; }

The concept is pretty simple: first, we calculate the distance between the two spatials. Next, we need to know how close the two spatials need to be in order to be considered as having collided, so we get the radius of each
gamedev.tutsplus.com/tutorials/implementation/make-a-neon-vector-shooter-in-jmonkeyengine-enemies-and-sounds/ 9/14

11/12/13

Make a Neon Vector Shooter in jMonkeyEngine: Enemies and Sounds | Gamedevtuts+

spatial and add them. (We set the user data radius in g e t S p a t i a l ( S t r i n gn a m e )in the previous tutorial.) So, if the actual distance is shorter than or equal to this maximum distance, the method returns t r u e , which means they collided. What now? We need to kill the player. Lets create another method: 1 2 3 4 5 6 7 8 p r i v a t ev o i dk i l l P l a y e r ( ){ p l a y e r . r e m o v e F r o m P a r e n t ( ) ; p l a y e r . g e t C o n t r o l ( P l a y e r C o n t r o l . c l a s s ) . r e s e t ( ) ; p l a y e r . s e t U s e r D a t a ( " a l i v e " ,f a l s e ) ; p l a y e r . s e t U s e r D a t a ( " d i e T i m e " ,S y s t e m . c u r r e n t T i m e M i l l i s ( ) ) ; e n e m y N o d e . d e t a c h A l l C h i l d r e n ( ) ; } }
?

First, we detach the player from its parent node, which automatically removes it from the scene. Next, we need to reset the movement in P l a y e r C o n t r o l otherwise, the player might still move when it spawns again. We then set the userdata a l i v eto f a l s eand create a new userdata d i e T i m e . (Well need that to respawn the player when its dead.) Finally, we detach all enemies, as the player would have a hard time fighting the already existing enemies off right when it spawns. We already mentioned respawning, so lets handle that next. We will, once again, modify the s i m p l e U p d a t e ( f l o a tt p f )method: 0 1 0 2 0 3 0 4 0 5 0 6 0 7 0 8 0 9 1 0 1 1 1 2

? @ O v e r r i d e p u b l i cv o i ds i m p l e U p d a t e ( f l o a tt p f ){ i f( ( B o o l e a n )p l a y e r . g e t U s e r D a t a ( " a l i v e " ) ){ s p a w n E n e m i e s ( ) ; h a n d l e C o l l i s i o n s ( ) ; }e l s ei f( S y s t e m . c u r r e n t T i m e M i l l i s ( )-( L o n g )p l a y e r . g e t U s e r D a t a ( " d i e / /s p a w np l a y e r p l a y e r . s e t L o c a l T r a n s l a t i o n ( 5 0 0 , 5 0 0 , 0 ) ; g u i N o d e . a t t a c h C h i l d ( p l a y e r ) ; p l a y e r . s e t U s e r D a t a ( " a l i v e " , t r u e ) ; } }

So, if the player is not alive and has been dead long enough, we set its position to the middle of the screen, add it to the scene, and finally set its userdata a l i v eto t r u eagain! Now may be a good time to start the game and test our new features. Youll have a hard time lasting longer than twenty seconds, though, because your gun is worthless, so lets do something about that. In order to make bullets kill enemies, well add some code to the h a n d l e C o l l i s i o n s ( )method: 0 1 0 2 / / s h o u l da ne n e m yd i e ? i n ti = 0 ;
?

gamedev.tutsplus.com/tutorials/implementation/make-a-neon-vector-shooter-in-jmonkeyengine-enemies-and-sounds/

10/14

11/12/13

Make a Neon Vector Shooter in jMonkeyEngine: Enemies and Sounds | Gamedevtuts+

0 3 0 4 0 5 0 6 0 7 0 8 0 9 1 0 1 1 1 2 1 3 1 4

w h i l e( i<e n e m y N o d e . g e t Q u a n t i t y ( ) ){ i n tj = 0 ; w h i l e( j<b u l l e t N o d e . g e t Q u a n t i t y ( ) ){ i f( c h e c k C o l l i s i o n ( e n e m y N o d e . g e t C h i l d ( i ) , b u l l e t N o d e . g e t C h i l d ( j ) ) ) e n e m y N o d e . d e t a c h C h i l d A t ( i ) ; b u l l e t N o d e . d e t a c h C h i l d A t ( j ) ; b r e a k ; } j + + ; } i + + ; }

The procedure for killing enemies is pretty much the same as for killing the player; we iterate through all enemies and all bullets, check whether they collide and, if they do, we detach both of them. Now run the game and see how far you get! Info: Iterating through each enemy and comparing its position with each bullets position is a very bad way to check for collisions. Its okay in this example for the sake of simplicity, but in a real game youd have to implement better algorithms to do that, like quadtree collision detection. Fortunately, the jMonkeyEngine uses the Bullet physics engine, so whenever you have complicated 3D physics, you dont need to worry about this. Now we are finished with the main gameplay. Were still going to implement black holes and display the score and lives of the player, and to make the game more fun and exciting well add sound effects and better graphics. The latter will be achieved through the bloom post processing filter, some particle effects and a cool background effect. Before we consider this part of the series finished, well add some audio and the bloom effect.

Playing Sounds and Music


In order to some audio to our game well create a new class, simply called S o u n d : 0 1 0 2 0 3 0 4 0 5 0 6 0 7 0 8 0 9 1 0 1 1 1 2 1 3 1 4 p u b l i cc l a s sS o u n d{ p r i v a t eA u d i o N o d em u s i c ; p r i v a t eA u d i o N o d e [ ]s h o t s ; p r i v a t eA u d i o N o d e [ ]e x p l o s i o n s ; p r i v a t eA u d i o N o d e [ ]s p a w n s ; p r i v a t eA s s e t M a n a g e ra s s e t M a n a g e r ; p u b l i cS o u n d ( A s s e t M a n a g e ra s s e t M a n a g e r ){ t h i s . a s s e t M a n a g e r=a s s e t M a n a g e r ; s h o t s=n e wA u d i o N o d e [ 4 ] ; e x p l o s i o n s=n e wA u d i o N o d e [ 8 ] ; s p a w n s=n e wA u d i o N o d e [ 8 ] ;
11/14

gamedev.tutsplus.com/tutorials/implementation/make-a-neon-vector-shooter-in-jmonkeyengine-enemies-and-sounds/

11/12/13

Make a Neon Vector Shooter in jMonkeyEngine: Enemies and Sounds | Gamedevtuts+

1 5 1 6 1 7 1 8 1 9 2 0 2 1 2 2 2 3 2 4 2 5 2 6 2 7 2 8 2 9 3 0 3 1 3 2 3 3 3 4 3 5 3 6 3 7 3 8 3 9 4 0 4 1 4 2 4 3 4 4 4 5 4 6 4 7 4 8 4 9 5 0 5 1 5 2 5 3 5 4 5 5 5 6 5 7 5 8 5 9 6 0 6 1

l o a d S o u n d s ( ) ;

p r i v a t ev o i dl o a d S o u n d s ( ){ m u s i c=n e wA u d i o N o d e ( a s s e t M a n a g e r , " S o u n d s / M u s i c . o g g " ) ; m u s i c . s e t P o s i t i o n a l ( f a l s e ) ; m u s i c . s e t R e v e r b E n a b l e d ( f a l s e ) ; m u s i c . s e t L o o p i n g ( t r u e ) ; f o r( i n ti = 0 ;i < s h o t s . l e n g t h ;i + + ){ s h o t s [ i ]=n e wA u d i o N o d e ( a s s e t M a n a g e r , " S o u n d s / s h o o t 0 " + ( i + s h o t s [ i ] . s e t P o s i t i o n a l ( f a l s e ) ; s h o t s [ i ] . s e t R e v e r b E n a b l e d ( f a l s e ) ; s h o t s [ i ] . s e t L o o p i n g ( f a l s e ) ; }

f o r( i n ti = 0 ;i < e x p l o s i o n s . l e n g t h ;i + + ){ e x p l o s i o n s [ i ] =n e wA u d i o N o d e ( a s s e t M a n a g e r , " S o u n d s / e x p l o s i o n e x p l o s i o n s [ i ] . s e t P o s i t i o n a l ( f a l s e ) ; e x p l o s i o n s [ i ] . s e t R e v e r b E n a b l e d ( f a l s e ) ; e x p l o s i o n s [ i ] . s e t L o o p i n g ( f a l s e ) ; } f o r( i n ti = 0 ;i < s p a w n s . l e n g t h ;i + + ){ s p a w n s [ i ] =n e wA u d i o N o d e ( a s s e t M a n a g e r , " S o u n d s / s p a w n 0 " + ( i + s p a w n s [ i ] . s e t P o s i t i o n a l ( f a l s e ) ; s p a w n s [ i ] . s e t R e v e r b E n a b l e d ( f a l s e ) ; s p a w n s [ i ] . s e t L o o p i n g ( f a l s e ) ; }

p u b l i cv o i ds t a r t M u s i c ( ){ m u s i c . p l a y ( ) ; } p u b l i cv o i ds h o o t ( ){ s h o t s [ n e wR a n d o m ( ) . n e x t I n t ( s h o t s . l e n g t h ) ] . p l a y I n s t a n c e ( ) ; }

p u b l i cv o i de x p l o s i o n ( ){ e x p l o s i o n s [ n e wR a n d o m ( ) . n e x t I n t ( e x p l o s i o n s . l e n g t h ) ] . p l a y I n s t a n c e ( ) } p u b l i cv o i ds p a w n ( ){ s p a w n s [ n e wR a n d o m ( ) . n e x t I n t ( s p a w n s . l e n g t h ) ] . p l a y I n s t a n c e ( ) ; }

Here, we start by setting up the necessary A u d i o N o d evariables and initialize the arrays. Next, we load the sounds, and for each sound we do pretty much the same thing. We create a new A u d i o N o d e , with the help of the a s s e t M a n a g e r . Then, we set it not positional and disable reverb. (We dont need the sound
gamedev.tutsplus.com/tutorials/implementation/make-a-neon-vector-shooter-in-jmonkeyengine-enemies-and-sounds/ 12/14

11/12/13

Make a Neon Vector Shooter in jMonkeyEngine: Enemies and Sounds | Gamedevtuts+

to be positional because we dont have stereo output in our 2D game, though you could implement it if you liked.) Disabling the reverb makes the sound be played just like it is in the actual audio file; if we enabled it, we could make jME let the audio sound like wed be in a cave or dungeon, for example. After that, we set the looping to t r u efor the music and to f a l s efor any other sound. Playing the sounds is pretty simple: we just call s o u n d X . p l a y ( ) . Info: When you simply call p l a y ( )on some sound, it just plays the sound. But sometimes we want to play the same sound twice or even more times simultaneously. Thats what p l a y I n s t a n c e ( )is there for: it creates a new instance for every sound so that we can play the same sound multiple times at the same time. Ill leave the rest of the work up to you: you need to call s t a r t M u s i c ,s h o o t ( ) ,e x p l o s i o n ( )(for dying enemies), and s p a w n ( )at the appropriate places in our main class M o n k e y B l a s t e r M a i n ( ) . When youre finished, youll see that the game is now much more fun; those few sound effects really add to the atmosphere. But lets polish the graphics a bit as well.

Adding the Bloom Post-Processing Filter


Enabling bloom is very simple in the jMonkeyEngine, as all of the necessary code and shaders are already implemented for you. Just go ahead and paste these lines into s i m p l e I n i t A p p ( ) : 1 2 3 4 5 6 7 8 9 F i l t e r P o s t P r o c e s s o rf p p = n e wF i l t e r P o s t P r o c e s s o r ( a s s e t M a n a g e r ) ; B l o o m F i l t e rb l o o m = n e wB l o o m F i l t e r ( ) ; b l o o m . s e t B l o o m I n t e n s i t y ( 2 f ) ; b l o o m . s e t E x p o s u r e P o w e r ( 2 ) ; b l o o m . s e t E x p o s u r e C u t O f f ( 0 f ) ; b l o o m . s e t B l u r S c a l e ( 1 . 5 f ) ; f p p . a d d F i l t e r ( b l o o m ) ; g u i V i e w P o r t . a d d P r o c e s s o r ( f p p ) ; g u i V i e w P o r t . s e t C l e a r C o l o r ( t r u e ) ;
?

Ive configured the B l o o m F i l t e ra bit; if you want to know what all these settings are there for, you should check out the jME tutorial on bloom.

Conclusion
Congratulations for finishing the second part. There are three more parts to go, so dont get distracted by playing for too long! Next time, well add the GUI and the black holes. Tags: geometry warsjavajmonkeyengine

By Daniel Gallenberger
gamedev.tutsplus.com/tutorials/implementation/make-a-neon-vector-shooter-in-jmonkeyengine-enemies-and-sounds/ 13/14

11/12/13

Make a Neon Vector Shooter in jMonkeyEngine: Enemies and Sounds | Gamedevtuts+

Student of Computer Sience at the Technical University of Munich

Note: Want to add some source code? Type <pre><code> before it and </code></pre> after it. Find out more

gamedev.tutsplus.com/tutorials/implementation/make-a-neon-vector-shooter-in-jmonkeyengine-enemies-and-sounds/

14/14

Вам также может понравиться