I'm trying to create an First Person View camera in XNA 4.0. I got the camera working and my scene renders fine. My movement with the W, A, S, D works fine as well but I cannot figure out why my Mouse rotations are messed up.
When I try to look Up with the camera, it tilts my entire world and looking Left & Right does the same thing and both look in the same direction. Eventually, my entire world flips :S.
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
namespace Brandon
{
public class FPC : GameComponent
{
private KeyboardState OldKeyboardState;
private MouseState OldMouseState;
private Vector3 Target = Vector3.Zero;
private Vector3 UpVector = Vector3.Up;
private Vector3 Position = new Vector3(0.0f, 0.0f, 1.0f);
private Vector2 Velocity = Vector2.Zero;
private Matrix View = Matrix.Identity;
private Matrix Projection = Matrix.Identity;
private BasicEffect Effects = null;
private float Speed = 5.0f;
private float WalkingSpeed = 1.0f;
private float RotationSpeed = 0.1f;
private float AngleX = 0.0f;
private float AngleY = 0.0f;
public BasicEffect Effect
{
get { return this.Effects; }
}
public FPC(Game game) : base(game)
{
Mouse.SetPosition(Game.GraphicsDevice.Viewport.Width / 2, Game.GraphicsDevice.Viewport.Height / 2);
Game.GraphicsDevice.RasterizerState = RasterizerState.CullNone;
this.Effects = new BasicEffect(Game.GraphicsDevice);
this.OldMouseState = Mouse.GetState();
}
public override void Initialize()
{
base.Initialize();
}
public void LookAt(float FOV_Degrees, float NearPlaneDistance, float FarPlaneDistance, Vector3 Position, Vector3 Target, Vector3 UpVector)
{
this.Position = Position;
this.Target = Target;
this.UpVector = UpVector;
this.Projection = Matrix.CreatePerspectiveFieldOfView(MathHelper.ToRadians(FOV_Degrees), Game.GraphicsDevice.Viewport.AspectRatio, NearPlaneDistance, FarPlaneDistance);
this.View = Matrix.CreateLookAt(Position, Target, UpVector);
}
private void UpdateView(Matrix rotationMatrix)
{
Vector3 finalTarget = this.Position + Vector3.Transform(this.Target, rotationMatrix);
Vector3 finalUp = Vector3.Transform(this.UpVector, rotationMatrix);
this.View = Matrix.CreateLookAt(this.Position, finalTarget, finalUp);
}
private void ProcessInput(GameTime gameTime)
{
bool isWalking = false;
KeyboardState CurrentKeyboardState = Keyboard.GetState();
Vector3 pos = Vector3.Zero;
if (CurrentKeyboardState.IsKeyDown(Keys.W)) pos.Z -= 1.0f;
if (CurrentKeyboardState.IsKeyDown(Keys.S)) pos.Z += 1.0f;
if (CurrentKeyboardState.IsKeyDown(Keys.A)) pos.X -= 1.0f;
if (CurrentKeyboardState.IsKeyDown(Keys.D)) pos.X += 1.0f;
if (CurrentKeyboardState.IsKeyDown(Keys.LeftShift)) isWalking = true;
this.OldKeyboardState = CurrentKeyboardState;
if (pos != Vector3.Zero)
{
pos.Normalize(); //So we don't move faster diagonally
pos *= (float)gameTime.ElapsedGameTime.TotalSeconds * (isWalking ? this.WalkingSpeed : this.Speed); //Smooth movement
}
this.ProcessMouseInput(gameTime);
Matrix rotationMatrix = Matrix.CreateRotationX(this.AngleX) * Matrix.CreateRotationY(this.AngleY);
this.Position += (isWalking ? this.WalkingSpeed : this.Speed) * Vector3.Transform(pos, rotationMatrix);
this.UpdateView(rotationMatrix);
}
//Rotate the camera using the mouse.
private void ProcessMouseInput(GameTime gameTime)
{
float amount = (float)gameTime.ElapsedGameTime.TotalSeconds;
MouseState mouse = Mouse.GetState();
if (mouse != this.OldMouseState)
{
int xDist = mouse.X - (Game.GraphicsDevice.Viewport.Width / 2);
int yDist = mouse.Y - (Game.GraphicsDevice.Viewport.Height / 2);
this.AngleX -= RotationSpeed * xDist * amount;
this.AngleY -= RotationSpeed * yDist * amount;
}
Mouse.SetPosition(Game.GraphicsDevice.Viewport.Width / 2, Game.GraphicsDevice.Viewport.Height / 2);
this.OldMouseState = mouse;
}
//Return a matrix for use with rendering hands holding weapons.
public Matrix ModelWorldMatrix(float xOffset, float yOffset, float zOffset, float scale)
{
Vector3 ModelPos = this.Position;
ModelPos += this.Target * zOffset;
ModelPos += Vector3.UnitY * yOffset;
ModelPos += Vector3.UnitX * xOffset;
return Matrix.CreateScale(scale) * Matrix.CreateRotationX(MathHelper.ToRadians(this.AngleX)) * Matrix.CreateRotationY(MathHelper.ToRadians(this.AngleY)) * Matrix.CreateTranslation(ModelPos);
}
public override void Update(GameTime gameTime)
{
ProcessInput(gameTime);
this.Effects.View = View;
this.Effects.Projection = Projection;
this.Effects.World = Matrix.Identity;
base.Update(gameTime);
}
}
}
I've tried all sorts of sample code and followed all tutorials I could find but none of them have the same problems I have. They either don't work or they lag a ton!
Any ideas what I'm doing wrong?
You initialize this.Target to 0,0,0. This value never changes.
then later in your UpdateView method, you calculate finalTarget by transforming this.Target by a matrix representing a rotation only.
The result of
Vector3.Transform(this.Target, rotationMatrix) is essentially the same as
Vector3.Transform(Vector3.Zero, rotationMatrix).
Essentialy, that always results in (0,0,0) which should place finalTarget at the same position as this.Position except for floating point error that will give very small values to each component which factor in to cause your issue.
Try starting off by giving this.Target the value of 0,0,-1 (which causes the initial look direction to be the same as what your current code is trying to do, but gives the Vector3.Transform() something to work with) and you should be ok.
Related
Why does my camera when moving up or down (camera has a top view) move to the y coordinate?
Here is the code:
using UnityEngine;
public class ScrollWheelMove : MonoBehaviour
{
private bool DragMoveActive;
private Vector2 LastMousePos;
private void Update()
{
Vector3 inputDir = new Vector3(0, 0, 0);
float DragPanSpeed = 3f;
if (Input.GetMouseButtonDown(2))
{
DragMoveActive = true;
LastMousePos = Input.mousePosition;
}
if (Input.GetMouseButtonUp(2))
{
DragMoveActive = false;
}
if (DragMoveActive)
{
Vector2 mouseMovementDelta = (Vector2)Input.mousePosition - LastMousePos;
inputDir.x = mouseMovementDelta.x * DragPanSpeed;
inputDir.z = mouseMovementDelta.y * 6f;
LastMousePos = Input.mousePosition;
}
float moveSpeed = 3f;
Vector3 moveDir = -transform.right * inputDir.x + -transform.forward * inputDir.z;
transform.position += moveDir * moveSpeed * Time.deltaTime;
}
}
I want my camera to move only along the coordinates x and z.
I tried to change the code with coordinates, speed. I also tried to constantly set the coordinates y = 40
I´ve followed a youtube tutorial https://www.youtube.com/watch?v=c1FYp1oOFIs&list=PLD_vBJjpCwJtrHIW1SS5_BNRk6KZJZ7_d&index=4
and the problem is when i start the game my camera moves up when it shouldnt.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace BARR3TT
{
public class CameraHandler : MonoBehaviour
{
public Transform targetTransform;
public Transform cameraTransform;
public Transform cameraPivotTransform;
private Transform myTransform;
private Vector3 cameraTransformPosition;
private LayerMask ignoreLayers;
private Vector3 cameraFollowVelocity = Vector3.zero;
public static CameraHandler singleton;
public float lookSpeed = 0.1f;
public float followSpeed = 0.1f;
public float pivotSpeed = 0.03f;
private float targetPosition;
private float defaultPosition;
private float lookAngle;
private float pivotAngle;
public float minimumPivot = -35;
public float maximumPivot = 35;
private float cameraSphereRadius = 0.2f;
public float cameraColisionOffset = 0.2f;
public float minimumColisionOffset = 0.2f;
private void Awake()
{
singleton = this;
myTransform = transform;
defaultPosition = cameraTransform.localPosition.z;
ignoreLayers = ~(1 << 8 | 1 << 9 << 10);
}
public void FollowTarget(float delta)
{
Vector3 targetPosition = Vector3.SmoothDamp(myTransform.position, targetTransform.position, ref cameraFollowVelocity, delta / followSpeed);
myTransform.position = targetPosition;
HandleCameraCollision(delta);
}
public void HandleCameraRotation(float delta, float mouseXInput, float mouseYInput)
{
lookAngle += (mouseXInput * lookSpeed) / delta;
pivotAngle -= (mouseYInput * pivotSpeed) / delta;
pivotAngle = Mathf.Clamp(pivotAngle, minimumPivot, maximumPivot);
Vector3 rotation = Vector3.zero;
rotation.y = lookAngle;
Quaternion targetRotation = Quaternion.Euler(rotation);
myTransform.rotation = targetRotation;
rotation = Vector3.zero;
rotation.x = pivotAngle;
targetRotation = Quaternion.Euler(rotation);
cameraPivotTransform.localRotation = targetRotation;
}
private void HandleCameraCollision(float delta)
{
targetPosition = defaultPosition;
RaycastHit hit;
Vector3 direction = cameraTransform.position - cameraPivotTransform.position;
direction.Normalize();
if(Physics.SphereCast(cameraPivotTransform.position, cameraSphereRadius, direction, out hit ,Mathf.Abs(targetPosition)))
{
float dis = Vector3.Distance(cameraPivotTransform.position, hit.point);
targetPosition = -(dis - cameraColisionOffset);
}
if(Mathf.Abs(targetPosition)<minimumColisionOffset)
{
targetPosition = -minimumColisionOffset;
}
cameraTransformPosition.z = Mathf.Lerp(cameraTransform.localPosition.z, targetPosition, delta / 0.2f);
cameraTransform.localPosition = cameraTransformPosition;
}
}
}
Ive checked every line and i dont see any mistakes the transforms are where they should be, i can kinda fix it adding some rotation in the x axis on the main camera but its still weird
You need to check if your camera has been attached to any script or if it is a child inside some objects. I think it is where the error comes from.
If the Camera Holder or Camera Pivot changes its direction so the Main Camera will be changed too.
Your code is very complicated and it doesn't have any comments. So that is why people when seeing your code are lazy to see, analyze and answer for you.
If you just begin with coding and I recommend that you need to build a good foundation first and then go to some difficult tutorials like those you followed. Don't follow step-by-step tutorials.
I have GameObject with Scroll Rect and Rect Mask in my canvas and there is an image in it. I want to zoom in and zoom out of that image. However I don't want to scale Main Camera because there will be other objects in the screen that I don't want to zoom. I searched it but all the tutorials are doing that by scaling Main Camera.
This video is exactly what I want but it doesn't work in android. https://www.youtube.com/watch?v=BFX3FpUnoio&ab_channel=JasonWeimann
This is the script in that video which is added to "image". I tried to modify it but I messed it up. How can I make it work in mobile?
using UnityEngine;
using UnityEngine.EventSystems;
public class UIZoomImage : MonoBehaviour, IScrollHandler
{
private Vector3 initialScale;
[SerializeField]
private float zoomSpeed = 0.1f;
[SerializeField]
private float maxZoom = 10f;
private void Awake()
{
initialScale = transform.localScale;
}
public void OnScroll(PointerEventData eventData)
{
var delta = Vector3.one * (eventData.scrollDelta.y * zoomSpeed);
var desiredScale = transform.localScale + delta;
desiredScale = ClampDesiredScale(desiredScale);
transform.localScale = desiredScale;
}
private Vector3 ClampDesiredScale(Vector3 desiredScale)
{
desiredScale = Vector3.Max(initialScale, desiredScale);
desiredScale = Vector3.Min(initialScale * maxZoom, desiredScale);
return desiredScale;
}
}
-------UPDATE---------
I found this in Unity forum: https://answers.unity.com/questions/1280592/pinch-and-zoom-functionality-on-canvas-ui-images.html
It almost works but I need to pinch the screen 2-3 to zoom in or zoom out. On first touch nothing happens. It's so annoying. I tried to change _minZoom, _maxZoom, speed and sensitivity values but didn't work.
This is the script there:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class PinchableScrollRect : ScrollRect
{
[SerializeField] float _minZoom = .1f;
[SerializeField] float _maxZoom = 10;
[SerializeField] float _zoomLerpSpeed = 10f;
float _currentZoom = 1;
bool _isPinching = false;
float _startPinchDist;
float _startPinchZoom;
Vector2 _startPinchCenterPosition;
Vector2 _startPinchScreenPosition;
float _mouseWheelSensitivity = 1;
bool blockPan = false;
protected override void Awake()
{
Input.multiTouchEnabled = true;
}
private void Update()
{
if (Input.touchCount == 2)
{
if (!_isPinching)
{
_isPinching = true;
OnPinchStart();
}
OnPinch();
}
else
{
_isPinching = false;
if (Input.touchCount == 0)
{
blockPan = false;
}
}
//pc input
float scrollWheelInput = Input.GetAxis("Mouse ScrollWheel");
if (Mathf.Abs(scrollWheelInput) > float.Epsilon)
{
_currentZoom *= 1 + scrollWheelInput * _mouseWheelSensitivity;
_currentZoom = Mathf.Clamp(_currentZoom, _minZoom, _maxZoom);
_startPinchScreenPosition = (Vector2)Input.mousePosition;
RectTransformUtility.ScreenPointToLocalPointInRectangle(content, _startPinchScreenPosition, null, out _startPinchCenterPosition);
Vector2 pivotPosition = new Vector3(content.pivot.x * content.rect.size.x, content.pivot.y * content.rect.size.y);
Vector2 posFromBottomLeft = pivotPosition + _startPinchCenterPosition;
SetPivot(content, new Vector2(posFromBottomLeft.x / content.rect.width, posFromBottomLeft.y / content.rect.height));
}
//pc input end
if (Mathf.Abs(content.localScale.x - _currentZoom) > 0.001f)
content.localScale = Vector3.Lerp(content.localScale, Vector3.one * _currentZoom, _zoomLerpSpeed * Time.deltaTime);
}
protected override void SetContentAnchoredPosition(Vector2 position)
{
if (_isPinching || blockPan) return;
base.SetContentAnchoredPosition(position);
}
void OnPinchStart()
{
Vector2 pos1 = Input.touches[0].position;
Vector2 pos2 = Input.touches[1].position;
_startPinchDist = Distance(pos1, pos2) * content.localScale.x;
_startPinchZoom = _currentZoom;
_startPinchScreenPosition = (pos1 + pos2) / 2;
RectTransformUtility.ScreenPointToLocalPointInRectangle(content, _startPinchScreenPosition, null, out _startPinchCenterPosition);
Vector2 pivotPosition = new Vector3(content.pivot.x * content.rect.size.x, content.pivot.y * content.rect.size.y);
Vector2 posFromBottomLeft = pivotPosition + _startPinchCenterPosition;
SetPivot(content, new Vector2(posFromBottomLeft.x / content.rect.width, posFromBottomLeft.y / content.rect.height));
blockPan = true;
}
void OnPinch()
{
float currentPinchDist = Distance(Input.touches[0].position, Input.touches[1].position) * content.localScale.x;
_currentZoom = (currentPinchDist / _startPinchDist) * _startPinchZoom;
_currentZoom = Mathf.Clamp(_currentZoom, _minZoom, _maxZoom);
}
float Distance(Vector2 pos1, Vector2 pos2)
{
RectTransformUtility.ScreenPointToLocalPointInRectangle(content, pos1, null, out pos1);
RectTransformUtility.ScreenPointToLocalPointInRectangle(content, pos2, null, out pos2);
return Vector2.Distance(pos1, pos2);
}
static void SetPivot(RectTransform rectTransform, Vector2 pivot)
{
if (rectTransform == null) return;
Vector2 size = rectTransform.rect.size;
Vector2 deltaPivot = rectTransform.pivot - pivot;
Vector3 deltaPosition = new Vector3(deltaPivot.x * size.x, deltaPivot.y * size.y) * rectTransform.localScale.x;
rectTransform.pivot = pivot;
rectTransform.localPosition -= deltaPosition;
}
}
This script does the trick if the camera projection is set to ortho. From this
source.
using UnityEngine;
public class Zoom : MonoBehaviour {
public float zoomSpeed = 1;
public float targetOrtho;
public float smoothSpeed = 2.0f;
public float minOrtho = 1.0f;
public float maxOrtho = 20.0f;
void Start() {
targetOrtho = Camera.main.orthographicSize;
}
void Update () {
float scroll = Input.GetAxis ("Mouse ScrollWheel");
if (scroll != 0.0f) {
targetOrtho -= scroll * zoomSpeed;
targetOrtho = Mathf.Clamp (targetOrtho, minOrtho, maxOrtho);
}
Camera.main.orthographicSize = Mathf.MoveTowards (Camera.main.orthographicSize, targetOrtho, smoothSpeed * Time.deltaTime);
}
}
Why don't you scale the Image?!
I am trying to build a trajectory arc that would predict the trajectory path of the object, the drag and shoot seem fine but the arc is not working. initially I used an arrow for showing the direction of the movement of the object but later I tried to do the same using an array which would store 2 points and would keep updating after every iteration and it would result in an arc since I used the equations of motion to predict the positions after each frame.
***
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class movement: MonoBehaviour
{
public float velocity;
float time;
float x;
float y;
float tt;
float g;
Vector2 force;
public float power = 2.0f;
Vector3 startpoint;
Vector3 endpoint;
Camera cam;
public Vector2 maxpower;
public Vector2 minpower;
public Rigidbody2D rb;
Vector3 currentposition;
Vector3 sp;
LineRenderer lr;
int resolution = 10;
Vector3 newpoint;
// Start is called before the first frame update
void Start()
{
time = 0f;
g = Mathf.Abs(Physics2D.gravity.y);
cam = Camera.main;
lr = GetComponent<LineRenderer>();
}
// Update is called once per frame
void Update()
{
time += Time.deltaTime;
x = gameObject.transform.position.x + velocity * time;
tt = time * time;
y = gameObject.transform.position.y + (g * tt) / 2f;
if(Input.GetMouseButtonDown(0))
{
startpoint = cam.ScreenToWorldPoint(Input.mousePosition);
startpoint.z = 5;
}
if(Input.GetMouseButton(0))
{
sp = new Vector3(gameObject.transform.position.x, gameObject.transform.position.y, 5);
currentposition = cam.ScreenToWorldPoint(Input.mousePosition);
currentposition.z = 5;
LineRenderer(sp);
}
if (Input.GetMouseButtonUp(0))
{
endpoint = cam.ScreenToWorldPoint(Input.mousePosition);
endpoint.z = 5;
force = new Vector2(Mathf.Clamp(startpoint.x - endpoint.x, minpower.x, maxpower.x), Mathf.Clamp(startpoint.y - endpoint.y, minpower.y, maxpower.y));
rb.AddForce(force * power, ForceMode2D.Impulse);
x = x + velocity * time;
y = y + (g * tt) / 2f;
EndLine();
}
}
public void LineRenderer(Vector3 p)
{
lr.positionCount = resolution;
Vector3 arc = p;
for(int i=0;i<resolution;i++)
{
newpoint = calculate(arc, i / (float)resolution);
lr.SetPosition(i, newpoint);
arc = newpoint;
}
}
public Vector3 calculate(Vector3 point, float t)
{
point.x += velocity * t;
point.y += 0.5f * g * t * t;
return point;
}
public void EndLine()
{
lr.positionCount = 0;
}
}
***
This the code, any help is appreciated.
A bug that I see is your delta-time:
You call Calculate(arc, i/resolution), with i and resolution both being integers.
The parameter might be float time, but C# will first calculate i/resolution as an integer division, then convert the result to float. The result will be zero as long as i is less than resolution.
Change it to: i/(float)resolution to force a floating-point division.
I have a problem with camera movement using joystick in Unity. I wrote this code to my joystick
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.EventSystems;
public class VirtualJoystick : MonoBehaviour, IDragHandler, IPointerUpHandler, IPointerDownHandler {
private Image bgImg;
private Image joystickImg;
private Vector2 pos;
private void Start()
{
bgImg = GetComponent<Image>();
joystickImg = transform.GetChild(0).GetComponent<Image>();
}
public virtual void OnDrag(PointerEventData ped)
{
Vector2 pos;
if (RectTransformUtility.ScreenPointToLocalPointInRectangle(bgImg.rectTransform, ped.position, ped.pressEventCamera, out pos))
{
pos.x = (pos.x * 2 + 1) / bgImg.rectTransform.sizeDelta.x;
pos.y = (pos.y * 2 - 1) / bgImg.rectTransform.sizeDelta.y;
pos = (pos.magnitude > 1.0f) ? pos.normalized : pos;
// Move Joystrick IMG
joystickImg.rectTransform.anchoredPosition = new Vector2(pos.x * (bgImg.rectTransform.sizeDelta.x / 3), pos.y * (bgImg.rectTransform.sizeDelta.y / 3));
}
}
public virtual void OnPointerDown(PointerEventData ped)
{
OnDrag(ped);
}
public virtual void OnPointerUp(PointerEventData ped)
{
pos = Vector2.zero;
joystickImg.rectTransform.anchoredPosition = Vector2.zero;
}
public float Horizontal()
{
if (pos.x != 0)
{
return pos.x;
}
else
{
return Input.GetAxis("Horizontal");
}
}
public float Vertical()
{
if (pos.y != 0)
{
return pos.y;
}
else
{
return Input.GetAxis("Vertical");
}
}
}
This code works well and return dynamicly Vector2(x,y). So, now I want to move camera (change position X,Y) using this joystick and these coordinates. Do you have any idea how to do it? Everyones show how to move cube or sphere and nowhere how to translate a camera...
Camera behave like any other game object in the scene
you translate , rotate , scale (will not be shown )
cause it is have Transform component .
This can be easily be done with the Translate function
Camera.main.transform.Translate(pos, Space.World);
You need to also multiply it a number(speed) and Time.deltaTime to make sure the movement is the-same on every devices.
So, this is how the code should look like:
private Vector2 pos;
public float moveSpeed = 100f;
Then, in your OnDrag or Update function:
Vector3 newPos = new Vector3(pos.x * moveSpeed, pos.y * moveSpeed, 0);
newPos *= Time.deltaTime;
Camera.main.transform.Translate(newPos, Space.World);