Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 13 Next capture
2021 2022 2023
1 capture
13 Jun 22 - 13 Jun 22
sparklines
Close Help
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
  • Asset Store
  • Get Unity

UNITY ACCOUNT

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account
  • Blog
  • Forums
  • Answers
  • Evangelists
  • User Groups
  • Beta Program
  • Advisory Panel

Navigation

  • Home
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
    • Blog
    • Forums
    • Answers
    • Evangelists
    • User Groups
    • Beta Program
    • Advisory Panel

Unity account

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account

Language

  • Chinese
  • Spanish
  • Japanese
  • Korean
  • Portuguese
  • Ask a question
  • Spaces
    • Default
    • Help Room
    • META
    • Moderators
    • Topics
    • Questions
    • Users
    • Badges
  • Home /
avatar image
1
Question by adamt · Apr 22, 2014 at 12:58 AM · cameramovementisometricorthographic

Constrain a GameObject's movement to an orthographic camera's viewport bounds

(I'm new here -- and to Unity itself -- please be gentle.)

I've got a simple orthographic camera projecting at a quad (the "ground") and a cube (my character). I'd like to have the character move randomly, but only within the bounds of the camera's projection.

Here's how I'm doing it now:

 void Start()
 {
     Ray topRightRay = Camera.main.ViewportPointToRay(Vector3.one);
     Ray bottomLeftRay = Camera.main.ViewportPointToRay(Vector3.zero);
 
     int groundLayerMask = 1 << LayerMask.NameToLayer("Ground");
 
     RaycastHit topRightRayHit;
     RaycastHit bottomLeftRayHit;
 
     if(Physics.Raycast(topRightRay, out topRightRayHit, Mathf.Infinity, groundLayerMask)
             && Physics.Raycast(bottomLeftRay, out bottomLeftRayHit, Mathf.Infinity, groundLayerMask))
     {
         cameraRect = Rect.MinMaxRect(bottomLeftRayHit.point.x, topRightRayHit.point.z, topRightRayHit.point.x, bottomLeftRayHit.point.z);
     }
 }
 
 void Update()
 {
     Debug.DrawLine (new Vector3(cameraRect.xMin, 0.5f, cameraRect.yMin), new Vector3(cameraRect.xMin, 0.5f, cameraRect.yMax), Color.red);
     Debug.DrawLine (new Vector3(cameraRect.xMax, 0.5f, cameraRect.yMin), new Vector3(cameraRect.xMax, 0.5f, cameraRect.yMax), Color.yellow);
     Debug.DrawLine (new Vector3(cameraRect.xMin, 0.5f, cameraRect.yMin), new Vector3(cameraRect.xMax, 0.5f, cameraRect.yMin), Color.blue);
     Debug.DrawLine (new Vector3(cameraRect.xMin, 0.5f, cameraRect.yMax), new Vector3(cameraRect.xMax, 0.5f, cameraRect.yMax), Color.green);
 }

This seems to work just fine when the camera is not rotated around the Y axis (e.g., if its rotation is set at (30, 0, 0)), creating colorful lines that represent the camera (and, hence, game world) boundaries for my character, projected against the "Ground" quad. It looks like this:

X axis rotation

However, once I change the camera's Y axis rotation to (30, 45, 0), my bounds get very small. It looks like this:

XY axis rotation

(ugh, apologies for the green-on-green, but it's a very thin rectangle, in case it's hard to tell)

I tried to do a rotation calculation (multiplied against each line) against a 45-degree rotation of the Y axis, but that seemed to just rotate the very small box:

 mCameraRotation = Quaternion.AngleAxis(45, Vector3.up);
 mBottomLeft = mCameraRotation * (new Vector3(cameraRect.xMin, 0.5f, cameraRect.yMin));
 // ...

Is there any hope for me?

ortho-x.jpeg (171.5 kB)
ortho-xy.jpeg (171.0 kB)
Comment
Add comment
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users

4 Replies

· Add your reply
  • Sort: 
avatar image
1
Best Answer

Answer by adamt · Apr 25, 2014 at 12:23 AM

I'm going to answer my own question, in case it helps other people.

It turned out that I was on the right track, but just didn't go far enough. I needed to raycast to the other two screen edges (i.e., the top left and bottom right) to get the full viewport dimensions. Then I created a new class called GameBounds that simply encapsulates 4 Vector objects representing these corners (I tried doing this with both a Rect and a Bounds object, but found it difficult since a Rect doesn't allow you to define verticies and there was a bit less math involved with defining these verticies statically versus deriving them from a Bounds object).

Anyhow... here's my code (```VisibleArea``` is a C# property of my GameBounds class):

 Ray bottomLeftRay = Camera.main.ViewportPointToRay(Vector3.zero);
 Ray topLeftRay = Camera.main.ViewportPointToRay(new Vector3(0, 1, 0));
 Ray bottomRightRay = Camera.main.ViewportPointToRay(new Vector3(1, 0, 0));
 Ray topRightRay = Camera.main.ViewportPointToRay(Vector3.one);

 int groundLayerMask = 1 << LayerMask.NameToLayer(GROUND_LAYER);

 RaycastHit bottomLeftRayHit;
 RaycastHit topLeftRayHit;
 RaycastHit bottomRightRayHit;
 RaycastHit topRightRayHit;

 if(Physics.Raycast(bottomLeftRay, out bottomLeftRayHit, Mathf.Infinity, groundLayerMask)
         && Physics.Raycast(topLeftRay, out topLeftRayHit, Mathf.Infinity, groundLayerMask)
         && Physics.Raycast(bottomRightRay, out bottomRightRayHit, Mathf.Infinity, groundLayerMask)
         && Physics.Raycast(topRightRay, out topRightRayHit, Mathf.Infinity, groundLayerMask))
 {
     VisibleArea = new GameBounds(bottomLeftRayHit.point, topLeftRayHit.point, bottomRightRayHit.point, 
             topRightRayHit.point);
 }

To get my cube wandering around, randomly, within the bounds of the game world, I just take half the bounds in the X and Z axes, and keep my Y axis as-is (so my cube always sits on the ground):

 float xPos = Random.Range(VisibleArea.BottomLeft.x / 2.0f, VisibleArea.TopRight.x / 2.0f);
 float zPos = Random.Range(VisibleArea.BottomRight.z / 2.0f, VisibleArea.TopLeft.z / 2.0f);

It's probably not the most efficient way to go about this, but it's working for me!

Comment
Add comment · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image
1

Answer by robertbu · Apr 22, 2014 at 03:09 AM

I see you are using Viewport points to construct the ray for your rect. To make your code work, you'd need to re-initialize your cameraRect with a new Raycast each time the camera is moved or rotated. You don't really need to do the Raycast. You can just do something like this in Update():

 Vector3 pos = Camera.main.WorldToViewportPoint(transform.position);
 pos.x = Mathf.Clamp01(pos.x);
 pos.y = Mathf.Clamp01(pos.y);
 transform.position = Camera.main.ViewportToWorldPoint(pos);

Note this clamps the pivot point, so 1/2 of your cube can leave the screen. If you want the entire cube on the screen, you'll have to figure a more restrictive clamping:

 Vector3 pos = Camera.main.WorldToViewportPoint(transform.position);
 pos.x = Mathf.Clamp(pos.x, 0.07f, 0.93f);
 pos.y = Mathf.Clamp01(pos.y, , 0.07f, 0.93f);
 transform.position = Camera.main.ViewportToWorldPoint(pos);
Comment
Add comment · Show 1 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image adamt · Apr 23, 2014 at 07:24 PM 0
Share

Thanks for the response. I should have been more clear in that I'm not actually moving nor rotating my camera -- its transform should be considered fixed at a rotation of (30, 45, 0). I've just extended the scale of the ground quad past the bounds of the camera so as to not get any background (i.e., non-ground) color in the game view.

Your solution led me towards what I feel like is the answer to my question, but I'm not exactly sure why. If I draw a line from (0, 0, -13) to (1, 1, 32.5) using ViewportToWorldPoint, I get a diagonal line across my viewport. For example:

 Debug.DrawLine(Camera.main.ViewportToWorldPoint(0, 0, -13), Camera.main.ViewportToWorldPoint(0, 0, 32.5));

The z value of the "from" line (-13) is set to the value of my camera's near clip plane, but I don't know why setting the z value of my "to" line to 32.5 works the way it does. The camera's transform is positioned at -10 in the z axis, has a size of 13 (I realize this could also be related to the z value of my "from" line) and a far clip plane of 50. Any ideas why 32.5 for the z value seems to be the magic number to get the full dimensions of the viewport?

avatar image
0

Answer by JacobHockey13 · Apr 22, 2014 at 03:09 AM

I had a very similar problem recently. I would recommend setting up colliders (on empty objects) outside of the camera view and adding a force (with a z and x components) when the level loads(this can be done with the awake function. Of course, you would put a material with a bounciness of 1 on the colliders and eliminate drag and friction

Comment
Add comment · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image
0

Answer by rakkarage · Apr 05, 2015 at 04:14 PM

 static public Vector2 ConstrainRect(Bounds screen, Bounds map)
 {
     return ConstrainRect(screen.min, screen.max, map.min, map.max);
 }
 static public Vector2 ConstrainRect(Vector2 minScreen, Vector2 maxScreen, Vector2 minMap, Vector2 maxMap)
 {
     var offset = Vector2.zero;
     var screenWidth = maxScreen.x - minScreen.x;
     var screenHeight = maxScreen.y - minScreen.y;
     var mapWidth = maxMap.x - minMap.x;
     var mapHeight = maxMap.y - minMap.y;
     if (screenWidth > mapWidth)
     {
         var diff = screenWidth - mapWidth;
         minMap.x -= diff;
         maxMap.x += diff;
     }
     if (screenHeight > mapHeight)
     {
         var diff = screenHeight - mapHeight;
         minMap.y -= diff;
         maxMap.y += diff;
     }
     if (minScreen.x < minMap.x) offset.x += minMap.x - minScreen.x;
     if (maxScreen.x > maxMap.x) offset.x -= maxScreen.x - maxMap.x;
     if (minScreen.y < minMap.y) offset.y += minMap.y - minScreen.y;
     if (maxScreen.y > maxMap.y) offset.y -= maxScreen.y - maxMap.y;
     return offset;
 }
Comment
Add comment · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users

Your answer

Hint: You can notify a user about this post by typing @username

Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.

Follow this Question

Answers Answers and Comments

22 People are following this question.

avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image

Related Questions

Moving a Rotated Camera 0 Answers

Creating a trimetric camera? 0 Answers

Ortho-Isometric camera not playing nice with culling 1 Answer

Isometric + Orthographic Player Movement 0 Answers

Constrain axis of isometric camera ("vertical" only) 0 Answers


Enterprise
Social Q&A

Social
Subscribe on YouTube social-youtube Follow on LinkedIn social-linkedin Follow on Twitter social-twitter Follow on Facebook social-facebook Follow on Instagram social-instagram

Footer

  • Purchase
    • Products
    • Subscription
    • Asset Store
    • Unity Gear
    • Resellers
  • Education
    • Students
    • Educators
    • Certification
    • Learn
    • Center of Excellence
  • Download
    • Unity
    • Beta Program
  • Unity Labs
    • Labs
    • Publications
  • Resources
    • Learn platform
    • Community
    • Documentation
    • Unity QA
    • FAQ
    • Services Status
    • Connect
  • About Unity
    • About Us
    • Blog
    • Events
    • Careers
    • Contact
    • Press
    • Partners
    • Affiliates
    • Security
Copyright © 2020 Unity Technologies
  • Legal
  • Privacy Policy
  • Cookies
  • Do Not Sell My Personal Information
  • Cookies Settings
"Unity", Unity logos, and other Unity trademarks are trademarks or registered trademarks of Unity Technologies or its affiliates in the U.S. and elsewhere (more info here). Other names or brands are trademarks of their respective owners.
  • Anonymous
  • Sign in
  • Create
  • Ask a question
  • Spaces
  • Default
  • Help Room
  • META
  • Moderators
  • Explore
  • Topics
  • Questions
  • Users
  • Badges