I'm new in Unity. I've got game with FPS mode, camera rotate with mouse's moves and sun is the directional light. I must write script where I check if sun is in player's field of view. I thought that I can calculate angle between 2 vectors and then I decide if sun is visible. First vector is:
var playerSun = light.transform.position - camera.transform.position;
But I have problem with the second one... I don't know which variable I should use, camera.transform.forward is ALWAYS (0,0,1)...
Can you help me? I'll be very grateful.
Vector3 direction = light.position - player.position;
float dot = Vector3.Dot(direction.normalized, player.forward);
if(dot > 0) { Debug.Log("Sun is on the front"); }
dot product returns 1 when two vectors are aligned, 0 when they are 90 degrees and -1 when they are opposite.
The value is in radians so if you need a 90 degrees FOV, it would be 45 degrees (since 90 is 45 left and right) and that is appr. 0.7f.
if(dot > 0.7f) { Debug.Log("Sun is withing 90 degrees");}
There are several ways to achieve that, but I suggest usage of Raycast.
I suppose sun is more than just a dot, it has some area visible to the player, so even if he does not see sun` center point, he still can see some part of its area. If so, I recommend to add a new script to sun object just to identify it programmatically. Then make sure that it has collider component attached with the size approximately equal to sun.
Then in your script in which you want to detect sun visibility to the player you can do something like that:
var ray = Camera.main.ScreenPointToRay(pos);
RaycastHit hit;
if (!Physics.Raycast(ray, out hit, 100))
return false; //sun or any other collider wasnt hit
var objHit = hit.collider.gameObject.GetComponent<Sun>();
So objHit != null means that player can see any part of area that sun has.
Related
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 have an object that rotates according to mouse position, but I want to clamp it so it doesn't get further or lower than certain value. Here is my code:
void LookAt () {
float distance = transform.position.z - Camera.main.transform.position.z;
Vector3 position = new Vector3(Input.mousePosition.x, Input.mousePosition.y, distance);
position = Camera.main.ScreenToWorldPoint(position);
position.x = Mathf.Clamp(position.x, -70, 70);
position.z = Mathf.Clamp(position.z, -70, 70);
Vector3 target = new Vector3 (position.x, transform.position.y, position.z); // Use current object positin.y
transform.LookAt(target);
}
But unfortunately it doesn't work, it keeps rotating 360.
Edit:
This is a 3D top-down game, I have a tank and I want to rotate it's upper half. The code I wrote above works perfect for the job, but now I don't know how to limit it so the barrel( the part I'm rotating) always facing upwards where the enemies will come from. 70 or whatever are just random values I was testing, first I want to figure what exactly the proper code is, then determining the values is the easy part.
Actually, the problem is that you're clamping a position, not a rotation. You're having it look at a certain point, but limiting that point rather than the angle that it will need to rotate to meet it. You'll have to use trigonometry to calculate the angle it wants to point in (more specifically, the atan2 function), clamp that value to (-70, 70), and then apply that rotation to the object (using euler angles). Do you require further clarification on any of these steps?
Cheers.
P.S. Note that atan2 returns a value in radians, but your range and euler angles use degrees.
You limit your target position by 70 units in world space, which is usually a lot, but depends on your game scale. What I think you wanted to do is to limit mouse position by 70 pixels around the screen center. (Please, provide this remarks in the question itself, so we won't have to guess). However, because you used the same variable both for screen space and world space position of the target, you likely got confused and clamped the position after converting it to world space.
Also, you made the y coordinate of the target to be the same as the object. But this means that the object would have to rotate 360 degrees every time the target passed it. I assume that what you wanted to do instead is to assume that the target location is located on camera place.
void LookAt () {
var cursorPosition = new Vector3(Input.mousePosition.x, Input.mousePosition.y, camera.main.nearClipPlane);
cursorPosition.x = Mathf.Clamp(position.x, -70, 70);
cursorPosition.z = Mathf.Clamp(position.z, -70, 70);
var targetPosition = Camera.main.ScreenToWorldPoint(cursorPosition);
transform.LookAt(targetPosition);
}
Please, provide details about your reasoning and desired behavior when you ask to find errors in your code.
I am currently in the process of writing a PONG game in Swift. I have gotten to the point where I am trying to get the game ball to rebound off the player's paddle. I am having trouble creating an if statement using the coordinates of the player's paddle. I will write in pseudo code what I mean.
If the game ball is in between the right most x coordinate of the player paddle and the right most coordinate of the player paddle and the y value of the game ball is the same as the y value of the player paddle {
Do this code
}
Currently, my code looks like this:
if GameBall.center.x <= PlayerPaddle.center.x + 50 && GameBall.center.x >= PlayerPaddle.center.x - 50 && GameBall.center.y - 5 == PlayerPaddle.center.y + 15 {
if GameBallDirection == "W" {
GameBallDirection = "E"
}
However this does not work. Is there a way to write a condition which requires the Game Ball to be within the left and right most x coordinates of the player paddle? I know this may seem vague but I have tried to explain it as best as possible and any and all help is appreciated.
The x part looks ok. The y part:
GameBall.center.y - 5 == PlayerPaddle.center.y + 15
is looking for float equality, which will basically never be true. You should be using >= instead, to check if the ball has reached or passed the start of the paddle.
Without seeing all your code I can't be sure, but you may also need to consider which side of the screen the paddle is at for >= or <= usage...
I want to move a rigid body in an elliptical movement like the player movement "whale trail" game.What I did is:
Created a Cube called "Player" with scale(1.5,0.5,0.1)
Created another small cube called Point with scale(0.1,0.1,0.1) and positioned same as Player but 0.5 more in x (So that now the player looks like a 2D rectangle and a point on it little right to the centre of the rectangle).
Then I created a fixed joint between both bodies
Now I applied for on the player at the position of the Point as follows ,
float mfAngle = 0.0f;
void update()
{
mfAngle=transform.eulerAngles.z;
mfAngle=mfAngle%360;
if(mfAngle>=0 && mfAngle<90)
{
mfXforce=-0.1f;
mfYforce=0.1f;
}
if(mfAngle>=90 && mfAngle<180)
{
mfXforce=-0.1f;
mfYforce=0.1f;
}
if(mfAngle>=180 && mfAngle<270)
{
mfXforce=-0.1f;
mfYforce=-0.1f;
}
if(mfAngle>=270 && mfAngle<360)
{
mfXforce=0.1f;
mfYforce=-0.1f;
}
Debug.Log("Angle ="+mfAngle+"X = "+mfXforce+"Y = "+mfYforce);
Vector3 pointPos=_goPointObject.transform.position;
transform.rigidbody.AddForceAtPosition(new Vector3(mfXforce,mfYforce,0),pointPos);
}
But it doesn't works fine.I just moves upwards and the turns and moves in different direction.If anyone know how to move the rigid body in elliptical motion by applying force give me a solution.(I want to use it as like whale trail game u can see the video of the "loop movement" in this http://www.youtube.com/watch?v=wwr6c2Ws1yI video).Thanks in advance.
I had found the solution by myself.To achieve that elliptical movement u have to create two bodies and connect them with joint by placing it horizontally next to each other.Then u have to apply force in x direction constantly and in Y direction only when the Screen is be touched on the first body.
And its important to reduce the X speed when moving up then u will get that elliptical rotation.
It works fine for me.
Thanks,
Ashokkumar M