restrict camera movement, Camera moves out of bounds - unity3d

I'm creating a simple camera pan and scroll for my mobile game and need some help.
Right now with the code I have a player can scroll of the map I created.
I got the code from this youtube video (for context) https://gist.github.com/ditzel/836bb36d7f70e2aec2dd87ebe1ede432
https://www.youtube.com/watch?v=KkYco_7-ULA&ab_channel=DitzelGames
Do you know how I could fix this?
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class ScrollAndPinch : MonoBehaviour
{
#if UNITY_IOS || UNITY_ANDROID
public Camera Camera;
public bool Rotate;
protected Plane Plane;
public Transform Map;
float distance;
private void Awake()
{
if (Camera == null)
Camera = Camera.main;
Input.multiTouchEnabled = true;
}
private void Update()
{
//Update Plane
if (Input.touchCount >= 1)
Plane.SetNormalAndPosition(transform.up, transform.position);
var Delta1 = Vector3.zero;
var Delta2 = Vector3.zero;
//Scroll
if (Input.touchCount >= 1)
{
Delta1 = PlanePositionDelta(Input.GetTouch(0));
if (Input.GetTouch(0).phase == TouchPhase.Moved)
Camera.transform.Translate(Delta1, Space.World);
}
}
protected Vector3 PlanePositionDelta(Touch touch)
{
//not moved
if (touch.phase != TouchPhase.Moved)
return Vector3.zero;
//delta
var rayBefore = Camera.ScreenPointToRay(touch.position - touch.deltaPosition);
var rayNow = Camera.ScreenPointToRay(touch.position);
if (Plane.Raycast(rayBefore, out var enterBefore) && Plane.Raycast(rayNow, out var enterNow))
return rayBefore.GetPoint(enterBefore) - rayNow.GetPoint(enterNow);
//not on plane
return Vector3.zero;
}
protected Vector3 PlanePosition(Vector2 screenPos)
{
//position
var rayNow = Camera.ScreenPointToRay(screenPos);
if (Plane.Raycast(rayNow, out var enterNow))
return rayNow.GetPoint(enterNow);
return Vector3.zero;
}
#endif
}

You can put in the update a control with the bounds of your area with a bool like this :
if(Camera.transform.position.x > valuexmax || Camera.transform.position.x < valuexmin
|| Camera.transform.position.y > valueymax || Camera.transform.position.y < valueymin)
{
InBounds = false; //just a bool variable set to true in start
}
And then you can put in the scroll something like this
if (Input.touchCount >= 1 && InBounds == true)
{
Delta1 = PlanePositionDelta(Input.GetTouch(0));
if (Input.GetTouch(0).phase == TouchPhase.Moved)
Camera.transform.Translate(Delta1, Space.World);
}
if(InBounds == false)
{
// reset position
}

Related

Unity 2D UI element direction changes according to its game object direction

So I've added a health bar below the main player, following a tutorial. I had a canvas with render mode set to "World Space". I added the UI elements for the healthbar to the canvas. Then I made the canvas a child of the player Mario. Now the healthbar follows the player. The problem is that whenever Mario changes direction on the x axis his sprite changes direction but also does the healthbar, because in Mario's script the localscale changes according to the direction of the player . Any ideas?
Mario's script:
public class MarioMove : MonoBehaviour
{
private Rigidbody2D rb;
private Animator anim;
private float moveSpeed;
private float dirX;
private bool facingRight = true;
private Vector3 localScale;
private bool doubleJumped;
[SerializeField] HealthBar healthbar;
private void Start()
{
rb = GetComponent<Rigidbody2D>();
anim = GetComponent<Animator>();
localScale = transform.localScale;
moveSpeed = 5f;
}
private void Update()
{
if (Input.GetKeyDown(KeyCode.DownArrow)) {
PlayerTakeDamage(20);
}
if (Input.GetKeyDown(KeyCode.UpArrow))
{
PlayerHeal(20);
}
dirX = Input.GetAxisRaw("Horizontal") * moveSpeed;
if (Input.GetButtonDown("Jump") && rb.velocity.y == 0)
rb.AddForce(Vector2.up * 400f);
if (Mathf.Abs(dirX) > 0 && rb.velocity.y == 0)
anim.SetBool("isRunning", true);
else
anim.SetBool("isRunning", false);
if (rb.velocity.y == 0)
{
anim.SetBool("isJumping", false);
anim.SetBool("isFalling", false);
doubleJumped = false;
}
if (rb.velocity.y > 0 && !doubleJumped)
{
if (Input.GetButtonDown("Jump")){
anim.SetBool("isDoubleJumping", true);
rb.AddForce(Vector2.up * 100f);
anim.SetBool("isJumping", false);
doubleJumped = true;
}
else anim.SetBool("isJumping", true);
}
if (rb.velocity.y > 0 && doubleJumped)
{
anim.SetBool("isDoubleJumping", true);
}
if (rb.velocity.y < 0)
{
if (Input.GetButtonDown("Jump") && !doubleJumped)
{
anim.SetBool("isDoubleJumping", true);
rb.velocity = Vector2.zero;
rb.AddForce(Vector2.up * 200f);
anim.SetBool("isFalling", false);
doubleJumped = true;
}
else {
anim.SetBool("isJumping", false);
anim.SetBool("isDoubleJumping", false);
anim.SetBool("isFalling", true);
}
}
}
private void FixedUpdate()
{
rb.velocity = new Vector2(dirX, rb.velocity.y);
}
private void LateUpdate()
{
if (dirX > 0)
facingRight = true;
else if(dirX < 0)
facingRight = false;
if (((facingRight) && (localScale.x < 0)) || ((!facingRight) && (localScale.x > 0)))
localScale.x *= -1;
transform.localScale = localScale;
}
private void PlayerTakeDamage(int damage)
{
GameManager.gameManager.playerHealth.DamageUnit(10);
healthbar.SetHealth(GameManager.gameManager.playerHealth.Health);
}
private void PlayerHeal(int healing)
{
GameManager.gameManager.playerHealth.HealUnit(10);
healthbar.SetHealth(GameManager.gameManager.playerHealth.Health);
}
}
I solved by making the scaling of the UI independent of the scaling of the Mario object (made the mario and u elements different children of a game object and applied different transformations to them that are independent to each other).

Having two variables that both flip the same sprite renderer in Unity

I'm trying to flip a sprite in a 3D environment. It should flip depending on the camera angle (the camera can rotate) and it should also flip depending on walking direction.
I have this script which have two variables (lastPosition to track when it moves and fyRot is camera position) that I can't get to work at the same time. If I remove the other one, they both work. But if I both have them together, only the fyRot seem to flip the sprite.
Would really appreciate any help with this, I'm quite new to coding!
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class flippety_flippety : MonoBehaviour
{
[SerializeField] SpriteRenderer spriteRenderer;
public static bool flipX;
Vector3 lastPos;
public Transform obj; // drag the object to monitor here
public float threshold = 1.0f; // minimum displacement to recognize a
void Start()
{
SpriteRenderer spriteRenderer = GetComponent<SpriteRenderer>();
lastPos = obj.position;
}
void Update()
{
float fYRot = Camera.main.transform.eulerAngles.y;
Vector3 offset = obj.position - lastPos;
if (offset.z > threshold)
// code to execute when Z is increased
{
// update lastPos
lastPos = obj.position;
if (flipX == false)
{
spriteRenderer.flipX = true;
Debug.Log("TestingTrue");
}
else if (flipX == true)
{
spriteRenderer.flipX = false;
Debug.Log("TestingFalse");
}
}
// code to execute when Z is getting smaller
else
if (offset.z < -threshold)
{
// update lastPos
lastPos = obj.position;
if (flipX == false)
{
spriteRenderer.flipX = true;
Debug.Log("TestingTrue2");
} else if(flipX == true)
{
spriteRenderer.flipX = false;
Debug.Log("TestingFalse2");
}
}
if (fYRot >= 180)
{
Debug.Log("TESTING");
spriteRenderer.flipX = false;
}
else if (fYRot >= -180)
{
Debug.Log("TESTING2");
spriteRenderer.flipX = true;
}
}
}

Unity3D. C#. Can can i add max and min values to zoom in this code?

In the 3D project I have script and i can rotate/move in the scene without doubts, but i have problem with Zoom, i can do this too close and soo far. I zoom it right to the floor or to far away to sky and i stack then. I use perspective camera.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
class ScrollAndPinch : MonoBehaviour
{
public Camera Camera;
public bool Rotate;
protected Plane Plane;
private void Awake()
{
if (Camera == null)
Camera = Camera.main;
}
private void Update()
{
//Update Plane
if (Input.touchCount >= 1)
Plane.SetNormalAndPosition(transform.up, transform.position);
var Delta1 = Vector3.zero;
var Delta2 = Vector3.zero;
//Scroll
if (Input.touchCount >= 1)
{
Delta1 = PlanePositionDelta(Input.GetTouch(0));
if (Input.GetTouch(0).phase == TouchPhase.Moved)
Camera.transform.Translate(Delta1, Space.World);
}
//Pinch
if (Input.touchCount >= 2)
{
var pos1 = PlanePosition(Input.GetTouch(0).position);
var pos2 = PlanePosition(Input.GetTouch(1).position);
var pos1b = PlanePosition(Input.GetTouch(0).position - Input.GetTouch(0).deltaPosition);
var pos2b = PlanePosition(Input.GetTouch(1).position - Input.GetTouch(1).deltaPosition);
//calc zoom
var zoom = Vector3.Distance(pos1, pos2) /
Vector3.Distance(pos1b, pos2b);
//edge case
if (zoom == 9 || zoom > 10)
return;
//Move cam amount the mid ray
Camera.transform.position = Vector3.LerpUnclamped(pos1, Camera.transform.position, 1 / zoom);
if (Rotate && pos2b != pos2)
Camera.transform.RotateAround(pos1, Plane.normal, Vector3.SignedAngle(pos2 - pos1, pos2b - pos1b, Plane.normal));
}
}
protected Vector3 PlanePositionDelta(Touch touch)
{
//not moved
if (touch.phase != TouchPhase.Moved)
return Vector3.zero;
//delta
var rayBefore = Camera.ScreenPointToRay(touch.position - touch.deltaPosition);
var rayNow = Camera.ScreenPointToRay(touch.position);
if (Plane.Raycast(rayBefore, out var enterBefore) && Plane.Raycast(rayNow, out var enterNow))
return rayBefore.GetPoint(enterBefore) - rayNow.GetPoint(enterNow);
//not on plane
return Vector3.zero;
}
protected Vector3 PlanePosition(Vector2 screenPos)
{
//position
var rayNow = Camera.ScreenPointToRay(screenPos);
if (Plane.Raycast(rayNow, out var enterNow))
return rayNow.GetPoint(enterNow);
return Vector3.zero;
}
private void OnDrawGizmos()
{
Gizmos.DrawLine(transform.position, transform.position + transform.up);
}
}
Sorry for noob question, i've recently started to my journey in unity3D.
How can i set the limits here?
If you mean you want to limit the zoom within a single pinch operation you could probably do e.g.
// Configure these in the Inspector
[SerializeField] private float minZoom = 0.1f;
[SerializeField] private float maxZoom = 10f;
...
var zoom = Vector3.Distance(pos1, pos2) / Vector3.Distance(pos1b, pos2b);
zoom = Mathf.Clamp(minZoom, maxZoom);
...
If you ment you rather want to limit the overall combined zoom you'll have to store and combine the zoom amounts like e.g.
private float finalZoom = 1;
...
var zoom = Vector3.Distance(pos1, pos2) / Vector3.Distance(pos1b, pos2b);
finalZoom *= zoom;
finalZoom = Mathf.Clamp(minZoom, maxZoom);
// And from here use finalZoom instead of zoom
Camera.transform.position = Vector3.LerpUnclamped(pos1, Camera.transform.position, 1 / finalZoom);
...
The answer is to use https://docs.unity3d.com/ScriptReference/Mathf.Clamp.html
Mathf.Clamp(xValue, xMin, xMax);

Detecting touch on a specific object in Unity

working on an android game in Unity 2D. Long story short, I have two separate objects in the scene which have this script attached on:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class SwipeScript : MonoBehaviour
{
Vector2 startPos, endPos, direction;
float touchTimeStart, touchTimeFinish, timeInterval;
public static int brojbacanja=0;
public static bool bacenaprva = false;
[Range (0.05f, 1f)]
public float throwForce = 0.3f;
void Update(){
if (Input.touchCount > 0 && Input.GetTouch (0).phase == TouchPhase.Began && brojbacanja == 0) {
touchTimeStart = Time.time;
startPos = Input.GetTouch (0).position;
}
if (Input.touchCount > 0 && Input.GetTouch (0).phase == TouchPhase.Ended && brojbacanja == 0) {
touchTimeFinish = Time.time;
timeInterval = touchTimeFinish - touchTimeStart;
endPos = Input.GetTouch (0).position;
direction = startPos - endPos;
GetComponent<Rigidbody2D> ().AddForce (-direction / timeInterval * throwForce);
brojbacanja = 1;
bacenaprva = true;
}
}
}
What this does is pretty much alowing me to swipe anywhere on the screen and throw an object which it's attached to. Since I have two different objects which I would like to throw separately, I want to change it a bit so when I touch object which I want to throw, other one stays still. I read about this problem alredy and tried using Raycast and OnMouseDown() but didn't know how to implement it.
If anyone can help, would be grateful.
Since this script will be on each object in the scene you will need to have an extra variable and a check to see if the initial touch is intersecting your object.
If you are using 3D objects (which I am assuming because you mentioned ray tracing), then you will want something that converts the touch position on the screen to a ray, that you then cast to see if it intersects your object. Your object will have to have collision for this to work.
public class SwipeScript : MonoBehaviour
{
// added these two values, set the coll value to your collider on this object.
bool isTouching;
public Collider coll;
Vector2 startPos, endPos, direction;
float touchTimeStart, touchTimeFinish, timeInterval;
public static int brojbacanja=0;
public static bool bacenaprva = false;
[Range (0.05f, 1f)]
public float throwForce = 0.3f;
void Update(){
if (Input.touchCount > 0 && Input.GetTouch (0).phase == TouchPhase.Began && brojbacanja == 0) {
if(IsTouchOverThisObject(Input.GetTouch(0))) {
isTouching = true;
touchTimeStart = Time.time;
startPos = Input.GetTouch (0).position;
}
}
if (isTouching && Input.touchCount > 0 && Input.GetTouch (0).phase == TouchPhase.Ended && brojbacanja == 0) {
isTouching = false;
touchTimeFinish = Time.time;
timeInterval = touchTimeFinish - touchTimeStart;
endPos = Input.GetTouch (0).position;
direction = startPos - endPos;
GetComponent<Rigidbody2D> ().AddForce (-direction / timeInterval * throwForce);
brojbacanja = 1;
bacenaprva = true;
}
}
bool IsTouchOverThisObject(Touch touch) {
Ray ray = Camera.main.ScreenPointToRay(new Vector3(touch.position.x, touch.position.y, 0));
RaycastHit hit;
// you may need to adjust the max distance paramter here based on your
// scene size/scale.
return coll.Raycast(ray, out hit, 1000.0f);
}
}

How to convert keyboard controls to touch screen in Unity

Complete newbie here. Using Unity C#. I'm looking at moving my PONG game from keyboard control to touch screen. Here is my working keyboard code:
// Player 1 => Controls left bat with W/S keys
public GameObject leftBat;
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update () {
//Defualt speed of the bat to zero on every frame
leftBat.GetComponent<Rigidbody>().velocity = new Vector3(0f, 0f, 0f);
//If the player is pressing the W key...
if (Input.GetKey (KeyCode.W)) {
//Set the velocity to go up 1
leftBat.GetComponent<Rigidbody>().velocity = new Vector3(0f, 8f, 0f);
}
//If the player is pressing the S key...
else if (Input.GetKey (KeyCode.S)) {
//Set the velocity to go down 1 (up -1)
leftBat.GetComponent<Rigidbody>().velocity = new Vector3(0f, -8f, 0f);
}
}
I found this code and been playing around with it but to now avail.
using UnityEngine;
using System.Collections;
public class Player_Input_Controller : MonoBehaviour {
public GameObject leftBat;
public float paddleSpeed = 1f;
public float yU;
public float yD;
private Ray ray;
private RaycastHit rayCastHit;
private Vector3 playerPos = new Vector3(0, -9.5f, 0);
// Update is called once per frame
void Update () {
if (Input.GetMouseButton (0))
{
ray = Camera.main.ScreenPointToRay(Input.mousePosition);
if(Physics.Raycast(ray, out rayCastHit)){
Vector3 position = rayCastHit.point;
float yPos = position.y;
playerPos = new Vector3(Mathf.Clamp(yPos, yU, yD), -9.5f, 0f);
transform.position = playerPos;
}
}
}
}
Any one have a touchscreen Pong script I could use, or know how to edit this one?
Again, I'm really new and I'm sorry if I look like the Dummy in the class.
Thanks for any help provided. I REALLY appreciate it. This is the last hurdle in completing my game.
In my opinion, you do not need any raycasting. Because you are working in 2D and you are only concerned about the y value of Input.mousePosition. Therefore, you can calculate the extent of your screen using your camera's z value. If your camera is at (0, 0, -10) lets say your extents in the game will be -5 - BatOffset to 5+BatOffset in your world coordinates. Therefore, you somehow need a function to map Screen.height to your world coordinate extents as you can see from the image.
In conclusion you need to find Input.mousePosition.y divide it to Screen.height. This will give you the ratio where you touch or click. Then find the position in world space.
Note that: you can also use Input.touchPosition.y. Following script will work for you to do this operation:
public GameObject cam;
private Vector3 batPos;
private float minY;
private float maxY;
private int Res;
private float deltaY;
void Start () {
minY = cam.transform.position.z / 2 - gameObject.transform.localScale.y;
maxY = (-cam.transform.position.z / 2) + gameObject.transform.localScale.y;
deltaY = maxY - minY;
Debug.Log(minY + " " + maxY + " " + deltaY);
Res = Screen.height;
batPos = gameObject.transform.position;
}
void Update () {
if(Input.GetMouseButtonDown(0))
{
// we find the height we have to go up from minY
batPos.y =minY + Input.mousePosition.y / Res * deltaY;
gameObject.transform.position = batPos;
}
}
This works for me in the editor when you click on screen with mouse. You just have to change the parts Input.GetMouseButtonDown to Touch commands such as Touch.tapCount > 0. Also this script should be attached to the bat. Good luck!
Also You can use Orthographic camera and Orthographic camera size instead of cam.transformation.z
May be helpfull
create script. for example player.cs
public class PlayerController : MonoBehaviour
{
bool swipeRight = false;
bool swipeLeft = false;
bool touchBlock = true;
bool canTouchRight = true;
bool canTouchLeft = true;
void Update()
{
swipeLeft = Input.GetKeyDown("a") || Input.GetKeyDown(KeyCode.LeftArrow);
swipeRight = Input.GetKeyDown("d") || Input.GetKeyDown(KeyCode.RightArrow);
TouchControl();
if(swipeRight) //rightMove logic
else if(swipeLeft) //leftMove logic
}
void TouchControl()
{
if(Input.touchCount == 1 && Input.GetTouch(0).phase == TouchPhase.Began )
{
//Jump logic
}
else if (Input.touchCount > 0 && Input.GetTouch(0).phase == TouchPhase.Moved && touchBlock == true)
{
touchBlock = false;
// Get movement of the finger since last frame
var touchDeltaPosition = Input.GetTouch(0).deltaPosition;
Debug.Log("touchDeltaPosition "+touchDeltaPosition);
if(touchDeltaPosition.x > 0 && canTouchRight == true)
{
//rightMove
swipeRight = true; canTouchRight = false;
Invoke("DisableSwipeRight",0.2f);
}
else if(touchDeltaPosition.x < 0 && canTouchLeft == true)
{
//leftMove
swipeLeft = true; canTouchLeft = false;
Invoke("DisableSwipeLeft",0.2f);
}
}
}
void DisableSwipeLeft()
{
swipeLeft = false;
touchBlock = true;
canTouchLeft = true;
}
void DisableSwipeRight()
{
swipeRight = false;
touchBlock = true;
canTouchRight = true;
}
}