Limiting player movement (Almost done, coding problem)

I am currently using this code to restrict player movement along the horizontal axis, to ensure that the player stays within the camera view. Right now it works for the horizontal axis, but not the vertical axis, for some reason.

In other words, topB and downB values do not seem to be read correctly.

void Update () {

        dist = (transform.position.z - cam.transform.position.z);
        leftB = cam.ViewportToWorldPoint(new Vector3(0, 0, dist)).x;
        rightB = cam.ViewportToWorldPoint(new Vector3(1, 0, dist)).x;

        topB = cam.ViewportToWorldPoint(new Vector3(0, 1, dist)).z;
        downB = cam.ViewportToWorldPoint(new Vector3(0, 0, dist)).z;

        Vector3 pos = transform.position;
        pos.x = Mathf.Clamp(transform.position.x, leftB, rightB);
        pos.z = Mathf.Clamp(transform.position.z, downB, topB); //Not working well: 
        // topB is roughly the center of the screen while downB is well beyond the 
        // bottom of the  screen.

        transform.position = pos;
    }

Why can’t I make the camera just follow the player?
I have two players on screen and a camera which increases the ortographicSize as they get farther away from each other. At a certain point it stops stretching and needs to start restricting player movement instead.

Notes
The game is top down at an angle. I have been looking for help on camera.ViewportToWorldPoint, but I think I am not getting the dist (distance) right, since the camera is rotated at an angle, not straight down on the players (the cubes in the pictures below).

At a glance, lines 7 and 8 both calculate the same value, but they should probably be different? I assume that you did have that correct though, based on your reported behaviour.

I’d start by getting dist right for the top and bottom, which you should be able to do with a bit of trigonometry. The ortho camera will make it look like stuff is the same distance, but (as you know) it isn’t, and that could potentially account for your error margin on its own.

Also, a quick check to see if that’s the problem is to make your camera point directly down and see if things line up properly.

Why not have a single var cameraAtLimit. If true, then var limitPlayerMovement is true. And if true then player can not go further from other player. Seems simple. Away from computer tho. So no scripts. Sorry.

I don’t understand. One is calculating the X and one is calculating the Z. the X is based on leftBorder and rightBorder while the Z is based on the topBorder and bottomBorder. It’s the top and bottom I can’t get right.

That is exactly what I don’t know how to do. I’ve did trigonometry at school, I just don’t know how to apply it :frowning:

Here’s a picture depicting the current sitiuation. When I move either the yellow or the green arrow both the X and the Y are changed, so I don’t actually even know exactly what values I have or can get. That’s why I’m so confused.

@renman3000
There are a few problems with your idea:
If you limit the player movement using anything but Mathf.Clamp, how do you know which side/movement to limit? Harder than you make it sound.

All I understood was that I have to create two booleans: cameraAtLimit and limitPlayerMovement. I have no information on how or when to set the value of any of them. How do I know if the camera is at the limit without using ViewPortToWorldPoint? When limitPlayerMovement is true, which movement of the player should I limit?

I guess you could try just using colliders that move along with the camera (children of the camera) and that way, as a player hits this “invisible wall” they stop at the limits of the cameras vision…

maybe like, casting rays from your camera origin, to the edges of your cameras vision (that way if your camera “zooms” at all it could follow that movement still) then create invisible objects with colliders that move along the collision of the ray. I dunno if this is what your trying to do at all :stuck_out_tongue:

Oh also for determining your camera “limit” you could raycast from camera origin to a “lookAtTarget” (an empty gameobject at a location in the middle of your players locations, to keep it centered would be fun with two moving players haha) and when the raycast distance gets too far, disable any further zooming out… I dunno if any of this would really benefit you but good luck!

That’s a bit too vague. That’s what I did, Colliders that move with the camera - at first.
The problem is, when the camera scales (or stretches) by increasing the ortographic size, the colliders don’t adjust accordingly.
How would I be able to take the ortographicSize into consideration please?

just limit the vector(s) that is at its limit. If this is a 2D game say, if y limit = 30 and they are 30 apart, prevent any positive y movement for top player, negative or bottom.

As far as setting the bools thats what you have to figure out. It can be done tho, pretty easily. For instance the above y or x or z limit, it true ( known by constantly monitoring position distance) then playerXLimit true. If true, camera is at max zoom out.

Kind of working right nw, but if you think i can help ask and i will help you out later.

I can’t do that at a fixed value. The camera moves with the player :frowning:

I’ll upload a video on this problem, I seem to be unable to explain it with words.

 topB = cam.ViewportToWorldPoint(new Vector3(0, 1, dist)).z;
 downB = cam.ViewportToWorldPoint(new Vector3(0, 0, dist)).z;

I just need to get those two lines fixed, it must be pretty easy but I can’t find a way.
I have tried to rotate the camera directly on top of the player (90 degree rotation) but that still doesn’t fix the problem.

Here’s a video of describing the problem: [http://youtu.be/wfGoLZ2GV84]

Renman’s idea should work. If the camera is always at the midpoint of the two players, then when the camera is at its furthest you can just stop the players getting any further apart, which is as easy as modifying their movement vectors so that it doesn’t increase the distance between them (i.e.: if they’re moving away, clip their movement vectors so that only their sideways component relative to the other player is retained).

The colliders attached to the camera idea should work as well, though you’ll need to ensure that their layers are set up so that only the players collide with them. Simply have a script on the camera which calculates the offset from the centre of the camera based on the size and aspect ratio. This is probably the simplest approach, because Unity will just take care of everything else for you. After thinking about it for a bit, this is almost certainly how I’d do it. It’d only take me about 10 minutes to implement, it’s using off-the-shelf tools for 90% of the work, and it gives you a super easy way to actually see where your movement is restricted, because you can just attach renderers to the colliders.

Your way is of course valid too, and it’s what I’d initially lean towards (being a programmer, and thus always first thinking of the code-based approach). However, there’s potential circumstances where that approach will get complex where the other approaches will “just work”. For instance, what if the players don’t end up waking around just on that plane, i.e. if they can walk up and down stairs or hills, or get Magical Boots of Flying or whatnot?

Anyway, unless I’m being dyslexic and am seeing it wrong, in these two lines…

 topB = cam.ViewportToWorldPoint(new Vector3(0, 1, dist)).z;
 downB = cam.ViewportToWorldPoint(new Vector3(0, 1, dist)).z;

… you’re setting topB and downB to have the same values. You’re putting the same vector (0, 1, diet) into both, and you’re reading the same component (z) out of each, and I don’t see any negations or anything… so I’m pretty sure there’s an issue right there. But taking care of that alone won’t fix things completely, because you still have the offset caused by the angle to worry about.

Also, in your diagram above, the red line marked “what I need” isn’t actually what you need (though it’s super easy to get - subtract position.z of the ground plane from position.z of your camera - done). What you need is the distance along the top and bottom frustum planes to where they reach the ground. (Alas, I can’t make a diagram right now.)

I dont see what the problem is.
Angrypenguin and i seem to concur.

:.

 topB = cam.ViewportToWorldPoint(new Vector3(0, 1, dist)).z;

 downB = cam.ViewportToWorldPoint(new Vector3(0, 0, dist)).z;

I’m sorry, so stupid of me! I have been using the above code but I pasted the wrong version.
The problem is that “TOP” isn’t the top of the viewport, it’s the CENTER! That’s why the black box in the video (that’s meant to be the top) ends up in the center. Nevertheless, I’ll try as you suggested when I get home. Thanks.

Note: It’s still center when I remove all camera rotation so I’m not sure if it’s a camera angle issue anymore.

I did that and it was really easy to do. It’s all good now except for one last problem.
Zombies can push the player around. It is possible that they can push the player out of the screen. Disabling a specific movement key was fair enough. What can I do now though?

Don’t disable the input, disable or constrain the actual movement.

Alternatively, apply whatever movement there is without modification, then test each palyer’s position at the end of the frame (so from LateUpdate()) and move them back to the closest valid position.

Well with my way of doing it. If player which ever vector limit at, is exceeded, the system will always place the player back to an expectable pos. So yes, the zombies may push him, and he may occasionally go offscreen, but it should, only be very temporary as the update should place him back into an expectable level.

Solved the problem completely with:

float distance = Vector3.Dot(cam.transform.forward, transform.position - cam.transform.position);