August 10, 2012 David Book buzztouch.com This is a companion file for the Custom Plugin Example - Android. It's a simple plugin example but demonstrates the flexibility of the system nicely. Watch this video in the Plugins Learning Path playlist on the buzztouch YouTube Channel: http://www.youtube.com/user/buzztouchApp Then.... 1) Create your own Custom Plugin in your control panel. 2) Add it to an app you're working on. Do this by adding a new screen and choosing your new Plugin as the screen type. 3) Add the "bug image" and the "splat image" to your project. You can get these images here: Bug: http://www.buzztouch.com/images/bug.png Splat: http://www.buzztouch.com/images/splat.png 3) Copy / Paste the code in this file (below) into your plugin's .java file --Rewind the video a bunch of times if you want, I go fast! BE SURE TO REPLACE "YOUR-PLUGIN-CLASS-FILE-NAME" with the name of your plugin. BE SURE TO REPLACE "YOUR-DELEGATE-NAME" with your app's delegate name. 4) Compile, run, smile. 5) Extend this simple idea by seeing if you can implement some additional methods found in most games. Some ideas include... -(void)showScore -(void)resetScore -(void)showTimer Super motivated folks may also see if they can modify the config.txt file for their app so it uses variables in the JSON (for the plugins screen) to allow dynamic values for things such as "bug speed", "bug image name", "start button text", etc. Feel free to look at all the other plugins for some ideas on how to do this. This is the code I copied and pasted in the .h file for this plugin... #################################################################### Required includes at the top of your Custom Plugin's class file: ---------------------------------------------------------------------------------- import java.util.ArrayList; import java.util.Random; import android.app.Dialog; import android.content.Context; import android.content.res.Configuration; import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.view.Display; import android.view.Gravity; import android.view.LayoutInflater; import android.view.Menu; import android.view.View; import android.view.View.OnClickListener; import android.view.ViewGroup.LayoutParams; import android.view.WindowManager; import android.widget.Button; import android.widget.LinearLayout; import android.widget.RelativeLayout; New Class Members (sometimes called variables or properties): ---------------------------------------------------------------------------------- Button buttonStart = null; Button removeSplatButton = null; RelativeLayout gameContainer = null; int bugSize = 100; int speed = 500; //milliseconds boolean gameIsRunning = false; Pasted in the onCreate method (just about the line that reads "didCreate = true" ---------------------------------------------------------------------------------- //get reference to game container (this is the relative layout in the XML file)... gameContainer = (RelativeLayout) thisScreensView.findViewById(R.id.containerView); //setup the start button... buttonStart = new Button(this); buttonStart.setText("Start Game"); //set onClick listener to start button... buttonStart.setOnClickListener(new OnClickListener() { public void onClick(View arg) { startGame(); } }); //add start button to "game container" (button is 200 x 60)... int buttonWidth = 200; int buttonHeight = 60; RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(buttonWidth, 60); params.leftMargin = (YOUR-DELEGATE-NAME.rootApp.getRootDevice().getDeviceWidth() / 2) - buttonWidth / 2; params.topMargin = YOUR-DELEGATE-NAME.rootApp.getRootDevice().getDeviceHeight() / 3; gameContainer.addView(buttonStart, params); //flag as created.. didCreate = true; Updated onPause() and onStop() methods ---------------------------------------------------------------------------------- //onPause @Override public void onPause() { super.onPause(); //BT_debugger.showIt(activityName + ":onPause"); //make sure timer turns off try{ updateBugHandler.removeCallbacks(mUpdateBugTask); }catch(Exception e){ } } //onStop @Override protected void onStop(){ super.onStop(); //BT_debugger.showIt(activityName + ":onStop"); //make sure timer turns off try{ updateBugHandler.removeCallbacks(mUpdateBugTask); }catch(Exception e){ } } //additional methods I created... ---------------------------------------------------------------------------------- //start game... public void startGame(){ BT_debugger.showIt(activityName + ":startGame"); //hide the start button... buttonStart.setVisibility(INVISIBLE); //flag as running... gameIsRunning = true; //remove splat button if it's not null. This happens when game is restarted... if(removeSplatButton != null){ timerDelayRemoveView(1, removeSplatButton); } //move bug... moveBug(); } //end game... public void endGame(int splatX, int splatY){ BT_debugger.showIt(activityName + ":endGame"); //stop the timer... updateBugHandler.removeCallbacks(mUpdateBugTask); //dynamic button, get created when game ends. This button doesn't do anything when clicked, //could easily be an image instead... Button buttonSplat = null; buttonSplat = new Button(this); buttonSplat.setBackgroundDrawable(BT_fileManager.getDrawableByName("splat.png")); RelativeLayout.LayoutParams paramsSplat = new RelativeLayout.LayoutParams(bugSize, bugSize); paramsSplat.leftMargin = splatX; paramsSplat.topMargin = splatY; gameContainer.addView(buttonSplat, paramsSplat); //remember this splat button as the "last button" so it can be removed when startGame() is clicked... removeSplatButton = buttonSplat; //remove previous start button... if(buttonStart != null){ timerDelayRemoveView(1, buttonStart); } //recreate start button. We do this here so the position is re-calculated after a rotation... buttonStart = new Button(this); buttonStart.setText("Play Again"); //set onClick listener to start button... buttonStart.setOnClickListener(new OnClickListener() { public void onClick(View arg) { startGame(); } }); //add start button to "game container" (button is 200 x 60)... int buttonWidth = 200; int buttonHeight = 60; RelativeLayout.LayoutParams paramsStartButton = new RelativeLayout.LayoutParams(buttonWidth, 60); paramsStartButton.leftMargin = (YOUR-DELEGATE-NAME.rootApp.getRootDevice().getDeviceWidth() / 2) - (buttonWidth / 2); paramsStartButton.topMargin = YOUR-DELEGATE-NAME.rootApp.getRootDevice().getDeviceHeight() / 2; gameContainer.addView(buttonStart, paramsStartButton); //invalidate gameContainer so it redraws itself... gameContainer.invalidate(); } //move bug method... public void moveBug(){ //BT_debugger.showIt(activityName + ": moveBug()"); Button b = null; b = new Button(this); b.setBackgroundDrawable(BT_fileManager.getDrawableByName("bug.png")); //set onClick listener to bug button... b.setOnClickListener(new OnClickListener() { public void onClick(View arg) { //need button's X and Y to show splat image in same place button was... int splatX = arg.getLeft(); int splatY = arg.getTop(); //end game, pass along the splat image's position... endGame(splatX, splatY); } }); int paddingWidth = 150; int paddingHeight = 200; //random number between left edge and width... int nextLeft = nextInt(new Random(), bugSize, (YOUR-DELEGATE-NAME.rootApp.getRootDevice().getDeviceWidth() - bugSize)); //random number between top edge and height... int nextTop = nextInt(new Random(), bugSize + 70, ((YOUR-DELEGATE-NAME.rootApp.getRootDevice().getDeviceHeight() - bugSize) - 70)); BT_debugger.showIt("Left: " + nextLeft + " Top: " + nextTop); RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(bugSize, bugSize); params.leftMargin = nextLeft; params.topMargin = nextTop; gameContainer.addView(b, params); gameContainer.invalidate(); timerDelayRemoveView(speed, b); //reset timer to move bug again... updateBugHandler.removeCallbacks(mUpdateBugTask); updateBugHandler.postDelayed(mUpdateBugTask, speed); } //get random number between two numbers... public int nextInt(Random r, int lower, int higher) { int ran = r.nextInt(); //double x = (double)ran/Integer.MAX_VALUE * higher; double x = (double)ran/Integer.MAX_VALUE * (higher-lower); int ret = (int) x + lower; ret = Math.abs(ret); return ret; } //removes buttons from screen... public void timerDelayRemoveView(long time, final Button b){ Handler handler = new Handler(); handler.postDelayed(new Runnable() { public void run() { b.setVisibility(View.GONE); } }, time); } //triggers updateBugHandler... private Runnable mUpdateBugTask = new Runnable() { public void run() { updateBugHandler.sendMessage(updateBugHandler.obtainMessage()); } }; //handles mUpdateBugTask Handler updateBugHandler = new Handler(){ @Override public void handleMessage(Message msg){ //BT_debugger.showIt(activityName + ": Handler:updateBugHandler()"); //move bug if the game is running... if(gameIsRunning){ moveBug(); } } };