So,been asking and google-ing for a massive ammount of time… ugh.
Basically,I have a sprite (a submarine…) and I want to move it on all directions without going off-screen.
I have this code that helps me a lot. I managed to move the sprite all by myself (ye,so proud),but I’ve got a code from somewhere else to keep that sprite inside the camera’s boundaries.
It works,sort of… half of the sprite HAS to go off-screen to stop going off-screen. And I seriously have no idea what to do. (I’m still learning if it wasn’t CLEAR ENOUGH)
Here’s that code I’m using:
using UnityEngine;
using System.Collections;
public class PlayerMovement : MonoBehaviour {
public Camera cam;
float maxSpeed = 6.5f;
float widthRel = 1 / (Screen.width); //relative width
float heightRel= 1 /(Screen.height); //relative height
void Start () {
if (cam == null) {
cam = Camera.main;
}
}
void Update () {
//KEEP the sprite on the camera's boundaries.
Vector3 viewPos = Camera.main.WorldToViewportPoint (this.transform.position);
viewPos.x = Mathf.Clamp(viewPos.x, widthRel, 1-widthRel);
viewPos.y = Mathf.Clamp(viewPos.y, heightRel, 1-heightRel);
this.transform.position = Camera.main.ViewportToWorldPoint (viewPos);
//MOVE the ship.
Vector3 pos = transform.position;
pos.y += Input.GetAxis("Vertical") * maxSpeed * Time.deltaTime;
pos.x += Input.GetAxis("Horizontal") * maxSpeed * Time.deltaTime;
transform.position = pos;
}
}
One way to make sure that the whole sprite stays inside the boundaries is to separately check the edges.
On the left edge, you will compare the edge to the sprite position, minus the half-width of the sprite.
On the right edge, you will add the half width to the position.
Top and bottom are the same but with half-height.
Definetly,I need to learn how to program properly… xd
halfWidth and Height are never used (obviously.) BTW,do I paste that code on the SAME ONE I’m using (and posted before),or should I make another script? D;
Just a warning, this may or may not be a great way to do things in terms of efficiency. Also, I haven’t tested this.
private Vector2 leftBottom;
private Vector2 rightTop;
private SpriteRenderer spriteRenderer;
private Vector2 spriteSize;
private Vector2 spriteHalfSize;
private void Start()
{
// get the world location of the bottom left corner and top right corner of camera
// if your camera moves, this will have to be in Update or LateUpdate
leftBottom = Camera.main.ViewportToWorldPoint(Vector3.zero);
rightTop = Camera.main.ViewportToWorldPoint(Vector3.one);
spriteRenderer = GetComponent<SpriteRenderer>();
spriteSize = spriteRenderer.sprite.bounds.size;
spriteHalfSize = spriteRenderer.sprite.bounds.extents;
}
// do your normal movement in Update, then LateUpdate will correct the position before rendering
private void LateUpdate()
{
// get the sprite's edge positions
float spriteLeft = transform.position.x - spriteHalfSize.x;
float spriteRight = transform.position.x + spriteHalfSize.x;
float spriteBottom = transform.position.y - spriteHalfSize.y;
float spriteTop = transform.position.y + spriteHalfSize.y;
// initialize the new position to the current position
Vector3 clampedPosition = transform.position;
// if any of the edges surpass the camera's bounds,
// set the position TO the camera bounds (accounting for sprite's size)
if(spriteLeft < leftBottom.x)
{
clampedPosition.x = leftBottom.x + spriteHalfSize.x;
}
else if(spriteRight > rightTop.x)
{
clampedPosition.x = rightTop.x - spriteHalfSize.x;
}
if(spriteTop < leftBottom.y)
{
clampedPosition.y = leftBottom.y + spriteHalfSize.y;
}
else if(spriteTop > rightTop.y)
{
clampedPosition.y = rightTop.y - spriteHalfSize.y;
}
transform.position = clampedPosition;
}
Let me know if this works/doesn’t work, or if you want me to explain any parts.
“halfWidth,Height and spritebottom are assigned but its value is never used”
A random question that might solve some things: do I have to 100% COPY-PASTE the code,or do I HAVE to change some words (FOR EXAMPLE,this.Camera.camera) and change that camera for the name I assigned?
Don’t know if it’s clear enough… and sorry for bothering you with something so simple,I’m sure. xd
EDIT: The sprite starts in the middle of the camera,instead of the position I assigned. And also it doesn’t move. Probably because I posted the code in a wrong place. :V
The Camera class always keeps a reference to your main camera. So from anywhere you can do Camera.main and you’ll have the camera.
Here’s your class with my code pasted in the right places. It’s in your best interest to fully understand what is happening on each line, so feel free to ask more questions.
using UnityEngine;
using System.Collections;
public class PlayerMovement : MonoBehaviour
{
public float maxSpeed = 6.5f;
private Vector2 leftBottom;
private Vector2 rightTop;
private SpriteRenderer spriteRenderer;
private Vector2 spriteSize;
private Vector2 spriteHalfSize;
private void Start()
{
// get the world location of the bottom left corner and top right corner of camera
// if your camera moves, this will have to be in Update or LateUpdate
leftBottom = Camera.main.ViewportToWorldPoint(Vector3.zero);
rightTop = Camera.main.ViewportToWorldPoint(Vector3.one);
spriteRenderer = GetComponent<SpriteRenderer>();
spriteSize = spriteRenderer.sprite.bounds.size;
spriteHalfSize = spriteRenderer.sprite.bounds.extents;
}
void Update()
{
//MOVE the ship.
Vector3 pos = transform.position;
pos.y += Input.GetAxis("Vertical") * maxSpeed * Time.deltaTime;
pos.x += Input.GetAxis("Horizontal") * maxSpeed * Time.deltaTime;
transform.position = pos;
}
private void LateUpdate()
{
// get the sprite's edge positions
float spriteLeft = transform.position.x - spriteHalfSize.x;
float spriteRight = transform.position.x + spriteHalfSize.x;
float spriteBottom = transform.position.y - spriteHalfSize.y;
float spriteTop = transform.position.y + spriteHalfSize.y;
// initialize the new position to the current position
Vector3 clampedPosition = transform.position;
// if any of the edges surpass the camera's bounds,
// set the position TO the camera bounds (accounting for sprite's size)
if(spriteLeft < leftBottom.x)
{
clampedPosition.x = leftBottom.x + spriteHalfSize.x;
}
else if(spriteRight > rightTop.x)
{
clampedPosition.x = rightTop.x - spriteHalfSize.x;
}
if(spriteTop < leftBottom.y)
{
clampedPosition.y = leftBottom.y + spriteHalfSize.y;
}
else if(spriteTop > rightTop.y)
{
clampedPosition.y = rightTop.y - spriteHalfSize.y;
}
transform.position = clampedPosition;
}
}
Nah the sprite’s bounds are always a box which encapsulates the whole thing. If you want to send me your project I could take a look if you’re comfortable doing that. I didn’t test any of that code so I’m not surprised if there’s some kinks in it. It also may be something else in your project that affects it, just speculating.
There’s always the solution of using box/edge colliders around the outside of the camera’s view if your camera doesn’t move.