Strategy Camera Blog Post: onewheelstudio.com/blog/2022/1/14/strategy-game-camera-unitys-new-input-system Project Files: github.com/onewheelstudio/Adventures-in-C-Sharp/tree/main/Strategy%20Camera
when dragging the camera (drag), for some reason the camera position twitches when the cursor leaves the screen. I tried to understand why it happens, but I couldn’t, can you tell me?)
I have LEGIT, been trying all day and searching throughout ALL the internet for a tutorial on the drag and move camera. Only now, at 3 AM in the morning, I was thinking: "Ok, last try, otherwise I go with WASD-based camera control". And to my HUGE surprise, I found your video. God took pity on me... Thanks a lot for the tutorial!
This is absolutely the best camera tutorial I have seen on RUclips. The one you referenced for the drag function was my go to before this one but you just beat it. I'm so glad that you take the time to thoroughly describe each line and what the different pieces do as you type it out for us. I've never learned so much from a Unity video before. Thanks for the effort you put into this.
Man, I just want to say these have been some of the most helpful and carefully explained tutorials I've watched. I really appreciate you making them for free like this here on RUclips, but I'd gladly have paid for a Udemy course containing this as well.
This was really well thought out and you have a good pace for a tutorial. It would be nice to have Q and E rotate too as alternative ways to rotate like you added drag as an alternative for movement.
This deserves the most viewed tutorial about camera movement in youtube especially because it's working with the new input system. I would also suggest to put some parts of codes in LateUpdate method instead of Update. I tried it before myself and there is a real difference between them when it comes to smoothness. The calculation codes must stay in Update to assign new values to some private fields. Then we only need to use those fields in LateUpdate to assign them to transforms.
Well, yes... Just when I finished working on my own "strategy camera" (on which I worked hard for a week) I find this useful video, released only three hours ago (crying softly, subscribing to the channel)
Great Tutorial, i really didnt want to start using the new input system in unity and have had an internal argument with myself on using it for a few days, but you have helped me get an understanding on how it works, and bite the bullet and start using it. I always learn better by example then just reading.
Wow! I noticed you said, "poop ton of variables", so you will have to excuse my langauge, but this was f'n fantastic! Your video covering Unity's new input system and this one are the first I've seen of your content! In the iconic words of Jessie Spano, "I'm so excited! I'm so excited!" Thank you for this!
This!!! is Great!! This can be the best camera control for strategy, tactical rpg, rts and more. It's a shame I am a newbie and I could understand only 10% of the code but I am very satisfied with the result. Thank you!!
@@tonylanglet Looking back in my code (it is in a project that I put aside for now), the main difference is that I expanded the tutorial to allow me to choose a 2D or 3D camera. The 3D is the same as in the tutorial but the camera transform I manipulate is the virtual camera's transform. Most of the methods have an if-else statement for if we are using a 2D camera or not. Here is an overview what I did to use Cinemachine. I set a private _vCam (of type CinemachineVirtualCamera) in my code. This is set in Awake() from _cameraRig.GetComponentInChildren(). The variable _cameraRig is set in the inspector. The camera transform (_camTransform) is equal to _vCam.transform which I set in Awake() after I set _vCam. This is what is manipulated for camera movement and rotation. The only other main difference is with zooming if I am using a 2D camera vs. a 3D one. This is because when zooming 2D you want to manipulate the camera's othrographic size vs. moving the camera (assuming you set the camera to othrographic). For 3D it is the same as in the tutorial. For 2D zoom I set the zoom to _vCam.m_Lens.OrthographicSize + (zoomValue * _stepSize) (where _stepSize is a float set in the inspector and zoomValue is read from the input context). The only other thing is a method to update the virtual camera's othrosize when in 2D. This is called in Update() as part of updating the camera's zoom. For 3D it is just like in the tutorial. Here is the method use for a 2D camera: private void UpdateCameraOrtho() { var ortho = _vCam.m_Lens.OrthographicSize; var target = _zoom + _zoomSpeed * (_zoom - ortho); ortho = Mathf.Lerp(ortho, target, Time.deltaTime * _zoomDampening); ortho = Mathf.Clamp(ortho, _minZoom, _maxZoom); _vCam.m_Lens.OrthographicSize = ortho; }
Thanks@@jeffreyhersh908, I'm not sure how some things might conflict, just thinking that the LookAt option might be conflicting with the Look At parameter on the Cinemachine. I did the same just replaced the camera with a VirtualCamera and it is working, just thought there might be more to it.
Great tutorial! Absolutely love your style of explanation. I wanted to use this for more of a building style game so i changed this small piece of code: float value = inputValue.ReadValue().x; float valueY = -inputValue.ReadValue().y; transform.rotation = Quaternion.Euler(valueY * maxRotationSpeed + transform.rotation.eulerAngles.x, value * maxRotationSpeed + transform.rotation.eulerAngles.y, 0f); which allows me to also rotate the camera vertically while holding the middle mouse button. Maybe someone also needs this.
The Tutorials Was nice at beginning and with time i got more and more errors , gitrepo wont help, the class names are completly different than in the tutorial and i give up at 20:29 Namespace CameraControllActions not found, then the autogenerated ones wont generate the files where you have in your Repository. Can you please explain how and what packages your have installed ? i removed the BoxGroup in reason the Package costs Money and i am A Beginner in unity the Explainations are Awesome but the code is Frusttrating ...
re: 28:10 - "... there's probably better ways to do this" Disclosure: I'm fairly new at unity dev myself, but this is the zoom math that I settled on, and I feel is probably a bit less brittle: private void ZoomCamera(InputAction.CallbackContext context) { float value = context.ReadValue().y * zoomStepSize; if (Mathf.Abs(value) < 0.1f) { return; } targetZoomHeight -= (value * zoomSpeed); targetZoomHeight = Mathf.Clamp(targetZoomHeight, zoomMinHeight, zoomMaxHeight); } private void UpdateZoomPosition() { float zoomDelta = cameraTransform.localPosition.y - targetZoomHeight; if (Mathf.Abs(zoomDelta) < 0.1f) { return; } Vector3 direction = cameraTransform.localRotation * Vector3.forward; Vector3 zoomTarget = cameraTransform.localPosition + (direction * zoomDelta); cameraTransform.localPosition = Vector3.Lerp(cameraTransform.localPosition, zoomTarget, Time.deltaTime * zoomDamping); cameraTransform.LookAt(transform); } The difference here is that we are moving the camera along its local forward axis, rather than approximating it by deleting components and relying on zoomSpeed across different events. Arguably, may not even need the final line of cameraTransform.LookAt(transform); with this solution, though it helps to avoid drift over time due to rounding errors.
At 23:45 the camera base object is rotating so the camera object orbits the base object. At 30:54 I am showing how the zoom works and that the rotation still works with the zooming. Unless I missed something or misspoke in the video. Does that help?
@@OneWheelStudio Thank you for answer. "At 23:45 the camera base object is rotating" Is this means that the base object's transform is same as it of the camera object(its child)? (Or positioned straight below, not in LOS, on the ground, possibly...)
Hello, First let me say that the explanation is absolutely fantastic, I love the content in this video. I was wondering if you could make a follow up video were you can implement these mechanism for touch input.
Hi. Zoom behaves weird. At some camera start positions, the zoom doesn't react to minZoom and zoom to the top view, turns 180 degrees, and moves away in the opposite direction. For example, at Y11 Z-11, but at position Y8 Z-8, this problem doesn't occur.
At 20 minutes, if the script is not working, go to edit > project settings > set "ActiveInputHandling" to "both" otherwise it doesnt work (I did set it to new only).
Very clear video. Thank you for completing with the blog, it is very useful for non English speakers. In the ZoomCamera method, you don't use Mathf.Clamping. Is there a particular reason?
Mmm. Clamping would be a good way to do it. The only reason I didn't was I didn't think about it! Oops. Glad the video and blog post are useful! Writing it out helps me too - most of my recent videos have a written post ;)
That depends on what you mean by a boundary. It wouldn't be too hard to set max and and min values for the x and z coordinates. Then every frame check if the camera is beyond those limits. If it is then slide it back to that limit. Using something like a collider could work, but might be messier. If I wanted to implement this, I'd start with simple values and check the position of the camera.
for rotating the camera you just use delta mouse position.. but i want to implement the same thing for mobile if i use game pad it keeps rotating how can i fix this problem ?
Thank you for this awesome camera controller. One question: I want to add in vertical camera rotation. So in the RotateCamera() method, I added a "valueY" and took the the Vector2().y value from the inputValue. Then I Clamped that value between a minVerticalRotation and maxVerticalRotation value and added it into the targetRotation Quaternion.Euler. However, I want the minVerticalRotation to be around (probably) -30 degrees, but if I set it lower than 0, I get weird behavior that doesn't work. I don't understand Quaternions well enough to get what's happening. Anyone have any ideas?
Adding in rotation in all directions isn't too bad: Add "float rightAxisRotationValue = inputValue.ReadValue().y;" to capture the y-component of mouse movement. Pass transform.rotation.eulerAngles.x and transform.rotation.eulerAngles.z instead of 0f and 0f in the Euler() method. Add "transform.Rotate(cameraTransform.right, -rightAxisRotationValue * maxRotationSpeed, Space.World):" to rotate the camera relative to the axis that goes through the camera to the left/right
Figured it out with One Wheel Studio on his discord!! such an incredibly nice and helpful person!! private float rotationTarget; private Quaternion rotTarget; //new variable private void RotateCamera(InputAction.CallbackContext obj) { if (!Mouse.current.rightButton.isPressed) return; rotationTarget = obj.ReadValue().x; rotTarget = Quaternion.Euler(0f, rotationTarget * maxRotationSpeed + transform.rotation.eulerAngles.y, 0f); } //this function needs to get called in the update function private void UpdateCameraRotation() { transform.rotation = Quaternion.Lerp(this.transform.rotation, rotTarget, Time.deltaTime * RotationDampening); }
Wow! I've seen this camera made a dozen different way but never like this! It was so easy to follow and extremely flexible. I've been developing for years, and this was the first in depth camera for strategy games I've seen that works right out of the gate, so to speak. My only question is I have my orthographic camera fixed at x: 30deg, and y:45deg like a tactics style game. It seems the rotation is being reset but I'm not sure where its doing that. I can rotate it back, but I'd like it to keep the rotation in the beginning and then be given the option of rotating. Is that difficult or would a few lines of code fix this?
Glad the video was useful! I do my best ;) I'm not sure what would be causing the rotation issue. I'm not able to reproduce the behavior on my end. Is it possible that you are rotating the camera object rather than the base object? Feel free to drop by the OWS discord (link in the description). Happy to take a look at code or the structure of the camera object.
Could have stored a reference to the camera when you were caching its transform. :D but as you said, many ways to deal with avoiding Camera.main. Was somehow expecting to see you use Cinemachine for this, but I guess Cinemachine could be considered overkill, depending on what you're going for. Good video regardless :)
I thought about using Cinemachine. Even started there when I was prototyping, but it felt complicated and a bit ugly. I think Cinemachine is amazing, but didn't feel like a good fit for this application.
@@OneWheelStudio Makes sense. I've never really done a strategy camera with cinemachine, but I suspect the zoom function you have set up here would require some extra work in cinemachine. Though the rotation and movement should be pretty straight forward.
Thanks, for the video, good stuff here. Question: You mention using Camera.Main for the drag mode to operate correctly, however, what if you have a camera system for different scenes/modes and want to use that, would you just need a reference to the active camera, or would you add some functionality/reference to that script for that camera? Curious on how you would address that. Thanks again.
Prob not important, but would be curious how you set that scene up. Did you use tilemaps, did you manually place the haxes. Did you use an asset store. I got a free 'Hexlands' and added some water, but yours looks a bit better, if not bland without art. (Not an artist, and prob not going to use hexes, but makes it look like Dwarf Romantic, or something as you show cased.)
The tiles are each a 3D prefab. I created each tile in Blender - easy to create a hex with a radius of one unit. Then to populate the map I start at the origin, randomize the number of a particular tile to add and then then search for empty neighboring slots - then repeat starting at a empty spot with a new type of tile. Red Blob Games has a great explanation of hex grids which was my main source for building up a hex grid library of functions. Does that help? Does that answer all your questions. Happy to chat more.
@@OneWheelStudio Great thanks, yay Red Blob is like the master of all of that. Thanks for your detailed answer. Looks great, so your doing something right.
Thanks for this tutorial! I already had a strategy game camera for my game but I tried this and it adds some functionality which was missing from my camera - drag-move and the mouse at edge-of-screen movement (which is what I was originally looking for). I have a bit of info to share and also a question, first the info: I felt that the movement forward and backward with W and S made an unneeded "zoom" effect, which I felt should only be on properly zooming with the scrollwheel. To fix this, in the "GetKeyboardMovement" method, I changed the last line to be: "targetPosition += new Vector3(inputValue.x, 0f, -inputValue.y);". This way only the z axis of the camera base object moves when w or s are pressed, without the y. Now for the question, when the camera is rotated and I move it with wasd keys, it moves in a weird direction, this is because when I press for example w it will still move forward according to the world space and not according to its rotation, is there a way to fix this so that w always moves the camera forward, s always moves backwards, and so on? The temporary fix I can think of is to allow the camera to rotate only temporarily and as soon as the user releases the scrollwheel button, it will rotate back to the original rotation, and if it's not in the original rotation, don't move when wasd are pressed, but I'd much rather let the users rotate the camera as they wish and allow it to be moved forward-backward-left-right no matter what its rotation currently is.
Hmm. The camera should move relative to the direction it's facing. I suspect your change to the GetKeyboardMovement function may be the culprit. Vector3(inputValue.x, 0f, - inputValue.y) would create a vector that is relative to the world X and Z axes rather than relative to the camera's forward and right directions. Instead I multiply the input values by the camera's forward and right direction vectors - this what the GetCameraForward and GetCameraRight functions are for. I could be wrong, but without seeing all your code that would be my best guess.
@@OneWheelStudio First of all, thanks for the quick response! You were right about my change affecting the camera's movement on rotation, for some reason I was convinced that I experienced the incorrect movement on a rotated camera even before my change, but I just tested it out now with the original line, and with it the camera moves as intended even when rotated. What I tried to do to fix it while keeping the correct camera movement while rotated is to set inputvalue.y = 0, this will make the camera move without zooming, however when rotated it won't move right or left correctly, for example if it's rotated to 90 degrees it won't move at all when W or S are pressed, it will only move left and right on A or D presses. I wonder if there's a way to fix it so that the camera moves without zooming and will also move correctly while rotated.
@@BurnEmDown1 The zooming was intentional on my part. The goal was to have the camera move in a sort of arch. All of that is happening in the UpCameraPosition function. If you check the code on GitHub, on line 195 of CameraMovement.cs you'll see the line responsible for the zoom in and out when the camera moves up and down. I think you can just remove the part on that line that is in the parentheses.
@@OneWheelStudio I think I found my problem, as always - a typo 🤦♂ In the GetCameraForward method, I accidentally wrote: forward.x = 0, instead of forward.y = 0 Fixing that solved all of my previously described issues! Thanks again for this tutorial and helping out in the comments more than a year later!
I'm new to unity and found this tutorial very helpful. However, after some frustration, I realized that transform.position bypasses colliders. If you want to restrict the camera to a specific area (ie. the edge of the terrain), how would you go about it?
Glad the video was useful! :) I wouldn't use colliders to restrict the location - if you were using the physics engine (rigidbody) there could be ways to do that but it could be messy - instead I would create additional variables for max and min positions (max X, min X, etc). Then when moving the camera see if the new location would exceed those limits. If it would, then don't move it. Hope that helps. Feel free to jump over to the OWS discord if you need more detail or help.
Hello, in function DragCamera, we should create plane as class member, instead of create it whenever right mouse button pressed. Do you think it will improve performance ?
Hello friend, could you know how I can change the screel wheel for pinch gesture for mobile new input system? I'm looking everywhere and I can't find any videos or anyone who knows, thanks!
Rotation with the mouse could be done a few ways. The way I have often done it is to capture the position of the mouse each frame and then calculate how far it moved since the last frame and use that to determine how far or how fast to rotate. As for clamping values you could use Vector3.Angle() to calculate the angle between the current direction and say "forward." From there you could stop the motion in a particular direction. There is also Vector3.SignedAngle() that can give you positive and negative values. Hope that helps.
hi there...why my visual studio has no " perfomed " word with the event icon ( the lighting icon )....so i stuck in line 67...vs error cs1061....please help
Hello, Do you have tutorial work on mobile device? As we don't have Mouse Input on mobile device? Or give me some hints, I will research it by myself Thank
After 5 month, finally dwelving in the newInputSystem I understand that you are using both Input system instead of using only the new one unlike the title of this video... as my previous comment figured out but without really understanding how the new input work. Is there a reason for that ?
I'm not sure what "underground" means. You could simply change the minimum height to go lower.... If you mean navigate through dungeons or caves you're going to need to find something on object avoidance - cinemaching has some of this built in, but you'd probably want to take it further. I can't point you to a specific tutorial - it can be a very complex topic.
This came up from another viewer too. It could be a fun follow up video for sure! In the mean time, my suggestion was to raycast from the camera to the mouse and get a point in the world. Then as you zoom you also lerp the camera towards the point hit by the raycast. 100% have not tested it, but it would be my first attempt. Hope that helps.
@@OneWheelStudio Totally understand and congrats on the move and new job. If/when you get to it I wanted to suggest a few more things that I'd love to see in a part 2. For example having the camera gently raise and lower as you pass over hills or dips in the landscape would be an awesome feature. I was also wondering how to rotate the camera up/down while holding the middle mouse button and moving the mouse forward/back without going through the ground. Adding keyboard keys for zooming in and out and rotating left/right would also be a plus.
Been looking months for this, thank you. Best strategy game camera video I've found yet. New sub from me. Everything works great, is it just me or is the rotation a bit choppy? I'm sure its not the code.. I,ve set it to .02 but I still feel like my pulse and/or the mouse pad surface is affecting the smoothness of the rotation. I'm wondering if I should add a damp variable to it as well?
I'm glad the video is helpful! As for the choppiness, I haven't seen it on my end, but other comments have seen choppiness with the drag IIRC. This came up when the speed was set higher and the solution seemed to be increasing the smoothing too.
Hey, I would like to ask, if I want to rotate the camera on the X axis as well, what are the step I should make? Thank you very much for thus tutorial!
Rotating in multiple dimensions can get tricky. But! To get started you can likely copy and modify the code for the y rotation and make it work for x rotation. First steps would be to create new action for the new rotation. Then create a new function for the X rotation (the copy and modify part). Subscribe the new function to the new actions and test!
Wow, what a great tutorial! Everything works perfectly as your tutorial intends, but I'd like to make a bit of a modification and I'm having a hell of a time. My project is using point and click controls on a nav mesh, on a terrain with a lot of elevation changes. I would like to modify the script so that the camera follows the player character height during navigation. So far, I have tried changing the 'ZoomCamera()' method a bit, to see if I could at least lower and raise the minimum/maximum depending on current position. So far, nothing I've tried has done the trick (though I have had a few funny camera behavior moments lol...) Does anyone have any ideas or suggestions as to how I might get this working the way I described? If so, I am eternally grateful! :)
I haven't done any real work with mobile, but I would imagine it's a matter of defining mobile bindings for the actions. That is one of the nicest parts of the new input system - the same actions can be bound to different inputs. How to define those inputs? Sorry, I wish I could be more helpful.
There's no reason this couldn't work for 2D. You might have to change the orientation so the controls work in x and y instead of a x and z, but that should be most of the changes needed.
Bro, if "you've taken an awful lot of your implementation" from somebody else, maybe it's a better idea to plug your source in closer to the beginning rather than 36:38 seconds in. You're doing a pretty big disservice to Game Dev Guide, as well as yourself because you’ve turned away a viewer.
My apologies if it came off wrong. It’s been a while since I made the video but what I was referring to was the drag functionality being heavily inspired by Game Dev Guide not the entire controller. It was not my intent to bury or hide a source. Again I’m sorry if it came off that way.
I usually love your videos, but this time I think you should have done a bit more research before doing this one. The idea of mappings is that you can use multiple devices to achieve the same thing, for example with this video, you are using Mouse.current instead of using the mappings to move and control the camera, and read the mouse position. This is problematic because what if we now need to move the game to a console, we are now going to have to rewrite a vast majority of this code because we now need to support a Controller to move the Camera. I am sure the more experienced will know what to do here, but as a learning for others, sadly this is only showing half the reason to switch to the New Input System.
The Drag camera gets shaky when the maxSpeed is increased i fixed it by adding float newMaxSpeed = maxSpeed; if (Mouse.current.rightButton.isPressed) { newMaxSpeed = 5f; } in UpdateUpdateBasePosition() and replaced MaxSpeed with newMaxSpeed
It gets shaky if maxSpeed is increased without also increasing the dampening. This makes the camera overshoot it's position, since it can't slow down fast enough, and because the mouse is still pressed, the target position remains the same and the camera will move back towards it (and overshoot because it can't slow down fast enough, repeating the process giving you a shaky looking camera). Increase the dampening when you increase the speed and this problem gets fixed.
Awesome tutorial! love it. There seems to be an issues with Zooming, however. Since we are using LookAt(this.transform), if the we zoom in too much, camera rotates 180 degrees instantly. Is there a way to combat this?
The min height should put a limit on how much you can zoom in. (This happens in the zoom function - line 183 in the code shared on github.) I'd try raising that value - it should work. If it doesn't then something is different about your setup - which is fine - and you could do a distance check instead of a height check.
@@OneWheelStudio Is it possible to somehow set the default height in code? The minHeight should match the height of the camera on game scene so that it does not rotate 180 degrees. But I wanted there to be some default value between the minHeight and maxHeight, so that the camera could go lower
@@OneWheelStudio Probably a bit late, but perhaps someone will find this useful. This happens because of some math between the Y and your Z values. And you use the moving forward on zoom part of the code. In some combinations of Y and Z, the line of code that moves the camera towards the target allows it to push the camera past the Z=0 point, turning it positive and thus flipping the camera. This happens when the Y minHeight has not yet been reached, but you get close enough to Z=0 that moving forward pushes you past that point. It DOES react to minHeight, it's just that you have moved forward too far and the minHeight has not yet been reached. MinHeight ONLY factors in the Y position. There is NO safety check for the Z value. To fix this, you can create a minDistance variable and set it to any negative number. The lower the number, the more of a top-down view you can get. Z=0 is directly above the camera's target, and thus a perfect top down view. This HAS to be a negative value, else you flip the camera. Then, after the line of code that starts with zoomTarget -= zoomSpeed etcetc, you add a new line: if (zoomTarget.z > minDistance) zoomTarget.z = minDistance; This will prevent the camera zoom movement from getting so close that it flips the camera. I encountered this problem myself after following along with your tutorial, and could not find a fix in the comments, so I hope this helps someone some day :)
Strategy Camera Blog Post: onewheelstudio.com/blog/2022/1/14/strategy-game-camera-unitys-new-input-system
Project Files: github.com/onewheelstudio/Adventures-in-C-Sharp/tree/main/Strategy%20Camera
when dragging the camera (drag), for some reason the camera position twitches when the cursor leaves the screen.
I tried to understand why it happens, but I couldn’t, can you tell me?)
@@JohnnyHazz check my comment its because you increased maxSpeed
I have LEGIT, been trying all day and searching throughout ALL the internet for a tutorial on the drag and move camera. Only now, at 3 AM in the morning, I was thinking: "Ok, last try, otherwise I go with WASD-based camera control". And to my HUGE surprise, I found your video. God took pity on me... Thanks a lot for the tutorial!
This is absolutely the best camera tutorial I have seen on RUclips. The one you referenced for the drag function was my go to before this one but you just beat it. I'm so glad that you take the time to thoroughly describe each line and what the different pieces do as you type it out for us. I've never learned so much from a Unity video before. Thanks for the effort you put into this.
Man, I just want to say these have been some of the most helpful and carefully explained tutorials I've watched. I really appreciate you making them for free like this here on RUclips, but I'd gladly have paid for a Udemy course containing this as well.
This was really well thought out and you have a good pace for a tutorial. It would be nice to have Q and E rotate too as alternative ways to rotate like you added drag as an alternative for movement.
Amazing video, I used this for 2d top down game with a few tweaks, but they way you explain things made makin those tweaks a lots easier, ty
This deserves the most viewed tutorial about camera movement in youtube especially because it's working with the new input system.
I would also suggest to put some parts of codes in LateUpdate method instead of Update. I tried it before myself and there is a real difference between them when it comes to smoothness.
The calculation codes must stay in Update to assign new values to some private fields. Then we only need to use those fields in LateUpdate to assign them to transforms.
This was so helpful - was looking all over for a camera tutorial like this. Thank you
Well, yes... Just when I finished working on my own "strategy camera" (on which I worked hard for a week) I find this useful video, released only three hours ago (crying softly, subscribing to the channel)
Great Tutorial, i really didnt want to start using the new input system in unity and have had an internal argument with myself on using it for a few days, but you have helped me get an understanding on how it works, and bite the bullet and start using it.
I always learn better by example then just reading.
Wow!
I noticed you said, "poop ton of variables", so you will have to excuse my langauge, but this was f'n fantastic!
Your video covering Unity's new input system and this one are the first I've seen of your content! In the iconic words of Jessie Spano, "I'm so excited! I'm so excited!"
Thank you for this!
I’m so glad they were useful! I do my best to cut through the BS and just get the info out there.
This!!! is Great!! This can be the best camera control for strategy, tactical rpg, rts and more. It's a shame I am a newbie and I could understand only 10% of the code but I am very satisfied with the result. Thank you!!
Thanks you soo much for this awesome and easy to understand tutorial about RTS camera movement!
This is just an EXCELLENT Tutorial, thanks this was really really helpful!
Nice tutorial. I used this and added some modifications for an options of a 2D camera and using a Cinemachine virtual camera.
I'm using Cinemachine as well, would you mind share what needs to be changed for this great script to work with cinemachine?
@@tonylanglet Looking back in my code (it is in a project that I put aside for now), the main difference is that I expanded the tutorial to allow me to choose a 2D or 3D camera. The 3D is the same as in the tutorial but the camera transform I manipulate is the virtual camera's transform. Most of the methods have an if-else statement for if we are using a 2D camera or not.
Here is an overview what I did to use Cinemachine.
I set a private _vCam (of type CinemachineVirtualCamera) in my code. This is set in Awake() from _cameraRig.GetComponentInChildren(). The variable _cameraRig is set in the inspector. The camera transform (_camTransform) is equal to _vCam.transform which I set in Awake() after I set _vCam. This is what is manipulated for camera movement and rotation.
The only other main difference is with zooming if I am using a 2D camera vs. a 3D one. This is because when zooming 2D you want to manipulate the camera's othrographic size vs. moving the camera (assuming you set the camera to othrographic). For 3D it is the same as in the tutorial.
For 2D zoom I set the zoom to _vCam.m_Lens.OrthographicSize + (zoomValue * _stepSize) (where _stepSize is a float set in the inspector and zoomValue is read from the input context).
The only other thing is a method to update the virtual camera's othrosize when in 2D. This is called in Update() as part of updating the camera's zoom. For 3D it is just like in the tutorial. Here is the method use for a 2D camera:
private void UpdateCameraOrtho() {
var ortho = _vCam.m_Lens.OrthographicSize;
var target = _zoom + _zoomSpeed * (_zoom - ortho);
ortho = Mathf.Lerp(ortho, target, Time.deltaTime * _zoomDampening);
ortho = Mathf.Clamp(ortho, _minZoom, _maxZoom);
_vCam.m_Lens.OrthographicSize = ortho;
}
Thanks@@jeffreyhersh908, I'm not sure how some things might conflict, just thinking that the LookAt option might be conflicting with the Look At parameter on the Cinemachine. I did the same just replaced the camera with a VirtualCamera and it is working, just thought there might be more to it.
Great tutorial! Absolutely love your style of explanation.
I wanted to use this for more of a building style game so i changed this small piece of code:
float value = inputValue.ReadValue().x;
float valueY = -inputValue.ReadValue().y;
transform.rotation = Quaternion.Euler(valueY * maxRotationSpeed + transform.rotation.eulerAngles.x, value * maxRotationSpeed + transform.rotation.eulerAngles.y, 0f);
which allows me to also rotate the camera vertically while holding the middle mouse button. Maybe someone also needs this.
The Tutorials Was nice at beginning and with time i got more and more errors , gitrepo wont help, the class names are completly different than in the tutorial and i give up at 20:29
Namespace CameraControllActions not found, then the autogenerated ones wont generate the files where you have in your Repository.
Can you please explain how and what packages your have installed ?
i removed the BoxGroup in reason the Package costs Money and i am A Beginner in unity
the Explainations are Awesome but the code is Frusttrating ...
Thank you, you just saved me a ton of time, I'm grateful! The tutorial is amazing.
Thank you for this great tutorial!
Thanks for this excellent tutorial
re: 28:10 - "... there's probably better ways to do this"
Disclosure: I'm fairly new at unity dev myself, but this is the zoom math that I settled on, and I feel is probably a bit less brittle:
private void ZoomCamera(InputAction.CallbackContext context) {
float value = context.ReadValue().y * zoomStepSize;
if (Mathf.Abs(value) < 0.1f) {
return;
}
targetZoomHeight -= (value * zoomSpeed);
targetZoomHeight = Mathf.Clamp(targetZoomHeight, zoomMinHeight, zoomMaxHeight);
}
private void UpdateZoomPosition() {
float zoomDelta = cameraTransform.localPosition.y - targetZoomHeight;
if (Mathf.Abs(zoomDelta) < 0.1f) {
return;
}
Vector3 direction = cameraTransform.localRotation * Vector3.forward;
Vector3 zoomTarget = cameraTransform.localPosition + (direction * zoomDelta);
cameraTransform.localPosition =
Vector3.Lerp(cameraTransform.localPosition, zoomTarget, Time.deltaTime * zoomDamping);
cameraTransform.LookAt(transform);
}
The difference here is that we are moving the camera along its local forward axis, rather than approximating it by deleting components and relying on zoomSpeed across different events. Arguably, may not even need the final line of cameraTransform.LookAt(transform); with this solution, though it helps to avoid drift over time due to rounding errors.
Very good tutorial, i love it
Thanks very much for tutorial
In 23:45 'Rotation' spins camera itself but
30:54 'Rotation' makes camera orbits target point.
What's the difference?
At 23:45 the camera base object is rotating so the camera object orbits the base object. At 30:54 I am showing how the zoom works and that the rotation still works with the zooming. Unless I missed something or misspoke in the video. Does that help?
@@OneWheelStudio Thank you for answer.
"At 23:45 the camera base object is rotating" Is this means that the base object's transform is same as it of the camera object(its child)?
(Or positioned straight below, not in LOS, on the ground, possibly...)
The base object is the cameras parent object.
@@OneWheelStudio Yes, I meant that. (Center-shared objects vs Spinning with stretched arm)
Hello,
First let me say that the explanation is absolutely fantastic, I love the content in this video.
I was wondering if you could make a follow up video were you can implement these mechanism for touch input.
Thank you very much. Great tutorial and it was very helpful!
Hi. Zoom behaves weird. At some camera start positions, the zoom doesn't react to minZoom and zoom to the top view, turns 180 degrees, and moves away in the opposite direction. For example, at Y11 Z-11, but at position Y8 Z-8, this problem doesn't occur.
I have same problem, did you manage to solve it?
At 20 minutes, if the script is not working, go to edit > project settings > set "ActiveInputHandling" to "both" otherwise it doesnt work (I did set it to new only).
Very clear video. Thank you for completing with the blog, it is very useful for non English speakers.
In the ZoomCamera method, you don't use Mathf.Clamping. Is there a particular reason?
Mmm. Clamping would be a good way to do it. The only reason I didn't was I didn't think about it! Oops.
Glad the video and blog post are useful! Writing it out helps me too - most of my recent videos have a written post ;)
This is cool, but why does the camera change the angle when approaching, how to remove it? I want to get a fixed tilt angle on the x-axis.
I've paid for worse tutorials, lol. Very clear explanations and wonderful pacing.
That's a really great video thanks !! but do you know how we could limit the camera movement within a boundary ?
That depends on what you mean by a boundary. It wouldn't be too hard to set max and and min values for the x and z coordinates. Then every frame check if the camera is beyond those limits. If it is then slide it back to that limit.
Using something like a collider could work, but might be messier. If I wanted to implement this, I'd start with simple values and check the position of the camera.
for rotating the camera you just use delta mouse position.. but i want to implement the same thing for mobile if i use game pad it keeps rotating how can i fix this problem ?
Thank you for this awesome camera controller. One question:
I want to add in vertical camera rotation. So in the RotateCamera() method, I added a "valueY" and took the the Vector2().y value from the inputValue. Then I Clamped that value between a minVerticalRotation and maxVerticalRotation value and added it into the targetRotation Quaternion.Euler.
However, I want the minVerticalRotation to be around (probably) -30 degrees, but if I set it lower than 0, I get weird behavior that doesn't work. I don't understand Quaternions well enough to get what's happening. Anyone have any ideas?
Adding in rotation in all directions isn't too bad:
Add "float rightAxisRotationValue = inputValue.ReadValue().y;" to capture the y-component of mouse movement.
Pass transform.rotation.eulerAngles.x and transform.rotation.eulerAngles.z instead of 0f and 0f in the Euler() method.
Add "transform.Rotate(cameraTransform.right, -rightAxisRotationValue * maxRotationSpeed, Space.World):" to rotate the camera relative to the axis that goes through the camera to the left/right
Whats the easiest way to Lerp the rotation? i tried to combine it using the Game Dev Guide tut but it's not working.
Figured it out with One Wheel Studio on his discord!! such an incredibly nice and helpful person!!
private float rotationTarget;
private Quaternion rotTarget; //new variable
private void RotateCamera(InputAction.CallbackContext obj)
{
if (!Mouse.current.rightButton.isPressed)
return;
rotationTarget = obj.ReadValue().x;
rotTarget = Quaternion.Euler(0f, rotationTarget * maxRotationSpeed + transform.rotation.eulerAngles.y, 0f);
}
//this function needs to get called in the update function
private void UpdateCameraRotation()
{
transform.rotation = Quaternion.Lerp(this.transform.rotation, rotTarget, Time.deltaTime * RotationDampening);
}
Wow! I've seen this camera made a dozen different way but never like this! It was so easy to follow and extremely flexible. I've been developing for years, and this was the first in depth camera for strategy games I've seen that works right out of the gate, so to speak. My only question is I have my orthographic camera fixed at x: 30deg, and y:45deg like a tactics style game. It seems the rotation is being reset but I'm not sure where its doing that. I can rotate it back, but I'd like it to keep the rotation in the beginning and then be given the option of rotating. Is that difficult or would a few lines of code fix this?
Glad the video was useful! I do my best ;)
I'm not sure what would be causing the rotation issue. I'm not able to reproduce the behavior on my end. Is it possible that you are rotating the camera object rather than the base object?
Feel free to drop by the OWS discord (link in the description). Happy to take a look at code or the structure of the camera object.
Could have stored a reference to the camera when you were caching its transform. :D but as you said, many ways to deal with avoiding Camera.main. Was somehow expecting to see you use Cinemachine for this, but I guess Cinemachine could be considered overkill, depending on what you're going for. Good video regardless :)
I thought about using Cinemachine. Even started there when I was prototyping, but it felt complicated and a bit ugly. I think Cinemachine is amazing, but didn't feel like a good fit for this application.
@@OneWheelStudio Makes sense. I've never really done a strategy camera with cinemachine, but I suspect the zoom function you have set up here would require some extra work in cinemachine. Though the rotation and movement should be pretty straight forward.
Thanks, for the video, good stuff here.
Question: You mention using Camera.Main for the drag mode to operate correctly, however, what if you have a camera system for different scenes/modes and want to use that, would you just need a reference to the active camera, or would you add some functionality/reference to that script for that camera? Curious on how you would address that. Thanks again.
I think all you would need is a reference to each camera. It should work. The camera is only used to generate the ray for the raycast.
Thanks a lot! Best camera tutorial for strategy games.. How can i set start position of camera ?
You should be able to just set the position of the base object. You can either move in the sceneview or set the position of it in an Awake function.
How can I achieve this behavior by adding scheme of Touch?
Prob not important, but would be curious how you set that scene up. Did you use tilemaps, did you manually place the haxes. Did you use an asset store. I got a free 'Hexlands' and added some water, but yours looks a bit better, if not bland without art.
(Not an artist, and prob not going to use hexes, but makes it look like Dwarf Romantic, or something as you show cased.)
The tiles are each a 3D prefab. I created each tile in Blender - easy to create a hex with a radius of one unit.
Then to populate the map I start at the origin, randomize the number of a particular tile to add and then then search for empty neighboring slots - then repeat starting at a empty spot with a new type of tile. Red Blob Games has a great explanation of hex grids which was my main source for building up a hex grid library of functions.
Does that help? Does that answer all your questions. Happy to chat more.
@@OneWheelStudio Great thanks, yay Red Blob is like the master of all of that. Thanks for your detailed answer. Looks great, so your doing something right.
Thanks for this tutorial! I already had a strategy game camera for my game but I tried this and it adds some functionality which was missing from my camera - drag-move and the mouse at edge-of-screen movement (which is what I was originally looking for).
I have a bit of info to share and also a question, first the info:
I felt that the movement forward and backward with W and S made an unneeded "zoom" effect, which I felt should only be on properly zooming with the scrollwheel. To fix this, in the "GetKeyboardMovement" method, I changed the last line to be: "targetPosition += new Vector3(inputValue.x, 0f, -inputValue.y);". This way only the z axis of the camera base object moves when w or s are pressed, without the y.
Now for the question, when the camera is rotated and I move it with wasd keys, it moves in a weird direction, this is because when I press for example w it will still move forward according to the world space and not according to its rotation, is there a way to fix this so that w always moves the camera forward, s always moves backwards, and so on?
The temporary fix I can think of is to allow the camera to rotate only temporarily and as soon as the user releases the scrollwheel button, it will rotate back to the original rotation, and if it's not in the original rotation, don't move when wasd are pressed, but I'd much rather let the users rotate the camera as they wish and allow it to be moved forward-backward-left-right no matter what its rotation currently is.
Hmm. The camera should move relative to the direction it's facing.
I suspect your change to the GetKeyboardMovement function may be the culprit. Vector3(inputValue.x, 0f, - inputValue.y) would create a vector that is relative to the world X and Z axes rather than relative to the camera's forward and right directions. Instead I multiply the input values by the camera's forward and right direction vectors - this what the GetCameraForward and GetCameraRight functions are for. I could be wrong, but without seeing all your code that would be my best guess.
@@OneWheelStudio
First of all, thanks for the quick response!
You were right about my change affecting the camera's movement on rotation, for some reason I was convinced that I experienced the incorrect movement on a rotated camera even before my change, but I just tested it out now with the original line, and with it the camera moves as intended even when rotated.
What I tried to do to fix it while keeping the correct camera movement while rotated is to set inputvalue.y = 0, this will make the camera move without zooming, however when rotated it won't move right or left correctly, for example if it's rotated to 90 degrees it won't move at all when W or S are pressed, it will only move left and right on A or D presses.
I wonder if there's a way to fix it so that the camera moves without zooming and will also move correctly while rotated.
@@BurnEmDown1 The zooming was intentional on my part. The goal was to have the camera move in a sort of arch. All of that is happening in the UpCameraPosition function. If you check the code on GitHub, on line 195 of CameraMovement.cs you'll see the line responsible for the zoom in and out when the camera moves up and down. I think you can just remove the part on that line that is in the parentheses.
@@OneWheelStudio
I think I found my problem, as always - a typo 🤦♂
In the GetCameraForward method, I accidentally wrote:
forward.x = 0, instead of forward.y = 0
Fixing that solved all of my previously described issues!
Thanks again for this tutorial and helping out in the comments more than a year later!
I'm new to unity and found this tutorial very helpful. However, after some frustration, I realized that transform.position bypasses colliders. If you want to restrict the camera to a specific area (ie. the edge of the terrain), how would you go about it?
Glad the video was useful! :)
I wouldn't use colliders to restrict the location - if you were using the physics engine (rigidbody) there could be ways to do that but it could be messy - instead I would create additional variables for max and min positions (max X, min X, etc). Then when moving the camera see if the new location would exceed those limits. If it would, then don't move it.
Hope that helps. Feel free to jump over to the OWS discord if you need more detail or help.
Hello,
in function DragCamera, we should create plane as class member, instead of create it whenever right mouse button pressed.
Do you think it will improve performance ?
It might, I wouldn't expect it to do much, but you can always try and check results in the profiler.
Hello friend, could you know how I can change the screel wheel for pinch gesture for mobile new input system? I'm looking everywhere and I can't find any videos or anyone who knows, thanks!
Sorry, virtually zero experience with mobile.
Great video btw! I just wanted to ask how you could add y rotation as well with a hold-right click and clamp it to only rotate a certain amount?
Rotation with the mouse could be done a few ways. The way I have often done it is to capture the position of the mouse each frame and then calculate how far it moved since the last frame and use that to determine how far or how fast to rotate.
As for clamping values you could use Vector3.Angle() to calculate the angle between the current direction and say "forward." From there you could stop the motion in a particular direction. There is also Vector3.SignedAngle() that can give you positive and negative values.
Hope that helps.
hi there...why my visual studio has no " perfomed " word with the event icon ( the lighting icon )....so i stuck in line 67...vs error cs1061....please help
Any chance you forgot to generate the C# code for input action asset? Could also be a VS autocomplete issue?
thankyou
Anyone know how to add an invisible border to the camera movement ?
Hello,
Do you have tutorial work on mobile device? As we don't have Mouse Input on mobile device?
Or give me some hints, I will research it by myself
Thank
Sorry, haven't done much of anything with mobile. I'd just start with "mobile unity new input system" as a search.
After 5 month, finally dwelving in the newInputSystem I understand that you are using both Input system instead of using only the new one unlike the title of this video... as my previous comment figured out but without really understanding how the new input work.
Is there a reason for that ?
Im missing here move camera to underground, is posible to find somewhere tutiral to that?
I'm not sure what "underground" means. You could simply change the minimum height to go lower.... If you mean navigate through dungeons or caves you're going to need to find something on object avoidance - cinemaching has some of this built in, but you'd probably want to take it further. I can't point you to a specific tutorial - it can be a very complex topic.
Any chance you could do a tutorial on how to zoom to the current cursor postion Supreme Commander style?
This came up from another viewer too. It could be a fun follow up video for sure!
In the mean time, my suggestion was to raycast from the camera to the mouse and get a point in the world. Then as you zoom you also lerp the camera towards the point hit by the raycast. 100% have not tested it, but it would be my first attempt. Hope that helps.
@@OneWheelStudio I'd love to see a follow up video, and thanks for the suggestion!
@@Wolvman I've just moved and will be starting a new job so don't hold you breath. OWS content is on hold for at least the next 2 weeks.
@@OneWheelStudio Totally understand and congrats on the move and new job. If/when you get to it I wanted to suggest a few more things that I'd love to see in a part 2. For example having the camera gently raise and lower as you pass over hills or dips in the landscape would be an awesome feature. I was also wondering how to rotate the camera up/down while holding the middle mouse button and moving the mouse forward/back without going through the ground. Adding keyboard keys for zooming in and out and rotating left/right would also be a plus.
How can I convert this system to mobile?
Been looking months for this, thank you. Best strategy game camera video I've found yet. New sub from me. Everything works great, is it just me or is the rotation a bit choppy? I'm sure its not the code.. I,ve set it to .02 but I still feel like my pulse and/or the mouse pad surface is affecting the smoothness of the rotation. I'm wondering if I should add a damp variable to it as well?
I'm glad the video is helpful!
As for the choppiness, I haven't seen it on my end, but other comments have seen choppiness with the drag IIRC. This came up when the speed was set higher and the solution seemed to be increasing the smoothing too.
Hey, I would like to ask, if I want to rotate the camera on the X axis as well, what are the step I should make? Thank you very much for thus tutorial!
Rotating in multiple dimensions can get tricky. But! To get started you can likely copy and modify the code for the y rotation and make it work for x rotation. First steps would be to create new action for the new rotation. Then create a new function for the X rotation (the copy and modify part). Subscribe the new function to the new actions and test!
Wow, what a great tutorial!
Everything works perfectly as your tutorial intends, but I'd like to make a bit of a modification and I'm having a hell of a time. My project is using point and click controls on a nav mesh, on a terrain with a lot of elevation changes. I would like to modify the script so that the camera follows the player character height during navigation. So far, I have tried changing the 'ZoomCamera()' method a bit, to see if I could at least lower and raise the minimum/maximum depending on current position. So far, nothing I've tried has done the trick (though I have had a few funny camera behavior moments lol...) Does anyone have any ideas or suggestions as to how I might get this working the way I described? If so, I am eternally grateful! :)
How to use this Camera Control System with mobile finger inputs?
I haven't done any real work with mobile, but I would imagine it's a matter of defining mobile bindings for the actions. That is one of the nicest parts of the new input system - the same actions can be bound to different inputs. How to define those inputs? Sorry, I wish I could be more helpful.
Any chance u can make this for 2D?
There's no reason this couldn't work for 2D. You might have to change the orientation so the controls work in x and y instead of a x and z, but that should be most of the changes needed.
Bro, if "you've taken an awful lot of your implementation" from somebody else, maybe it's a better idea to plug your source in closer to the beginning rather than 36:38 seconds in. You're doing a pretty big disservice to Game Dev Guide, as well as yourself because you’ve turned away a viewer.
My apologies if it came off wrong. It’s been a while since I made the video but what I was referring to was the drag functionality being heavily inspired by Game Dev Guide not the entire controller. It was not my intent to bury or hide a source. Again I’m sorry if it came off that way.
I usually love your videos, but this time I think you should have done a bit more research before doing this one. The idea of mappings is that you can use multiple devices to achieve the same thing, for example with this video, you are using Mouse.current instead of using the mappings to move and control the camera, and read the mouse position. This is problematic because what if we now need to move the game to a console, we are now going to have to rewrite a vast majority of this code because we now need to support a Controller to move the Camera.
I am sure the more experienced will know what to do here, but as a learning for others, sadly this is only showing half the reason to switch to the New Input System.
The Drag camera gets shaky when the maxSpeed is increased
i fixed it by adding
float newMaxSpeed = maxSpeed;
if (Mouse.current.rightButton.isPressed) { newMaxSpeed = 5f; }
in UpdateUpdateBasePosition()
and replaced MaxSpeed with newMaxSpeed
It gets shaky if maxSpeed is increased without also increasing the dampening. This makes the camera overshoot it's position, since it can't slow down fast enough, and because the mouse is still pressed, the target position remains the same and the camera will move back towards it (and overshoot because it can't slow down fast enough, repeating the process giving you a shaky looking camera). Increase the dampening when you increase the speed and this problem gets fixed.
Its is complicated, better split video for each type of control. I need pan move, but to get it i need to watch whole video
First
Awesome tutorial! love it.
There seems to be an issues with Zooming, however. Since we are using LookAt(this.transform), if the we zoom in too much, camera rotates 180 degrees instantly.
Is there a way to combat this?
The min height should put a limit on how much you can zoom in. (This happens in the zoom function - line 183 in the code shared on github.) I'd try raising that value - it should work. If it doesn't then something is different about your setup - which is fine - and you could do a distance check instead of a height check.
@@OneWheelStudio Is it possible to somehow set the default height in code? The minHeight should match the height of the camera on game scene so that it does not rotate 180 degrees. But I wanted there to be some default value between the minHeight and maxHeight, so that the camera could go lower
@@OneWheelStudio Probably a bit late, but perhaps someone will find this useful. This happens because of some math between the Y and your Z values. And you use the moving forward on zoom part of the code. In some combinations of Y and Z, the line of code that moves the camera towards the target allows it to push the camera past the Z=0 point, turning it positive and thus flipping the camera. This happens when the Y minHeight has not yet been reached, but you get close enough to Z=0 that moving forward pushes you past that point. It DOES react to minHeight, it's just that you have moved forward too far and the minHeight has not yet been reached.
MinHeight ONLY factors in the Y position. There is NO safety check for the Z value. To fix this, you can create a minDistance variable and set it to any negative number. The lower the number, the more of a top-down view you can get. Z=0 is directly above the camera's target, and thus a perfect top down view. This HAS to be a negative value, else you flip the camera. Then, after the line of code that starts with zoomTarget -= zoomSpeed etcetc, you add a new line:
if (zoomTarget.z > minDistance) zoomTarget.z = minDistance;
This will prevent the camera zoom movement from getting so close that it flips the camera. I encountered this problem myself after following along with your tutorial, and could not find a fix in the comments, so I hope this helps someone some day :)