I don't know if this is a simple problem or not, but I just can't see what the problem is. I've gotten three reports now from my app in Google Play of an IndexOutOfBoundsException at points.get(++i).
public GameThread(SurfaceHolder sHolder, Context context, Handler handler)
{
points = new ArrayList<Float>();
running = true;
mSurfaceHolder = sHolder;
}
protected void doDraw(Canvas canvas)
{
Paint p = new Paint();
p.setStyle(Paint.Style.FILL);
p.setColor(Color.WHITE);
for (int i = 0; i < points.size(); i++)
{
float x = points.get(i);
float y = points.get(++i);
canvas.drawPoint(x, y, p);
}
}
public boolean onTouchEvent(MotionEvent event)
{
float x = event.getX();
float y = event.getY();
points.add(x);
points.add(y);
return true;
}
The index it fails at is trying to access the location equal to its size (Actually one error says
java.lang.IndexOutOfBoundsException: Invalid index 2205, size is 2206 which makes NO sense at all to me), and its size varies.
The only way I can see this happening is if for some reason only one object is added to points, and I don't know why that would happen. onTouchEvent isn't running in its own thread, is it?
The problem is at this line:
float y = points.get(++i);
When i = points.size()-1, you preincrement, and then you invoke points.get(++i);. At this point, i = points.size() => Out of bounds. Just remove the ++ to fix it.
EDIT
Alternatively, you can try this approach:
List<Point> points = ...
protected void doDraw(Canvas canvas) {
Paint p = new Paint();
p.setStyle(Paint.Style.FILL);
p.setColor(Color.WHITE);
for (Point p : points) {
canvas.drawPoint(p.x, p.y, p);
}
}
public boolean onTouchEvent(MotionEvent event) {
float x = event.getX();
float y = event.getY();
points.add(new Point(x, y));
return true;
}
I would make the for-loop safe from problems like this by letting the for loop construct handle all of the i variable logic, don't try to do it yourself.
for (int i = 0; i+1 < points.size(); i+=2){
float x = points.get(i);
float y = points.get(i+1);
canvas.drawPoint(x, y, p);
}
Your problem is in your for-loop. While the first access would work, the second access is not guaranteed to be correct. If you only have one object, then the loop can't work because you are trying to access the next element in the array, which doesn't exist.
Try
for (int i = 0; i < points.size()-1; i++)
suppose your array length is 10
float y = points.get(++i);
you can replace this statement by
^^^
float y = points.get(i+1);
You are increasing value of Y here as well as here
for (int i = 0; i < points.size(); i++)
^^^
In for loop it checks i<points.size() means it 9 or less than 9
when you reach to 9
and in for loop you are accessing points.get(++i);
it will access points.get(10) <-------- here you gets exception
and your arry is 0-9 then is no element at 10
Use your Point object correctly, like:
Point point = new Point();
point.x = value;
point.y = value;
to print, or use.. its just point.x and point.y still. (in case of android.graphics.Point;)
If you want to store several points, you can use for example ArrayList
ArrayList<Point> pointArray = new ArrayList<Point>();
pointArray.add(new Point(event.getX(), event.getY()));
To loop it throught:
for(Point p : pointArray){
// do something with p.x and p.y
}
Related
I'm trying to make a pong game using JavaFX and I've decided to use Point2D for the paddle and ball positions.
I created this method to check for wall collisions
public void checkWallCollision(){
boolean ballHitBottom = posBall.getY() > 500;
boolean ballHitTop = posBall.getY() < 50;
boolean ballHitLeft = posBall.getX() < 0;
boolean ballHitRight = posBall.getX() > 725;
if (ballHitTop || ballHitBottom){
ballDirVector = ballDirVector.multiply(-1);
}
if(ballHitLeft || ballHitRight){
ballDirVector = ballDirVector.multiply(-1);
}
}
But with a Point2D object like that, I can't just multiply it like that. I need the angle to be reflected. I guess another thing I could show to help is how I launch the ball. In this method I do have the angle, but I'm not sure what way I should go about accessing it.
public void launchBall(){
// Launch the ball
boolean ballDirection = random.nextBoolean();
// bound to an acute angle on start
double ballAngle = Constants._PADDLE_ANGLES[random.nextInt(5) + 1];
if (ballDirection){
ballAngle *= -1;
}
ballSpeed = Constants._BallStartSpeed;
ballDirVector = new Point2D(Math.cos(ballAngle), Math.sin(ballAngle));
}
So for this java project I´m working on I need a loop that reads trough an 2d array from center first then 4 adjecent values then the corners of that and keep doing that till it reaches and completes the most outer layer. I need it to work on all odd sizes of square 2d arrays. I made this image to clarify my goal: http://gyazo.com/80ed4502cb16795d37b75a14ee57f565 . I personally was not able to achieve this. Thank you for your time! any piece of pseudo code or java code is welcome!
You could logically redefine the grid so that the center is 0,0.
Then, sort each grid coordinate according to distance from the center.
This assumes that the grid is an odd width.
For example:
class Point
{
int x;
int y;
}
Point gridCenter;
Comparator<Point> comparator = new Comparator<Point>()
{
#Override
public int compare(Point arg0, Point arg1)
{
int x = arg0.x - gridCenter.x;
int y = arg0.y - gridCenter.y;
int distance0 = x*x + y*y;
x = arg1.x - gridCenter.x;
y = arg1.y - gridCenter.y;
int distance1 = x*x + y*y;
return distance0 - distance1;
}
};
void test()
{
int width = 11;
int height = 13;
gridCenter = new Point();
gridCenter.x = width/2;
gridCenter.y = height/2;
List<Point> points = new ArrayList<>();
for(int x=0;x<width;x++)
{
for(int y=0;y<height;y++)
{
Point p = new Point();
p.x = x;
p.y = y;
points.add(p);
}
}
Collections.sort(points, comparator);
for(Point p : points)
{
System.out.println(p.x + "," + p.y);
}
}
You could bias center slightly if you want to guarantee that it chooses left,top before right,bottom in the sort.
I have been trying to scale a Shape in java, but I'm having some problems. When i try it the Shape simple dissapears... This method receives 2 points, toScale is the point that i want the shape to extend to, and p1 is the point that I clicked in the rectangle that is around the shape to select (there's a rectangle(boundingBox) surrounding the shape wheter is a polygone or a rectangle or just polylines)
Here's the scale method code:
public void scale(Point toScale, Point p1) {
Graphics g = parent.getGraphics();
int distanceToClicked = 0;
int distanceToBoundingBox = 0;
int scaleFactor = 0;
Vector<Point> pointsAux = new Vector<Point>();
Iterator<Point> it = points.iterator();
while (it.hasNext()){
Point p = it.next();
distanceToClicked = (int) Math.sqrt(Math.pow(getCentroid().getX()-p1.getX(), 2)+Math.pow(getCentroid().getY()-p1.getY(),2));
distanceToBoundingBox = (int) Math.sqrt(Math.pow(getCentroid().getX()-toScale.getX(),2)+Math.pow(getCentroid().getY()-toScale.getY(),2));
scaleFactor = distanceToClicked/distanceToBoundingBox;
p = new Point((int)p.getX()*scaleFactor,(int) p.getY()*scaleFactor);
pointsAux.add(p);
}
points.clear();
points.addAll(pointsAux);
}
public Point getCentroid(){
int sumx = 0;
int sumy = 0;
for(int i = 0; i<points.size();i++){
sumx+=points.get(i).getX();
sumy+=points.get(i).getY();
}
Point centroid = new Point(sumx/points.size(), sumy/points.size());
return centroid;
}
Any help would be appreciated
Thanks in advance, and eventually I'm sorry for the misunderstanding code
Something like that would do the trick:
public Collection<Point> scaleShape(float scale, Collection<Point> shape) {
Point centroid = getCentroid();
Collection<Point> scaledShape = new ArrayList<>(shape.size());
for (Point point : shape) {
Point diff = new Point(point.x() - centroid.x(), point.y() - centroid.y());
Point scaledPoint = new Point(
(int) (centroid.x() + scale * diff.x()),
(int) (centroid.y() + scale * diff.y()));
scaledShape.add(scaledPoint);
}
return scaledShape;
}
Basically, every points make a linear function with the centroid. Centroid's relative x = 0, while the current computed point is at relative x = 1. You want to find the point if it were at relative x = scale.
I'm trying to move an object on the click of a mouse while the object remains animated. There are a few similar posts on this website, and I've based my code off this answer:
An efficient algorithm to move ostrichs along a line at a constant speed
But I want to use a thread to keep the object animated. How should I do this? Here's my code:
public void movePlayer(Graphics g, int finalX, int finalY)
{
int length = finalX - xpos;
int height = finalY - ypos;
int oldXpos = xpos;
int oldYpos = ypos;
double speed = 20;
double distanceX = (length)/speed;
double distanceY = (height)/speed;
double distance = (Math.hypot(length,height));
double distanceTraveled = 0;
//This currently doesn't work:
move = new Thread(this);
{
while (distanceTraveled<distance)
{
//move the object by increments
xpos += distanceX;
ypos += distanceY;
distanceTraveled = Math.hypot(xpos-oldXpos, ypos - oldYpos);
drawPlayer(img, g);
for(int x = 0; x < 100000; x ++);
}
}
}
If this is Swing, why not simply use a MouseListener to help you drag the object? If you want to animate separate from the mouse, don't use a while(true) loop unless you want to freeze the event thread. Use a Swing Timer instead. If this isn't Swing, tell us more details (shoot, do this anyway)!
the method is:
Robot robot = new Robot();
Color inputColor = new Color();
Rectangle rectangle = new Rectangle(0, 0, 1365, 770);
BufferedImage image = robot.createScreenCapture(rectangle);
for(int x = 0; x < rectangle.getWidth(); x++)
{
for (int y = 0; y < rectangle.getHeight(); y++)
{
if (image.getRGB(x, y) == inputColor.getRGB())
{
robot.mouseMove(x, y);
break;
}
}
}
return;
}
i want to call that method with a value for Color have it search the screenshot for that color and return with the (x, y) values for the pixel if it is found can that happen or can a method have only one input and the output has to be the same?
You can do something like this:
Point methodName(Color color) {
Point p = new Point();
// logic for finding point
return p; // or perhaps return null if color not found
}
You could also just return a two-element int[] instead of a point.
Method input and output could be different, but it can't return more than one type(or)value, either x or y. If you want to return both x,y. You may need to return as array (or) You can have a POJO class something like below, set x,y to instance of that class and return.
Dimension
{
int x;
int y;
setter..
getter..
}
You can return the java.awt.Point with the x and y values or use an int array if that would be fine.