b4.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (b4.getCompoundDrawables() == null) {
if (turn == 1) {
turn = 2;
b4.setBackgroundResource(R.drawable.iks);
} else if (turn == 2) {
turn = 1;
b4.setBackgroundResource(R.drawable.oks);
}
}
}
});
I have drawable iks (X) and oks (O) (making X-O game), and I wanna use my IF command to check if b4 (button) already have background drawn on it, in order to be able to make only 1 change to button so you can't use button that is already been used again.
You can use getBackground to see whether the background drawable has been set:
if (b4.getBackground() == null)
However, you should really design a "model" for your tic-tac-toe game.
Here's an idea:
Store a 2D int array that can store three possible values: 0, 1 and 2. 0 means nothing in the square. 1 means there is a cross and 2 means there is a nought. You can create constants for these:
public static final int EMPTY = 0;
public static final int CROSS = 1;
public static final int NOUGHT = 2;
Expose a method called updateArray(int x, int y, int value) that updates the value at the specified x and y position.
Each time you call this method, set the drawable of the correct view.
Now to check whether there is nothing in a "square", you can just check the array for EMPTY.
Related
I'm trying to make a grid of squares that change their fill (from black to white and vice-versa) when clicked. I'm able to turn the entire grid on or off currently, but I'm unable to figure out how to specify which particular square should be toggled when the mouse clicks within its borders. I've created buttons using mouseX and mouseY coordinates before, but they were for specific objects that I could adjust manually. I can't figure out how to do this using for loops and arrays.
I've been told to create a boolean array and pass the value of that array to the grid array, but again, I don't know how to specify which part of the array it needs to go to. For example, how do I change the fill value of square [6][3] upon mousePressed?
Here is my code so far:
int size = 100;
int cols = 8;
int rows = 5;
boolean light = false;
int a;
int b;
void setup() {
size (800, 600);
background (0);
}
void draw() {
}
void mousePressed() {
light = !light;
int[][] box = new int[cols][rows];
for (int i = 0; i < cols; i++) {
for (int j = 0; j < rows; j++) {
box[i][j] = i;
int a = i*100;
int b = j*100;
if (light == true) {
fill(255);
} else {
fill(0);
}
rect(a, b, 100, 100);
println(i, j);
}
}
}
First of all, you are currently recreating the entire board whenever the mouse is pressed. You must retain that info between mouse clicks, so make box a global array up there with the others. Further, it's sufficient to make it a boolean array if all you care about is the on/off state of each square:
boolean[][] isSquareLight = new boolean[cols][rows];
Instead of
if (light == true) {
you should then just check
if (isSquareLight[i][j] == true) {
(note that the == true is redundant).
Now, you've already written code that finds the coordinates for each box: You're passing it to rect!
rect(a, b, 100, 100);
All that is left to do is check whether the mouse is inside this rect, i.e. whether mouseX is between a and a+100 (and similar for mouseY) - if that's the case, then the user clicked in the box given by the current (i, j), so you can just negate isSquareLight[i][j] (before checking it like above) and it will work.
There are ways to calculate this without looping through the entire grid every time, but maybe the above helps you find the path yourself instead of just getting the code made for you.
PS: The int a; int b; at the top does nothing and can be removed. You are using the local variables a and b in your function, which is correct.
Greetings one and all,
So I am using onDraw in a custom View class to draw shapes on a RelativeLayout + TableLayout, all that works fine.
Inside the MotionEvent's ACTION_MOVE I pass the X & Y to my CustomView and call a method that returns a unique ID value for each set of coordinates / shape respectively.
Due to dragging my finger from one Shape to another: multiple values will be returned to the Console as expected and I would like to store these values in an Arrayfor future use. The issue I am having is that when I try to store the values, it only stores one value in a case where the console shows 4.
Console output looks like:
06-22 07:28:56.173 zar.myapp I/System.out: value: 354
06-22 07:28:56.193 zar.myapp I/System.out: value: 858
06-22 07:28:56.213 zar.myapp I/System.out: value: 989
06-22 07:28:56.213 zar.myapp I/System.out: value: 789
Code:
ArrayList XYcoords = new ArrayList();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
return true;
case MotionEvent.ACTION_MOVE:
///Single value for each finger movement.
DotView endView = getChildForTouch((TableLayout) v, x, y);
XYcoords.add(endView.getId() );
break;
case MotionEvent.ACTION_UP:
///I tried adding them from here as well.
///When I check the size of `XYcoords` it allways return 1
System.out.println("Array Size: " + XYcoords.size());
break;
DotView class: in my MainActivity where I construct my table grid I call: Dotview.setId(i); to assign a unique ID to each cell (verified). (I only shared the relevant codes):
private static class DotView extends View {
private static final int DEFAULT_SIZE = 100;
private Paint mPaint = new Paint();
private Rect mBorderRect = new Rect();
private Paint mCirclePaint = new Paint();
private int mRadius = DEFAULT_SIZE / 4;
int id;
public DotView(Context context) {
super(context);
mPaint.setStrokeWidth(2.0f);
mPaint.setStyle(Style.STROKE);
mPaint.setColor(Color.RED);
mCirclePaint.setColor(Color.CYAN);
}
#Override
protected void onDraw(Canvas canvas) {
canvas.drawColor(Color.parseColor("#0099cc"));
mBorderRect.left = 0;
mBorderRect.top = 0;
mBorderRect.right = getMeasuredWidth();
mBorderRect.bottom = getMeasuredHeight();
canvas.drawRect(mBorderRect, mPaint);
canvas.drawCircle(getMeasuredWidth() / 2, getMeasuredHeight() / 2,
mRadius, mCirclePaint);
}
public void setId(Int id){
this.id = id;
}
public int getId()
{
return this.id;
}
}
getChildForTouch
private DotView getChildForTouch(TableLayout table, float x, float y) {
final int childWidth = ((TableRow) table.getChildAt(0))
.getChildAt(0).getWidth();
final int childHeight = ((TableRow) table.getChildAt(0))
.getChildAt(0).getHeight();
// find out the row of the child
int row = 0;
do {
if (y > childHeight) {
row++;
y -= childHeight;
} else {
break;
}
} while (y > childHeight);
int column = 0;
do {
if (x > childWidth) {
column++;
x -= childWidth;
} else {
break;
}
} while (x > childWidth);
return (DotView) ((TableRow) table.getChildAt(row))
.getChildAt(column);
}
More code can be supplied on request.
Thanks in advance
The issue I am having is that when I try to store the values, it only
stores one value in a case where the console shows 4
I'm assuming you're creating the XYcoords list inside the onTouch() callback, in which case it will have a size of 1 corresponding to the current touch event. As the user moves his finger onTouch() will be called again with another touch event, at this point you'll create a new XYcoords list with one entry and so on...
To solve this, move the XYcoords list initialization outside of the onTouch() callback, like a field in the class. This way you'll not recreate it every time a touch event happens.
As a side note, I'm assuming that with your current code you're trying to store in a list the DotViews the user has touched as he moved his finger. In this case you'll most likely not want to simply do XYcoords.add(endView.getId()) in MotionEvent.ACTION_MOVE as you'll end up with hundreds of duplicate entries(as there will be a lot of touch events that will be triggered inside a single DotView). Instead don't allow duplicates:
if (XYcoords.size() != 0) {
// check to see if we aren't trying to add the same DotView reference
// (meaning we are still inside the same DotView)
int lastId = XYcoords.get(XYcoords.size() - 1);
if (lastId != endView.getId()) {
// not the same DotView so add it
XYcoords.add(endView.getId());
}
} else {
XYcoords.add(endView.getId()); // first event, must add it
}
In the case for MotionEvent.ACTION_UP you need to use(or store somewhere else the info in XYcoords) the data in XYcoords and clear it so next time the user starts touching the DotViews you have a fresh history(no items in XYcoords).
I have a textual WebView that I'm trying to re-size the contents of each time the user puts next text in. The idea is to fit the WebView into the screen without it getting cut off and without showing the scroll bars.
Currently the only reliable method that I have is extending the WebView class and using the base class's protected methods that measure the scrolling bar distances:
public class ExtendedWebView extends WebView {
public ExtendedWebView(Context context) {
super(context);
}
public ExtendedWebView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public int getHorRange() {
return computeHorizontalScrollRange();
}
public int getVerRange() {
return computeVerticalScrollRange();
}
public int getScreenX() {
return computeHorizontalScrollExtent();
}
public int getScreenY() {
return computeVerticalScrollExtent();
}
}
The only limitation I found is if the content is smaller and doesn't get out of bounds, there's no way to know how small it is, as it will return the size of the WebView.
Under another thread, I have the constantly looping method that checks if the WebView is out of bounds, and then re-sizes it. Here's the associated code, simplified:
ExtendedWebView webView; // assume this is initialized
while (true) {
int a, b, c, d;
a = webView.getHorRange();
b = webView.getScreenX();
c = webView.getVerRange();
d = webView.getScreenY();
if (a > b || c > d) {
//shrinking to accommodate text...
int val, x, y;
x = a - b;
y = c - d;
val = x > y ? x : y;
val*=0.1;
val = val == 0 ? 1 : val;
scale-=val;
}
else{
//TODO enlarging webView
}
if (scale <= 50) {
scale = 50;
//prevent from webView being too small
}
if (scale > 200)
scale = 200;
webView.setInitialScale(scale);
}
The shrinking of the WebView works, what I can't figure out is how to enlarge it again once the text has been erased. Whenever I tried simply increasing the scale from the else block, it simply alternates between enlarging and shrinking the text, and the limitation of not knowing the size of the content while it has no scroll bars hinders me from making better solutions.
To clarify, it's not the WebView that I'm trying to re-size, but it's contents.
Using Slick2D I am looping through my buttons and highlighting the one that is currently being hovered over. I do this by saving the index of a button whose onHover event fires. However, when I hover over the first button, it highlights the last. Hovering over the second button highlights the second to last, etc. If I use the keyboard to change the selected button it works perfectly, though.
Here is the method to save the index :
public void onHover(int x, int y) {
Button but;
for (int i = 0; i < b.size(); i++) {
but = b.get(i);
if (but.isClicked(x, y)) {
choice = i;
return;
}
}
}
And the one to compare them :
public void draw(Graphics g) {
Button but;
for (int i = 0; i < b.size(); i++) {
but = b.get(i);
if (i == choice) {
but.drawHighlighted(g);
} else {
but.draw(g);
}
}
}
Is there a special way to do this?
EDIT : I figured out where the problem was.
Mouse.getY() from LWJGL (which i use with onHover method) returns the height of the window minus the Y position of the mouse ; while mouseReleased(button, x, y) from Slick2D (which i use with draw method) returns the "true" Y position.
But both returns the same value with the x position.
I still don't know why the values are different (since Slick2D is based on LWJGL), but to bypass the problem, i use now HEIGHT - Mouse.getY() to have the right position.
Thanks everbody for helping me with that problem !
I am making a racing game using Libgdx. I want to touch the half right side of screen to speed up, at the same time without removing previous touch point touch again another on the left side of the screen to fire a shot. I am unable to detect later touch points.
I have searched and get Gdx.input.isTouched(int index) method, but cannot determin how to use it. My screen touch code is:
if(Gdx.input.isTouched(0) && world.heroCar.state != HeroCar.HERO_STATE_HIT){
guiCam.unproject(touchPoint.set(Gdx.input.getX(), Gdx.input.getY(), 0));
if (OverlapTester.pointInRectangle(rightScreenBounds, touchPoint.x, touchPoint.y)) {
world.heroCar.state = HeroCar.HERO_STATE_FASTRUN;
world.heroCar.velocity.y = HeroCar.HERO_STATE_FASTRUN_VELOCITY;
}
} else {
world.heroCar.velocity.y = HeroCar.HERO_RUN_VELOCITY;
}
if (Gdx.input.isTouched(1)) {
guiCam.unproject(touchPoint.set(Gdx.input.getX(), Gdx.input.getY(), 0));
if (OverlapTester.pointInRectangle(leftScreenBounds, touchPoint.x, touchPoint.y)) {
world.shot();
}
}
You'll want to use the Gdx.input.getX(int index) method. The integer index parameter represents the ID of an active pointer. To correctly use this, you will want to iterate through all the possible pointers (in case two people have 20 fingers on the tablet?).
Something like this:
boolean fire = false;
boolean fast = false;
final int fireAreaMax = 120; // This should be scaled to the size of the screen?
final int fastAreaMin = Gdx.graphics.getWidth() - 120;
for (int i = 0; i < 20; i++) { // 20 is max number of touch points
if (Gdx.input.isTouched(i)) {
final int iX = Gdx.input.getX(i);
fire = fire || (iX < fireAreaMax); // Touch coordinates are in screen space
fast = fast || (iX > fastAreaMin);
}
}
if (fast) {
// speed things up
} else {
// slow things down
}
if (fire) {
// Fire!
}
An alternative approach is to setup an InputProcessor to get input events (instead of "polling" the input as the above example). And when a pointer enters one of the areas, you would have to track that pointer's state (so you could clear it if it left).