Unity3D: Camera is unable to move with firstperson script - c#

The object is a satellite type so I have a script to move the object in an orbit using its position. And I also have a script to move the satellite object in first person mode.
Problem is that the user is unable to move the camera by the axis "Mouse X" and "Mouse Y" for first person mode. The problem is happening because the orbit script and the first person script are both controlling the camera so it is unable to move. In the game, when you move the mouse you see the camera jerk and when I disable the orbit script, the first person works.
How can I fix this problem?
A solution can be to use only position for the orbit, and the rotation for first person control?? The first person mode will not control the objects position only rotation. The orbit will not control the objects rotation only position.
Thank you!
Orbit Script
private void FixedUpdate()
{
transform.RotateAround(centerOfOrbit.position, orbitAxis, orbitSpeed * Time.deltaTime);
desiredOrbitPosition = (transform.position - centerOfOrbit.position).normalized * orbitRadius + centerOfOrbit.position;
transform.position = Vector3.MoveTowards(transform.position, desiredOrbitPosition, Time.deltaTime * orbitAdjustSpeed);
}
First Person mode control (does not work with Orbit)
private void Update()
{
if(allowFirstPerson)
{
x+= Input.GetAxis ("Mouse X") * turnSpeed;
if (allowTiltingForward)
{
y -= Input.GetAxis("Mouse Y") * turnSpeed;
}
y = ClampAngle(y, minVerticalAngle, maxVerticalAngle);
if (minHorizontalAngle != 0 || maxHorizontalAngle != 0)
{
x = ClampAngle(x, minHorizontalAngle, maxHorizontalAngle);
}
Quaternion rotation = Quaternion.Euler(y, x, 0);
Vector3 direction = (rotation * Vector3.forward * 100);
aimPoint = new Vector3(direction.x + aimError, direction.y + aimError, direction.z + aimError);
aimDir = (aimPoint - playerCamera.transform.position).normalized;
}
}
This Top View mode control works with the Orbit script but the top view does not use the same controls as the first person but I can not seem to figure out why one works and the other does not.
Top View mode control (does work with Orbit)
private void Update()
{
if(allowTopView)
{
Ray ray = playerCamera.ScreenPointToRay(Input.mousePosition);
RaycastHit hit;
topDownAimPoint = new Vector3(0,0,0);
if(Physics.Raycast(ray, out hit))
{
topDownAimPoint = hit.point;
}
aimPoint = new Vector3(topDownAimPoint.x + aimError, topDownAimPoint.y + aimError, topDownAimPoint.z + aimError);
}
}

My understanding is that your problem is caused by two scripts trying to set the rotation for the same object: a camera. If this is the case, you can create an empty Satellite object and make the camera a child of that object in the Hierarchy. Attaching the Orbit Script to the Satellite object and the First Person script to the camera will allow the camera to move in the satellite's orbit but still have its own independent rotation.
EDIT:
To accommodate a 3d model in this situation, create an empty parent object called SatteliteWrapper (or something similar) and attach the Orbit Script to that object. Then make the camera a child of SatteliteWrapper and make the 3d model a child of the camera. That allows the model to rotate with the camera.

Related

Adapting player behaviour to AI in unity

I have designed an attack method for a player that is full functional, however I am new to AI and have no idea as to where I would begin when it comes to adapting this into a state for an FSM.
protected void UpdateAttackState()
{
// check for input
float rot = transform.localEulerAngles.y + rotationSpeed * Time.deltaTime * Input.GetAxis("Horizontal");
Vector3 fwd = transform.forward * moveSpeed * Time.deltaTime * Input.GetAxis("Vertical");
// Tank Chassis is rigidbody, use MoveRotation and MovePosition
GetComponent<Rigidbody>().MoveRotation(Quaternion.AngleAxis(rot, Vector3.up));
GetComponent<Rigidbody>().MovePosition(_rigidbody.position + fwd);
if (turret) {
Plane playerPlane = new Plane(Vector3.up, transform.position + new Vector3(0, 0, 0));
// Generate a ray from the cursor position
Ray RayCast = Camera.main.ScreenPointToRay(Input.mousePosition);
// Determine the point where the cursor ray intersects the plane.
float HitDist = 0;
// If the ray is parallel to the plane, Raycast will return false.
if (playerPlane.Raycast(RayCast, out HitDist))
{
// Get the point along the ray that hits the calculated distance.
Vector3 RayHitPoint = RayCast.GetPoint(HitDist);
Quaternion targetRotation = Quaternion.LookRotation(RayHitPoint - transform.position);
turret.transform.rotation = Quaternion.Slerp(turret.transform.rotation, targetRotation, Time.deltaTime* turretRotSpeed);
}
}
if(Input.GetButton("Fire1"))
{
if (elapsedTime >= shootRate)
{
//Reset the time
elapsedTime = 0.0f;
//Also Instantiate over the PhotonNetwork
if ((bulletSpawnPoint) & (bullet))
Instantiate(bullet, bulletSpawnPoint.transform.position, bulletSpawnPoint.transform.rotation);
}
}
// Update the time
elapsedTime += Time.deltaTime;
}
This is completely dependent on how you want your state machine to work. An example of this would be the AI trying to seek and destroy other players.
Seeking State: AI would move around the map with a detection zone (collider) that would change state on trigger enter. This would then save a position of the detection's generalized location which would be used to move and rotate the AI tank towards that position.
Firing State: AI enters a new detection zone (collider) within firing range, turret will move to aim at target. AI will also move around the map to keep firing range at a maximum while also keeping track of the last known position of the enemy if they happen to go out of range.
Detecting Fire: Player or other AI fires their weapon this could increase the detection radius resulting in a seeking state being called.
After those functions are figured out, place a switch or something similar within the Update() to allow everything within the AI to run alongside Unity's functions.

Clamping an object axis in Vuforia AR camera

screenshot hereI want to clamp Y-axis on a cube. I can do it in Unity camera. But, it does not react correctly when I am using it in Vuforia camera.
My problem was that the cube follows the camera. I would like the cube to stay in its position and ignore the AR camera position. I sense it has something to do with WorldtoViewpoint but I cannot figure it out. Can you teach me how to do this please? thankyou
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ClampMovementController : MonoBehaviour
{
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
Vector3 pos = transform.localPosition;
pos.y = Mathf.Clamp(transform.position.y, 0f, 0f);
transform.localPosition = pos;
}
}
This is my solution:
Actually its very simple. The INcorrect concept was my object attached to the AR camera, hence, object position is always moving related to camera position. Now. In order to make the object stays in its place. I need to get its localPosition. First. Store the localposition in Vector3 pos. And then do modification on Vector3 pos. At last, reassign the new value to the object localposition.
public class ClampMovementController : MonoBehaviour
{
public float currentPos;
public GameObject capsule;
void Update()
{
//store the value of object localPosition
Vector3 pos = capsule.transform.localPosition;
//modification on the value
pos.y = Mathf.Clamp(pos.y, currentPos, currentPos);
//rerassign the new value to the object localPosition
capsule.transform.localPosition = pos;
}
}
First of all your cube is moving with the camera because your image target is child of your ARCamera. Therefore, when you move the camera image target moves, then your cube moves as well. Make sure your ImageTarget has no parent.
I did not understand why you have to lock any movement in Y axis. I guess you are doing something wrong with lean touch when you move object. I have not used lean touch but i have achieved this with keyboard inputs. You can convert it to lean touch by modifying following script. Just add these line to your ImageTarget's DefaultTrackableEventHandler script:
//Variables for getting capsule and checking if ImageTarget is tracked
private bool isTracked = false;
private GameObject capsule;
Then create an Update method for getting input from user like this.
void Update()
{
if(isTracked)
{
if(Input.GetKey(KeyCode.W))
{
//using forward for moving object in z axis only.
//Also using local position since you need movement to be relative to image target
//Global forward can be very different depending on your World Center Mode
capsule.transform.localPosition += Vector3.forward * Time.deltaTime;
}
else if (Input.GetKey(KeyCode.S))
{
capsule.transform.localPosition -= Vector3.forward * Time.deltaTime;
}
if (Input.GetKey(KeyCode.A))
{
//Using Vector3.left and right to be make sure movement is in X axis.
capsule.transform.localPosition += Vector3.left * Time.deltaTime;
}
else if (Input.GetKey(KeyCode.D))
{
capsule.transform.localPosition += Vector3.right * Time.deltaTime;
}
}
}
As you can see there is no movement in Y axis because i used forward, left and right vectors to make sure movement in in only X and Y axis.
Last you have to make sure isTracked is updated. In order to do that you have to add isTracked = false; in OnTrackingLost method and isTracked = true; in OnTrackingFound method. Good luck!

Player rotation and camera rotation

i want the player to look into the direction, the camera is looking.
The camera follows the player (3rd person game style).
I've tried it with
transform.localRotation = new Quaternion(transform.localRotation.x,
cameraMain.transform.localRotation.y,
transform.localRotation.z,
transform.localRotation.w);
but it doesn't work.
Sometimes the player starts rotating the other direction.
the following code will make the object (specified in the parameter) face in the direction of where the main camera is looking:
public void lookInDirectionOfCamera(Transform object) {
RayCastHit hit;
if (Physics.raycast(cameraMain.transform.position, cameraMain.transform.forward, out hit)) {
object.forward = hit.point - object.position;
}else { //if the raycast didnt hit anything, make the object face 100 units in front of the camera
Vector3 point = Camera.main.transform.position + Camera.main.transform.forward * 100;
object.forward = point - object.position;
}
}
This will make the player face the point that is forward to the camera. If you just want them to have the same rotation in the y-axis don't use Quaternions!
Instead, you can just do it with Euler angles:
transform.eulerAngles = new Vector3(transform.eulerAngles.x,
cameraMain.transform.eulerAngles.y,
transform.eulerAngles.y);
The reason not to use transform.localRotation is because that is a Quaternion. The y component in a Quaternion is not the same as the y-axis in a Euler angle (what you are used to seeing), Quaternions are very confusing so you should almost never set individual values in them. If you want to edit them only use the built-in methods.
Get the direction the camera is looking with cameraMain.transform.forward, make a copy with a y value of zero, then use Quaternion.SetLookRotation to look in that direction with the global up direction.:
Vector3 cameraDirection = cameraMain.transform.forward;
Vector3 characterLookDirection = new Vector3(cameraDirection.x,
0f,
cameraDirection.z);
Quaternion newRotation = new Quaternion();
newRotation.SetLookRotation(characterLookDirection, Vector3.up);
transform.rotation = newRotation;

how to snap two objects in runtime in unity?

this is the 3d model i wanted to connect another model like this to its silver connectors on top side and also another model to right side(so do help me to snap it)I want to know how to snap two 3D objects together in runtime. i.e during "play" the user must be able to dragup, down, left, right to snap one object with the other object .for example like "lego", ie. one 3D object should snap to another 3D object. How would I achieve this?
This is the code I use for dragging:
using System.Collections;
using UnityEngine;
public class drag : MonoBehaviour {
Vector3 dist;
float posX;
float PosY;
void OnMouseDown()
{
dist = Camera.main.WorldToScreenPoint(transform.position);
posX = Input.mousePosition.x - dist.x;
PosY = Input.mousePosition.y - dist.y;
}
void OnMouseDrag()
{
Vector3 curPos = new Vector3(Input.mousePosition.x - posX, Input.mousePosition.y - PosY, dist.z);
Vector3 worldPos = Camera.main.ScreenToWorldPoint(curPos);
transform.position = worldPos;
}
}
There are many many ways to accomplish this. Here is the first method I came up with. If we break down what might comprise a snap, we can muster up a script to attach to each snappable child:
1) Assign tag "parentblock" to the object you are dragging around.
2) Attach a trigger collider to both the parent object and the snappable child object.
3) When the the dragged object enters the collision area, snap it to the parent.
4) Store the offset from the parent to maintain its position once snapped.
bool snapped = false;
GameObject snapparent; // the gameobject this transform will be snapped to
Vector3 offset; // the offset of this object's position from the parent
Update()
{
if (snapped == true)
{
//retain this objects position in relation to the parent
transform.position = parent.transform.position + offset;
}
}
void OnTriggerEnter(Collider col)
{
if (col.tag == "parentblock")
{
snapped = true;
snapparent = col.gameObject;
offset = transform.position - snapparent.transform.position; //store relation to parent
}
}
Keep in mind this will only snap child objects to 1 master parent object that you are dragging around. It should go without saying you may need to tweak this for it to perform specifically to your project like you want, but hopefully this gets you in the right direction. (FYI I have not tested this so am not guaranteeing it will work right out of the gate)

Need help getting camera to follow instantiated GameObject (player)

Working on a multiplayer game in Unity3D. Like many others, I've got some serious issues getting the camera to follow the player. In a normal game, you simply make the camera object a child of the player object to make it follow the player. In multiplayer, this is not an option as players need to spawn (prefab).
So instead you need to use C# to make the camera follow the player using the player objects transform position. This is what I've tried:
public Transform target;
public float smoothing = 5f;
Vector3 offset;
public GameObject playerPrefab;
private void SpawnPlayer()
{
Network.Instantiate(playerPrefab, Vector3.up * 5, Quaternion.identity, 0);
offset = transform.position - target.position;
}
void LateUpdate()
{
Vector3 targetCamPos = target.position + offset;
transform.position = Vector3.Lerp(transform.position, targetCamPos, smoothing * Time.deltaTime);
}
Ofcourse I've assigned the player prefab to target. So when the game starts, the cameras position is transformed to the players position. But after that, it refuses to follow the player. It just sits there.
So I've started debugging this with:
Debug.log(target.position);
It returns the starting location of the player, but doesn't get updated as the player moves around. It remains the same. So that's obviously the reason the camera won't follow the player.
The question is: Why doesn't the player position get updated? Or most likely it does, but the script doesn't see it. What am I doing wrong?
According to your comments,here is your problem.
When you drag the prefab you assign the transform of the prefab. The player is actually an instance of the prefab (a clone) but not the prefab itself.
You need to create the new object and assign its transform to it.
GameObject player = (GameObject)Network.Instantiate(playerPrefab, Vector3.up * 5, Quaternion.identity, 0);
target = player.transform;
offset = transform.position - target.position;

Categories