I'm trying to make whack a mole game using project tango.
When user start the game, the program will create holes at random point for the moles to come out. Right now, I already can make the hole and spawn the mole at random, though I have a problem with the created hole.
The hole sometimes spawn at an edge contour of table and stuff and make the hole partially floating in the air. Is there any way to check if the centerPlane is near an edge or not?
Here's the screenshot of the problem I meant. I want the "hole" not to spawn on area that doesn't fit with it's height and width. Currently, I'm using farandole release.
EDIT 1:
I'm trying to do as Hristo suggest. But it doesn't work, the FindClosestPoint always return -1, even when I use the center of the screen. Here's the script I used. And for some additional info, I'm using the unitySDK and unity 5.5.2f1
bool CheckTheCorner(Camera cam,Vector3 planeCenter){
Vector2 firstPointInScreen = WorldToScreenConverter(cam,new Vector3 (planeCenter.x,planeCenter.y,planeCenter.z-holeheight));
Vector2 secondPointInScreen = WorldToScreenConverter(cam,new Vector3 (planeCenter.x,planeCenter.y,planeCenter.z+holeheight));
Vector2 thirdPointInScreen = WorldToScreenConverter(cam,new Vector3 (planeCenter.x-holewidth,planeCenter.y,planeCenter.z));
Vector2 fourthPointInScreen = WorldToScreenConverter(cam,new Vector3 (planeCenter.x+holewidth,planeCenter.y,planeCenter.z));
DebugText.text = m_pointCloud.FindClosestPoint (cam, new Vector2(Screen.width / 2, Screen.height / 2), 1).ToString ();
Vector3 firstPoint = m_pointCloud.m_points[m_pointCloud.FindClosestPoint(cam, firstPointInScreen, 1)];
Vector3 secondPoint = m_pointCloud.m_points[m_pointCloud.FindClosestPoint(cam, secondPointInScreen, 1)];
Vector3 thirdPoint = m_pointCloud.m_points[m_pointCloud.FindClosestPoint(cam, thirdPointInScreen, 1)];
Vector3 fourthPoint = m_pointCloud.m_points[m_pointCloud.FindClosestPoint(cam, fourthPointInScreen, 1)];
return false;
}
Vector2 WorldToScreenConverter(Camera cam,Vector3 worldPos){
Vector3 screenPos = cam.WorldToScreenPoint (worldPos);
return new Vector2 (screenPos.x,screenPos.z);
}
Ah yes, don't mind the return false one for the moment, I just put it there to avoid error since I'm still figuring out the FindClosestPoint.
What you can do is take the 4 corners on your plane and decide if they are all laying on a surface in the real world, if not you can make the plane elsewhere.
That can happen with the use of FindClosestPoint() method in the TangoPointCloud.cs. What that method does is makes a Raycast from your camera trough a certain point on the screen landing in the real world environment. The method then returns the index of that point. The list to search with the indexes is called m_points
So lets split it in steps:
Make 4 Vectors using the `FindClosestPoint().
Check if all 4 vectors are on the same plane (simple math).
If step 2 is true -> Instantiate your GameObject on that plane.
To get one of the vectors your code should be something like this:
Vector3 firstPoint = m_pointCloud.m_points[m_pointCloud.FindClosestPoint(Camera.main, new Vector2(Screen.width / 2, Screen.height / 2), 1)];
In this example I'm using the center of the screen as my Vector2 parameter. However you don't want the center of the screen . Instead you want the position of one corner from your plane translated as a screen point.
Hope that solves your problem. Cheers.
Related
I have a skeleton game object which I make move by increasing its velocity on the Update function, like this:
body.velocity = new Vector2((isFacingLeft ? -1 : 1) * speed, body.velocity.y);
Which is also controlled by a direction isFacingLeft, which determines movement for the skeleton from left to right.
int direction = isFacingLeft ? -1 : 1;
But, since my skeleton is in a platform, I want to use a ray cast to ensure I detect whenever no platform is in front (so the cast points diagonally down in front of the skeleton), so I prepare a few variables to ensure I have a proper position for the ray cast. Then, if no floor has been found, the isFacingLeft variable is flipped, so the skeleton moves in the opposite direction as it approaches an edge:
Vector2 beginFloorCast = new Vector2(transform.position.x + ((enemyWidth / 2) * direction), transform.position.y - enemyHeight / 2);
Vector2 floorCastDirection = transform.TransformDirection(new Vector2(1 * (direction), -1));
float floorCastLength = 1f;
RaycastHit2D hit = Physics2D.Raycast(beginFloorCast, floorCastDirection, floorCastLength);
if (!hit) {
isFacingLeft = !isFacingLeft;
}
While this all works, I am now trying to draw a debug ray so I can visualize in debug mode how long the floor ray is (and so I can use this in the future to detect if the player is in range of the skeleton with another ray), so I use the following:
Debug.DrawRay(beginFloorCast, floorCastDirection.normalized * floorCastLength, Color.green, 5f);
This also works, but in the Scene mode, the ray is drawn once for every Update call:
Is there a way for me to clear the debug screen after the Update function is done? Or what could I change in my code to make sure I only call it once and that the ray follows the skeleton?
this is my first time posting on here. I'm working on a game using the new Unity multiplayer networking solution.
In summary, the issue is that the player is not moving as intended.
I am trying to take player input as follows:
Vector3 worldSpaceDir = new Vector3(Input.GetAxisRaw("Vertical"), 0, Input.GetAxisRaw("Horizontal"));
then convert it to the object space coordinates of the player character:
_inputDirection = transform.InverseTransformDirection(worldSpaceDir);
The issue I'm having is with a rotation of 0 or 180 the player moves as expected with the WASD inputs, however, at 90 or 270 all the inputs are flipped(A = right, D = left, W = backward, S = forward).
I found a question that is exactly my question but no one responded with an answer. The question is quite old now so I wanted to ask it again for more visibility.
Here's a link to the original question.
Firstly, you are taking the worldSpaceDir wrong, it should be as follow
Vector3 worldSpaceDir = new Vector3(Input.GetAxisRaw("Horizontal"), 0, Input.GetAxisRaw("Vertical"));
here we take horizontal input as X and vertical input as Z, because in Unity Forward is pointed as Z and not Y.
Secondly, we do not need to use InverseTransformDirection() we just need TransformDirection() something like following
Vector3 inputDirection = transform.TransformDirection(worldSpaceDir);
here we are telling unity to convert the worldSpaceDir that is relative to transform (local direction) into a world space direction, so we might actually give a proper name to worldSpaceDir.
The following would work for you.
private void Update() {
Move();
}
private void Move() {
Vector3 directionToMove = new Vector3(Input.GetAxisRaw("Horizontal"), 0, Input.GetAxisRaw("Vertical"));
Vector3 inputDirection = transform.TransformDirection(directionToMove);
transform.position += inputDirection * Time.deltaTime;
}
I think you want to go the other way round actually!
Transform.InverseTransformDirection converts a vector from world space into local space.
What you get as input however is a local vector on the XZ plane. You want to apply this direction according to your player objects orientation, if e.g. pressing right (your input is 1,0,0) the object shall move towards its transform.right vector.
So you rather want to convert in the opposite direction into world space to move the object in the Unity world space.
You should rather be using Transform.TransformDirection!
var worldMove = transform.TransformDirection(input);
Or alternatively you can also just multiply by the rotation like
var worldMove = transform.rotation * input;
Note that if you are also using a Rigidbody like the question you linked there is also Rigidbody.AddRelativeForce which basically works the same way and expects a local space vector which is then internally converted into a world space force.
I am having an issue with linecasting in Unity 2D. What I am trying to do is have a linecast go from the player, through the cursor on screen, and then indefinitely (or for a large time, say times 10). I have made successful attempts at having a Debug.Drawline pass from the player and stop at the location of the mouse. It looks like this:
Do note that the location of my cursor is on the upper left corner of that block. below is the code I use to accomplish this:
mousePos = Camera.main.ScreenToWorldPoint (new Vector2 (Input.mousePosition.x, Input.mousePosition.y));
Debug.DrawLine(new Vector2 (player.transform.position.x, player.transform.position.y+32), new Vector2 (mousePos.x, mousePos.y), Color.green);
Do note that the +32 is used to center the drawline to my characte. However, if I were to multiply the mousePos vector by 2, I get this offset in the drawcast (and also linecast).
Once again my cursor is on the upper left corner of the block. Why is this offset behaving so oddly?
Linecast means from one point to another point. You seem to describe raycast which goes from one point in a direction.
So in your case you'd take the direction from the player to the mouse pointer, normalize that and use infinity as distance.
Don't know exactly what you want to achieve, but as it has already been pointed out I think you should use raycast instead. For example:
var mousePos = Camera.main.ScreenToWorldPoint((Vector2)Input.mousePosition);
var playerPos = (Vector2)player.transform.position;
var direction = (playerPos - mousePos).normalized;
Debug.DrawRay(new Vector2(playerPos.x, playerPos.y + 32), direction, Color.green);
I would like a RectTransform (panel) in Unity 4.6 to follow a worldObject. I got this working, but the movement is not as smooth as I'd like. It seems a bit jagged and it lags behind when I start moving the camera.
Vector2 followObjectScreenPos = Camera.main.WorldToScreenPoint (planet.transform.position);
rectTransform.anchoredPosition = new Vector2 (followObjectScreenPos.x - Screen.width / 2, followObjectScreenPos.y - Screen.height / 2);
Tips and tricks are greatly appreciated. :-)
There is a bunch of options:
1) You can add a gui canvas to the worldObject and render your panel with this canvas (just add it as a child), but that may not be exactly what you need.
2) To eliminate jagged movement you should tween in one way or another. DOTween is my personal preference, where something along the following lines would give you the required result:
Tweener tweener = transfrom.DOMove (Target.position, 1).SetSpeedBased();
tweener.OnUpdate (() => tweener.ChangeEndValue (Target.position, true));
3) if you don't want to include dependencies in your code, you can perform linear interpolation between current and desired position (or in your case - anchoredPosition) in Update function.
I'd suggest using a tweener so as not to clutter your update function and generally tweeners have loads of potential uses in all kinds of games.
Below is code sample for linear interpolation in case you don't want to use tweener library:
float smoothFactor = 1.0f; //used to sharpen or dull the effect of lerp
var newPosition = new Vector3(x,y,z);
var t = gameObject.transform;
t.position = Vector3.Lerp (t.position,
newPosition,
Time.deltaTime * smoothFactor);
Place it in Update function and it will make the gameObject follow specific newPosition.
I have a scene with a body maked with makehuman, and I need to add a simple prefab (a torus) around the arm of the body when the user touch the arm.
I tried:
Instantiate the prefab in the point where the user touch, but the prefab apear in the border of the arm.
Instantiate the prefab in the center of the arm, with this code:
float radio = hit.transform.collider.radius; // the arm has a capsuleCollider
Ray r = Camera.main.ScreenPointToRay(Input.GetTouch(0));
Vector3 origin = r.origin;
float distance = (origin - hit.point).magnitude;
RaycastHit ou;
Vector3 position = hit.point;
Ray r2 = new Ray(r.GetPoint(distance + 10f), -r.direction);
if (cc.Raycast(r2, out ou, distance + 10f))
position = (hit.point + ou.point) / 2;
Instantiate(Prefab, position, Quaternion.identity);
This try to Select the center of the arm and initialite a torus.
The second option works in some cases, but the general impression is that is the wrong way to do it.
How can I add a prefab around a collider? or, how can I modify the mesh to add a visual indicator?
This should work a lot better as well as look a lot cleaner:
Vector3 center = hit.transform.collider.bounds.center;
Instantiate(Prefab, center, Quaternion.identity);
hit.transform.collider is a vital part of this process and you got that part. collider.bounds is the bounding box that surrounds the collider (http://docs.unity3d.com/ScriptReference/Collider-bounds.html), and bounds.center is the center of the bounding box (http://docs.unity3d.com/ScriptReference/Bounds-center.html). The Vector3 that bounds.center returns is where you want to spawn your prefab.
From there, you should be able to rotate the prefab to the desired angle and perform any number of operations you want.