-
-
Save ErikHellman/6069322 to your computer and use it in GitHub Desktop.
public class PaintView extends View { | |
public static final int MAX_FINGERS = 5; | |
private Path[] mFingerPaths = new Path[MAX_FINGERS]; | |
private Paint mFingerPaint; | |
private ArrayList<Path> mCompletedPaths; | |
private RectF mPathBounds = new RectF(); | |
public PaintView(Context context) { | |
super(context); | |
} | |
public PaintView(Context context, AttributeSet attrs) { | |
super(context, attrs); | |
} | |
public PaintView(Context context, AttributeSet attrs, int defStyle) { | |
super(context, attrs, defStyle); | |
} | |
@Override | |
protected void onAttachedToWindow() { | |
super.onAttachedToWindow(); | |
mCompletedPaths = new ArrayList<Path>(); | |
mFingerPaint = new Paint(); | |
mFingerPaint.setAntiAlias(true); | |
mFingerPaint.setColor(Color.BLACK); | |
mFingerPaint.setStyle(Paint.Style.STROKE); | |
mFingerPaint.setStrokeWidth(6); | |
mFingerPaint.setStrokeCap(Paint.Cap.BUTT); | |
} | |
@Override | |
protected void onDraw(Canvas canvas) { | |
super.onDraw(canvas); | |
for (Path completedPath : mCompletedPaths) { | |
canvas.drawPath(completedPath, mFingerPaint); | |
} | |
for (Path fingerPath : mFingerPaths) { | |
if (fingerPath != null) { | |
canvas.drawPath(fingerPath, mFingerPaint); | |
} | |
} | |
} | |
@Override | |
public boolean onTouchEvent(MotionEvent event) { | |
int pointerCount = event.getPointerCount(); | |
int cappedPointerCount = pointerCount > MAX_FINGERS ? MAX_FINGERS : pointerCount; | |
int actionIndex = event.getActionIndex(); | |
int action = event.getActionMasked(); | |
int id = event.getPointerId(actionIndex); | |
if ((action == MotionEvent.ACTION_DOWN || action == MotionEvent.ACTION_POINTER_DOWN) && id < MAX_FINGERS) { | |
mFingerPaths[id] = new Path(); | |
mFingerPaths[id].moveTo(event.getX(actionIndex), event.getY(actionIndex)); | |
} else if ((action == MotionEvent.ACTION_POINTER_UP || action == MotionEvent.ACTION_UP) && id < MAX_FINGERS) { | |
mFingerPaths[id].setLastPoint(event.getX(actionIndex), event.getY(actionIndex)); | |
mCompletedPaths.add(mFingerPaths[id]); | |
mFingerPaths[id].computeBounds(mPathBounds, true); | |
invalidate((int) mPathBounds.left, (int) mPathBounds.top, | |
(int) mPathBounds.right, (int) mPathBounds.bottom); | |
mFingerPaths[id] = null; | |
} | |
for(int i = 0; i < cappedPointerCount; i++) { | |
if(mFingerPaths[i] != null) { | |
int index = event.findPointerIndex(i); | |
mFingerPaths[i].lineTo(event.getX(index), event.getY(index)); | |
mFingerPaths[i].computeBounds(mPathBounds, true); | |
invalidate((int) mPathBounds.left, (int) mPathBounds.top, | |
(int) mPathBounds.right, (int) mPathBounds.bottom); | |
} | |
} | |
return true; | |
} | |
} |
My approach to getting the percentages would probably be to have a two-dimensional grid (stored as an int[][]-array) to roughly store where the lines have been drawn. You could do it like this:
// somewhere in your app put these values (feel free to change their visibility):
// this stores the grid:
// lets say if a value is...
// ...0, it hasn't been drawn onto
// ..1 or 2, it has been drawn onto with a specific color
public int[][] colorsGrid;
// this stores the size of one tile:
public float gridTileSize;
// this defines how many tiles there are on the y axis.
// If you make this number too low, the calculations are going to be very inaccurate,
// if you make it too high, it's hard to fill up everything.
public static final int DRAWGRID_TILES_Y = 20
// call the code inside this method on create
// you can also call it to reset the grid
public void initGrid(float screenWidth, float screenHeight)
{
// calculate the size of one tile
gridTileSize = (float) screenHeight / DRAWGRID_TILES_Y;
// calculate the number of tiles on the x axis (we defined y already)
int gridTilesX = (int) Math.ceil(screenWidth / gridTileSize);
// initialize the array
colorsGrid = new int[grildTilesX][DRAWGRID_TILES_Y];
}
// call this method for each finger thats currently touching
public void setGridTile(int fingerColorID, float fingerPositionPixelsX, float fingerPositionPixelsY)
{
// get the position of the finger on the grid
int touchingTileX = (int) (fingerPositionPixelsX / gridTileSize);
int touchingTileY = (int) (fingerPositionPixelsY / gridTileSize);
// set the value of that grid tile to the finger color's id
colorsGrid[touchingTileX][touchingTileY] = fingerColorID;
}
// call this method to calculate the percentage of each finger id (pass the total number of finger ids)
public float[] getFilledPercentages(int fingerColorIDCount)
{
// get the total amount of tiles in our grid
int totalGridTiles = colorsGrid.length * colorsGrid[0].length;
// get the amount of tiles the finger has been on
int[] fingerIDTileCounts = new int[fingerColorIDCount + 1]; // +1 so we can leave 0 empty (because your first fingerID was 1 too)
// go through each tile
for(int tileX = 0; tileX < colorsGrid.length; tileX++)
{
for(int tileY = 0; tileY < colorsGrid[0].length; tileY++)
{
// increment the amount of tiles of the finger that this tile touched
fingerIDTileCounts[colorsGrid[tileX][tileY]] += 1;
}
}
// calculate the percentages for each finger
float[] percentages = new float[fingerIDTileCounts.length];
for(int fingerID = 0; fingerID < percentages.length; fingerID++)
{
percentages[fingerID] = fingerIDTileCounts[fingerID] / (float) totalGridTiles;
}
// return the numbers
return percentages;
}
What this code does:
initGrid -> creates an empty grid with it's size corresponding the the dimensions of the display.
setGridTile -> sets the value of the grid tile a finger is touching, so it can be calculated later on.
getFilledPercentages -> calculates the total amount of tiles (percent) for each finger, and returns it as an array, where:
- index 0: the amount of tiles that have not been drawn to yet.
- index 1: the amount of tiles that have been drawn to from finger color ID 1.
- index 2: the amount of tiles that have been drawn to from finger color ID 2.
- ...
So the code essentially works like a game of splatoon, but with tiles (or blocks) like in Minecraft, if you understand it better this way.
DRAWGRID_TILES_Y
defines how many of these tiles there are, so you can play around with the precision.
Do with the code whatever you want.
I hope this enough to help you.
I can't test the code right now so better go through everything to check if it's working alright.
Also, Code blocks with multiple lines can be done with 3 backticks (```) at the ends of the block (on their own lines).
You can also click on preview to check if it's working. By adding the language name right at the end of the opening backticks you can also work with fancy syntax highlighting.
(sorry for the late response btw)
Happy coding!
Wow this code looks great, thanks for the amazing response, please don't be sorry for being late when your reply is of this quality. I have a few questions I hope you don't mind. You comment on initGrid saying call this code in onCreate so would it look something like this?
I've added a timer as I want the results to appear after 10 seconds of intense drawing. I know its not this simple but I hope I am getting the right idea.
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
initGrid();
setGridTile();
final Handler handler = new Handler(Looper.getMainLooper());
handler.postDelayed(new Runnable() {
@Override
public void run() {
Toast.makeText(context, getFilledPercentages(), Toast.LENGTH_LONG).show();
}
}, 10000);
Thanks again.
You are correct. initGrid
is supposed to be called inside of onCreate
, like you wrote. If you want to empty the grid (to start the game again), you can call initGrid
again. setGridTile
can then be called in your onTouchEvent
-method, where you pass the ID of the finger (or color) and the position.
If i want to draw a circle graphic by using canvas.drawCircle
how can I do
Thanks for the response @DevTaube . I am currently unable to test however I have implemented this:
``
protected void onDraw(Canvas canvas) {
if(idColor == 1)
mFingerPaint.setColor(Color.BLUE);
if(idColor == 2)
mFingerPaint.setColor(Color.RED);
public boolean onTouchEvent(MotionEvent event) {
idColor = id;
``
Is it also possible to calculate which color has been drawn the most? For example if blue has covered 75% of the screen and red 25% can this be calculated and displayed on screen?
Please forgive the poor formatting this is my first time commenting code on github.