I'm tring to implement a simple (but realistic as possible) 2D flight simulator in Unity using its 2D engine.
I have taken some sources around and tried to compile my own (without success) ... i must admit i'm a math and c# newbie; forgive my ignorance ..
Ideally i would like to achieve something like this :
http://runway.countlessprojects.com/prototype/index.html
Any ideas / corrections / suggestions welcome
using UnityEngine;
using System.Collections;
public class FlightControl : MonoBehaviour {
public float energy;
public float roll;
public float tilt;
public float yaw;
public float airspeed;
public float fall;
public float tip;
Rigidbody2D rb;
void Awake()
{
rb = GetComponent<Rigidbody2D>();
}
void Start () {
}
void Update () {
energy = transform.position.y + GetComponent<Rigidbody2D>().velocity.magnitude;
}
void FixedUpdate () {
tilt = Mathf.Clamp (energy / 100, -8f, 5f);
tilt /= Time.deltaTime * 10;
if (Input.GetButton("Jump")) {
GetComponent<Rigidbody2D>().AddForce((Vector2)transform.up * Time.deltaTime * 10000);
}
transform.rotation = Quaternion.Euler(0, 0, 270+Mathf.Rad2Deg * Mathf.Atan2(rb.velocity.y, rb.velocity.x));
if (((Vector2)transform.forward + GetComponent<Rigidbody2D>().velocity.normalized).magnitude < 1.4)
tilt += 1f;
if (tilt != 0)
transform.Rotate (new Vector3 (0f, 0f, tilt * Time.deltaTime));
GetComponent<Rigidbody2D>().velocity -= Vector2.up * Time.deltaTime;
// Velocity
Vector2 vertvel = GetComponent<Rigidbody2D>().velocity - (Vector2)Vector3.ProjectOnPlane (transform.up, GetComponent<Rigidbody2D>().velocity);
fall = vertvel.magnitude;
GetComponent<Rigidbody2D>().velocity -= vertvel * Time.deltaTime;
GetComponent<Rigidbody2D>().velocity += vertvel.magnitude * (Vector2)transform.right * Time.deltaTime / 10;
// Drag
Vector2 forwardDrag = GetComponent<Rigidbody2D>().velocity - (Vector2)Vector3.ProjectOnPlane ((Vector2)transform.right, GetComponent<Rigidbody2D>().velocity);
GetComponent<Rigidbody2D>().AddForce (forwardDrag * forwardDrag.magnitude * Time.deltaTime / 1000);
airspeed = GetComponent<Rigidbody2D>().velocity.magnitude;
}
}
Related
Im making a 3d game in unity, and so I made a cs script for movement of my charecter, walking and moveing the camera works fine, however when i added the jump function, it had a delay. You could press the jump button 5 times, with no result. Then you press it again, and it jumps. I cant figure out why this does this.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerMovement : MonoBehaviour
{
public CharacterController characterController;
public int speed = 6;
public float gravity = 9.87f;
private float verticalspeed = 0;
private Vector3 moveDirection = Vector3.zero;
public Transform Camera;
public float Sensitivity = 2f;
public float uplimit = -50;
public float downlimit = -50;
public float jumpspeed = 5.0f;
void Update()
{
move();
cameramove();
void cameramove()
{
float horizontal = Input.GetAxis("Mouse X");
float vertical = Input.GetAxis("Mouse Y");
transform.Rotate(0, horizontal * Sensitivity, 0);
Camera.Rotate(-vertical * Sensitivity, 0, 0);
Vector3 currentRotation = Camera.localEulerAngles;
if (currentRotation.x > 180) currentRotation.x -= 360;
currentRotation.x = Mathf.Clamp(currentRotation.x, uplimit, downlimit);
Camera.localRotation = Quaternion.Euler(currentRotation);
}
void move()
{
float horizontalMove = Input.GetAxis("Horizontal");
float verticalMove = Input.GetAxis("Vertical");
if (characterController.isGrounded) verticalspeed = 0;
else verticalspeed -= gravity * Time.deltaTime;
Vector3 gravityMove = new Vector3(0, verticalspeed, 0);
Vector3 move = transform.forward * verticalMove + transform.right * horizontalMove;
characterController.Move(speed * Time.deltaTime * move + gravityMove * Time.deltaTime);
if (characterController.isGrounded && Input.GetButton("Jump"))
{
moveDirection.y = jumpspeed;
}
moveDirection.y -= gravity * Time.deltaTime;
characterController.Move(moveDirection * Time.deltaTime);
}
}
}
Assuming your character has a RigidBody assigned to it, you can refer it on your script as,
public class PlayerMovement : MonoBehaviour
{
private Rigidbody myrigidbody;
void Start () {
myrigidbody = GetComponent<Rigidbody>();
}
}
Then you can pass the jumpspeed as a Vector3, and probably you might have to trigger your animation here as well.
if (characterController.isGrounded && Input.GetButton("Jump"))
{
characterController.isGrounded = false;
myrigidbody.AddForce(new Vector3(0, jumpspeed, 0));
// Trigger your animation, myanimator.SetTrigger("jump");
}
Unity character controller move documentation also contains jump function.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Example : MonoBehaviour
{
private CharacterController controller;
private Vector3 playerVelocity;
private bool groundedPlayer;
private float playerSpeed = 2.0f;
private float jumpHeight = 1.0f;
private float gravityValue = -9.81f;
private void Start()
{
controller = gameObject.AddComponent<CharacterController>();
}
void Update()
{
groundedPlayer = controller.isGrounded;
if (groundedPlayer && playerVelocity.y < 0)
{
playerVelocity.y = 0f;
}
Vector3 move = new Vector3(Input.GetAxis("Horizontal"), 0, Input.GetAxis("Vertical"));
controller.Move(move * Time.deltaTime * playerSpeed);
if (move != Vector3.zero)
{
gameObject.transform.forward = move;
}
// Changes the height position of the player..
if (Input.GetButtonDown("Jump") && groundedPlayer)
{
playerVelocity.y += Mathf.Sqrt(jumpHeight * -3.0f * gravityValue);
}
playerVelocity.y += gravityValue * Time.deltaTime;
controller.Move(playerVelocity * Time.deltaTime);
}
}
I have a problem with my camera movement. I want to limit my camera rotation, but I don't know how to do this. I searched for a solution, but I was not able to find one.
In my current code, my camera rotates rapidly in any direction and I don't know how to implement the Mathf.Clamp correctly.
Here is my code:
public float rightSpeed = 20.0f;
public float leftSpeed = -20.0f;
public float rotationLimit = 0.0f;
void Update()
{
//EdgeScrolling
float edgeSize = 40f;
if (Input.mousePosition.x > Screen.width - edgeSize)
{
//EdgeRight
transform.RotateAround(this.transform.position, Vector3.up, rotationLimit += rightSpeed * Time.deltaTime);
}
if (Input.mousePosition.x < edgeSize)
{
//EdgeLeft
transform.RotateAround(this.transform.position, Vector3.up, rotationLimit -= leftSpeed * Time.deltaTime);
}
rotationLimit = Mathf.Clamp(rotationLimit, 50f, 130f);
}
RotateAround method rotates by an angle. It doesn't assign the angle value you pass it. In this case I would suggest using a different approach. Instead of RotateAround method use the eulerAngles property and assign the rotation values directly.
Example
using UnityEngine;
public class TestScript : MonoBehaviour
{
public float rightSpeed = 20.0f;
public float leftSpeed = -20.0f;
private void Update()
{
float edgeSize = 40f;
if (Input.mousePosition.x > Screen.width - edgeSize)
RotateByY(rightSpeed * Time.deltaTime);
else if (Input.mousePosition.x < edgeSize)
RotateByY(leftSpeed * Time.deltaTime);
}
public void RotateByY(float angle)
{
float newAngle = transform.eulerAngles.y + angle;
transform.eulerAngles = new Vector3(
transform.eulerAngles.x,
Mathf.Clamp(newAngle, 50f, 130f),
transform.eulerAngles.z);
}
}
I have began developing an fps script and followed a tutorial to help with the script. Everything works great now but the only issue is any objects in the view seem to stutter whenever the player is moving and rotating at the same time.
The script for the player's movement and camera rotation is below.
Can anybody point me in the right direction?
Thank you.
{
public Transform cam;
public Rigidbody rb;
public float camRotationSpeed = 5f;
public float camMinimumY = -60f;
public float camMaximumY = 75f;
public float rotationSmoothSpeed = 10f;
public float walkSpeed = 9f;
public float runSpeed = 14f;
public float maxSpeed = 20f;
public float jumpPower = 30f;
public float extraGravity = 45;
float bodyRotationX;
float camRotationY;
Vector3 directionIntentX;
Vector3 directionIntentY;
float speed;
public bool grounded;
void Update()
{
LookRotation();
Movement();
ExtraGravity();
GroundCheck();
if(grounded && Input.GetButtonDown("Jump"))
{
Jump();
}
}
void LookRotation()
{
Cursor.visible = false;
Cursor.lockState = CursorLockMode.Locked;
bodyRotationX += Input.GetAxis("Mouse X") * camRotationSpeed;
camRotationY += Input.GetAxis("Mouse Y") * camRotationSpeed;
camRotationY = Mathf.Clamp(camRotationY, camMinimumY, camMaximumY);
Quaternion camTargetRotation = Quaternion.Euler(-camRotationY, 0, 0);
Quaternion bodyTargetRotation = Quaternion.Euler(0, bodyRotationX, 0);
transform.rotation = Quaternion.Lerp(transform.rotation, bodyTargetRotation, Time.deltaTime * rotationSmoothSpeed);
cam.localRotation = Quaternion.Lerp(cam.localRotation, camTargetRotation, Time.deltaTime * rotationSmoothSpeed);
}
void Movement()
{
directionIntentX = cam.right;
directionIntentX.y = 0;
directionIntentX.Normalize();
directionIntentY = cam.forward;
directionIntentY.y = 0;
directionIntentY.Normalize();
rb.velocity = directionIntentY * Input.GetAxis("Vertical") * speed + directionIntentX * Input.GetAxis("Horizontal") * speed + Vector3.up * rb.velocity.y;
rb.velocity = Vector3.ClampMagnitude(rb.velocity, maxSpeed);
if (Input.GetKey(KeyCode.LeftShift))
{
speed = runSpeed;
}
if (!Input.GetKey(KeyCode.LeftShift))
{
speed = walkSpeed;
}
}
void ExtraGravity()
{
rb.AddForce(Vector3.down * extraGravity);
}
void GroundCheck()
{
RaycastHit groundHit;
grounded = Physics.Raycast(transform.position, -transform.up, out groundHit, 1.25f);
}
void Jump()
{
rb.AddForce(Vector3.up * jumpPower, ForceMode.Impulse);
}
}
This probably happens because the frame needs to update the camera rotation and the player position at the same time. i would suggest doing the rotation of the camera in fixed update. because this will run at the end of each frame.
like this:
void FixedUpdate()
{
LookRotation();
}
another thing i would suggest is to move the player while the groundcheck is being ran, because if you do it seperately i can see a bug coming up when the player moves faster then the code can run or something. so a tip would be or to run it inside the movement method, or call the method while you are calling the movement method.
this:
void Movement()
{
directionIntentX = cam.right;
directionIntentX.y = 0;
directionIntentX.Normalize();
directionIntentY = cam.forward;
directionIntentY.y = 0;
directionIntentY.Normalize();
rb.velocity = directionIntentY * Input.GetAxis("Vertical") * speed + directionIntentX * Input.GetAxis("Horizontal") * speed + Vector3.up * rb.velocity.y;
rb.velocity = Vector3.ClampMagnitude(rb.velocity, maxSpeed);
if (Input.GetKey(KeyCode.LeftShift))
{
speed = runSpeed;
}
if (!Input.GetKey(KeyCode.LeftShift))
{
speed = walkSpeed;
}
GroundCheck();
}
or litteraly copy and paste the code within your movement method.
I can make the camera move the way I want, but I need it to be confined to within the 3D hollow sphere that I created. Currently the player can fly the camera out of the game area.
I've tried parenting the camera to a spherical game object, but the camera still leaves the game area but the sphere stays inside.
This was my attempt at using the BoundingSphere method to keep the camera inside the sphere.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class SphericalBoundary : MonoBehaviour
{
public Vector3 pos;
public float r;
void Start()
{
BoundingSphere();
}
private void FixedUpdate()
{
BoundingSphere();
}
public void BoundingSphere()
{
pos = new Vector3(0, 0, 0);
r = (100);
}
}
============================================================================
============================================================================
This is the script that makes the camera fly around. Works perfectly.
using UnityEngine;
using System.Collections;
public class CameraFlight : MonoBehaviour
{
/*
EXTENDED FLYCAM
Desi Quintans (CowfaceGames.com), 17 August 2012.
Based on FlyThrough.js by Slin (http://wiki.unity3d.com/index.php/FlyThrough), 17 May 2011.
LICENSE
Free as in speech, and free as in beer.
FEATURES
WASD/Arrows: Movement
Q: Climb
E: Drop
Shift: Move faster
Control: Move slower
End: Toggle cursor locking to screen (you can also press Ctrl+P to toggle play mode on and off).
*/
public float cameraSensitivity = 90;
public float climbSpeed = 4;
public float normalMoveSpeed = 10;
public float slowMoveFactor = 0.25f;
public float fastMoveFactor = 3;
private float rotationX = 0.0f;
private float rotationY = 0.0f;
void Start()
{
// Screen.lockCursor = true;
}
void Update()
{
rotationX += Input.GetAxis("Mouse X") * cameraSensitivity * Time.deltaTime;
rotationY += Input.GetAxis("Mouse Y") * cameraSensitivity * Time.deltaTime;
rotationY = Mathf.Clamp(rotationY, -90, 90);
transform.localRotation = Quaternion.AngleAxis(rotationX, Vector3.up);
transform.localRotation *= Quaternion.AngleAxis(rotationY, Vector3.left);
if (Input.GetKey(KeyCode.LeftShift) || Input.GetKey(KeyCode.RightShift))
{
transform.position += transform.forward * (normalMoveSpeed * fastMoveFactor) * Input.GetAxis("Vertical") * Time.deltaTime;
transform.position += transform.right * (normalMoveSpeed * fastMoveFactor) * Input.GetAxis("Horizontal") * Time.deltaTime;
}
else if (Input.GetKey(KeyCode.LeftControl) || Input.GetKey(KeyCode.RightControl))
{
transform.position += transform.forward * (normalMoveSpeed * slowMoveFactor) * Input.GetAxis("Vertical") * Time.deltaTime;
transform.position += transform.right * (normalMoveSpeed * slowMoveFactor) * Input.GetAxis("Horizontal") * Time.deltaTime;
}
else
{
transform.position += transform.forward * normalMoveSpeed * Input.GetAxis("Vertical") * Time.deltaTime;
transform.position += transform.right * normalMoveSpeed * Input.GetAxis("Horizontal") * Time.deltaTime;
}
if (Input.GetKey(KeyCode.Q)) { transform.position += transform.up * climbSpeed * Time.deltaTime; }
if (Input.GetKey(KeyCode.E)) { transform.position -= transform.up * climbSpeed * Time.deltaTime; }
//if (Input.GetKeyDown(KeyCode.End))
//{
// Screen.lockCursor = (Screen.lockCursor == false) ? true :][1]
false;
//}
}
}
No errors are showing up. During play the player can fly the camera out of the sphere but I want them confined to the sphere.
I think you must look your camera position on every frame and also check if it's going out of bound of the sphere here is some code which might help you(it is not tested)
public class TestScriptForStackOverflow : MonoBehaviour {
public Transform CameraTrans, SphereTrans;
private float _sphereRadius;
void Start() {
//if we are talking about sphere its localscale.x,y,z values are always equal
_sphereRadius = SphereTrans.localScale.x / 2;
}
void Update() {
if (IsOutsideTheSphere(_sphereRadius, CameraTrans.position, SphereTrans.position)) {
//lets find direction of camera from sphere center
Vector3 direction = (CameraTrans.position - SphereTrans.position).normalized;
//this is bound point for specific direction which is point is on the end of the radius
Vector3 boundPos = SphereTrans.position + direction * _sphereRadius;
//finally assign bound position to camera to stop it to pierce the sphere bounds
CameraTrans.position = boundPos;
}
}
private bool IsOutsideTheSphere(float sphereRadius, Vector3 cameraPosition, Vector3 sphereCenterPosition) {
//distance betweeen cameraPosition and sphereCenterPosition
float distanceBetween = (cameraPosition - sphereCenterPosition).magnitude;
//returns true if distance between sphere center and camera position is longer then sphere radius
return distanceBetween > sphereRadius;
}
If there is something you don't understand ask me in comments
I am trying to clamp the value of y for my game object to be 4 and -4 but it keeps jumping to the ymax and ymin. and the only reason i can think of is because of the last line code. i am only clamping the y values because the x and z values are not changed in the game. the game is similar to pong.
using UnityEngine;
using System.Collections;
public class Movement1 : MonoBehaviour
{
public Vector3 Pos;
void Start ()
{
Pos = gameObject.transform.localPosition;
}
public float yMin, yMax;
void Update ()
{
if (Input.GetKey (KeyCode.W)) {
transform.Translate (Vector3.up * Time.deltaTime * 10);
}
if (Input.GetKey (KeyCode.S)) {
transform.Translate (Vector3.down * Time.deltaTime * 10);
}
Pos.y = Mathf.Clamp(Pos.y,yMin,yMax);
gameObject.transform.localPosition = Pos;
}
}
The Pos.y assignment never happens, because you can't change just the y-value; you have to make a new Vector3. Try the following:
using UnityEngine;
using System.Collections;
public class Movement1 : MonoBehaviour
{
public float yMin, yMax; // be sure to set these in the inspector
void Update ()
{
if (Input.GetKey (KeyCode.W)) {
transform.Translate (Vector3.up * Time.deltaTime * 10);
}
if (Input.GetKey (KeyCode.S)) {
transform.Translate (Vector3.down * Time.deltaTime * 10);
}
float clampedY = Mathf.Clamp(transform.localPosition.y,yMin,yMax);
transform.localPosition = new Vector3 (transform.localPosition.x, clampedY, transform.localPosition.z);
}
}
You didn't initialize any values for the yMin, yMax.
Also, you should put an else if for the second Translate, otherwise pressing both could cause jitters.
But really, it should be more like this:
using UnityEngine;
using System.Collections;
public class Movement1 : MonoBehaviour
{
public Vector3 Pos;
public float speed = 10f;
public float yMin = 10f;
public float yMax = 50f;
void Update ()
{
Pos = gameObject.transform.localPosition;
if (Input.GetKey (KeyCode.W))
Pos += (Vector3.up * Time.deltaTime * speed);
if (Input.GetKey (KeyCode.S))
Pos += (Vector3.down * Time.deltaTime * speed);
Pos.y = Mathf.Clamp(Pos.y,yMin,yMax);
gameObject.transform.localPosition = Pos;
}
}