I would like to make a simple game about a boy at the bottom of the screen trying to catch the falling apples. The apples are falling straight down at random x coordinates, and the boy at the bottom can just scroll right or left.
So far the apples now can be generated randomly and correctly animated, and the boy can scroll properly.
However, I am having difficulties in the game core condition: When apple is in the boy's width, the apple is considered successful caught.
The apples are generated and stored as follows:
private final Queue<Button> spots = new ConcurrentLinkedQueue<Button>();
and when generating new apples to the view:
spots.add(spot);
and when the apples are disappeared from the view:
spots.remove(spot);
Checking condition:
I use the below code to check for the condition:
(BOY_X is the x-coordinate of the boy)
public void Check_all_Spot(int BOY_X)
{
int [] apple_x;
int [] apple_y;
int apple_shown_length =spots.size();
Button [] apples = null;
String text_x ="";
String text_y = "";
if (!spots.isEmpty())
{
apples = spots.toArray(new Button[apple_shown_length]);
}
apple_x = new int [apple_shown_length];
apple_y = new int [apple_shown_length];
for (int w = 0; w < apple_shown_length ; ++w)
{
apple_x[w] = (int) apples[w].getX();
apple_y[w] = (int) apples[w].getY();
text_x = text_x+ "\n" +apple_x[w];
text_y = text_y+ "\n" +apple_y[w];
if ( (apple_x[w]+SPOT_DIAMETER)/2 >= BOY_X ||
(apple_x[w]+SPOT_DIAMETER)/2 <= (BOY_X+BOY_WIDTH) ||
(apple_y[w]+SPOT_DIAMETER) >= (viewHeight - BOY_HEIGHT) ||
(apple_y[w]+SPOT_DIAMETER) <= (viewHeight - (BOY_HEIGHT)/2) )
// check text
{
}
}
Toast.makeText(getContext(), "X=" +text_x+"\nY=" +text_y, Toast.LENGTH_LONG).show();
}
Question:
In this way of converting the spots queue to a button array apple, the toast reports the x and y coordinates for all the apples in the view.
My question is, though now I know about which apple is satisfying the checking condition, how could it be instructing to the spots queue to remove the apple??
Or should I use a game thread and counting the time elasped?
Or I should not convert the ConcurrentLinkedQueue to button array?
I would like to obtain some of your advice. Many thanks!
Related
I've got a properly generated array of x-y pairs. Some of those values are NaN
The Canvas.drawLines() in ICS, JB 4.1 and LP 5.1 just ignores those values and skips them, drawing the rest of the lines, but for some reason KK does not draw anything in such cases. Any way to fix it?
Turning off antialiasing and hardware acceleration does not help
Run a quick bit of code to remove all the NaN XY pairs. You could equally replace them with copies of the last valid XY pair, depending on how your code is working. You can always pretty efficiently fix these issues. But, if KitKat is doing that either set your app version above that or play ball. It's feeding it into the gpu and it doesn't have any documentation as to how it is required to handle NaN. It apparently messes with the tesselator which later only killed that one line segment but at kitkat would balk at the whole thing.
If you have x-y pairs with NaN just consider those improper. Loop and remove them, efficiently.
public int nanDrop(int index) {
int arrayIndex = index << 1;
int returnIndex = index;
int validPosition = 0;
float mx, my;
for (int pos = 0, s = count; pos < s; pos += 2) {
mx = pointlist[pos];
my = pointlist[pos + 1];
if (pos == arrayIndex) returnIndex = validPosition >> 1;
if (!Float.isNaN(mx)) {
pointlist[validPosition] = mx;
pointlist[validPosition + 1] = my;
validPosition += 2;
}
}
count = validPosition;
return returnIndex;
}
I have a TextView with an OnTouchListener. What I want is the character index the user is pointing to when I get the MotionEvent. Is there any way to get to the underlying font metrics of the TextView?
Have you tried something like this:
Layout layout = this.getLayout();
if (layout != null)
{
int line = layout.getLineForVertical(y);
int offset = layout.getOffsetForHorizontal(line, x);
// At this point, "offset" should be what you want - the character index
}
Hope this helps...
I am not aware of a simple direct way to do this but you should be able to put something together using the Paint object of the TextView via a call to TextView.getPaint()
Once you have the paint object you will have access to the underlying FontMetrices via a call to Paint.getFontMetrics() and have access to other functions like Paint.measureText() Paint.getTextBounds(), and Paint.getTextWidths() for accessing the actual size of the displayed text.
While it generally works I had a few problems with the answer from Tony Blues.
Firstly getOffsetForHorizontal returns an offset even if the x coordinate is way beyond the last character of the line.
Secondly the returned character offset sometimes belongs to the next character, not the character directly underneath the pointer. Apparently the method returns the offset of the nearest cursor position. This may be to the left or to the right of the character depending on what's closer by.
My solution uses getPrimaryHorizontal instead to determine the cursor position of a certain offset and uses binary search to find the offset underneath the pointer's x coordinate.
public static int getCharacterOffset(TextView textView, int x, int y) {
x += textView.getScrollX() - textView.getTotalPaddingLeft();
y += textView.getScrollY() - textView.getTotalPaddingTop();
final Layout layout = textView.getLayout();
final int lineCount = layout.getLineCount();
if (lineCount == 0 || y < layout.getLineTop(0) || y >= layout.getLineBottom(lineCount - 1))
return -1;
final int line = layout.getLineForVertical(y);
if (x < layout.getLineLeft(line) || x >= layout.getLineRight(line))
return -1;
int start = layout.getLineStart(line);
int end = layout.getLineEnd(line);
while (end > start + 1) {
int middle = start + (end - start) / 2;
if (x >= layout.getPrimaryHorizontal(middle)) {
start = middle;
}
else {
end = middle;
}
}
return start;
}
Edit: This updated version works better with unnatural line breaks, when a long word does not fit in a line and gets split somewhere in the middle.
Caveats: In hyphenated texts, clicking on the hyphen at the end of a line return the index of the character next to it. Also this method does not work well with RTL texts.
So I want to make a simple touch screen guitar tablature creator for android but I really do not know what method to use. I am fairly new to writing apps but I am comfortable with java.
The guitar fret board would look something like this. http://upload.wikimedia.org/wikipedia/commons/3/37/Guitar_Fretboard_Open_Strings_Diagram.png
1) At first I was leaning towards making buttons for each string and fret but I thought that may be a little difficult considering there are 24 frets on a guitar plus 6 strings (144 buttons) and each time the button was pushed it would update and array that has 6 rows and x amount of columns. I would make place the buttons on the image at the frets and make them invisible, but having the buttons line up may be tricky and they may not scale the way I would like.
An array would be pretty handy to hold the values because tablature is written like so...
e string -------
b string ----2--
g string ------3
d string 0-0----
a string -------
E string -------
the fret numbers are written in.
I am not even sure where to begin with this method. Should I have a separate method for each button because they all have different values?
To get a value from the button to the array I would need to put something like
strArray[count,n]
where count is a variable out side the method and n is the variable that is returned when the button is clicked. Count would be increased or decreased with a next/previous button so it can traverse the array
2) I was looking at this method http://blahti.wordpress.com/2012/06/26/images-with-clickable-areas/ and it looks like it could work but the developer was using colors to tell the different hot spot, and I was thinking that would probably not be feasible either considering I would need 144 different colors.
Is there an easier way that I could implement this instead?
Sorry if I haven't explained very well, I am new to developing on android and I have a lot of questions.
Using invisible buttons over the top of a larger background would be conceptually easy, but would have the scalability issues that you mention. It also won't handle recognizing multiple simultaneous touches very well. the The core of the second approach, using touch, is probably the way you want to go. The MotionEvent in the onTouch() method will provide you with the location and action of the touches. Then it just becomes an exercise in translating the coordinate of the spot touched/moved/lifted with the appropriate fret or string.
There are many decent tutorials available on doing touch recognition. Here's one.
Edit:
There are a couple of ways to translate between touch position and the desired string & fret. One way is to just do the calculations strng = x / (width / NUM_STRINGS) and fret = y / (height / NUM_FRETS) for each touch event. (Assuming the strings are drawn lengthwise on the display.)
Another straightforward way is to build and use lookup tables to do the translation. This does cost a few thousand bytes to store the ints, but allows for a couple of fast array lookups to determine the string and fret.
Here's a sample activity that implements the latter approach. It contains some assumptions and shortcuts, but the basic functionality should is fairly sound. Only the down event shows the translation; you'll want to do something appropriate for the up and move events as well.
MainActivity.java
package com.example.guitar;
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
import android.view.ViewTreeObserver;
import android.widget.ImageView;
import android.widget.LinearLayout;
public class MainActivity extends Activity
implements OnTouchListener, ViewTreeObserver.OnGlobalLayoutListener {
final static String TAG = "MainActivity";
final static int NUM_STRINGS = 6;
final static int NUM_FRETS = 12;
ImageView img = null;
LinearLayout layout = null;
int width = 0;
int height = 0;
int touchToString[] = null;
int touchToFret[] = null;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
layout = (LinearLayout) findViewById(R.id.layout);
layout.setOnTouchListener(this);
layout.getViewTreeObserver().addOnGlobalLayoutListener(this);
}
public boolean onTouch(View v, MotionEvent event) {
// Handle the touch event:
int idx = event.getActionIndex();
int id = event.getPointerId(idx);
int x = (int) event.getX(idx);
int y = (int) event.getY(idx);
switch (event.getActionMasked()) {
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_POINTER_DOWN:
Log.d(TAG, String.format("DOWN event for pointer %d at %d, %d", id, x, y));
// If touch is within the bounds of the layout:
if (x > 0 && x < width && y > 0 && y < height)
Log.i(TAG, String.format("Pressed string %d at fret position %d",
touchToString[x], touchToFret[y]));
break;
case MotionEvent.ACTION_MOVE:
for (int ptr = 0; ptr < event.getPointerCount(); ptr++)
Log.d(TAG, String.format("MOVE event for pointer %d at %d, %d",
event.getPointerId(ptr), (int) event.getX(ptr), (int) event.getY(ptr)));
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_POINTER_UP:
case MotionEvent.ACTION_CANCEL:
Log.d(TAG, String.format("UP event for pointer %d at %d, %d", id, x, y));
break;
}
return true;
}
public void onGlobalLayout() {
// Get the current width and height of the layout:
width = layout.getMeasuredWidth();
height = layout.getMeasuredHeight();
Log.i(TAG, String.format("The layout is now (%d x %d)", width , height));
// (Re)build the string position translation array:
touchToString = new int[width];
for (int x = 0; x < width; x++)
touchToString[x] = x / (width / NUM_STRINGS);
// (Re)build the fret position translation array:
touchToFret = new int[height];
for (int y = 0; y < height; y++)
touchToFret[y] = y / (height / NUM_FRETS);
}
}
I want to ask about some ideas / study materials connected to binarization. I am trying to create system that detects human emotions. I am able to get areas such as brows, eyes, nose, mouth etc. but then comes another stage -> processing...
My images are taken in various places/time of day/weather conditions. It's problematic during binarization, with the same treshold value one images are fully black, other looks well and provide me informations I want.
What I want to ask you about is:
1) If there is known way how to bring all images to the same level of brightness?
2) How to create dependency between treshold value and brightness on image?
What I have tried for now is normalize the image... but there are no effects, maybe I'm doing something wrong. I'm using OpenCV (for android)
Core.normalize(cleanFaceMatGRAY, cleanFaceMatGRAY,0, 255, Core.NORM_MINMAX, CvType.CV_8U);
EDIT:
I tried adaptive treshold, OTSU - they didnt work for me. I have problems with using CLAHE in Android but I managed to implement Niblack algorithm.
Core.normalize(cleanFaceMatGRAY, cleanFaceMatGRAY,0, 255, Core.NORM_MINMAX, CvType.CV_8U);
nibelBlackTresholding(cleanFaceMatGRAY, -0.2);
private void nibelBlackTresholding(Mat image, double parameter) {
Mat meanPowered = image.clone();
Core.multiply(image, image, meanPowered);
Scalar mean = Core.mean(image);
Scalar stdmean = Core.mean(meanPowered);
double tresholdValue = mean.val[0] + parameter * stdmean.val[0];
int totalRows = image.rows();
int totalCols = image.cols();
for (int cols=0; cols < totalCols; cols++) {
for (int rows=0; rows < totalRows; rows++) {
if (image.get(rows, cols)[0] > tresholdValue) {
image.put(rows, cols, 255);
} else {
image.put(rows, cols, 0);
}
}
}
}
The results are really good, but still not enough for some images. I paste links cuz images are big and I don't want to take too much screen:
For example this one is tresholded really fine:
https://dl.dropboxusercontent.com/u/108321090/a1.png
https://dl.dropboxusercontent.com/u/108321090/a.png
But bad light produce shadows sometimes and this gives this effect:
https://dl.dropboxusercontent.com/u/108321090/b1.png
https://dl.dropboxusercontent.com/u/108321090/b.png
Do you have any idea that could help me to improve treshold of those images with high light difference (shadows)?
EDIT2:
I found that my previous Algorithm is implemented in wrong way. Std was calculated in wrong way. In Niblack Thresholding mean is local value not global. I repaired it according to this reference http://arxiv.org/ftp/arxiv/papers/1201/1201.5227.pdf
private void niblackThresholding2(Mat image, double parameter, int window) {
int totalRows = image.rows();
int totalCols = image.cols();
int offset = (window-1)/2;
double tresholdValue = 0;
double localMean = 0;
double meanDeviation = 0;
for (int y=offset+1; y<totalCols-offset; y++) {
for (int x=offset+1; x<totalRows-offset; x++) {
localMean = calculateLocalMean(x, y, image, window);
meanDeviation = image.get(y, x)[0] - localMean;
tresholdValue = localMean*(1 + parameter * ( (meanDeviation/(1 - meanDeviation)) - 1 ));
Log.d("QWERTY","TRESHOLD " +tresholdValue);
if (image.get(y, x)[0] > tresholdValue) {
image.put(y, x, 255);
} else {
image.put(y, x, 0);
}
}
}
}
private double calculateLocalMean(int x, int y, Mat image, int window) {
int offset = (window-1)/2;
Mat tempMat;
Rect tempRect = new Rect();
Point leftTop, bottomRight;
leftTop = new Point(x - (offset + 1), y - (offset + 1));
bottomRight = new Point(x + offset, y + offset);
tempRect = new Rect(leftTop, bottomRight);
tempMat = new Mat(image, tempRect);
return Core.mean(tempMat).val[0];
}
Results for 7x7 window and proposed in reference k parameter = 0.34: I still can't get rid of shadow on faces.
https://dl.dropboxusercontent.com/u/108321090/b2.png
https://dl.dropboxusercontent.com/u/108321090/b1.png
things to look at:
http://docs.opencv.org/java/org/opencv/imgproc/CLAHE.html
http://docs.opencv.org/java/org/opencv/imgproc/Imgproc.html#adaptiveThreshold(org.opencv.core.Mat,%20org.opencv.core.Mat,%20double,%20int,%20int,%20int,%20double)
http://docs.opencv.org/java/org/opencv/imgproc/Imgproc.html#threshold(org.opencv.core.Mat,%20org.opencv.core.Mat,%20double,%20double,%20int) (THRESH_OTSU)
The below code is my attempt to send mMyView to the front or the back of the set of children of mPivotParent so it will be rendered on top or behind the others. Hiding the view will not suffice in my case.
mPivotParent is a FrameLayout.
Looking at mPivotParent.mChildren shows that my code below "works" in that the ordering is being set correctly. Yet it has no impact on the z order. Not only this, but the framerate gets cumulatively slower and slower the more times the repositioning code gets called. There are 4 children total and mPivotParent.mChildrenCount remains at 4 throughout as expected.
I'm targeting API Level 7.
#Override
public boolean onTouchEvent(MotionEvent event) {
Display display = getWindowManager().getDefaultDisplay();
float x = event.getRawX();
float sWidth = (int)display.getWidth();
float xLerpFromCenter = ((x / sWidth) - .5f) * 2.f; // [-1, 1]
mRotateAnimation.mfLerp = xLerpFromCenter;
if(xLerpFromCenter < -0.2f && mPivotParent.getChildAt(0) != mMyView)
{
mPivotParent.removeView(mMyView);
mPivotParent.addView(mMyView, 0);
refreshEverything();
}
else if(xLerpFromCenter > 0.2f && mPivotParent.getChildAt(0) == mMyView)
{
mPivotParent.removeView(mMyView);
mPivotParent.addView(mMyView, mPivotParent.getChildCount() - 1);
refreshEverything();
}
return super.onTouchEvent(event);
}
private void refreshEverything()
{
for(int i = 0; i < mPivotParent.getChildCount(); ++i)
{
mPivotParent.getChildAt(i).invalidate();
mPivotParent.getChildAt(i).requestLayout();
}
mPivotParent.invalidate();
mPivotParent.requestLayout();
}
Partial Solution
Here's a somewhat inefficient hack but it works for my purpose, which is to take the top item and send it to the back, keeping all other items in their same order.
private void putFrontAtBack()
{
for(int i = 0; i < mPivotParent.getChildCount() - 1; ++i)
{
mPivotParent.getChildAt(0).bringToFront();
}
refreshEverything();
}
Note: This doesn't work in the general case of arbitrary re-ordering.
Try this.
private void reorder(int[] order)
{
if(order == null || order.length != mPivotParent.getChildCount()) return;
for(int i = order.length - 1; i >= 0; i--)
{
mPivotParent.getChildAt(order[i]).bringToFront();
}
refreshEverything();
}
This code provides arbitrary reordering. The integer array "order" is used to indicate the new order of each view, where order[n]=x means the new order of childAt(x) is n.