Using Android accelerometer y axis falls through terrain - Unity3D - android

This works much better, thank you. However, it still does not work very well. While I don't go completely through the terrain, the FP controller seems to hover just below the terrain. Adding a +10 helps, but there is another strange issue:
I have the camera set up as a child of the FP controller, at 0,0,0. When the game begins to run, the Y value in the transform of the controller window goes steadily down, in minus numbers, while the camera Y value goes steadily up, in the positive direction. The Y values are mirrored. Any ideas of what is going on?
void Update () {
moveX = Input.acceleration.x * 1;
moveY = Input.acceleration.y * 1;
moveZ = (1+ (Input.acceleration.z));
transform.Translate (0, 0, 0); //transform.translate Moves the transform in the direction and distance of translation
temp = transform.position; //temp = the position of the transform in world space. World Space: the absolute XYZ coordinates of all objects
temp.y = terrainY; //y component of Vector3 (float)
transform.position = temp; //put the position of the transform in world space back into temp
terrainY = Terrain.activeTerrain.SampleHeight(temp); //Sample.height Samples the height at the given position defined in world space
temp2 = transform.position.y; //this shows transform.position.y axis is the same as terrainY, but not the same value as shown in the inspector
if (moveZ >= 0.055 && moveZ >= -0.1) {
zeroZFlag = 1;
if(moveZ >= 0.041){
moveZ = moveZ*10; //multiply by 10 to make it faster when going forward
if (moveY >= 0) {
transform.Translate (moveX,terrainY + 10,moveZ);
//transform.translate needs to be three floats. So the middle one needs to be the y value of the top of the terrain
}
if (moveY < 0){
transform.Translate (moveX,terrainY,-moveZ);
}
}
I have added to my code as suggested but am still having trouble getting the first person controller to stay on the same y-value as the terrain. In the following iteration of code, the First person y value leaves the world entirely and goes up forever.
My code uses
`transform.Translate (moveX,terrainY,moveZ);
to move the FP controller around, where moveX and moveY are acceleration values and terrainY theoretically should be the actual value of the Y-axis as shown in the transform box.
I think that the first issue is that I am mixing acceleration values (X,Z) with a terrain transform for Y, so different meaning to the values.
BTW X and Z axis move very well with the accelerometer with this code, but I will change everything if necessary!
I am not sure what kind of float value operation translate.transform does. The manual states that it returns in the space.world, but does it move by the number of units or position?
Here is my new code, and thank you in advance for help:
public float terrainY;
// y axis falls through terrain
// travels through walls even though collider is set
void LateUpdate (){
//terrainY = Terrain.activeTerrain.SampleHeight (transform.position);
}
void Update () {
moveX = Input.acceleration.x * 1;
moveY = Input.acceleration.y * 1;
moveZ = (1+ (Input.acceleration.z));
transform.Translate (0, 0, 0);
terrainY = Terrain.activeTerrain.SampleHeight (transform.position);
if (moveZ >= 0.055 && moveZ >= -0.1) {
zeroZFlag = 1;
if(moveZ >= 0.041){
moveZ = moveZ*10; //multiply by 10 to make it faster when going forward
if (moveY >= 0) {
transform.Translate (moveX,terrainY,moveZ);
//transform.translate needs to be three floats. so the middle one needs to be the y value of the top of the terrain
}
if (moveY < 0){
transform.Translate (moveX,terrainY,-moveZ);
}
My code causes me to go through and under my terrrain in Unity 3D because the y axis is always zero. In this world, x-axis is left/right and z is depth. Y axis is up/down and shold follow the mountains, hills, valleys in the terrain. However, it just goes through, at 0 height.
Does anyone know what variable/class should be in the y-axis spot instead of the "0" I have there? Thanks in advance!
public class Movement2 : MonoBehaviour {
public float moveX = Input.acceleration.x;
public float moveY = Input.acceleration.y;
public float moveZ = Input.acceleration.z;
public float Speed = 20.0f;
public int zeroZFlag;
void Update () {
moveX = Input.acceleration.x * 1;
moveY = Input.acceleration.y * 1;;
//moveZ = Mathf.Abs(1+ (Input.acceleration.z) * 20);
moveZ = (1+ (Input.acceleration.z));
transform.Translate (0, 0, 0);
if (moveZ >= 0.055 && moveZ >= -0.1) { zeroZFlag = 1;
if (moveY >= 0) {
transform.Translate (moveX,0,moveZ);
}
if (moveY < 0){
transform.Translate (moveX,0,-moveZ);
}
else {
zeroZFlag = 0;
}
}

Try using Terrain.SampleHeight(), it returns the height of the terrain with a given X and Z coordinate. Update its Y position to the height of the terrain every Update().
Reference: http://docs.unity3d.com/ScriptReference/Terrain.SampleHeight.html.
EDIT 1:
The reason your FP controller always goes up forever is because you keep translating it with a Y value.
transform.Translate(moveX, terrainY, moveZ)
// this way you keep adding terrainY value to the Y position
// thus it always goes up and will never end
While you need your FP controller to be constantly the same Y position with the terrain. You should instead modify the position of Y directly.
Vector3 temp = transform.position;
temp.y = terrainY;
transform.position = temp;
EDIT 2:
I try my best to help you see through your code:
void Update () {
moveX = Input.acceleration.x * 1;
moveY = Input.acceleration.y * 1;
moveZ = (1+ (Input.acceleration.z));
transform.Translate (0, 0, 0); // why do you need this? this basically does nothing
// you should get terrain height first to be used as temp.y below
terrainY = Terrain.activeTerrain.SampleHeight(transform.position);
temp = transform.position;
temp.y = terrainY + 10; // you said +10 helped, so I put it here
transform.position = temp;
if (moveZ >= 0.055 && moveZ >= -0.1) {
zeroZFlag = 1;
if(moveZ >= 0.041){
moveZ = moveZ*10;
if (moveY >= 0) {
// here I think you shouldn't move the Y anywhere,
// because you've updated position of Y in every update frame
// so you only need to move X and Z due to device tilt
transform.Translate (moveX,0,moveZ);
}
if (moveY < 0){
transform.Translate (moveX,0,-moveZ);
}
}

This also works:
using UnityEngine;
using System.Collections;
[RequireComponent(typeof(CharacterController))]
public class Movement6 : MonoBehaviour {
public float speed = 30.0f;
public float moveX = Input.acceleration.x;
public float moveY = Input.acceleration.y;
public float moveZ = Input.acceleration.z;
void Update() {
moveX = Input.acceleration.x * 1;
moveY = Input.acceleration.y * 1;
moveZ = (1+ (Input.acceleration.z));
CharacterController controller = GetComponent<CharacterController>();
Vector3 forward = transform.TransformDirection(moveX,0,moveZ);
controller.SimpleMove (forward * speed);
}
}

Related

Afree chart : How to increase X axis values(gap or domain range) while zooming

Can anyone help me on below zooming!
While doing horizontal zoom, I would like to increase and display the gap or range.
Now the range is on attached link is 10,12,14,16... while zooming it should display as 10,11,12,13,...
How I can increase this domain range while zooming. Please guide me.
protected static int gapValue; //gap between two dates
private void zoom(PointF source, double startDistance, double endDistance) {
Plot plot = this.chart.getPlot();
PlotRenderingInfo info = this.info.getPlotInfo();
if (plot instanceof Zoomable) {
float scaleDistance = (float) (startDistance / endDistance);
//for maintaining the limit of zooming range horizontally
if (this.mScale * scaleDistance <= 1.0f
&& this.mScale * scaleDistance > 0.1f) {
this.mScale *= scaleDistance;
Zoomable z = (Zoomable) plot;
z.zoomDomainAxes(scaleDistance, info, source, false);
int sealValue = (int) (gapValue * this.mScale);
// gap shoud be greater than zero
if (sealValue == 0)
sealValue = 1;
// To re-render the graph dates in domain axis
((DateAxis) this.getChart().getXYPlot().getDomainAxis())
.setTickUnit(new DateTickUnit(DateTickUnitType.DAY,
sealValue, new SimpleDateFormat("MM/dd")));
}
}
// repaint
invalidate();

Calculating a BoundingBox from a set of points

I really cant find any resource to know how to compute the bounding box of a set of points.
I have a float/int array of points for which I wish to compute the bounding box ( I want to know all the four corners of the rectangle of the bounding box ). How do I accomplish this?
You could loop through the array:
int minX = Integer.MAX_VALUE, minY, maxX, maxY = Integer.MAX_VALUE;
for (int i=0;i<myArray.length;i++){
if (myArray[i].x > maxX){
maxX = myArray[i].x;
} else if (myArray[i].x < minX) {
minX = myArray[i].x;
} else if (myArray[i].y > maxY){
maxY = myArray[i].y;
} else (myArray[i].y < minY) {
minY = myArray[i].y;(
}
}
You didn't say what kind of list you are using (array of points or whatever) so you'll need to adjust myArray[i].y and maxY = Integer.MAX_VALUE as required.
Computing AABB (Axis aligned bounding box) is fairly trivial. Just sort the points in each axis, find the min max on each axis. The intersection of the 4 lines from these points is your AAB rectangle.
Computing OBB (oriented bounding box) is slightly non trivial. Luckily there is a method on GestureUtils that does exactly that, namely :
GestureUtils.computeOrientedBoundingBox(float[] points)
pass it your float array of points and life is good :)
Although you didn't really specify what sort of points you were referring to, this bit of code should still work. I use it for creating a bounding box around the vertices of a model. It should also be noted that rotation should happen separate to loading the vertices. I'm actually fairly certain you can't detect rotation unless it's explicitly stated, or serialized with the vertex data. Also, AABB's and OBB's are technically—from a mathematical perspective—the same thing, as I proved here: https://stackoverflow.com/a/63094985/3214889. So even though your question specifically states Oriented Bounding Box, the following code will work for both. However, you will need to rotate the box afterwards; unless you serialize the rotation somehow.
public void FromVertices(Vertex[] vertices)
{
// Calculate Bounding Box
float minX = float.PositiveInfinity;
float maxX = float.NegativeInfinity;
float minY = float.PositiveInfinity;
float maxY = float.NegativeInfinity;
float minZ = float.PositiveInfinity;
float maxZ = float.NegativeInfinity;
for (int i = 0; i < vertices.Length; i++)
{
Vector3 vertex = vertices[i].Location;
// Check for maximum
if (vertex.X > maxX)
{
maxX = vertex.X;
}
if (vertex.Y > maxY)
{
maxY = vertex.Y;
}
if (vertex.Z > maxZ)
{
maxZ = vertex.Z;
}
// Check for Minimum
if (vertex.X < minX)
{
minX = vertex.X;
}
if (vertex.Y < minY)
{
minY = vertex.Y;
}
if (vertex.Z < minZ)
{
minZ = vertex.Z;
}
}
this.Minimum = new Vector3(minX, minY, minZ);
this.Maximum = new Vector3(maxX, maxY, maxZ);
}

How to write an intersects for Shapes in android

I have an written an Object called Shape which has a Point representing the topLeftCorner and a Dimension with represents its width and height.
To get the topRightCorner I can simply add the width to the topLeftPoint.x. I use to rotate them on a certain degree around their center. The problem after the rotation is, that my intersects(Shape) method fails, because it does not honor the rotation of the Shapes. The rotation will be the same for each Shape. My current implementation looks like this inside my Shape Object:
public boolean intersects(Shape s){
// functions returning a Point of shape s
return intersects(s.topLeft())
|| intersects(s.topRight())
|| intersects(s.bottomLeft())
|| intersects(s.bottomRight())
|| intersects(s.leftCenter())
|| intersects(s.rightCenter())
|| intersects(s.center());
}
public boolean intersects(Point p){
return p.x >= leftX()
&& p.x <= rightX()
&& p.y >= topY()
&& p.y <= bottomY();
}
Basically I need functions like rotatedLeftX() or rotatedTopRight() to work properly. Also for that calculation I think it doesn't matter when the topLeft point before a rotation of ie 90 will turn into topRight...
I already read this and this Question here, but do not understand it fully.
I modified an algorithm from Stackoverflow to do what you are indicating with rectangles for a battleship game I wrote. Here is the code:
private boolean overlaid(int [][][] shps, int curr)
{
for (int i = curr-1; i>=0; --i)
{
// From: http://stackoverflow.com/questions/306316/determine-if-two-rectangles-overlap-each-other/306332#306332
// if (RectA.X1 < RectB.X2 && RectA.X2 > RectB.X1 &&
// RectA.Y1 < RectB.Y2 && RectA.Y2 > RectB.Y1)
if (shps[curr][0][1] <= shps[i][1][1] &&
shps[curr][1][1] >= shps[i][0][1] &&
shps[curr][0][0] <= shps[i][1][0] &&
shps[curr][1][0] >= shps[i][0][0])
return true;
}
return false;
}
private int [][][] shps = { {{-1,-1},{-1,-1}},
{{-1,-1},{-1,-1}},
{{-1,-1},{-1,-1}} };
The shps parameter is just a matrix indicating the location of the top-left and bottom-right corners of each rectangle using {x0,y0}, {x1,y1}. For example, shps[curr][0][1] == the current shp's y0. For my purposes, I had to use <= and >=. Also, you have to be mindful of the reverse of y if you are using screen coordinates versus Cartesian coordinates. Also DeMorgan's Law if you want to use NOT overlaid.
I have a solution:
lets assume I want to calculate the rotation (90 degrees) of a Shape with x =1, y=1 (topLeft Point) and a width of 4 and a height of 6 around its center (3, 4) == (x1, y2)
rotatedX = x1 + cos(q) * (x - x1) - sin(q) * (y - y1)
rotatedY = y1 + sin(q) * (x - x1) + cos(q) * (y - y1)
in this case:
rotatedX = 3 + cos(90) * (1 - 3) - sin(90) * (1 - 4)
rotatedY = 4 + sin(90) * (1 - 3) + cos(90) * (1 - 4)
this is for a rotation in a cartesian-plane (where positive rotation values means rotation counter-clockwise)
So if you wanna aply a rotation of 90 degrees CLOCKWISE you just have to multiply rotation with -1;

Android touch direction northwest, northeast for UP direction

Sorry if the title sounds confusing - but this is what I am trying to do:
I have a large circular button on which I detect touch direction. I am able to find the UP/DOWN/LEFT/RIGHT from the dy and dx of the change in touch input coordinates like this:
if(Math.abs(dX) > Math.abs(dY)) {
if(dX>0) direction = 1; //left
else direction = 2; //right
} else {
if(dY>0) direction = 3; //up
else direction = 4; //down
}
But now I would like to handle cases where the button can be slightly rotated and thus the touch direction will also need to adjust for this. For example, if the button is rotated slightly to the left, then UP is now the finger moving northwest instead of just pure north. How do I handle this?
Use Math.atan2(dy, dx) to get the angle anticlockwise from the positive horizontal of the coordinate in radians
double pressed = Math.atan2(dY, dX);
subtract the rotation amount (anticlockwise rotation amount in radians) from this angle, putting the angle into the coordinate system of the button
pressed -= buttonRotation;
or if you have your angle in degrees, convert it to radians
pressed -= Math.toRadians(buttonRotation);
You can then calculate an easier direction number from this angle
int dir = (int)(Math.round(2.0d*pressed/Math.PI) % 4);
This gives right 0, up 1, left 2 and down 3. We need to correct the case where the angle is negative, as the modulo result will also be negative.
if (dir < 0) {
dir += 4;
}
Now supposing that these numbers are bad and you don't want to use them, you can just switch on the result to return whatever you like for each direction. Putting that all together:
/**
* #param dY
* The y difference between the touch position and the button
* #param dX
* The x difference between the touch position and the button
* #param buttonRotationDegrees
* The anticlockwise button rotation offset in degrees
* #return
* The direction number
* 1 = left, 2 = right, 3 = up, 4 = down, 0 = error
*/
public static int getAngle(int dY, int dX, double buttonRotationDegrees)
{
double pressed = Math.atan2(dY, dX);
pressed -= Math.toRadians(buttonRotationDegrees);
// right = 0, up = 1, left = 2, down = 3
int dir = (int)(Math.round(2.0d*pressed/Math.PI) % 4);
// Correct negative angles
if (dir < 0) {
dir += 4;
}
switch (dir) {
case 0:
return 2; // right
case 1:
return 3; // up
case 2:
return 1; // left;
case 3:
return 4; // down
}
return 0; // Something bad happened
}

Android image with clickable areas

I need an advice how to achieve the following functionality under Android:
I need an image that represents something like a graph (from discrete math), with vertices and edges, where I can click every vertice or edge and fire a different action.
Please advise me how to achieve this (maybe with imagebuttons) or another approach to represent this functionality.
I was bored, so I coded up this crude example...
It assumes straight edges between points.
public class App extends Activity
{
PlotView plot;
#Override
public void onCreate(Bundle sis)
{
super.onCreate(sis);
plot = new PlotView(this);
setContentView(plot);
}
public class PlotView extends View
{
Paint paint1 = new Paint();
Paint paint2 = new Paint();
Point[] points = new Point[10];
public PlotView(Context context)
{
super(context);
paint1.setColor(Color.RED);
paint2.setColor(Color.BLUE);
for (int i = 0; i < points.length; i++)
{
points[i] = new Point();
points[i].x = (float) (Math.random() * 320);
points[i].y = (float) (Math.random() * 480);
}
Arrays.sort(points);
}
#Override
protected void onDraw(Canvas canvas)
{
canvas.drawColor(Color.WHITE);
for (int i = 0; i < points.length; i++)
{
if (i < points.length - 1)
{
canvas.drawLine(points[i].x, points[i].y, points[i + 1].x, points[i + 1].y, paint2);
}
canvas.drawCircle(points[i].x, points[i].y, 5, paint1);
}
super.onDraw(canvas);
}
#Override
public boolean onTouchEvent(MotionEvent event)
{
switch(event.getAction())
{
case MotionEvent.ACTION_DOWN:
{
float x = event.getX();
float y = event.getY();
int hitPoint = -1;
int closestLeft = -1;
int closestRight = -1;
for (int i = 0; i < points.length; i++)
{
float dx = x - points[i].x;
float dy = y - points[i].y;
if(i < points.length - 1)
{
if(points[i].x < x && x < points[i + 1].x)
{
closestLeft = i;
closestRight = i + 1;
}
}
if (Math.abs(dx) <= 16.0f && Math.abs(dy) <= 16.0f)
{
hitPoint = i;
break;
}
}
if (hitPoint != -1)
{
Toast.makeText(getContext(), "Hit Point: " + hitPoint, Toast.LENGTH_SHORT).show();
}
else
if(closestLeft != -1 && closestRight != -1)
{
float dx = points[closestLeft].x - points[closestRight].x;
float dy = points[closestLeft].y - points[closestRight].y;
final float u = ((x - points[closestLeft].x) * dx + (y - points[closestLeft].y) * dy) / (dx * dx + dy * dy);
float px = points[closestLeft].x + u * dx;
float py = points[closestLeft].y + u * dy;
if (Math.abs(x - px) <= 16.0f && Math.abs(y - py) <= 16.0f)
{
Toast.makeText(getContext(), "Hit Line Between: " + closestLeft + " & " + closestRight, Toast.LENGTH_SHORT).show();
}
}
}
}
return super.onTouchEvent(event);
}
public class Point implements Comparable<Point>
{
float x;
float y;
#Override
public int compareTo(Point other)
{
if (x < other.x) return -1;
if (x > other.x) return 1;
return 0;
}
}
}
}
I can imagine how to do this with SurfaceView:
create a Vertex class, which among other things, has an x,y coordinate representing where to draw the vertex. If your vertex was a png image of a circle, then the top-left x,y coordinates of the image are stored in the Vertex class.
Have all your verticies in a List, and iterate through and draw each vertex.
the edges are more complicated since they might criss-cross or curve around.
assuming they are straight lines, then you can have a Edge class that contains the starting x,y and ending x,y coordinates.
you can iterate through a List of Edges and draw the lines accordingly
In order to detect when a user clicks on them, you should override the onTouch method and check the event.rawX() and event.rawY() values to see if they match up to a Vertex or Edge class.
for a Vertex class, you can check if x <= event.rawX <= x + image_width and y <= event.rawY <= y + image_height
for an Edge, you can check if the event.rawX, event.rawY coordinates are found in the line formed by the two sets of coordinates you stored in the Edge class.
I've used a similar method to draw a set of nodes in a game. I'm not so sure how to do the edges though - the method I outline would only work if they were straight and do not criss-cross.
I am sure there is a better way to do this using openGL, but I have not used openGL before.
Hopefully you can get some ideas out of this.
I think you might be best off with a SurfaceView:
http://developer.android.com/reference/android/view/SurfaceView.html
And handling the onTouchEvent() as a whole for the surface, and mapping that to underlying entities in the image. If you're calculating the drawing the graph as you go should be easy to also create a map of tapable areas and grabbing the X and Y of the touch event to figure out if it corresponds to an element in the image.
If you literally have an image, as an already processed PNG for example, you would need some way to also carry in the touch event areas. Depends where that image comes in from.
According to android help, "drawing to a View, is your best choice when you want to draw simple graphics that do not need to change dynamically and are not part of a performance-intensive game." This is the right way to go when making a snake or a chess game, for instance. So I don't see a point in suggesting using a SurfaceView for this, it will just overcomplicate things.
For clickable areas you override public boolean onTouchEvent(MotionEvent event) where you manage x and y coordinates of the click for identifying the clicked area.

Categories

Resources