@Override public void update(View v) { long newtime = System.nanoTime(); // �ɋ}������ // �[������ if (lastSeedCount != fruitsSplatted.size()) { Random random = new Random(); int randomIndex = random.nextInt(2) + 1; if (randomIndex % 2 == 0) { // ����������+0.5�͈͂ł����Ă��� // 1~5�͈̔͂��쐬����1/10�ɂ��� randomSpeed += (random.nextInt(3) + 1) / 10.0f; float decimalSpeed = random.nextFloat(); // 0.1~1.0 // randomSpeed = random.nextInt(4) + decimalSpeed + 1; // 1~5 System.out.println(randomSpeed); } lastSeedCount = fruitsSplatted.size(); // �ʕ��̕\���� } String speedStr = String.format("SPEED:%f", randomSpeed); System.out.println(speedStr); float elapsedsecs = (float) (newtime - frtime) / ONESEC_NANOS * randomSpeed; frtime = newtime; fps = (int) (1 / elapsedsecs); // update combo hits Iterator<Combo> hcit = hitCombos.keySet().iterator(); while (hcit.hasNext()) { Combo combo = hcit.next(); ComboHit ch = hitCombos.get(combo); ch.y -= COMBOHIT_SPEED * elapsedsecs; float chtime = frtime - ch.hitTime; ch.alpha = (int) (255 * (1.0f - chtime / COMBOHIT_DISPLAYTIME)); if (frtime - ch.hitTime > COMBOHIT_DISPLAYTIME / 3) fps = 0; // excuse to put a breakpoint here if (frtime - ch.hitTime > COMBOHIT_DISPLAYTIME) hcit.remove(); } if (gamestate == State.STARTROUND) { // this goofy construction is to make sure we initialize the round from // the update/draw thread, not from the UI thread. initRound(); return; } if (width == 0) { // set variables that rely on screen size width = v.getWidth(); height = v.getHeight(); wallxcenter = width / 2; wallycenter = (int) (height * WALL_Y_CENTER_FACTOR); inity = (int) (INIT_SELECTABLE_Y_FACTOR * height); // initial fruit placement, also bottom of wall. // attempt to compute wall bounds at wall z from screen size. constants are pure // magic, found thru trial and error iterations. // if the background picture changes, they will need to be recalibrated. wallbounds_at_wall_z.set( (int) (-1.5 * width), (int) (-height * .94), (int) (2.43 * width), inity); // wall bounds AT WALL Z (!!WaLLzeY!!) // magic trial and error world-bounds contants, based on screen image size minXbound = 8 * -width; maxXbound = 8 * width; maxYbound = 5 * height; // compute wall bounds at screen z, used for clipping. int effl = (int) (wallbounds_at_wall_z.left + (WALLZFACT * (wallxcenter - wallbounds_at_wall_z.left))); int efft = (int) (wallbounds_at_wall_z.top + (WALLZFACT * (wallycenter - wallbounds_at_wall_z.top))); int effr = (int) (wallbounds_at_wall_z.right + (WALLZFACT * (wallxcenter - wallbounds_at_wall_z.right))); int effb = (int) (wallbounds_at_wall_z.bottom + (WALLZFACT * (wallycenter - wallbounds_at_wall_z.bottom))); wallbounds_at_screen_z.set(effl, efft, effr, effb); p.setTextSize(act.TS_NORMAL); p.setTypeface(act.getGameFont()); String t = "SCORE: 999999"; rhstextoffset = (int) p.measureText(t); p.getTextBounds(t, 0, t.length() - 1, scaledDst); statstextheight = (int) (scaledDst.height() + 5); statstextheight2 = statstextheight * 2; } if (gamestate == State.RUNNING && fruitsSelectable.size() < maxShownSelectableFruit && seedsQueued.size() > 0 && frtime > possspawntime + MIN_SPAWN_INTERVAL_NANOS) { possspawntime = frtime; // "every now and then" make a fruit available if (Math.random() > .6) { Fruit newf = null; if (fruitsRecycled.size() > 0) { // recycle a fruit if we can newf = fruitsRecycled.get(0); fruitsRecycled.remove(0); } else { // create if needed newf = new Fruit(); } // choose fruit Seed s = seedsQueued.get(0); seedsQueued.remove(0); int initx = (int) -s.halfWidth; int speed = selectable_speed; if (Math.random() > .5) { initx = (int) (width + s.halfWidth); speed = -speed; } newf.init(s, initx, inity, 0, speed); fruitsSelectable.add(newf); } } else if (gamestate == State.RUNNING && fruitsSelectable.size() == 0 && fruitsFlying.size() == 0 && seedsQueued.size() == 0) { // round is complete if (nWallSplats * 100 / nTotFruit >= minRoundPassPct) { act.playSound(Sound.PASSLEVEL); round++; gamestate = State.ROUNDSUMMARY; } else loseLife(); } // update fruit positions synchronized (fruitsFlying) { Iterator<Fruit> fit = fruitsFlying.iterator(); while (fit.hasNext()) { Fruit f = fit.next(); f.x += f.vx * elapsedsecs; f.y += f.vy * elapsedsecs; f.z += f.vz * elapsedsecs; f.vy += ACC_GRAVITY * elapsedsecs; if (f.z >= WALL_Z && wallbounds_at_wall_z.contains((int) f.x, (int) f.y)) { // fruit has hit wall fit.remove(); fruitsSplatted.add(f); nWallSplats++; if (f.isBonus == true) { score += f.seed.points * 5; } else { score += f.seed.points; } act.playSound(f.getSplatSound()); // check combo for (Combo c : combos) { neededSeeds.clear(); neededSeeds.addAll(c.seeds); neededSeeds.remove(f.seed); comboFruits.clear(); comboFruits.add(f); for (Fruit spf : fruitsSplatted) { if (neededSeeds.contains(spf.seed)) { if (spf.getBounds().intersect(f.getBounds())) { neededSeeds.remove(spf.seed); comboFruits.add(spf); } if (neededSeeds.size() == 0) break; } } if (neededSeeds.size() == 0) { // combo is hit score += c.points; for (Fruit spf : comboFruits) { fruitsSplatted.remove(spf); } // display combo hit message "somewhere next to" combo hit effpt = renderFromZ(f.x, f.y, f.z, wallxcenter, wallycenter); ComboHit ch = new ComboHit(); ch.x = effpt.x + (float) Math.random() * 100 - 50; ch.y = effpt.y + (float) Math.random() * 100 - 80; // play sound act.playSound(Sound.COMBO); // ensure combo display is fully onscreen p.getTextBounds(c.name, 0, c.name.length(), scaledDst); if (ch.x < 0) ch.x = 0; else if (ch.x > width - scaledDst.width()) ch.x = width - scaledDst.width(); ch.hitTime = System.nanoTime(); hitCombos.put(c, ch); } } } else if (f.y > inity && f.y < inity + f.vy * elapsedsecs && f.z > WALL_Z / 2) { // fruit has hit ground near wall fit.remove(); fruitsSplatted.add(f); } else if (f.z > WALL_Z // here we goofily force java to call render function when we need it && (effpt = renderFromZ(f.x, f.y, f.z, wallxcenter, wallycenter)) != null && wallbounds_at_screen_z.contains(effpt.x, effpt.y)) { // wild pitch, behind wall fit.remove(); fruitsRecycled.add(f); } else if (f.y > maxYbound || f.x >= maxXbound || f.x <= minXbound) { // wild pitch, out of bounds fit.remove(); fruitsRecycled.add(f); } } } if (gamestate == State.RUNNING) { synchronized (fruitsSelectable) { Iterator<Fruit> fit = fruitsSelectable.iterator(); while (fit.hasNext()) { Fruit f = fit.next(); if (f != selectedFruit) { // f.x += f.vx * elapsedsecs; f.x += f.vx * elapsedsecs * f.scroll; // wobble displayable fruit up and down, and return them to regular line when let go // int targy = inity + (int)(Math.sin(f.x/15)* selectable_y_play); // f.y += (targy - f.y) / SELECTABLE_FRUIT_BRAKING_FACTOR; int targy = inity + (int) (Math.sin(f.x / 65) * selectable_y_play); f.y += (targy - f.y) / SELECTABLE_FRUIT_BRAKING_FACTOR; } if (f.x < -f.seed.halfWidth || f.x > width + f.seed.halfWidth) { // we floated off screen fit.remove(); fruitsRecycled.add(f); } } } } }
/** * draw the screen. * * @param c * @param v */ @Override public void draw(Canvas c, View v) { try { // actually draw the screen scaledDst.set(0, 0, width, height); c.drawBitmap(wallbtm, null, scaledDst, p); // draw wall's bounds, for debugging // p.setColor(Color.RED); // c.drawRect(wallbounds_at_screen_z, p); // draw fruits for (Fruit f : fruitsSplatted) { drawFruit3Dcoords(c, f, f.getSplatBitmap(), wallxcenter, wallycenter); } synchronized (fruitsFlying) { for (Fruit f : fruitsFlying) { drawFruit3Dcoords(c, f, f.getBitmap(System.nanoTime()), wallxcenter, wallycenter); } } synchronized (fruitsSelectable) { for (Fruit f : fruitsSelectable) { // selectable fruit is on z=0, so we can just display normally: c.drawBitmap(f.getBitmap(), f.x - f.seed.halfWidth, f.y - f.seed.halfHeight, p); } } // draw combo hits for (Combo combo : hitCombos.keySet()) { ComboHit ch = hitCombos.get(combo); // p.setColor(Color.YELLOW); p.setARGB( ch.alpha, 190 + (int) (Math.random() * 60), 190 + (int) (Math.random() * 60), (int) (Math.random() * 60)); p.setTypeface(act.getGameFont()); p.setTextSize(act.TS_NORMAL); c.drawText(combo.name, ch.x, ch.y, p); } // c.drawText("fps: "+fps // +" w:"+width + " h:" +height // +"x:"+touchx+" y:"+touchy+" // tvx:"+(int)touchvx+"\ttvy:"+(int)touchvy+ // "\tflying:" + fruitsFlying.size() // + "\nff vz:" + (fruitsFlying.size() > 0 ? fruitsFlying.get(0).vz // : -1) // + "\nff vy:" + (fruitsFlying.size() > 0 ? fruitsFlying.get(0).vy // : -1) // + " ffvz:" + (fruitsFlying.size() > 0 ? fruitsFlying.get(0).vz : // -1), // , 0, 200, p); p.setColor(Color.WHITE); p.setTextSize(act.TS_NORMAL); p.setTypeface(act.getGameFont()); p.setFakeBoldText(true); // drawtext draws bottom-aligned? c.drawText("ROUND: " + round, width - rhstextoffset, statstextheight, p); c.drawText("LIVES: " + lives, width - rhstextoffset, statstextheight2, p); c.drawText("SCORE: " + score, 10, statstextheight, p); if (score >= hiscore) { hiscore = score; hilev = round; } c.drawText("HIGH: " + hiscore + ", r" + hilev, 10, statstextheight2, p); // game programming! pure and constant state manipulation! // this is like fingernails on a chalkboard for the functional programming crowd if (gamestate == State.ROUNDSUMMARY || gamestate == State.STARTGAME || gamestate == State.PLAYERDIED || gamestate == State.GAMEOVER) { if (gamestate != State.STARTGAME) { // round ended, by completion or player death, display stats int splatPct = (int) (nWallSplats * 100 / nTotFruit); drawCenteredText( c, splatPct + "% sPLAttaGe! (" + minRoundPassPct + "% required)", height / 3, p, 0); if (gamestate == State.ROUNDSUMMARY) { if (splatPct < 80) drawCenteredText(c, "not too bad.", (int) (height / 2.5), p, 0); else if (splatPct < 85) drawCenteredText(c, "nice!", (int) (height / 2.5), p, 0); else if (splatPct <= 95) { drawCenteredText(c, "cRudE!", (int) (height / 2.5), p, 0); } else if (round > 10) { c.drawText("Dude, really?!", width / 4, (int) (height / 2.5), p); c.drawText("Awesome.", width / 3, (int) (height / 2.2), p); } else { drawCenteredText(c, "eEEeEeeEh!! sPAzMiC!", (int) (height / 2.5), p, 0); } } else if (gamestate == State.PLAYERDIED || gamestate == State.GAMEOVER) c.drawText("...Ooops.", width / 3, (int) (height / 2.5), p); } if (gamestate != State.PLAYERDIED && gamestate != State.GAMEOVER) { String msg = levelmsgMap.get(Integer.valueOf(round)); if (msg != null) { if (msg.contains(LINE_SPLIT_MARKER)) { drawCenteredText( c, msg.substring(0, msg.indexOf(LINE_SPLIT_MARKER)), height * 3 / 5, p, 0); drawCenteredText( c, msg.substring(msg.indexOf(LINE_SPLIT_MARKER) + 1), height * 2 / 3, p, 0); } else drawCenteredText(c, msg, height * 3 / 5, p, 0); } } if (gamestate != State.GAMEOVER) { p.setTextSize(act.TS_BIG); p.setColor(Color.RED); drawCenteredText(c, "Touch to continue", height * 4 / 5, p, -2); p.setColor(Color.WHITE); drawCenteredText(c, "Touch to continue", height * 4 / 5, p, 0); } } if (gamestate == State.GAMEOVER) { p.setTextSize(act.TS_BIG); p.setColor(Color.RED); drawCenteredText(c, "GamE oVeR!", height / 2, p, -2); drawCenteredText(c, "Touch to end game", height * 4 / 5, p, -2); p.setColor(Color.WHITE); drawCenteredText(c, "GamE oVeR!", height / 2, p, 0); drawCenteredText(c, "Touch to end game", height * 4 / 5, p, 0); } } catch (Exception e) { Log.e(MainActivity.LOG_ID, "draw", e); e.printStackTrace(); } }
public PlayScreen(MainActivity act) { p = new Paint(); this.act = act; AssetManager assetManager = act.getAssets(); try { // wall InputStream inputStream = assetManager.open("wall1_800x1104_16.png"); wallbtm = BitmapFactory.decodeStream(inputStream); inputStream.close(); // pear pearbtm = new Bitmap[4]; pearbtm[0] = act.getScaledBitmap("pear1.png"); pearbtm[1] = act.getScaledBitmap("pear2.png"); pearbtm[2] = act.getScaledBitmap("pear3.png"); pearbtm[3] = act.getScaledBitmap("pearsplat1.png"); // banana banbtm = new Bitmap[5]; banbtm[0] = act.getScaledBitmap("ban1.png"); banbtm[1] = act.getScaledBitmap("ban2.png"); banbtm[2] = act.getScaledBitmap("ban3.png"); banbtm[3] = act.getScaledBitmap("ban4.png"); banbtm[4] = act.getScaledBitmap("bansplat.png"); // orange orangebtm = new Bitmap[4]; orangebtm[0] = act.getScaledBitmap("orange1.png"); orangebtm[1] = act.getScaledBitmap("orange2.png"); orangebtm[2] = act.getScaledBitmap("orange3.png"); orangebtm[3] = act.getScaledBitmap("orangesplat.png"); // nutella nutbtm = new Bitmap[5]; nutbtm[0] = act.getScaledBitmap("nut1.png"); nutbtm[1] = act.getScaledBitmap("nut2.png"); nutbtm[2] = act.getScaledBitmap("nut3.png"); nutbtm[3] = act.getScaledBitmap("nut4.png"); nutbtm[4] = act.getScaledBitmap("nutsplat.png"); // ice cream icbtm = new Bitmap[5]; icbtm[0] = act.getScaledBitmap("icecream1.png"); icbtm[1] = act.getScaledBitmap("icecream2.png"); icbtm[2] = act.getScaledBitmap("icecream3.png"); icbtm[3] = act.getScaledBitmap("icecream4.png"); icbtm[4] = act.getScaledBitmap("icecreamsplat.png"); // milk milkbtm = new Bitmap[5]; milkbtm[0] = act.getScaledBitmap("milk1.png"); milkbtm[1] = act.getScaledBitmap("milk2.png"); milkbtm[2] = act.getScaledBitmap("milk3.png"); milkbtm[3] = act.getScaledBitmap("milk4.png"); milkbtm[4] = act.getScaledBitmap("milksplat1.png"); // ketchup ketbtm = new Bitmap[2]; ketbtm[0] = act.getScaledBitmap("ketch1.png"); ketbtm[1] = act.getScaledBitmap("ketchsplat.png"); // initialize types of fruit (seeds), point values pearseed = new Seed(pearbtm, 10, Sound.WETSPLAT, SeedType.pearseed); orangeseed = new Seed(orangebtm, 15, Sound.WETSPLAT, SeedType.orangeseed); banseed = new Seed(banbtm, 20, Sound.WETSPLAT, SeedType.banseed); milkseed = new Seed(milkbtm, 25, Sound.SPLAT, SeedType.milkseed); icseed = new Seed(icbtm, 30, Sound.SPLAT, SeedType.icseed); nutseed = new Seed(nutbtm, 40, Sound.SPLAT, SeedType.nutseed); ketseed = new Seed(ketbtm, 0, Sound.KSPLAT, SeedType.ketseed); // init combos ArrayList<Seed> sl = new ArrayList<Seed>(); sl.add(pearseed); sl.add(orangeseed); sl.add(banseed); combos.add(new Combo(sl, "Fruit Salad!", 100)); sl = new ArrayList<Seed>(); sl.add(milkseed); sl.add(banseed); combos.add(new Combo(sl, "BanaNa MiLKshaKe!", 80)); sl = new ArrayList<Seed>(); sl.add(orangeseed); sl.add(icseed); combos.add(new Combo(sl, "OrangE CreaM!", 80)); sl = new ArrayList<Seed>(); sl.add(milkseed); sl.add(nutseed); combos.add(new Combo(sl, "chOcolaTe MiLK!", 100)); sl = new ArrayList<Seed>(); sl.add(banseed); sl.add(icseed); sl.add(nutseed); combos.add(new Combo(sl, "bAnaNA sPLiT!!", 150)); levelmsgMap.put(Integer.valueOf(1), "tImE to SPlaT!#fling the fruit at the wall!"); levelmsgMap.put(Integer.valueOf(LEVEL_ORANGE), "Orange ya glad there's more#fruit to throw?"); levelmsgMap.put( Integer.valueOf(LEVEL_BANANA), "Splat pear+orange+banana#in the same place...fruit salad!"); levelmsgMap.put( Integer.valueOf(LEVEL_MILK), "how about Some milk to wash#all that fruit down?"); levelmsgMap.put( Integer.valueOf(LEVEL_KETCHUP), "Don't pop the keTChup packets!#Nobody likes that."); levelmsgMap.put( Integer.valueOf(LEVEL_ICECREAM), "time for ICE CREAM!#And more combinations!"); levelmsgMap.put(Integer.valueOf(LEVEL_NUT), "Mmm...chocolate sauce!#Hit those COMBOS!"); levelmsgMap.put( Integer.valueOf(LEVEL_DANCING_FRUIT), "Sometimes...the fruit...#likes to DANCE!"); levelmsgMap.put(Integer.valueOf(LEVEL_MOREFRUIT1), "more fruit!#fling, fling, fling"); levelmsgMap.put(Integer.valueOf(LEVEL_MOREFRUIT2), "getting a little crazy now, yes?"); p.setTypeface(act.getGameFont()); round = 1; } catch (IOException e) { Log.d(act.LOG_ID, "wha?", e); } }