I am trying to make a 2.5D SHMUP type game in which the world continuously moves forward while the player's spaceship and camera stay in place. This means that even if the world is moving, if the player's ship is in the middle of the screen it will stay there.
To do this I've created an empty game object named Moving World and attached the following script to it:
public class movingWorldController : MonoBehaviour
{
private float movementSpeed = 5f;
void Update()
{
transform.position = transform.position + new Vector3(0, 0, movementSpeed * Time.deltaTime);
}
}
I then added the camera and spaceship as children to of this object, and as a result they indeed move with the moving world object. However, I also have a script attached to the spaceship to allows it to move according to the player's input, and if I enable the script above the ship stops responding to the player's input. The ship's script looks like this:
public class ShipController : MonoBehaviour
{
public Rigidbody rb;
public float moveSpeed = 5f;
private Vector3 movement;
void Update()
{
movement.x = Input.GetAxisRaw("Horizontal");
movement.z = Input.GetAxisRaw("Vertical");
}
private void FixedUpdate()
{
rb.MovePosition(rb.position + movement * moveSpeed * Time.deltaTime);
}
}
The ship controller works just fine when the world-moving script is disabled, so I suspect the world script is somehow overwriting the spaceship position. How may I solve this?
For a POC example see this video: https://www.youtube.com/watch?v=-fVjWgfUKn4&t=282s (jump to 4:00 to see the game in action). Note that in the video gamemaker is used to achieve the effect, while I am trying to achieve a similar effect using just code.
I achieved the effect I was aiming for by doing the following. First, I removed the MovingWorld object and instead applied the following script to the camera:
public class movingWorldController : MonoBehaviour
{
public float movementSpeed = 5f;
void FixedUpdate()
{
transform.position = transform.position + new Vector3(0, 0, movementSpeed * Time.deltaTime);
}
}
This will cause the camera to continuously move forward. Next, to make sure the player's ship keeps up with the camera, and is maneuverable at the same time, I applied the following script to the ship's object:
public class ShipController : MonoBehaviour
{
public Rigidbody rb;
private float shipVelocity = 5f;
public float moveSpeed = 10f;
private Vector3 movement;
void Update()
{
movement.x = Input.GetAxisRaw("Horizontal") * moveSpeed;
movement.z = Input.GetAxisRaw("Vertical") * moveSpeed + shipVelocity;
}
private void FixedUpdate()
{
rb.MovePosition(rb.position + movement * Time.deltaTime);
}
}
Two important notes:
The shipVelocity variable was introduced to make sure the ship continues to cruise at camera-speed.
Even though the camera is not a RigidBody its position update must occur during the FixedUpdate method to make sure it moves on the same frame as the ship. Updating it using the Update method will introduce jittering to the ship due to de-synchronization.
Related
I'm making a first-person movement script for the player, and everything movement-wise seems to work fine (other than an unrelated issue of the player not moving in the camera's direction), however when running in the game, the player moves at a very slow speed.
Here's the movement script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerMovement : MonoBehaviour
{
private Rigidbody RB;
[SerializeField] private GameObject cam;
private float walkVel; // Forward & backward movement
private float strafeVel; // Sideways movement
[SerializeField] public float walkSpeed = 5f;
private void Start()
{
RB = GetComponent<Rigidbody>();
}
private void Update()
{
walkVel = Input.GetAxis("Vertical");
strafeVel = Input.GetAxis("Horizontal");
}
private void FixedUpdate()
{
transform.localRotation = Quaternion.Euler(0f, cam.transform.rotation.y * Time.deltaTime, 0f);
Vector3 Up = new Vector3(RB.velocity.x, RB.velocity.y, RB.velocity.z);
RB.velocity = (transform.forward * strafeVel + transform.right * walkVel).normalized * walkSpeed * Time.deltaTime;
}
}
I'm pretty sure the issue is not related to the camera script, but here it is:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerCamPositioning : MonoBehaviour
{
private Vector2 camTurn;
[SerializeField] public float camSensitivity = 5f;
private void Start()
{
Cursor.lockState = CursorLockMode.Locked;
}
private void Update()
{
camTurn.x += Input.GetAxis("Mouse X") * camSensitivity;
camTurn.y -= Input.GetAxis("Mouse Y") * camSensitivity;
transform.localRotation = Quaternion.Euler(camTurn.y, camTurn.x, 0);
}
}
I tried to implement a very basic velocity script, and alternatively RB.AddVelocity to the Rigidbody, however it did not solve my problem.
I also tried simply increasing the walkSpeed variable to increase player speed, which actually solves my problem, HOWEVER I want to refrain from using this solution as previously the player moved at a relatively normal speed with walkSpeed set to 5f.
Sounds like you just need to tweak your values. Try splitting your equation into pieces and logging the individual and multiplied value so you can understand what values you see versus what values you're expecting.
I see many variables in your code that can be less than 1. strafeVel, walkVel and Time.deltaTime. In fact, in my experience, Time.deltaTime is always a very small float.
Perhaps you would prefer to use RB.velocity with += or *= along with a Mathf.Clamp() to gradually increase your speed.
All I had to do to solve my problem was remove Time.deltaTime from the RB.Velocity vector. The vector already runs in the FixedUpdate function, so I think it should work as intended now.
I have the following script which should make the main camera follow and rotate with the player's movements.
public class FollowPlayer : MonoBehaviour
{
[SerializeField]
float mouseSensitivity;
public Vector3 cameraOffset;
public Transform Player;
public Transform mainCamera;
void Start()
{
Cursor.lockState = CursorLockMode.Locked;
cameraOffset = transform.position - Player.transform.position;
}
void Update()
{
Rotate();
}
private void Rotate()
{
float mouseX = Input.GetAxis("Mouse X") * mouseSensitivity * Time.deltaTime;
Player.Rotate(Vector3.up, mouseX);
mainCamera.Rotate(Vector3.up, mouseX); //shows abnormal rotation (hides the player as well)
}
private void LateUpdate()
{
Vector3 newPosition = Player.position + cameraOffset;
transform.position = newPosition;
}
}
The camera follows the player, however, but it does not rotate with the player's rotations. Please note that making the main camera the child of the player is not an option here, since I have to use this script on multiplayer. I want the mouse to be able to rotate both the main camera and the player at the same time.
The reason the camera is not rotating, is that you capture the initial offset on start, which is expressed in absolute (world space) position. This can be easily fixed using transform.TransformPoint method. What you then need to do is address camera rotation. In the simplest case you can just use 'LookAt' method
private void LateUpdate()
{
Vector3 newPosition = Player.position + Player.TransformPoint(cameraOffset);
mainCamera.position = newPosition;
mainCamera.LookAt(Player.position, Vector3.up);
}
I also noticed that you use transform.position (a transform from the object your script is attached to) but then you also use mainCamera transform as a seperate transform, mixing it like that might lead to confusion later. You should either always access the camera via mainCamera reference, or you could always keep the script attached to the camera and use transform reference.
I also noticed that you use one script to do two seperate things, it controls both player rotation and camera position/rotation while following the player. While there is nothing stoping you from doing that, its often a good idea to split it into doing two things each doing one logical thing
This code tries to find the player and have the zombies play an animation as they do it. My problem is that it isn't following the player however I know why. The reason this happens is because it isn't selecting the player, it selects the prefab of the player in the assets instead of the one in the hierarchy and it makes them buggy. This happens because I have a spawn manager that spawns in the player instead of just placing it in the scene because I want to make the player have a random spawn. I also want a random spawn for the zombies so I can't just add them in the unity editor. I think I can fix this problem if I can make the zombies track the players tag instead of the gameobject. Is there a way to change the code to make it track the players tag? Also if it is not possible please tell me because I don't want to waste time on finding a solution that is not possible. Thanks
Sorry if the code is bad I am a noob.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ZK_Attacking : MonoBehaviour
{
public Transform Player;
public float MoveSpeed = 3.5f;
public float AttackRange = 1.0f;
private Animator anim;
private void Start()
{
anim = GetComponent<Animator>();
Player = GameObject.Find("Player").transform;
}
void Update()
{
transform.LookAt(Player);
float dstSqr = (Player.position - transform.position).sqrMagnitude;
bool inAttackRange = (dstSqr <= AttackRange * AttackRange);
anim.SetBool("AttackingPlayer", inAttackRange);
transform.position += transform.forward * MoveSpeed * Time.deltaTime;
transform.position = Vector3.MoveTowards(transform.position, Player.position, MoveSpeed * Time.deltaTime);
}
}
I have a simple movement that relvolves around moving foward depending on where I look. The camera is made to follow the player. The problem I am havaing is that whenever I hit an object, my character(along with the camera) start spinning crazily all over the place. (I am new to coding)
Here is the code to the movement of where my character is facing :
public class Player : MonoBehaviour {
public float movementSpeed = 10;
public float turningSpeed = 60;
public Rigidbody rb;
void Start()
{
rb = GetComponent<Rigidbody> ();
}
void Update() {
float horizontal = Input.GetAxis("Mouse X") * turningSpeed *
Time.deltaTime;
transform.Rotate(0, horizontal,0);
float vertical = Input.GetAxis("Mouse Y")* turningSpeed * Time.deltaTime;
transform.Rotate(vertical, 0, 0);
float movement = Input.GetAxis("Foward") * movementSpeed *
Time.deltaTime;
transform.Translate(0, 0,movement);
}
}
(Sorry for bad format)
The Mouse X just makes it so that it rotates on the x axis of mouse(same with y axis). The Foward is just the vertical input preset in unity.
Here is the code to the lookAt player :
public class LookAtCamera : MonoBehaviour {
public GameObject target;
void LateUpdate() {
transform.LookAt(target.transform);
}
}
Answer
I believe your rigidbody is being more heavily affected than what you desire by the bounce force occuring as you hit the object.
Possible solutions
Depending on which collider type acts as your legs, the weight of the objects involved, what behaviour you intend and more the solution can vary.
Possible solution 1:
One option is to freeze the rotation of your object on it's Rigidbody component, you can decide which axes to freeze rotation on. If freezed they can't be pushed by outside forces.
Possible solution 2:
If you wish the player to only be affected by your script you can set the rigidbody kinematic, meaning that it only is affected by scripts and animation. This is a contrast to being set to dynamic where other objects can affect it.
Possible solution 3:
Play around with the angular drag and mass of the rigidbody to slow down rotation.
I'm following the official multiplayer networking tutorial, but I'm having some trouble with the "bullets".
Each bullet prefab is spawned on the server-side through a command, according to the position of a spawn point on the player prefab. The basic system works well, but for all players except the host there is a large amount of lag between the location of the spawn point and the spawned bullet.
The bullets are spawned correctly according to the player's location on the server, as expected. However, this is behind the player's client position.
Is there a solution to this? Should I be using RigidBody at all? I've seen methods which use raycasting for projectiles which may be an improvement, but I would like to be able to see the projectiles travel through the air. Any help would be very appreciated!
For reference, the relevant PlayerController code:
using UnityEngine;
using UnityEngine.Networking;
using System.Collections;
public class PlayerController : NetworkBehaviour {
public float speed;
public float turnSpeed;
public GameObject bulletPrefab;
public Transform bulletSpawn;
void Update () {
if (!isLocalPlayer) {
return;
}
float power = Input.GetAxis ("Vertical") * Time.deltaTime * speed;
float turn = Input.GetAxis ("Horizontal") * Time.deltaTime * turnSpeed;
transform.Rotate(0, turn, 0);
transform.Translate (power, 0, 0);
if (Input.GetKeyDown (KeyCode.Space)) {
CmdFire ();
}
}
[Command]
void CmdFire() {
var bullet = (GameObject)Instantiate (bulletPrefab, bulletSpawn.position, bulletSpawn.rotation);
bullet.GetComponent<Rigidbody>().velocity = bullet.transform.forward * 6;
NetworkServer.Spawn (bullet);
Destroy (bullet, 2.0f);
}
}