Created
December 25, 2017 07:16
-
-
Save ssaurel/5af045b56e1913b831957d012c1e54fe to your computer and use it in GitHub Desktop.
Conway's Game Of Life specific view for a tutorial on the SSaurel's Blog
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.ssaurel.gameoflife; | |
import android.content.Context; | |
import android.graphics.Canvas; | |
import android.graphics.Color; | |
import android.graphics.Paint; | |
import android.graphics.Point; | |
import android.graphics.Rect; | |
import android.util.AttributeSet; | |
import android.view.Display; | |
import android.view.MotionEvent; | |
import android.view.SurfaceView; | |
import android.view.WindowManager; | |
public class GameOfLifeView extends SurfaceView implements Runnable { | |
// Default size of a cell | |
public static final int DEFAULT_SIZE = 50; | |
// Default color of an alive color (white in our case) | |
public static final int DEFAULT_ALIVE_COLOR = Color.WHITE; | |
// Default color of a dead color (black in our case) | |
public static final int DEFAULT_DEAD_COLOR = Color.BLACK; | |
// Thread which will be responsible to manage the evolution of the World | |
private Thread thread; | |
// Boolean indicating if the World is evolving or not | |
private boolean isRunning = false; | |
private int columnWidth = 1; | |
private int rowHeight = 1; | |
private int nbColumns = 1; | |
private int nbRows = 1; | |
private World world; | |
// Utilitaries objects : a Rectangle instance and a Paint instance used to draw the elements | |
private Rect r = new Rect(); | |
private Paint p = new Paint(); | |
public GameOfLifeView(Context context) { | |
super(context); | |
initWorld(); | |
} | |
public GameOfLifeView(Context context, AttributeSet attrs) { | |
super(context, attrs); | |
initWorld(); | |
} | |
@Override | |
public void run() { | |
// while the world is evolving | |
while (isRunning) { | |
if (!getHolder().getSurface().isValid()) | |
continue; | |
// Pause of 300 ms to better visualize the evolution of the world | |
try { | |
Thread.sleep(300); | |
} catch (InterruptedException e) { | |
} | |
Canvas canvas = getHolder().lockCanvas(); | |
world.nextGeneration(); | |
drawCells(canvas); | |
getHolder().unlockCanvasAndPost(canvas); | |
} | |
} | |
public void start() { | |
// World is evolving | |
isRunning = true; | |
thread = new Thread(this); | |
// we start the Thread for the World's evolution | |
thread.start(); | |
} | |
public void stop() { | |
isRunning = false; | |
while (true) { | |
try { | |
thread.join(); | |
} catch (InterruptedException e) { | |
} | |
break; | |
} | |
} | |
private void initWorld() { | |
WindowManager wm = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE); | |
Display display = wm.getDefaultDisplay(); | |
Point point = new Point(); | |
display.getSize(point); | |
// we calculate the number of columns and rows for our World | |
nbColumns = point.x / DEFAULT_SIZE; | |
nbRows = point.y / DEFAULT_SIZE; | |
// we calculate the column width and row height | |
columnWidth = point.x / nbColumns; | |
rowHeight = point.y / nbRows; | |
world = new World(nbColumns, nbRows); | |
} | |
// Method to draw each cell of the world on the canvas | |
private void drawCells(Canvas canvas) { | |
for (int i = 0; i < nbColumns; i++) { | |
for (int j = 0; j < nbRows; j++) { | |
Cell cell = world.get(i, j); | |
r.set((cell.x * columnWidth) - 1, (cell.y * rowHeight) - 1, | |
(cell.x * columnWidth + columnWidth) - 1, | |
(cell.y * rowHeight + rowHeight) - 1); | |
// we change the color according the alive status of the cell | |
p.setColor(cell.alive ? DEFAULT_ALIVE_COLOR : DEFAULT_DEAD_COLOR); | |
canvas.drawRect(r, p); | |
} | |
} | |
} | |
// We let the user to interact with the Cells of the World | |
@Override | |
public boolean onTouchEvent(MotionEvent event) { | |
if (event.getAction() == MotionEvent.ACTION_DOWN) { | |
// we get the coordinates of the touch and we convert it in coordinates for the board | |
int i = (int) (event.getX() / columnWidth); | |
int j = (int) (event.getY() / rowHeight); | |
// we get the cell associated to these positions | |
Cell cell = world.get(i, j); | |
// we call the invert method of the cell got to change its state | |
cell.invert(); | |
invalidate(); | |
} | |
return super.onTouchEvent(event); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment