Trying to freeze the camera location in unity 3D - c#

I'm trying to make the camera follow the player in unity 3D I attached the camera to the player but it also rotates with him cause he's a ball I don't want that to happen I added a rigidbody to the camera it worked one time IDK how but then it stopped following him due to the rigidbody any help ??

So you have made your camera a child of your player? If so the camera will inherit all transformations on you player, which is definitely not what you want. You can follow this video to learn a camera follow script. https://www.youtube.com/watch?v=MFQhpwc6cKE
And you will almost never need to put a rigidbody on a camera, so you can remove that.

Child objects always inherit the transform of the parent object, as Christopher already said. So, your camera will also spin around if the ball rolls through the world (controlled by the RigidBody / physics in this case).
In order to make the camera follow any object in the scene, you can use a separate GameObject for the camera, that follows the player object controlled by a simple script. - For example something like this (modified example from the Unity documentation):
using UnityEngine;
public class SmoothFollow : MonoBehaviour
{
public Transform target;
public float smoothTime = 0.3f;
public Vector3 offset = new Vector3(0.0f, 5.0f, -10.0f);
private Vector3 velocity = Vector3.zero;
void Update()
{
// Define a target position above and behind the target transform
Vector3 targetPosition = target.TransformPoint(offset);
// Smoothly move the camera towards that target position
transform.position = Vector3.SmoothDamp(transform.position,
targetPosition, ref velocity, smoothTime);
// Make the camera point towards the target
transform.LookAt(target);
}
}
(This is a very basic question, and has been answered many times before. You can easily find many similar examples by just searching the web. - And the title of the post doesn't really match the question. It's important to find the right words and cues in order to keep this site working nicely (clear technical questions -> clear answers).)

Related

Rigidbody2D goes through walls

I want to add the ability for the player to pick up boxes and move them around, but when the player picks up a box and touches a wall, it starts to twitch and go through it.
Please tell me how this can be fixed. I'm at a dead end.
Here is a video displaying my problem: https://youtu.be/TGt73ASBYpQ
Some code:
//The point at which an box is attracted
attractedTo = player.transform.position + (player.lookDirection * player.itemHoldDistance);
//Attraction
transform.position += attractedTo - transform.position;
P.S. Sorry for my bad English
You are modifying the position of the held object use the rigidbody functions like AddForce instead.
In fact, transform.position creates an absolute component and changing it creates point-to-point displacement. transform never considers physics and colliders. Use rigidbody to solve the problem.
private Rigidbody2D rigidbody;
public void Start() => rigidbody = GetComponent<Rigidbody2D>();
rigidbody.MovePosition(attractedTo);
If the problem persists, you must create a condition not to be on the wall.
public LayerMask wallLayer; // define layer field
if (boxCollider.IsTouchingLayers(wallLayer.value)) return; // =

Lag occurs after loading from other scenes

Assumptions / What I want to achieve
I am making an action game that moves only the x and z axes in 3D.
I'm trying to make this compatible with online multiplayer.The Player object has such a component.
Use Joystick of StandardAssets for OnlinePlayerController.cs,
There is code to move using the rigidbody velocity.
The code is written below.
The problem I am having
Lag always occurs when loading an online scene from another scene.
Applicable source code
using UnityEngine;
using Photon.Pun;
using Photon.Realtime;
using UnityStandardAssets.CrossPlatformInput;
public class OnlinePlayerController : MonoBehaviourPunCallbacks
{
public float speed;
[SerializeField]
GameObject Rotation; //Omitted because it has nothing to do with movement
void Update()
{
x = CrossPlatformInputManager.GetAxisRaw("Horizontal");
z = CrossPlatformInputManager.GetAxisRaw("Vertical");
rigd.velocity = new Vector3(x * speed, 0, z * speed);
}
}
What I tried
As you can see from this article, I tried to fix the lag, but there was no change.
The Player object has a Rigidbody only to use Rigidbody.velocity.
Gravity is ineffective and friction with the floor is high and will not slip.
Supplementary information
Unity2019.2.6f1
PUN2 Free
It's important to note that there is no lag when playing from the scene in the editor.
I think that Photon is not the cause, as in other questions, but I think Unity is the major cause. (For example, the previous scene is interfering, etc.)
This is my first time using PUN2, so I don't know much about this.
What should I do to solve this?
Sorry, everything was my mistake.
This code was running before the scene transition.
Time.fixedDeltaTime = 0.2f;

Camera following Rigidbody jitter every few seconds with background objects

Camera following Rigidbody2D jitter every few seconds with background (non rigidbody) objects (Obstacles). The FPS in profiler is fine it is near to 100. also Interpolate is also fine. Using Unity 2017.4.12 (LTS)
GIF GIF Video here
Camera Follow Script
public class CameraFollow : MonoBehaviour {
public float followRange = 0.5f;
public float cameraZ;
public Transform Player;
public Vector3 newPos;
void Start () {
cameraZ = transform.position.z;
}
void FixedUpdate() {
newPos = new Vector3(Player.position.x + followRange, 0, cameraZ);
transform.position = Vector3.Lerp(transform.position, newPos, 0.5f);
}
}
Player Script :
public class PlayerBall : MonoBehaviour {
public float xSpeed = 10;
// Update is called once per frame
void FixedUpdate () {
this.transform.position = new Vector3(this.transform.position.x + Time.fixedDeltaTime * xSpeed,
this.transform.position.y , transform.position.z);
}
}
Player Rigidbody
Project File Download
The rate at which FixedUpdate is called is different than the frame rate which dictates the rate at which Update and LateUpdate are called.
FixedUpdate should be used to set velocities on rigidbodies. Setting positions in FixedUpdate always runs the risk of jitter as it is called out of synch with your frame rate. Setting position on a simulated Rigidbody also goes against the point of simulating it as you are overriding whatever impact the physics might have on the Rigidbody.
The Manual page for Ridgidbody 2D also states that:
The Rigidbody 2D component overrides the Transform and updates it to a position/rotation defined by the Rigidbody 2D. Note that while you can still override the Rigidbody 2D by modifying the Transform component yourself (because Unity exposes all properties on all components), doing so will cause problems such as GameObjects passing through or into each other, and unpredictable movement.
[...] A Collider 2D should never be moved directly using the Transform or any collider offset; the Rigidbody 2D should be moved instead. This offers the best performance and ensures correct collision
detection.
For a Rigidbody that should be moving, you have the choice between using a Dynamic BodyType or a Kinematic one, depending on your usecase. If you want the plane to be pushed around by other non-static colliders, it should be Dynamic. If it should not be moved around, it should be Kinematic (which is also more performant).
Use-case 1: Dynamic Rigidbody 2D
This is the setup you have currently. However, the Manual page for Ridgidbody 2D also states that:
Do not use the Transform component to set the position or rotation of a Dynamic Rigidbody 2D. The simulation repositions a Dynamic Rigidbody 2D according to its velocity; you can change this directly via forces applied to it by scripts
, or indirectly via collisions and gravity.
So you should change the Player script to use the Rigidbody2D method AddForce
public class PlayerBall : MonoBehaviour {
public float thrust = 10;
Rigidbody2D body;
Vector2 forwardDirection = Vector2.right;
void Awake() {
body = GetComponent<Ridigbody2d>();
}
// FixedUpdate is called once per physics update
void FixedUpdate () {
body.AddForce(forwardDirection * thrust)
}
}
Now this will just continuously add a force to the plane, propelling it forwards and accelerating it. So you'll likely want to figure out a way to stabilize the speed by reducing the added force as you approach a target velocity (you can check the current velocity with body.velocity.x) and by slowing the plane down using drag.
I won't go further into the details because I suspect that Kinematic is actually what you'd want to use:
Use-case 2: Kinematic Rigidbody 2D
A Ridgedbody2D with the Body Type set to Kinematic can safely be moved with the Ridgedbody2D components MovePosition method.
So with that setup, you're player script would look like this:
public class PlayerBall : MonoBehaviour {
public float xSpeed = 10;
Rigidbody2D body;
Vector2 forwardDirection = Vector2.right;
void Awake() {
body = GetComponent<Ridigbody2d>();
}
// FixedUpdate is called once per physics update
void FixedUpdate () {
body.MovePosition(forwardDirection + xSpeed * Time.deltaTime)
}
}
Note: I'm using Time.deltaTime here because the value returned by this property will always be the correct delta time for the type of Update method it is used in.
Following Camera
Updating the position of the camera should always be in sync with the framerate. Doing so in FixedUpate can cause stutter. Instead it should be done in Update or (if you want to e.g. wait until position changes due to animations are applied before you set the position) in LateUpdate
Lastly
If the bombs in the game are also moving, and are Ridgidbodies where the position is updated similarly in their FixedUpate, you should change them to use a solution as described in either of the 2 use cases.
Note that Kinematic Rigidbodies wont cause any collision events (trigger events will still be caused) If you want to move both the bombs and the plane as Kinematic Ridigbodies but collision events to still be cause, you can set Use Full Kinematic Contacts on the rigidbodies which should receive these updates.
I'm not sure if this would have any performance impacts (besides the one for generating these events) and you might still want to read the 1[full documentation on the Ridigbody2D component].
Overall TL;DR: what you're seeing is likely not a performance problem (or it would show up in the Profiler and you'd have fluttering and poorer FPS) but movement jitter due to using the wrong update methods and schemes to apply movement to physical bodies. This is a very common pitfall in Unity.
If there is a performance problem, please attach a screenshot of the profiler. With the FPS display method you are using, likely you are triggering a GC.Collect every so often for string manipulations in the FPS script (and GC.Allocs elsewhere).

Find and add the velocity of a Rigidbody that's directly below another? (Unity + C#)

I have an issue that I've not been able to solve for a few days now and without it working I can't move on with my project, so your help would be greatly appreciated!
What I'm trying to do is 'find' the velocity of an object that is directly below my 2D sprite (that also contains a Rigidbody and 2D box collider) and then add that velocity (in the same direction) to the object that is 'looking' for it.
I feel like ray-casting might be part of the answer but I'm not sure how to use that, especially in this context.
The idea behind this is I have a platform that can carry objects stacked on top of each other, so you move the mouse, it manipulates the platforms velocity, but this causes the objects on-top to fly backwards, no mater how high the friction is.
Here is the platform code:
void Update()
{
float distance_to_screen = Camera.main.WorldToScreenPoint(gameObject.transform.position).z;
Vector3 pos_move = Camera.main.ScreenToWorldPoint(new Vector3(Input.mousePosition.x, Input.mousePosition.y, distance_to_screen));
mouseDelta = pos_move - lastMousePosition;
acceleration = mouseDelta.x * 0.4f;
platformVelocity += acceleration;
platform.velocity = new Vector2(platformVelocity, 0) * speed;
lastMousePosition = pos_move;
}
Thank you for taking the time to read this, I would very much appreciate any help you can give!
Is it necessary to 'find' that object? 'Finding' may be difficult & costing.
Can you hold the 'below-thing' reference and pass it to 'above-thing'?
I'm assuming you have some method on objects that checks whether it's on a moving platform. One option is to add an IsOnMovingPlatform flag on those objects. Then use a similar method to check if any object is on top of the "IsOnMovingPlatform == true" objects. Keep doing passes on that method until you don't come up with any more flags set to true.
So, i'm trying to understand your question and I think I might know what you're talking about.
Are you saying that you want your game object (2d sprite) to stay on the platform as its moving? I have had the same problem, where a platform is moving and my player (game object) slides off- and this is how I fixed it.
Add a box collider to the platform (trigger). When the player enters the platform, make the player's transform the platform. That way, when the platform moves- the player moves with it no matter what the speed is.
For example:
void OnTriggerEnter2D(Collider2d collider){
if(collider.tag.equals("Player")){ // you only want the player to work
// attach script to platform for "this.transform" to work
collider.transform.SetParent(this.transform);
}
}
then, to unparent the transform "otherwise, even when the player is off the platform, it will move with the platform.
void OnTriggerExit(Collider2d collider){
// assuming your player isn't supposed to have a parent!
collider.transform.parent = null;
}
Sorry if I misunderstood your question! If this is what you were going for, finding the velocity of the platform is not necessary. Also, this is uncompiled code- if you have issues let me know.
EDIT:
To add a bit of a give, for the entire duration that the player is in contact with the platform, we can add a little bit of a negative force to shove the player a little bit!
We do this by using OnTriggerStay2D (assuming your game is 2d, otherwise use OnTriggerStay).
For example:
void OnTriggerStay2D(Collider2d collider){
if(collider.tag.equals("Player")){
collider.getComponent<Rigidbody2D>().addForce(new vector2(forceToAdd, 0));
}
}
now, that "forceToAdd" variable should be based on the speed and direction that your platform is going. Does your platform have a rigid body on it? if so you can get your force variable by retrieving the rigid body from the platform (getcomponent()) and get the X velocity from it. With this velocity, experiment with dividing it by numbers until you find a good fit, multiply it by -1 (because you want to push the player in the opposite direction of the platform travel), then this will be your forceToAdd!
However, if your platform is not using a Rigidbody, then a way you can do this is record the x positions in your script (just two positions, and subtract these to find the distance in an update method), multiply by -1, try dividing by a number (experiment with this) and that can be your force to add variable.
Also, my code for the OnTriggerStay2d is rough, the spelling could be a bit wrong- but this will give you a rough idea for a solution! ALSO.. I don't think getting the component of a rigid body should be done in every frame, a way around this would to have your rigid body component as a global variable in the script, then set your rigid body on OnTriggerEnter2d, this way it will only retrieve it once (instead of every frame) which I assume would be more efficient!
Good luck! and if you have any questions il try to help!
This is a raycast2d version, I tested it and it works much better than the trigger collider version :).
using UnityEngine;
using System.Collections;
public class RaycastFeetDeleteLater : MonoBehaviour {
[SerializeField] private float raycastDist = 0.1f;
[SerializeField] Transform feet;
[SerializeField] private float xForceDampener = 0.1f;
private Rigidbody2D rb2d;
// Use this for initialization
void Start () {
rb2d = GetComponent<Rigidbody2D> ();
}
// Update is called once per frame
void FixedUpdate () {
RaycastDown ();
}
private void RaycastDown(){
RaycastHit2D hit = Physics2D.Raycast (feet.position, Vector2.down, raycastDist);
if (hit.collider != null) {
print (hit.transform.tag);
if (hit.collider.tag.Equals ("Platform")) {
transform.SetParent (hit.transform);
Vector2 force = new Vector2 ((hit.transform.gameObject.GetComponent<Rigidbody2D> ().velocity.x * xForceDampener) * -1, 0);
print (force);
rb2d.AddForce (force);
} else if (transform.parent != null) {
print ("UNPARENT");
transform.parent = null;
}
} else {
if (transform.parent != null) {
transform.parent = null;
}
}
Debug.DrawRay (feet.position, Vector3.down, Color.green, raycastDist);
}
}
This script is attached to the player! No need to have scripts on the platforms, which was the main reason my previous method was a pain :P
Basically this script does the following:
- Gets rigidbody2d of the player on start (we will be adding forces to the player with it soon, so might as well store it in a variable!
On FixedUpdate (Different than Update, FixedUpdate is called on Physics update, where as Update is called every frame) I have read that raycast should use FixedUpdate, I suppose because it is a Physics method!
RaycastDown shoots a 2D raycast directly down from the feet position (to get the feet, create a child object of the player, put the position of the feet a tiny bit below the player, NOT ON THE PLAYER- I will explain why in a second why that will mess up everything! Then drag the feet GameObject on to the "feet" slot of the script.)
Raycast shoots from feet directly down at a distance that is changeable in the editor (raycastDist) I found a distance of 0.1f was perfect for my needs, but play around with it for yours! You can actually see a drawing of your Ray by using Debug.DrawRay as seen in the code, the ray is only visible in the editor- not game view! But this will help, especially with positioning the feet.
Checks if it hit an object with a collider, if so check if the objects tag is a Platform (set the platforms to a new tag and call it Platform).
If it hits a platform set the parent of the player to the platform (like the last script) and start applying a little force to the player in the negative direction that the platform is traveling (we get the rigid body of the platform to find its velocity).
If the raycast does not hit a platform, unparent it so the player can move freely.
Thats basically it, however...
Please note:
This script needs to be on the player, not any of the players child objects, since this script will unparent the player from any platforms- if you have the script on a child object of the player it will unparent from the player- which is horrible. So The script MUST be on the root game object of the player. There are ways around this if for some reason you can't.
As mentioned before, the "feet" child object must be a little bit under the player- this is because when the Raycast2d "fires" it will find the FIRST object with a collider it hits- so if you have the start of the raycast hit a collider on the player then it will always show the raycast hitting the player, not a platform. So to get around this have the raycast fire from the feet- and have the feet position a tiny bit below the player. To help with this I added a print statement that will print to the console which object the raycast is hitting, if it doesn't say "Platform" then you need to lower the feet! :)
Furthermore, I'm not sure how you are moving your platforms- but if the Velocity of the platform always prints "0,0" then its because you are moving the platforms position directly, instead of moving it by forces (this happened to me when I was testing this script). I got around this by moving the platform by "AddForce". Also depending on the "Mass" of your platforms, you may need to drastically increase the "xForceDampener" which I should of actually labeled "xForceMultiplier" as I found while testing I needed to set it much higher- like at 60, instead of 0.25 which I previously thought would be okay..
Hope this helped :D
EDIT: Linking the unity docs for 2D Raycasts in case you need
http://docs.unity3d.com/ScriptReference/Physics2D.Raycast.html

Creating "brick breaker" game and upon starting a level I get a sound effect before ball even launches

I'm still very much a newbie with understanding scripting and the vocab associated with it. I'm following a course online right now and I'm trying to be brave and venture out from the videos and make my own script work using different sounds on different bricks.
I want the ball to make a certain sound ("bip") when it bounces off of the paddle. However, when I start a level, before the ball is even launched, I get the "bip" sound. In the tutorial video he puts the sound associated with the ball and so doesn't have this issue after changing some of his code. Mine still persists. I already have a script for my ball, brick, and paddle. In my Ball script I have a public bool hasStarted = false; before my Start function. And I don't want to make hasStarted a private bool in each script. I want to just be able to call it from another script, and I don't want to make it static either so that I can support having multiple balls in one level.
So question number one: are all bool considered static by default?
Question two: Here's what I have for my paddle script. What can I do to prevent the starting "bip" when starting a level?
public class Paddle : MonoBehaviour {
//private bool hasStarted = false;
//Use this for initialization
void Start () {
}
//Update is called once per frame
void Update(){
Vector3 paddlePos = new Vector3 (0.5f, this.transform.position.y, 0f); //initial set position of the paddle on screen
float mousePosInBlocks = Input.mousePosition.x / Screen.width * 16; //creates a variable called mousePosInBlocks to track
//the position of the mouse X vector in game units
paddlePos.x = Mathf.Clamp(mousePosInBlocks, 0.5f, 15.5f); //setting the x vector of paddlePos e.g. the left/right function
//of the paddle to be the same as the mouse position on screen
this.transform.position = paddlePos; //the Object with the attached script (Paddle) is fed the updated
//position info from the preceding 3 lines of code
}
void OnCollisionEnter2D(Collision2D col){
// I need to do something with the code here to prevent a "bip" from starting before the ball is even launched
// Find the game object which is called "Ball".
GameObject ballObject = GameObject.Find("Ball");
// Get the instance of the script, which is attached to the ball
Ball ball = ballObject.GetComponent<Ball>();
// Check if the ball has started
if (ball.hasStarted) {
audio.Play();
}
}
}
Feel free, too, to correct me on my notes. I'm trying to take notes as I write code so that I understand it when I come back to it later.
EDIT: here is a pastebin screen with both the paddle and ball scripts on them (thanks Joonas).

Categories