how to make coordinates relative to a canvas - android

I have a 600x1000 pixel screen and my player starts near the bottom left. His x and y coordinates are (50, 900). I'm drawing this player to a canvas and using
canvas.translate(-player.getX()+GAMEWIDTH/2, 0)
to make sure the player stays in the middle of the screen with respect to the x-axis. This results in my player being rendered at (300, 900), however the player's x and y coordinates remain at (50, 900). This presents an issue because I need the player's coordinates to be the same as his rendered location because I use touch events on the player's collision rectangles to move him around. Is there any way to make my screen's coordinates be relative to my canvas coordinates so that my player's coordinates correspond to where they actually get rendered? Or is there maybe another way to do it?

The touchEvents are always based on the the x & y relative to the canvas element itself. Since the view is centering the character by translating the view canvas.translate(-player.getX() + GAMEWIDTH/2 , 0); you need to also apply that translation to the touchEvent. You can do it in the touch handler itself, or you could store both a relative and absolute position for the items in your game world. This will become more important if items become nested in one another. This is typically done by storing the parent element of a sprite/object.
//example of how I usually handle object hierarchy
this._x = this.x + this.parent._x;
this._y = this.y + this.parent._y;
the canvas/stage would also store it's center as a ._x and ._y which would be the parent of the the objects added, this way when you generate the global position to do your touchEvents against instead of passing in the .x or .y you would pass in the ._x and ._y which are already translated by the GAMEWIDTH/2.

Related

How to draw an arrow instead of a dragshadow?

I need the user to drag an arrow between two views, but all info I can find online is to make a dragshadow.
here's an exemple of the result i need.
https://imgur.com/pfQxtSK
thanks in advance.
What you want requires you to observe touch events inside of your parent ViewGroup, or custom view (whatever is drawing the light-blue grid from the image), using onTouchEvent(MotionEvent) callback. Next, you wanna determine the direction of the drag using the MotionEvent's x and y coordinates and some basic trigonometry. This will allow you to determine the angle of the drag and therefore dynamically the adjust the angle (rotation) of your arrow so that it accurately tracks the finger. Next use the same x and y coordinates you got from the MotionEvent to determine where on the canvas to draw the arrow. If the arrow is another view added as a child, you can set that view's x and y coordinates or translate the view using methods provided by the View class (you may need to play with offset's so the view doesn't get drawn off-screen after several drags/touches). If the arrow is a bitmap our drawable, you will need to adjust the draw coordinates in your view's onDraw(Canvas) method.

Generating Objects outside of Screen and then Moving them to Center?

Is it possible to generate a series of objects outside of the screen, and then making those objects move inwards? I am creating a live-wall paper with circles that start outside of the screen, and move inwards and bounce off the walls. I have created an illustration to better describe what i mean:
The 2 Issues im facing are:
Generating Objects outside of screen
Making them move inward and then bounce off the edges
How can i achieve this?
One solution to this problem would be to create a class which would contain following attributes:
X and Y coordinated (could be Point)
speedX
speedY
Then you could create objects with coordinates:
(X < 0) or (X > screenWidth)
and/or
(Y < 0) or (Y > screenHeight)
and give them appropriate speed (so they move towards the screen boundaries).
In each step you would:
update each object's coordinates, moving it in appropriate direction corresponding to its current speed
redraw all objects on your canvas
The offset of object's coordinates depends on time step between each two redraws. It's up to you how you want to evaluate it.
Until an object reaches screen boundaries it will be drawn outside the screen and not visible.
To draw the objects on canvas you could extend View class (or SurfaceView - difference between these two is discussed here) and override onDraw() method. You can follow this tutorial or find another one by yourself (there are lots of it).
If an object reaches the screen boundary from its inside (i.e. when its X is in range [0, screenWidth] and its Y is in range [0, screenHeight]) you can negate its speed (in X or Y direction, depending on which boundary has been reached) so it would go in the other direction (like in an elastic collision with a wall).
You can adjust speedX and speedY minimum and maximum values to see which give the most satisfying results.

What is the unit of the coordinate system of Canvas? - android

I find that the unit of the coordinate system of Canvas is different from that of screen.
For example in my case as below:
For one particular point, its on-screen coordinate obtained from ImageView.getX() and ImageView.getY() is (336, 578).
Then by trial and error, I draw a dot on the Canvas so that this dot falls EXACTLY the same position as the ImageView. I called canvas.drawCircle(330, 440, radius, paint); to achieve this.
Here comes the question:
Why would the 2 coordinates, (336, 578) and (330, 440), different?
Is it because the screen and the canvas use different units?
Is it an issue regarding pixel, dp and all that?
You could try converting to and from window coordinates using View.getLocationInWindow this way you'll always be sure you are using the same coordinates system.
Coordinates of ImageView.getX an Y are relative to the parent. Canvas coordinates are relative to the view. This could cause the differences
Edit:
I assume in one place you get the coordinates of the view (using getX and getY). Convert these to window coordinates. Call these viewXY[].
When you need to use them, to draw in your canvas, also convert the top and left coordinates to window coordinates. We call these canvasXY[].
Now, the X position to draw at would be viewXY[0] - canvasXY[0], and the Y position would be viewXY[1] - canvasXY[1].
A view's position co-ordinates are always relative to it's parent. It's like saying, where with respect to it's parent is this view placed.
There in another thing, screen Co-ordinate. This says where with respect to the window top/left (think actual physical screen) is this object placed. This can be obtained through View.getLocationOnScreen.
If you want to compare two locations, they will only be equivalent if the parent view of both these locations is same or you're using absolute screen co-ordinates. Otherwise, you'll only get results that "seem" different.
If you want to unify the two either take them to a common parent or use absolute co-ordinates.

Touch event for visible part of the Image

I need to apply click/touch events for only visible part of the View. Say for example a image of size 200X200. Apart from center 50X50, remaining part is transparent. I want to get touch events only for that 50X50 visible part Not on remaining transparent part.
In above image (its single image), only inner Diamond has got visible part. Apart from that Diamond is transparent area. So, if I touch Diamond then only I want to do something else ignore.
Edit :
Rachita's link helped me. I gone through that link and got idea how can I implement. But I could not understand some constants like 320, 240 etc while creating Points. In my case, I know the Diamond (in above image) x and y Ponits (hard coded values asctually). So, using those how can I determine, whether I touched inside Diamond or outside?
my Diamond points are as below
pointA = new Point(0, 183);
pointB = new Point(183, 0);
pointC = new Point(366, 183);
pointD = new Point(183, 366);
Edit :
Finally got solution from Luksprog. Its based on checking touched point pixel color. If color is 0 means, you touched transparent layer else you touched some colored part of the image. Simple, but very effective. Have a look at it here.
AFAIK you can not implement this with onclick listener or my any other direct way .You will have to use onTouchListener .
Firstly set your view dynamically at a specific (x,y) position using this How can I dynamically set the position of view in Android?
Calculate the region your diamond will occupy (you should khow the size of image inorder to calculate area of diamond)
3.Trigger a action in onTouchListener only when x, y fall in the required region. Use How to get the Touch position in android?
check this link to calculate if a given point lies in the required square
EDIT
To understand the coordinate system of android refer to this link How do android screen coordinates work?
Display mdisp = getWindowManager().getDefaultDisplay();
int maxX= mdisp.getWidth();
int maxY= mdisp.getHeight();
(x,y) :-
1) (0,0) is top left corner.
2) (maxX,0) is top right corner
3) (0,maxY) is bottom left corner
4) (maxX,maxY) is bottom right corner
here maxX and maxY are screen maximum height and width in pixels, which we have retrieved in above given code.
Remember if you want to support multiple devices with different screen sizes,make sure you use a relative value for x,y ie some ratio of screen height or width ,as different devices have different ppi
Check if touched point lies in the required polygon
I thinks these link might help you determining if the point touched (you can get x,y from onTouch event eg.event.getX()) lies in the required polygon whose points you have mentioned in the question . determine if a given point is inside the polygon and How can I determine whether a 2D Point is within a Polygon?

how to draw a small bitmap on a large bitmap at a psition outside the screen in android?

Assuming that i have an android phone with max x=400 and max y=300
I have a 5000 by 5000 px bitmap and i display a 400 by 300 part of it on screen. I scroll it around using touch events. I want to draw a smaller bitmap(30 by 30px) onto that larger bitmap at location (460,370). But i cant statically do it(as my game requires). I want to draw and undraw that smaller image according to the player's input or collision detections.
What i am confused about is that suppose currently (50,50) to (450,350) of the larger image is displayed on the screen and now ,due to a certain requirement of the game at this moment, i have to draw that 30by30 bitmap at (460,370) but this point is in two systems - 1)In the big bitmap's co-ordinate system it's 460,370 but when it will come inside the visible area of screen it will have values something between (0,0) and (400,300) depending upon its position on the screen as per the player's movements...
So how do i track that image- i mean using which co-ordinate system, and how do i go about doing all this?
I know I've put it here in a very confusing way but that's the best way i can put it and i'll be really glad, and grateful to you if somebody could help me on this.....
Terminology:
Let's call the coordinates on the big map world coordinates
Let's call the coordinates on the screen view coordinates. You are talking to the drawing system (canvas?) in view coordinates.
Your currently displayed region of the bigger map is 100% defined by an offset, let's call this (offsetX, offsetY). Formally, this offset maps your world coordinates onto your view coordinates.
If you have the small image displayed at position (x, y) in world coordinates, all you need to do is subtract your offset to get to view coordinates, i.e.
viewX = worldX - offsetX;
viewY = worldY - offsetY;

Categories

Resources