Bygning af en spilleautomat i Android: ViewFlipper mødes gestaldetektor

Jeg har været i Vegas et par gange, selvom jeg ikke meget kan lide at spille. Den ene gang, jeg vandt $ 150 fra en spilleautomat, udbetalte jeg straks og brugte pengene til at købe sæder på første række til et Penn & Teller-magi. Den autograferede billetstubbe er gemt blandt mine mest værdifulde ejendele - lige ved siden af ​​Jayne-hatten, som jeg hentede, da Adam Baldwin kom til Dallas Comic Con for et par år siden. Jeg tager af.

I sidste uges indlæg brugte vi tid på at pirke på Android's gestusdetektor. I mine afsluttende bemærkninger foreslog jeg, at gestus-API'et kunne bruges til at dreje hjulene på en spilleautomat, og det fik mig til at tænke. Mens mange af mine TechRepublic-tutorials stammer fra virkelige udfordringer, som jeg støder på som en del af min fuldtidsjob som Android-konsulent, bruger jeg bloggen som en afsætningsmulighed til at prøve noget uden anden grund end jeg tror det ville være sjovt.

Så selvom jeg ikke rigtig kan lide at spille slots med mine egne penge, var ingeniøren i mig fascineret og lidt begejstret over ideen om at kombinere Android's ViewFlipper-klasse med bevægelsesdetektoren for at simulere det roterende hjul i et tilfældighedsspil. Jeg var nødt til at finde ud af en måde at anvende animationerne dynamisk på, samt en algoritme til beregning af antallet af rotationer ... åh og lad os ikke glemme en metode til at reducere hastigheden over tid baseret på hvor hurtigt eller langsomt brugeren kaster hjul. Jeg fortalte dig, det lyder som sjovt.

Er du stadig med mig? I så fald skal du følge med trinvis vejledning nedenfor eller downloade og importere hele projektet direkte til Eclipse.

1. Opret et nyt projekt i Eclipse, der er målrettet mod Android 1.6 eller nyere. Sørg for at omdøbe startaktiviteten til Main.java.

2. Vi ønsker aldrig, at vores spilleautomat-app skal køre i andet end portrættilstand, så rediger din AndroidManifest.xml-fil for at synke orienteringsændringer.

AndroidMainfest.xml

 "1.0" encoding = "utf-8" ?> 
 "Http://schemas.android.com/apk/res/android" 
 package = "com.authorwjf.slot" 
 android: versionCode = "1" 
 android: versionName = "1.0" > 
 "4" /> 
 android: icon = "@ drawable / ic_launcher" 
 android: label = "@ string / app_name" > 
 android: name = ".Main" 
 android: configChanges = "orientering" 
 android: screenOrientation = "portræt" 
 android: label = "@ string / app_name" > 
 "android.intent.action.MAIN" /> 
 "android.intent.category.LAUNCHER" /> 

3. Du skal oprette en / tegnbar mappe under dit / res-bibliotek og tilføje tre PNG-billeder - enhver frugt gør. Jeg fandt billeder af offentligt ejendom af et kirsebær, en citron og en pære. Mmmmm!

4. Definition af layout til vores spilleautomat er lidt mere kompliceret end hvad jeg normalt prøver at gøre i disse tutorials; Årsagen er ViewFlipper. Den gode nyhed skyldes, at så meget af ViewFlippers opførsel er defineret i XML, når vi kommer rundt og bruger det, er der næsten ingen kode tilknyttet widgeten. For nu skal du bare åbne /res/layout/main.xml og indsætte i følgende layout.

main.xml

 "1.0" encoding = "utf-8" ?> 
 "Http://schemas.android.com/apk/res/android" 
 android: layout_width = "fill_parent" 
 android: layout_height = "fill_parent" 
 android: orientering = "lodret" > 
 android: layout_width = "fill_parent" 
 android: layout_height = "wrap_content" 
 android: tyngdekraft = "center" 
 android: textSize = "28sp" 
 android: paddingTop = "10dip" 
 android: textColor = "# 00ff00" 
 android: text = "Eksempel på en maskine" 
 android: paddingBottom = "50dip" /> 
 android: layout_margin = "6dip" 
 android: id = "@ + id / view_flipper" 
 android: layout_width = "wrap_content" 
 android: layout_height = "wrap_content" 
 android: layout_gravity = "center" 
 android: gravitation = "center" > 
 android: layout_width = "fill_parent" 
 android: layout_height = "fill_parent" 
 android: orientering = "lodret" 
 android: layout_gravity = "center" 
 android: gravitation = "center" > 
 android: layout_height = "wrap_content" 
 android: layout_width = "fill_parent" 
 android: layout_gravity = "center" 
 android: tyngdekraft = "center" 
 android: src = "@ tegnbar / pære" /> 
 android: layout_width = "fill_parent" 
 android: layout_height = "fill_parent" 
 android: orientering = "lodret" 
 android: layout_gravity = "center" 
 android: gravitation = "center" > 
 android: layout_height = "wrap_content" 
 android: layout_width = "fill_parent" 
 android: layout_gravity = "center" 
 android: src = "@ tegnbar / kirsebær" /> 
 android: layout_width = "fill_parent" 
 android: layout_height = "fill_parent" 
 android: orientering = "lodret" 
 android: layout_gravity = "center" 
 android: gravitation = "center" > 
 android: layout_height = "wrap_content" 
 android: layout_width = "fill_parent" 
 android: layout_gravity = "center" 
 android: src = "@ trækbar / citron" /> 
 android: layout_width = "fill_parent" 
 android: layout_height = "wrap_content" 
 android: id = "@ + id / hastighed" 
 android: tyngdekraft = "center" /> 
 android: layout_width = "fill_parent" 
 android: layout_height = "wrap_content" 
 android: id = "@ + id / tæller" 
 android: tyngdekraft = "center" /> 
 android: layout_width = "fill_parent" 
 android: layout_height = "wrap_content" 
 android: id = "@ + id / hastighed" 
 android: tyngdekraft = "center" /> 

5. Nu er det tid til at få kodning! I mappen / src skal du åbne Main.java og begynde med at oprette nogle klassevariabler og initialisere dem i on create tilsidesættelse.

 Main.java 
 pakke com.authorwjf.slot; 
 import android.app.Aktivitet; 
 import android.os.Bundle; 
 import android.os.Handler; 
 import android.view.GestureDetector; 
 import android.view.MotionEvent; 
 import android.view.GestureDetector.OnGestureListener; 
 import android.view.animation.AccelerateInterpolator; 
 import android.view.animation.Animation; 
 import android.view.animation.TranslateAnimation; 
 import android.widget.TextView; 
 import android.widget.ViewFlipper; 
 public class Main udvider Aktivitetsimplementerer OnGestureListener { 
 privat ViewFlipper mViewFlipper; 
 privat GestureDetector mDetector; 
 privat int mSpeed; 
 privat int mCount; 
 privat int mFactor; 
 privat boolsk mAnimating; 
 @Override 
 offentligt tomrum onCreate (Bundle gemtInstanceState) { 
 super .onCreate (gemtInstanceState); 
 setContentView (R.layout. main ); 
 mViewFlipper = (ViewFlipper) findViewById (R.id. view_flipper ); 
 mDetector = ny GestureDetector ( dette ); 
 mAnimating = falsk ; 
 mCount = 0; 
 mSpeed ​​= 0; 
 } 
 } 

6. Hvis du husker fra sidste uge, betyder det at lade hovedaktiviteten implementere on gestus-lytteren, at vi er nødt til at tilføje syv tilbagekaldsfunktioner - hvoraf fem vi bare kan lade Android Eclipse plug-in generere for os.

 @Override 
 offentligt ugyldigt onLongPress (MotionEvent arg0) { 
 // TODO Auto-genereret metodestub 
 } 
 @Override 
 offentlig boolsk onScroll (MotionEvent arg0, MotionEvent arg1, float arg2, 
 float arg3) { 
 // TODO Auto-genereret metodestub 
 vende tilbage falsk ; 
 } 
 @Override 
 offentligt ugyldigt onShowPress (MotionEvent arg0) { 
 // TODO Auto-genereret metodestub 
 } 
 @Override 
 offentlig boolsk onSingleTapUp (MotionEvent arg0) { 
 // TODO Auto-genereret metodestub 
 vende tilbage falsk ; 
 } 
 @Override 
 offentlig boolsk onDown (MotionEvent arg0) { 
 // TODO Auto-genereret metodestub 
 vende tilbage falsk ; 
 } 

7. De resterende bevægelsesrelaterede tilsidesættelser kræver tilpasset kode. Den første udbreder berøringshændelsen til gestusdetektoren, mens den anden implementerer vores on-fling-logik. Det kan være nødvendigt, at du læser logikken on fling et par gange; det er ansvarligt for at starte et antal rotationer såvel som starthastigheden og den tidsindstillede formindskelsesfaktor, baseret på det indledende argument for lodret hastighed. Tryk / fangst forhindrer en skillelinje med nul-fejl, der kan opstå, hvis en bruger fejede skærmen smertefuldt langsomt, hvilket medfører en hastighed på næsten nul. Da vi taler om Y-aksen, betragtes alt andet end 0 som en nedadgående svip; ellers antager vi det.

 @Override 
 offentlig boolsk onTouchEvent (MotionEvent me) { 
 returner mDetector.onTouchEvent (mig); 
 } 
 @Override 
 offentlig boolsk onFling (MotionEvent-start, MotionEvent-finish, float xVelocity, float yVelocity) { 
 prøv { 
 hvis (mAnimating) returneres sandt ; 
 mAnimating = sandt ; 
 mCount = ( int ) Matematik. abs (yVelocity) / 300; 
 mFactor = ( int ) 300 / mCount; 
 mSpeed ​​= mFactor; 
 if (yVelocity> 0) { 
 //ned 
 Håndterer h = ny Håndterer (); 
 h.post Forsinket (r2, mSpeed); 
 } andet { 
 //op 
 Håndterer h = ny Håndterer (); 
 h.post Forsinket (r1, mSpeed); 
 } 
 ((TextView) findViewById (R.id. Hastighed )). SetText ("VELOCITY =>" + Float. ToString (yVelocity)); 
 } fangst (ArithmeticException e) { 
 // swiped for langsomt tilmelder sig ikke 
 mAnimating = falsk ; 
 } 
 vende tilbage sandt ; 
 } 

8. Som det ofte er tilfældet med Android, kommer nogle af de vanskeligste logikker ind, når du anvender animationer. Til dette formål har jeg ansat to matchende par rutiner. Til håndtering af op gestus har jeg en kørsel sammen med de dynamiske animationer. Da animationstimingen ikke behøver at være nøjagtig, bruger jeg en handler og kæder indlæg.

 private Runnable r1 = new Runnable () { 
 @Override 
 offentlig annullering () { 
 op(); 
 if (mCount <1) { 
 mAnimating = falsk ; 
 } andet { 
 Håndterer h = ny Håndterer (); 
 h.post Forsinket (r1, mSpeed); 
 } 
 } 
 }; 
 privat tomrum op () { 
 mCount--; 
 MSPEED + = mFactor; 
 Animation inFromBottom = nyt TranslateAnimation ( 
 Animation. RELATIVE_TO_PARENT, 0.0f, 
 Animation. RELATIVE_TO_PARENT, 0.0f, 
 Animation. RELATIVE_TO_PARENT, 1.0f, 
 Animation. RELATIVE_TO_PARENT, 0, 0f); 
 inFromBottom.setInterpolator ( ny AccelerateInterpolator ()); 
 inFromBottom.setDuration (MSPEED); 
 Animation outToTop = ny TranslateAnimation ( 
 Animation. RELATIVE_TO_PARENT, 0.0f, 
 Animation. RELATIVE_TO_PARENT, 0.0f, 
 Animation. RELATIVE_TO_PARENT, 0.0f, 
 Animation. RELATIVE_TO_PARENT, -1.0f); 
 outToTop.setInterpolator ( ny AccelerateInterpolator ()); 
 outToTop.setDuration (MSPEED); 
 mViewFlipper.clearAnimation (); 
 mViewFlipper.setInAnimation (inFromBottom); 
 mViewFlipper.setOutAnimation (outToTop); 
 if (mViewFlipper.getDisplayedChild () == 0) { 
 mViewFlipper.setDisplayedChild (2); 
 } andet { 
 mViewFlipper.showPrevious (); 
 } 
 ((TextView) findViewById (R.id. Tæller )). SetText ("COUNTER =>" + Heltal. ToString (mCount)); 
 ((TextView) findViewById (R.id. Hastighed )). SetText ("SPEED =>" + Heltal. ToString (mSpeed)); 
 } 

9. Ikke imod retning, har vi to næsten identiske funktioner til at håndtere en nedadgående drejning af vores hjul.

 private Runnable r2 = new Runnable () { 
 @Override 
 offentlig annullering () { 
 ned(); 
 if (mCount <1) { 
 mAnimating = falsk ; 
 } andet { 
 Håndterer h = ny Håndterer (); 
 h.post Forsinket (r2, mSpeed); 
 } 
 } 
 }; 
 privat tomrum nedad () { 
 mCount--; 
 MSPEED + = mFactor; 
 Animation outToBottom = nyt TranslateAnimation ( 
 Animation. RELATIVE_TO_PARENT, 0.0f, 
 Animation. RELATIVE_TO_PARENT, 0.0f, 
 Animation. RELATIVE_TO_PARENT, 0.0f, 
 Animation. RELATIVE_TO_PARENT, 1.0f); 
 outToBottom.setInterpolator ( ny AccelerateInterpolator ()); 
 outToBottom.setDuration (MSPEED); 
 Animation inFromTop = ny TranslateAnimation ( 
 Animation. RELATIVE_TO_PARENT, 0.0f, 
 Animation. RELATIVE_TO_PARENT, 0.0f, 
 Animation. RELATIVE_TO_PARENT, -1.0f, 
 Animation. RELATIVE_TO_PARENT, 0, 0f); 
 inFromTop.setInterpolator ( ny AccelerateInterpolator ()); 
 inFromTop.setDuration (MSPEED); 
 mViewFlipper.clearAnimation (); 
 mViewFlipper.setInAnimation (inFromTop); 
 mViewFlipper.setOutAnimation (outToBottom); 
 if (mViewFlipper.getDisplayedChild () == 0) { 
 mViewFlipper.setDisplayedChild (2); 
 } andet { 
 mViewFlipper.showPrevious (); 
 } 
 ((TextView) findViewById (R.id. Tæller )). SetText ("COUNTER =>" + Heltal. ToString (mCount)); 
 ((TextView) findViewById (R.id. Hastighed )). SetText ("SPEED =>" + Heltal. ToString (mSpeed)); 
 } 

Jackpot! Mens den endelige løsning endte med at være mere kode end jeg forestillede mig ved starten, er ingeniøren i mig tilfreds med resultaterne. Animationen er temmelig glat på min Nexus S, der kører Jelly Bean. Hvis du har en ældre telefon, ville jeg være nysgerrig efter at vide, hvordan den ser ud. Sørg for at lægge tanker om dette emne i diskussionstråden. I mellemtiden skal jeg dreje hjulet et par gange mere og derefter logge ud.

© Copyright 2021 | pepebotifarra.com