- Home /
Fixing Issues with custom RTS Camera Controll Script
Um Hello everyone, I've been working on a project for a while thats really close to my heart and has been a vision in my head for many years that's finally beginning to take shape for the first time. The problem is that one of the cameras wont work properly. When i use the edge scrolling or arrow keys I can only go down or to the left. The zoom doesnt work at all either. Its a custom script I created using the best parts of several other scripts so here it is below, I really could use some help here.
using UnityEngine;
using System.Collections;
public class StrategyMovement : MonoBehaviour
{ private const int ZoomSpeed = 50;
private const int ZoomMin = 25;
private const int ZoomMax = 100;
private const int PanSpeed = 50;
private const int PanAngleMin = 50;
private const int PanAngleMax = 80;
// Update is called once per frame
void Update () {
// Init camera translation for this frame.
var translation = Vector3.zero;
// Mouse Buttons and Edge Scrolling Stuff
float mousePosX = Input.mousePosition.x;
float mousePosY = Input.mousePosition.y;
int scrollDistance = 5;
float scrollSpeed = 70;
float ScrollAmount = scrollSpeed *Time.deltaTime;
//mouse left
if ((mousePosX < scrollDistance) && (transform.position.x > 500)) {
transform.Translate (-ScrollAmount,0,0, Space.World);
}
//mouse right
if ((mousePosX >= Screen.width - scrollDistance) && (transform.position.x < 500)) {
transform.Translate (ScrollAmount,0,0, Space.World);
}
//mouse down
if ((mousePosY < scrollDistance) && (transform.position.z > 500)) {
transform.Translate (0,0,-ScrollAmount, Space.World);
}
//mouse up
if ((mousePosY >= Screen.height - scrollDistance) && (transform.position.z < 500)) {
transform.Translate (0,0,ScrollAmount, Space.World); ;
}
//Keyboard controls
if ((Input.GetKey(KeyCode.UpArrow)) && (transform.position.z < -500)) {
transform.Translate (0,0,ScrollAmount, Space.World); ;
}
if ((Input.GetKey(KeyCode.DownArrow)) && (transform.position.z > 500)) {
transform.Translate (0,0,-ScrollAmount, Space.World);
}
if ((Input.GetKey(KeyCode.LeftArrow)) && (transform.position.x > 500)) {
transform.Translate (-ScrollAmount,0,0, Space.World);
}
if ((Input.GetKey(KeyCode.RightArrow)) && (transform.position.x < -500)) {
transform.Translate (ScrollAmount,0,0, Space.World);
}
// Zoom in or out
var zoomDelta = Input.GetAxis("Mouse ScrollWheel")*ZoomSpeed*Time.deltaTime;
if (zoomDelta!=0){
translation -= Vector3.up * ZoomSpeed * zoomDelta;
}
// Start panning camera if zooming in close to the ground or if just zooming out.
var pan = camera.transform.eulerAngles.x - zoomDelta * PanSpeed;
pan = Mathf.Clamp(pan, PanAngleMin, PanAngleMax);
if (zoomDelta < 0 || camera.transform.position.y < (ZoomMax / 2)){
camera.transform.eulerAngles = new Vector3(pan, 0, 0);
}
}
}
Answer by Zodiarc · Jun 03, 2014 at 10:30 AM
I don't really see why the code would not work, but I can show you how I did something similar (but for a TBS game).
#pragma strict
class CameraControls extends MonoBehaviour{
public var speed: float = 5.0f;
public var terrain: GameObject;
public var xRotator: GameObject;
private var terrainHeight:float;
private var t:float = 0.0f;
private var mouseClickPosition:Vector2;
private function moveRight():void{
if(Input.mousePosition.x > Screen.width * 0.95f || Input.GetKey(KeyCode.RightArrow)){
this.transform.Translate(Vector3.right * this.speed * Time.deltaTime);
this.getTerrainHeight();
}
}
private function moveLeft():void{
if(Input.mousePosition.x < Screen.width * 0.05f || Input.GetKey(KeyCode.LeftArrow)){
this.transform.Translate(-Vector3.right * this.speed * Time.deltaTime);
this.getTerrainHeight();
}
}
private function moveForward():void{
if(Input.mousePosition.y < Screen.height * 0.05f || Input.GetKey(KeyCode.DownArrow)){
this.transform.Translate(-Vector3.forward * this.speed * Time.deltaTime);
this.getTerrainHeight();
}
}
private function moveBackward():void{
if(Input.mousePosition.y > Screen.height * 0.95f || Input.GetKey(KeyCode.UpArrow)){
this.transform.Translate(Vector3.forward * this.speed * Time.deltaTime);
this.getTerrainHeight();
}
}
private function getTerrainHeight(){
var hit: RaycastHit;
this.terrain.layer = 0;
// Get terrain y value at current position.
if(Physics.Raycast(Vector3(this.transform.position.x, 300, this.transform.position.z), -Vector3.up, hit, 500)){
this.terrainHeight = hit.point.y;
}
this.terrain.layer = 2;
}
private function adjustToTerrainHeight(){
if(this.transform.position.y != this.terrainHeight){
this.transform.position.y = Mathf.Lerp(this.transform.position.y, this.terrainHeight, this.t);
//this.transform.position.y = this.terrainHeight;
Debug.Log("y " + this.terrainHeight);
t += Time.deltaTime;
}
else{
this.t = 0;
}
}
private function rotateCamera():void{
if(Input.GetMouseButtonDown(1)){
this.mouseClickPosition = Input.mousePosition;
}
if(Input.GetMouseButton(1)){
var delta = this.mouseClickPosition - Input.mousePosition;
this.mouseClickPosition = Input.mousePosition;
this.transform.Rotate(Vector3.up * -this.speed * delta.x * Time.deltaTime);
this.xRotator.transform.Rotate(Vector3.right * this.speed * delta.y * Time.deltaTime);
this.xRotator.transform.rotation.eulerAngles.x = ClampAngle(this.xRotator.transform.rotation.eulerAngles.x, 0.0f, 40.0f);
}
}
private function ClampAngle(angle: float, min: float, max: float): float {
if (angle<90 || angle>270){ // if angle in the critic region...
if (angle>180) angle -= 360; // convert all angles to -180..+180
if (max>180) max -= 360;
if (min>180) min -= 360;
}
angle = Mathf.Clamp(angle, min, max);
if (angle<0) angle += 360; // if angle negative, convert to 0..360
return angle;
}
public function Update(){
if(!Input.GetMouseButton(1)){
this.moveRight();
this.moveLeft();
this.moveForward();
this.moveBackward();
}
if(Input.GetKeyDown(KeyCode.Escape)){
Application.Quit();
}
}
public function LateUpdate(){
this.adjustToTerrainHeight();
this.rotateCamera();
}
}
The camera setup is like this (as tree):
You won't probably need the terrain. I need it to switch its layers dynamically because I don't want my grid to hit it with raycasts to determine the moving radius with built-in obstacle detection.
The script is attached to the yRotator.
For the zooming I would do it in a separate script, use Translate(Vector3.forward speed Time.deltaTime) and attach it to the main camera (in the setup i showed you here) or add another public variable for the main camera. Speed should of course be negative or positive depending on the scroll direction.
Maybe you can get some inspiration from it.
C# version (no guarantee for correctness)
using UnityEngine;
using System.Collections;
public class CameraControls : MonoBehaviour{
public float speed = 5.0f;
public GameObject terrain;
public GameObject xRotator;
private float terrainHeight;
private float t = 0.0f;
private Vector2 mouseClickPosition;
private void moveRight(){
if(Input.mousePosition.x > Screen.width * 0.95f || Input.GetKey(KeyCode.RightArrow)){
this.transform.Translate(Vector3.right * this.speed * Time.deltaTime);
this.getTerrainHeight();
}
}
private void moveLeft(){
if(Input.mousePosition.x < Screen.width * 0.05f || Input.GetKey(KeyCode.LeftArrow)){
this.transform.Translate(-Vector3.right * this.speed * Time.deltaTime);
this.getTerrainHeight();
}
}
private void moveForward(){
if(Input.mousePosition.y < Screen.height * 0.05f || Input.GetKey(KeyCode.DownArrow)){
this.transform.Translate(-Vector3.forward * this.speed * Time.deltaTime);
this.getTerrainHeight();
}
}
private void moveBackward(){
if(Input.mousePosition.y > Screen.height * 0.95f || Input.GetKey(KeyCode.UpArrow)){
this.transform.Translate(Vector3.forward * this.speed * Time.deltaTime);
this.getTerrainHeight();
}
}
private void getTerrainHeight(){
RaycastHit hit;
this.terrain.layer = 0;
// Get terrain y value at current position.
if(Physics.Raycast(Vector3(this.transform.position.x, 300, this.transform.position.z), -Vector3.up, hit, 500)){
this.terrainHeight = hit.point.y;
}
this.terrain.layer = 2;
}
private void adjustToTerrainHeight(){
if(this.transform.position.y != this.terrainHeight){
this.transform.position.y = Mathf.Lerp(this.transform.position.y, this.terrainHeight, this.t);
//this.transform.position.y = this.terrainHeight;
Debug.Log("y " + this.terrainHeight);
t += Time.deltaTime;
}
else{
this.t = 0;
}
}
private void rotateCamera():void{
if(Input.GetMouseButtonDown(1)){
this.mouseClickPosition = Input.mousePosition;
}
if(Input.GetMouseButton(1)){
Vector2 delta = this.mouseClickPosition - Input.mousePosition;
this.mouseClickPosition = Input.mousePosition;
this.transform.Rotate(Vector3.up * -this.speed * delta.x * Time.deltaTime);
this.xRotator.transform.Rotate(Vector3.right * this.speed * delta.y * Time.deltaTime);
this.xRotator.transform.rotation.eulerAngles.x = ClampAngle(this.xRotator.transform.rotation.eulerAngles.x, 0.0f, 40.0f);
}
}
private float ClampAngle(float angle, float min, float max) {
if (angle<90 || angle>270){ // if angle in the critic region...
if (angle>180) angle -= 360; // convert all angles to -180..+180
if (max>180) max -= 360;
if (min>180) min -= 360;
}
angle = Mathf.Clamp(angle, min, max);
if (angle<0) angle += 360; // if angle negative, convert to 0..360
return angle;
}
public void Update(){
if(!Input.GetMouseButton(1)){
this.moveRight();
this.moveLeft();
this.moveForward();
this.moveBackward();
}
if(Input.GetKeyDown(KeyCode.Escape)){
Application.Quit();
}
}
public void LateUpdate(){
this.adjustToTerrainHeight();
this.rotateCamera();
}
}
Thanks for the answer, im going to try out your way and see where it takes me, though could I please have a variation of this in C#?
Unfortunately I'm not an expert in C# but I can try to translate it.
EDIT: I translated it, but I'm unable to say if it will work from scratch. $$anonymous$$aybe you will have to remove some syntax errors.
You are also free to mess around with the values in all functions to adjust them to your needs but don't touch ClampAngle() because it will ruin the rotation on the x axis (but you can change the paramteres passed to the function).
Thankyou so much for your help, I now have enough examples of working code to update my script and get everything to work properly
works really well, few small problems but once i removed the terrain checkers and the raycast it worked pretty well, thankyou :D
You should show your appreciation with some thumbs up :)
Your answer
Follow this Question
Related Questions
RTS Mouse Click Movement 1 Answer
3D RTS camera 3 Answers
Attaching an RTS scrolling script to a camera (Noob Question) 3 Answers
Move Camera According to Mouse Movement While Button is Pressed 1 Answer