Z>KN(~'-XV?(@?( @RRTT~ььќўѠѬRѰѲѴTѲGџХЮвиоpackage mobi.offbyone.Bix; import net.rim.device.api.ui.Font; import net.rim.device.api.ui.DrawStyle; // #ifdef fourseven //@import net.rim.device.api.ui.TouchEvent; //@import net.rim.device.api.ui.TouchGesture; //#endif import net.rim.device.api.ui.XYRect; import net.rim.device.api.ui.FontFamily; import net.rim.device.api.ui.Keypad; import net.rim.device.api.ui.UiApplication; import net.rim.device.api.ui.container.FullScreen; import net.rim.device.api.ui.Graphics; import net.rim.device.api.system.Bitmap; import net.rim.device.api.system.Characters; import net.rim.device.api.system.Application; import net.rim.device.api.system.*; import java.lang.Thread; import java.lang.Math; import java.util.*; // Gameplay extends FullScreen only, it doesn't need the functionality of the // MainScreen object public class GamePlayNew extends FullScreen { // These three objects are called from many places and are made public public static Random rndGenerator; // Static object for random numbers Refresher _refresher; // Thread that continually refreshes the game public static final int DEATH_WAIT_TIME = 2000; // wait 2000ms after player death to reset playfield static boolean _active; // Flag if our game is currently active or not (eg did we lose) static boolean _paused = false; static boolean _block = false; static boolean textNeedRedraw; // set to true when the score, lives or % coverage changes, prevents unnecessary redraw static boolean bgNeedsRedraw; static int oldTouchX = -1; static int oldTouchY = -1; static int _score; // Player's current score static int _lives; static int _level; static boolean lifeBallTaken; static int filledPercentage; static int filledPixels; static float speedFactor; static long timeStamp; static long waitTimer; static final int percentageWinLevel= 75; static Bitmap _backgroundBM; // The bitmap for the background static Font _gameFont; // The font used for drawing score and lives static Font _bannerFont; static Bitmap alpha; static Bitmap player; static Bitmap lightBlueBall; static Bitmap darkBlueBall; static Bitmap violetBall; static Bitmap greenBall; static int playfieldPositionX; static int playfieldPositionY; static int mapWidth; static int mapHeight; static int mapSize; static int numberEmptyCells; static int screenWidth; static int screenHeight; static int playerX; static int playerY; static int playerPosition; static int traceStart; static int vectorStart; static int playerRotation; static int playerStatus; static int playerDirection; static int fillColor; static int tempColor; static int tempColor2; static int peripheralBlockColor; static int pathBlockColor; static int emptyColor; static int traceColor; static int pathColor; static int traceBorderColor; static int fps; static long fpsSum; static int fpsCount; static int status; static long timeSpent; static int surface; static int speed; static Ball ball; static final XYRect clip = new XYRect(); static int first_dir; static int second_dir; static int oldPercentage; static float xdiff; static int surface1; static int surface2; static int frontLeftColor; static int frontRightColor; static int forwardColor; static int forwardIndex; static int frontLeftIndex; static int frontRightIndex; static boolean zone1Smaller; static final int NORMALBALL=0; static final int LIFEBALL=1; static final int RESPAWNBALL=2; static final int SLOWDOWNBALL = 3; static final int FASTBALL = 4; static final int REMOVEDBALL = -1; static final int OK = 0; static final int KILLED = 1; static final int WON = 2; static final int ballDimension=8; static final int halfBallDimension = 4; static final int playerDimension = 8; static final int halfPlayerDimension = 4; static final int borderSize = 3; static final float defaultSpeedFactor = (float)0.5; // Player Directions in CW order static final int DOWN = 0; static final int LEFT = 1; static final int UP = 2; static final int RIGHT = 3; // Directions vectors in screen coordinate (x,y) - DOWN, LEFT, UP, RIGHT static final int[] dirVectors = {0,1,-1,0,0,-1,1,0}; static int[] dirOffsets; // Player rotations (used when branching on a path) static final int CCW = 0; // CounterClockWise static final int CW = 1; // ClockWise // Player status static final int NOT_TRACING = 0; static final int TRACING = 1; static final int DEAD = 2; static final int FINISHED_LEVEL= 3; // Banner Status static int bannerStatus; static final int BANNER_NONE=0; static final int BANNER_TRY_AGAIN=1; static final int BANNER_GAME_OVER =2; static final int BANNER_NEW_LEVEL =3; static final int BANNER_PAUSE = 4; private static final String livesText = "x3"; private static final String scoreText = "Score: 0000000"; private static final String levelText = "Level 00"; private static final String fillText = "% / 75%"; private static final String tryAgainBanner = "TRY AGAIN!"; private static final String levelBanner = "LEVEL "; private static final String gameOverBanner = "GAME OVER!"; private static final String pausedBanner = "GAME PAUSED "; private static int levelTextLength; private static int fillTextLength; private static StringBuffer livesSB; private static StringBuffer scoreSB; private static StringBuffer levelSB; private static StringBuffer fillPercentSB; private static StringBuffer levelBannerSB; private static long mainColor; private static int emptyPixelSearch; private static int start1; private static int start2; private static int[]scanLineStack1X; private static int[]scanLineStack1XEnd; private static int[]scanLineStack1Y; // private static int scanLineStackPointer1 = 0; // private static int lineLength1; private static int fillSurface1 = 0; private static int x1; private static int y1; private static int linePos1; private static int wantedDirection = -1; static char[] cheatCode ={'p','a','d','a','d','a','z'}; static int cheatCounter = 0; // it's the playfield model (one byte per pixel linear) // it's also the view of the playfield since each color value is assigned to a playfield state // This is pretty dirty, but done for performance reasons private static int[] map; private static int[] bgMap; private static int[] colorMap; private static int[] mapCopy1; private static int[] mapCopy2; private static int[] tempMap; private static int[] traceDirection; private static int[] traceLength; private static int tracePointer = 0; private static int currentTraceSegmentLength = 0; //private static int[][] vectorMapSegmentType; // 0 : empty; 1:full; 2:vertical trace; 3: horizontal trace private static int[][] vectorMapSegmentStart; private static int[][] vectorMapSegmentLength; private static int[] vectorMapLineLength; private static int[] vectorMapFilledSegments; private static int[] vectorMapFilledSegmentsCopy; private static final int VECTOR_MAX = 200; // ugly but avoids using Vector static Ball[] balls; static int numberBalls = 0; // Getters for active and score boolean getActive() { return _active; } int getScore() {return _score; } int getLevel() {return _level;} // Refresh is a type of thread that runs to refresh the game. // Its job is to make sure all the processing is called for each object, update the background, // update score, check for end of game, etc. This is the main heartbeat. private class Refresher extends Thread { // When the object is created it starts itself as a thread Refresher() { start(); } public synchronized void block() { try { this.wait(); }catch(Exception e){} } public synchronized void unBlock() { try { this.notify(); }catch(Exception e){} } // This method defines what this thread does every time it runs. public void run() { int loopCount = 0; // This thread runs while the game is active while (_active) { // FPS counting stuff // #ifdef FPS //@ fpsSum += System.currentTimeMillis()-timeStamp; //@ if ((fpsCount % 30) ==0) //@ { //@ fps = (int)((30*1000)/(fpsSum+1)); // +1 to prevent div/0 //@ fpsSum=0; //@ } //@ fpsCount++; // #endif timeStamp = System.currentTimeMillis(); if (_paused) { bannerStatus = BANNER_PAUSE; if (_block) { _block = false; block(); } } else if (playerStatus == TRACING || playerStatus == NOT_TRACING) { status = OK ; if (wantedDirection >= 0) // if wantedDirection is >= 0, a direction change event from the player has occured in the event thread { if (playerStatus == NOT_TRACING) // if the game is wandering around the path, check if the player wants to reverse direction on the path or start a new trace { if (wantedDirection == (playerDirection +2) %4) // check if wanted direction is the opposite of current direction { playerRotation = (playerRotation + 1) %2; // inverse rotation playerDirection = wantedDirection; } else if (wantedDirection == playerDirection) { //Do nothing in that case } else // it's a command to start tracing { // check if it is possible to start a trace in that direction if (map[playerPosition +dirOffsets[wantedDirection]] < 0) // check that the map is empty in the wanted direction { // Check that both sides are empty if (map[playerPosition +dirOffsets[wantedDirection]+dirOffsets[(wantedDirection+1)%4]]<0 && map[playerPosition +dirOffsets[wantedDirection]+dirOffsets[(wantedDirection+3)%4]]<0) { // get a pixel on the two opposite sides of the trace line to have two starting points for the fill algo start1 = playerPosition +dirOffsets[wantedDirection]+dirOffsets[(wantedDirection+1)%4]; start2 = playerPosition +dirOffsets[wantedDirection]+dirOffsets[(wantedDirection+3)%4]; // make two copies of the current state of the map for the fill algo System.arraycopy(map, 0, mapCopy1, 0, mapSize); System.arraycopy(map, 0, mapCopy2, 0, mapSize); playerStatus = TRACING; playerDirection = wantedDirection; traceStart = playerPosition; // This one is used to correct the path after a fill, overlaps with the path vectorStart= playerPosition +dirOffsets[wantedDirection]; // this one is used by the fill algorithm, can't overlap with the path // Store the vector information about the first trace segment tracePointer = 0; currentTraceSegmentLength=-1; // Little hack since the first pixel of the trace is removed (TODO: in fact maybe not a hack, first pixel of every segment should be removed) traceDirection[tracePointer] = wantedDirection; } } } } else if (playerStatus == TRACING) { if (playerDirection != (wantedDirection +2) %4) // Player can't go back on his track { playerDirection = wantedDirection; traceLength[tracePointer] = currentTraceSegmentLength; currentTraceSegmentLength = 0; tracePointer++; traceDirection[tracePointer] = wantedDirection; } } wantedDirection = -1; // work done, reset wanted direction flag } for (loopCount = 0; loopCount < speed && status == OK; loopCount++) // move player several pixels per frame, depending on device { bannerStatus = BANNER_NONE; // Move player status = movePlayer(); if ( status == OK) { //move Balls status = moveBalls(); if (status == KILLED) { playerStatus = DEAD; } } else if (status == KILLED) { playerStatus = DEAD; } else if (status == WON) { playerStatus = FINISHED_LEVEL; } } } else if (playerStatus == DEAD) // player died display something for a bit { if (waitTimer == 0) { _lives--; Alert.startVibrate(400); if (_lives ==0) { bannerStatus = BANNER_GAME_OVER; } else { bannerStatus = BANNER_TRY_AGAIN; } waitTimer = timeStamp; } else if (timeStamp - waitTimer > DEATH_WAIT_TIME) { playerStatus = NOT_TRACING; waitTimer = 0; if (_lives == 0) { _active = false; } else { resetPlayField(); } } } else if (playerStatus == FINISHED_LEVEL) { if (waitTimer == 0) { levelBannerSB.setLength(0); levelBannerSB.append(levelBanner); levelBannerSB.append(_level+1); bannerStatus = BANNER_NEW_LEVEL; waitTimer = timeStamp; } else if (timeStamp - waitTimer > DEATH_WAIT_TIME) { waitTimer = 0; _level++; lifeBallTaken = false; resetPlayField(); } } UiApplication.getUiApplication().invokeAndWait(new Runnable() { public void run() { //We want to clear the entire screen so call invalidate //instead of invalidate(#, #, #, #). if (bgNeedsRedraw) { invalidate(); } else { invalidate(playfieldPositionX,playfieldPositionY,mapWidth,mapHeight); } } }); bgNeedsRedraw = false; timeSpent = System.currentTimeMillis() - timeStamp; // maximum ~33 FPS if (timeSpent < 30) { try { // Attempt to sleep Thread.sleep(30-timeSpent); } catch (InterruptedException e) { // Do nothing if we couldn't sleep, we don't care about exactly perfect // timing. } } } } } public static final void setScore() // Should be rewritten, it's awful { int scoreLength; if (_score <10) { scoreLength= 1; } else if (_score <100) { scoreLength= 2; } else if (_score <1000) { scoreLength= 3; } else if (_score <10000) { scoreLength= 4; }else if (_score <100000) { scoreLength= 5; }else if (_score <1000000) { scoreLength= 6; } else { scoreLength= 7; } scoreSB.delete(14-scoreLength,15); scoreSB.setLength(0); scoreSB.append(scoreText); scoreSB.delete(14-scoreLength,15); scoreSB.append(_score); } public static final void setFillPercent() { fillTextLength = 9; fillPercentSB.delete(0,9); if (filledPercentage <10) { fillPercentSB.append(' '); } fillPercentSB.append(filledPercentage); fillPercentSB.append(fillText); } public static final void resetPlayField() { scanLineStackPointer1 = 0; filledPercentage = 0; filledPixels = 0; speedFactor = defaultSpeedFactor; emptyPixelSearch = mapWidth; // first line is never empty livesSB.delete(1,2); livesSB.append(_lives); if (_level >= 10) { levelTextLength = 8; } else { levelTextLength = 7; } levelSB.delete(6, 9); levelSB.append(_level); setScore(); setFillPercent(); switch (_level%10) { case 1: mainColor = (long) 0x00310064;break; case 2: mainColor = (long) 0x00640064;break; case 3: mainColor = (long) 0x00640000;break; case 4: mainColor = (long) 0x00543200;break; case 5: mainColor = (long) 0x00444000;break; case 6: mainColor = (long) 0x00004044;break; case 7: mainColor = (long) 0x00204000;break; case 8: mainColor = (long) 0x00004031;break; case 9: mainColor = (long) 0x00310064;break; case 0: mainColor = (long) 0x00000064;break; default: mainColor = (long) 0x00640031;break; } fillColor = (int)(mainColor + (long)0x00606060); emptyColor = (int)((long)(0xFF<<24) +(long)(97 << 16) + (long)(97 << 8) + (long) (97)); tempColor = 1; tempColor2 = 2; //traceColor = (int) ( (long)(0xFF << 16) + (long) (0xFF)); traceColor = fillColor+1; traceBorderColor = (int) (mainColor + 0xFF505050L); pathColor = (int) mainColor; peripheralBlockColor = pathColor+2; pathBlockColor = pathColor +1; prepareMap(); createBalls(); playerPosition = borderSize + (mapSize/2); playerX = borderSize; playerY = mapHeight/2; playerDirection = DOWN; playerRotation = CCW; playerStatus = NOT_TRACING; bgNeedsRedraw= true; } public GamePlayNew() { bgNeedsRedraw = true; dirOffsets = new int[4]; livesSB = new StringBuffer(livesText); scoreSB = new StringBuffer(scoreText); levelSB = new StringBuffer(levelText); levelBannerSB = new StringBuffer(levelBanner); fillPercentSB = new StringBuffer(); textNeedRedraw = true; try { _gameFont = FontFamily.forName("BBCondensed").getFont(FontFamily.SCALABLE_FONT,16); _bannerFont = FontFamily.forName("BBAlpha Sans").getFont(FontFamily.SCALABLE_FONT,30).derive(Font.BOLD); } catch (Exception e) { } screenWidth = Config.screenWidth; screenHeight = Config.screenHeight; speed = Config.speed; _backgroundBM = Config.backGround; player = Bitmap.getBitmapResource("88play1.png"); lightBlueBall = Bitmap.getBitmapResource("88darkblue1.png"); darkBlueBall = Bitmap.getBitmapResource("88blue1.png"); violetBall = Bitmap.getBitmapResource("88purple1.png"); greenBall = Bitmap.getBitmapResource("88green1.png"); rndGenerator = new Random(); // Create random number generator scanLineStack1X = new int[5000]; scanLineStack1XEnd = new int[5000]; scanLineStack1Y = new int[5000]; scanLineStackPointer1 = 0; mapWidth = Config.mapWidth; mapHeight = Config.mapHeight; playfieldPositionX = (screenWidth - mapWidth) /2; playfieldPositionY = Config.playfieldPositionY; mapSize = mapWidth*mapHeight; dirOffsets[0] = mapWidth; dirOffsets[1] = -1; dirOffsets[2] = -mapWidth; dirOffsets[3] = 1; map = new int[mapSize]; bgMap = new int[mapSize]; colorMap = new int[mapSize]; mapCopy1 = new int[mapSize]; mapCopy2 = new int[mapSize]; traceDirection = new int[500]; traceLength = new int[500]; // vectorMapSegmentType = new int [mapHeight][200]; // 0 = empty; 1 = colored; 3 = path vectorMapSegmentLength = new int [mapHeight][VECTOR_MAX]; vectorMapSegmentStart = new int [mapHeight][VECTOR_MAX]; vectorMapLineLength = new int [mapHeight]; vectorMapFilledSegments = new int [mapHeight*VECTOR_MAX]; vectorMapFilledSegmentsCopy = new int [mapHeight*VECTOR_MAX]; _backgroundBM.getARGB(bgMap,0, mapWidth,playfieldPositionX,playfieldPositionY,mapWidth,mapHeight); } public void startGame() { bgNeedsRedraw = true; _active = true; // Mark the game as active _score = 0; // Start with a score of 0 _level = 1; _lives = 3; lifeBallTaken = false; resetPlayField(); _refresher = new Refresher(); } public static final void prepareMap() { int indexY=0; int indexX=0; numberEmptyCells = (mapWidth-borderSize*2)*(mapHeight-borderSize*2); // remove borders, x pixels on each side _backgroundBM.getARGB(map,0, mapWidth,playfieldPositionX,playfieldPositionY,mapWidth,mapHeight); // paint top and bottom borders for (indexX = 0; indexX < borderSize *mapWidth; indexX++) { map[indexX] = peripheralBlockColor; map[mapSize- indexX -1] = peripheralBlockColor; } // Top and bottom path for (indexX = 0; indexX < mapWidth ; indexX++) { map[borderSize*mapWidth + indexX] = pathColor; map[mapSize- indexX -1 -borderSize*mapWidth] = pathColor; } // left and right borders + left and right path for (indexY = borderSize; indexY < mapHeight-borderSize ; indexY +=1) { for (indexX = 0;indexX 0) { surface = vectorFill(start2,2); tempMap = map; map = mapCopy2; mapCopy2 = tempMap; //surface = surface2; numberEmptyCells = surface1; } else if (surface1 < surface2) { tempMap = map; map = mapCopy1; mapCopy1 = tempMap; surface = surface1; numberEmptyCells = surface2; } else { surface = vectorFill(start2,2); tempMap = map; map = mapCopy2; mapCopy2 = tempMap; numberEmptyCells= surface1; } System.arraycopy(vectorMapFilledSegmentsCopy, 0, vectorMapFilledSegments, 0, mapHeight*VECTOR_MAX); // cleanup of the list of used segments during fill // check if some balls are in the filled surface // if yes, take the appropriate action depending on ball type checkCapturedBalls(); // First eliminate pixel adjacent to the trace that are part of the peripheral path eliminatePathPoints(traceStart); // start of trace eliminatePathPoints(forwardIndex); // end of trace if ( frontLeftColor == pathColor) { eliminatePathPoints(frontLeftIndex); } if (frontRightColor == pathColor) { eliminatePathPoints(frontRightIndex); } // compute score oldPercentage = filledPercentage; filledPixels += surface; filledPercentage = (int)(100*((float)filledPixels / (float)(mapSize))); xdiff = filledPercentage - oldPercentage; _score += (int)((xdiff*50)*(1+xdiff/20)); setScore(); setFillPercent(); bgNeedsRedraw = true; if (filledPercentage >= percentageWinLevel) { return WON; } } // player dies if the pixel AHEAD is own trace (this prevents "islands") // or if he is parallel but touching the trace (prevents zero pixel surfaces and "stuck in hole" player) else if (forwardColor == traceColor || frontLeftColor == traceColor || frontRightColor == traceColor) // hoho, collided with own trace { return KILLED; } } return OK; } private static final void cleanupVectorFilledSegments() { System.arraycopy(vectorMapFilledSegmentsCopy, 0, vectorMapFilledSegments, 0, mapHeight*VECTOR_MAX); } private static final void addSegment(int addSegmentX,int addSegmentY,int addSegmentLength) { // Take the line, find the correct offset, move the tail, add the segment int addSegmentIndex= 0; //int addSegmentCurrentX = 0; int addSegmentFinalX; int addSegmentFinalLength; int insert= 0; int addSegmentLine; int[] segmentStartArray; // segment with a negative length (i.e segments going from right to left must be inverted to a left-right segment if ( addSegmentLength < 0) { addSegmentFinalLength = -addSegmentLength; addSegmentFinalX = addSegmentX - addSegmentFinalLength+1; } else { addSegmentFinalLength = addSegmentLength; addSegmentFinalX = addSegmentX; } addSegmentLine = vectorMapLineLength[addSegmentY]; segmentStartArray = vectorMapSegmentStart[addSegmentY]; for (int index = 0; index < addSegmentLine ;index++) { if (segmentStartArray[addSegmentIndex] > addSegmentFinalX) // vectorMapSegmentLength[addSegmentY][addSegmentIndex] { insert = 1; // insert break; } else if (addSegmentFinalLength == 1 && segmentStartArray[addSegmentIndex] == addSegmentFinalX ) // don't insert vertical segments that overlap an horizontal segment { insert = 0; // don't insert break; } else if (addSegmentFinalLength > 1 && segmentStartArray[addSegmentIndex] == addSegmentFinalX) { insert = 3; // replace break; } else if (segmentStartArray[addSegmentIndex] + vectorMapSegmentLength[addSegmentY][addSegmentIndex] > addSegmentFinalX) { insert = 0; break; } addSegmentIndex++; } // Move the tail if (insert == 1) { // System.arraycopy(vectorMapSegmentType[addSegmentY], addSegmentIndex, vectorMapSegmentType[addSegmentY], addSegmentIndex+1, vectorMapLineLength[addSegmentY]-addSegmentIndex); System.arraycopy(vectorMapSegmentLength[addSegmentY], addSegmentIndex, vectorMapSegmentLength[addSegmentY], addSegmentIndex+1, vectorMapLineLength[addSegmentY]-addSegmentIndex); System.arraycopy(segmentStartArray, addSegmentIndex, segmentStartArray, addSegmentIndex+1, vectorMapLineLength[addSegmentY]-addSegmentIndex); if (addSegmentFinalLength == 1) { //vectorMapSegmentType[addSegmentY][addSegmentIndex] = 2; vectorMapSegmentLength[addSegmentY][addSegmentIndex] = 1; segmentStartArray[addSegmentIndex] = addSegmentFinalX; vectorMapLineLength[addSegmentY]++; } else { //vectorMapSegmentType[addSegmentY][addSegmentIndex] = 3; vectorMapSegmentLength[addSegmentY][addSegmentIndex] = addSegmentFinalLength; segmentStartArray[addSegmentIndex] = addSegmentFinalX; vectorMapLineLength[addSegmentY]++; } } else if (insert == 3) { // vectorMapSegmentType[addSegmentY][addSegmentIndex] = 3; vectorMapSegmentLength[addSegmentY][addSegmentIndex] = addSegmentFinalLength; segmentStartArray[addSegmentIndex] = addSegmentFinalX; vectorMapLineLength[addSegmentY]++; } } private static final void eliminatePathPoints(int position) { // Eliminate pixel adjacent to the trace that are part of the peripheral path // (in fact replace them with a filler block of a close color) // but that don't have any adjacent free pixel (warning, possible overflow? maybe not) // This way, the player ball won't around filled places boolean eliminate = true; int adjacent; for (int adjacentDir = 0; adjacentDir < 4; adjacentDir++) { eliminate = true; adjacent = position+dirOffsets[adjacentDir]; if (map[adjacent] == pathColor) { for (int direction =0; direction <4; direction++) { if (map[adjacent + dirOffsets[direction]] <0) { eliminate = false; } } if (eliminate) { map[adjacent] = pathBlockColor; } } } } private static void findSpan(int x,int y) { int index; int spanStart; int spanEnd; for (index = 0; index < vectorMapLineLength[y]-1;index++) { spanStart = vectorMapSegmentStart[y][index] +vectorMapSegmentLength[y][index]; spanEnd = vectorMapSegmentStart[y][index+1]-1; // Spans where the border and trace intersect might have zero or negative length // Need to tag spans to avoid endless loop if (spanStart <= x && spanEnd >= x && spanEnd >= spanStart && vectorMapFilledSegments[y*VECTOR_MAX+index] == 0) { vectorMapFilledSegments[y*VECTOR_MAX+index] = 1; scanLineStack1X[scanLineStackPointer1]=spanStart; scanLineStack1Y[scanLineStackPointer1]=y; scanLineStack1XEnd[scanLineStackPointer1]= spanEnd; scanLineStackPointer1++; } } } private static final int vectorFill(int start, int zone) { int[] zmap; int xEnd; fillSurface1= 0; scanLineStackPointer1 = 0; findSpan(start%mapWidth,start/mapWidth); if (zone == 1) { zmap = mapCopy1; } else { zmap = mapCopy2; } while (scanLineStackPointer1 > 0) { scanLineStackPointer1--; x1 = scanLineStack1X[scanLineStackPointer1]; y1 = scanLineStack1Y[scanLineStackPointer1]; // Should stack the start and the end of the span since they are already known xEnd = scanLineStack1XEnd[scanLineStackPointer1]; linePos1 = mapWidth*y1; // Find the start of the span //findSpan(x1,y1); // Compute Span Length // Add to fill surface lineLength1 = xEnd-x1+1; fillSurface1 += lineLength1; // Fill the surface in the map System.arraycopy(colorMap, linePos1+x1, zmap, linePos1+x1, lineLength1); // Find other surface above and below // * // * findSpans(x1,xEnd, y1); // * int line; int index = 0; int spanStart; int spanEnd; int lineLength = 0; // Over spans line = y1-1; if (line >= borderSize+1) { lineLength = vectorMapLineLength[line]-1; for (index = 0; index < lineLength;index++) { spanStart = vectorMapSegmentStart[line][index] +vectorMapSegmentLength[line][index]; spanEnd = vectorMapSegmentStart[line][index+1]-1; // Spans where the border and trace intersect might have zero or negative length // Need to tag spans to avoid endless loop if (spanStart <= xEnd && spanEnd >= x1 && spanEnd >= spanStart && vectorMapFilledSegments[line*VECTOR_MAX+index] == 0) { vectorMapFilledSegments[line*VECTOR_MAX+index] = 1; scanLineStack1X[scanLineStackPointer1]=spanStart; scanLineStack1Y[scanLineStackPointer1]=line; scanLineStack1XEnd[scanLineStackPointer1]= spanEnd; scanLineStackPointer1++; } } } line = y1+1; if ( line < mapHeight - (borderSize+1)) { lineLength = vectorMapLineLength[line]-1; for (index = 0; index < lineLength;index++) { spanStart = vectorMapSegmentStart[line][index] +vectorMapSegmentLength[line][index]; spanEnd = vectorMapSegmentStart[line][index+1]-1; // Spans where the border and trace intersect might have zero or negative length // Need to tag spans to avoid endless loop if (spanStart <= xEnd && spanEnd >= x1 && spanEnd >= spanStart && vectorMapFilledSegments[line*VECTOR_MAX+index] == 0) { vectorMapFilledSegments[line*VECTOR_MAX+index] = 1; scanLineStack1X[scanLineStackPointer1]=spanStart; scanLineStack1Y[scanLineStackPointer1]=line; scanLineStack1XEnd[scanLineStackPointer1]= spanEnd; scanLineStackPointer1++; } } } } return fillSurface1; } private static final void changeDir(int newDirection) { wantedDirection= newDirection; } private static final int countCapturedBalls() { int count = 0; Ball ball; int[] xmap; xmap = mapCopy1; for (int ballIndex = 0; ballIndex = 0) { switch (ball.type) { case NORMALBALL: ball.type=REMOVEDBALL; break; case FASTBALL: ball.type= REMOVEDBALL; break; case LIFEBALL: ball.type = REMOVEDBALL; _lives++; livesSB.delete(1,2); livesSB.append(_lives); lifeBallTaken=true; bgNeedsRedraw = true; break; case RESPAWNBALL: findNewPosition(ball); break; case SLOWDOWNBALL: ball.type = REMOVEDBALL; // Slow the balls for x frames speedFactor= defaultSpeedFactor / 100; break; } } } removeBalls(); } // Find a new position for a respawn ball // for those limited device, we use a simple algorithm // chose a random number X in the range of the empty cells // traverse the map until the X free cell is found static final void findNewPosition(Ball ball) { int randomEmptyCell = rndGenerator.nextInt(numberEmptyCells); int numberEmptyCellFound=0; for (int index=emptyPixelSearch; index < mapSize;index++) { if (map[index] <0 ) { if (numberEmptyCellFound == randomEmptyCell) { ball.positionX = index % mapWidth; ball.positionY = index / mapWidth; return; } numberEmptyCellFound++; } } } static final void removeBalls() { int currentBall=0; for (int index=0;index6) { numberBalls=6+(_level-6)/2; } else { numberBalls = _level; } balls = new Ball[numberBalls]; // Decide the type of the ball for (int i=0;i5 && (_level%2==0) && i==1) { if (!lifeBallTaken) // first time we do this level { ball.type = LIFEBALL; } else { ball.type = SLOWDOWNBALL; } } if (_level>1 && (_level%3==0) && i==2) { ball.type = SLOWDOWNBALL; } if (_level>7 && i==3) { ball.type = SLOWDOWNBALL; } // ball angle in a 1 radiant range in the middle of a quadrant // if I am correct, 1 quadrant = 1 radiant + 0.285 *2 // this avoids balls that move too vertically or too horizontally direction = 0.29 + Math.abs(rndGenerator.nextDouble()); // project in a random quadrant ball.speedX = (float)((rndGenerator.nextInt() <0? -1 : 1) *Math.sin(direction)); ball.speedY = (float)((rndGenerator.nextInt() <0? -1 : 1) *Math.cos(direction)); if (ball.type == FASTBALL) { ball.speedX *= 2; ball.speedY *= 2; } ball.positionX = (float) (10 + (Math.abs(rndGenerator.nextInt()) % (mapWidth-20))); ball.positionY = (float) (10 + (Math.abs(rndGenerator.nextInt()) % (mapHeight-20))); // Add ball to balls array balls[i] = ball; } } private static final int moveBalls() { int pixelColor; int pixelColor2; Ball ball; if (speedFactor < defaultSpeedFactor) { speedFactor += 0.0008; } for (int ballIndex = 0; ballIndex = 0) // Ball got badly stuck (might happen in some corner cases), it should respawn somewhere else { findNewPosition(ball); } } } return OK; } ////////////////////////////////////////////////////////////// // Paint ////////////////////////////////////////////// // This method is called when the invalidate method is called from the refresh thread. // We have it passing the graphics object over to our graphics engine so our // custom graphics routines can take care of any drawing necessary. protected void paint(Graphics graphics) { graphics.getAbsoluteClippingRect(clip); // draw playfield graphics.drawRGB(map,0,mapWidth,playfieldPositionX,playfieldPositionY, mapWidth, mapHeight); // Draw balls for(int index = 0; index 0) { changeDir(RIGHT); } else if (dx < 0) { changeDir(LEFT); } else if (dy <0) { changeDir(UP); } else if (dy >0) { changeDir(DOWN); } } return true; } protected boolean navigationClick(int status,int time) { if (_paused) { _paused = false; } return true; } protected void onObscured() { _paused = true; _block = true; } protected void onExposed() { if (_paused) { _refresher.unBlock(); } } // #ifdef fourseven //@ protected boolean touchEvent(TouchEvent message) { //@ //@ int eventCode = message.getEvent(); //@ //@ if (_paused) //@ { //@ _paused = false; //@ } //@ else //@ { //@ if (eventCode == TouchEvent.DOWN) //@ { //@ oldTouchX = message.getX(1); //@ oldTouchY = message.getY(1); //@ } //@ else if (eventCode == TouchEvent.MOVE) //@ { //@ int x = message.getX(1); //@ int y = message.getY(1); //@ int xDiff = x- oldTouchX; //@ int yDiff = y - oldTouchY; //@ //@ if (xDiff < 0 ) //@ { //@ if ((-xDiff) > Math.abs(yDiff)) //@ { //@ changeDir(LEFT); //@ } //@ else if (yDiff < 0) //@ { //@ changeDir(UP); //@ } //@ else //@ { //@ changeDir(DOWN); //@ } //@ } //@ else if (xDiff > Math.abs(yDiff)) //@ { //@ changeDir(RIGHT); //@ } //@ else if (yDiff<0) //@ { //@ changeDir(UP); //@ } //@ else //@ { //@ changeDir(DOWN); //@ } //@ } //@ //@ /*if (eventCode == TouchEvent.GESTURE) //@ { //@ TouchGesture gesture = message.getGesture(); //@ //@ eventCode = gesture.getEvent(); //@ //@ if(eventCode == TouchGesture.SWIPE) { //@ //@ eventCode = gesture.getSwipeDirection(); //@ //@ switch (eventCode) //@ { //@ case TouchGesture.SWIPE_EAST: //@ changeDir(RIGHT); //@ break; //@ case TouchGesture.SWIPE_WEST: //@ changeDir(LEFT); //@ break; //@ case TouchGesture.SWIPE_NORTH: //@ changeDir(UP); //@ break; //@ case TouchGesture.SWIPE_SOUTH: //@ changeDir(DOWN); //@ break; //@ default: //@ break; //@ //@ } //@ } //@ //@ } //@*/} //@ return true; //@ } // #endif } BixRIMsosPul1Hashtab~Obj[m.. sosp?pul.?.1.1.24.2.1.89BixBix-1Bix-2Bix-3Bix-4Bix-5Bix-6Bix-7Bix-8Bix-9$GamePlayNew.java.svn-base:$mobi/offbyone/Bix/.svn/text-base/GamePlayNew.java.svn-basenet_rim_cldc_&(((***** 7s|эЂ RBB;A(?xY,9:yϝ{f|I<-P?cL#j 욵*>;Ol.N<2S]1xIj0t~I qO  :P޺qjp\RCR+<ռJPM ߕ{x[! '|9