2D collision detection when using transform.position. How to enable? - c#

I just started with unity and followed thair 2D UFO example project.
In an effort to extend it, I came up with a quirky way of contolling my Player.
It always moves in circular paths and once I click a button, the circle's direction changes and the imaginary circle center is tanslated as shown in the picture below. That allows you to move in a figure 8 or S shape pattern and is quite fun.
However, once I figured out how to do this motion, the player object did not have any collision detection anymore.
In the original example the whole movemet handling is done within FixedUpdate(). I, however, use Update() since the former does not seem to work at all with my code (i.e. no movement at all).
This is my code for the movement so far:
public class ControlledRotation : MonoBehaviour
{
public float radius = 3f;
public float speed = 3f;
private float timeCounter = 0;
private float direction = 1f;
private Vector3 offset;
private Rigidbody2D rb2d;
void Start()
{
offset = transform.position;
}
void Update()
{
if (Input.GetKeyDown(KeyCode.RightArrow))
{
//change the offset from the circle center and the rotation direction on keypress
offset += new Vector3(Mathf.Cos(timeCounter), Mathf.Sin(timeCounter), 0) * radius * direction * 2;
direction *= -1;
}
timeCounter += Time.deltaTime * direction * speed;
transform.position = new Vector3(Mathf.Cos(timeCounter), Mathf.Sin(timeCounter)) * radius * direction + offset;
}
}
The Plyer object has a Rigidbody 2D and a Circle Collider 2D. The walles it should collide with have Box Collider 2D. Yet, the UFO can simply pass the walls.
I assume a probable cause in the fact that I simply change transform.position or since im using Update/FixedUpdate wrong.
If you happen to have any advice on how I can keep my chosen movement control mechanism and still be able to collide with objects, I'd highly appreciate it :)
Edit:
I feel I need to go with using the rigidbody and applying some force... but I haven't figured out how to reproduce this movement with forces and also forces seem to not be super crisp in response

When you need to move an object that has a Rigidbody, you need to move it using forces, you cannot do it with just transform.position, it ignores physics. that's why you cannot detect the collision.. I suggest you move it like that. I have some examples when I had to move a character that needed to interact with physics.
gameObject.GetComponent<Rigidbody>().velocity = Vector3.zero;
And this one is for moving it in certain directions:
//Keys for controlling the player (move and shoot) only when he's alive
if (Input.GetKey(KeyCode.UpArrow) && alive)
{
GetComponent<Rigidbody>().MovePosition(transform.position + Vector3.forward * Time.deltaTime * 4);
}
if (Input.GetKey(KeyCode.DownArrow) && alive)
{
GetComponent<Rigidbody>().MovePosition(transform.position + Vector3.back * Time.deltaTime * 4);
}
I hope it helps.. greetings :)

Related

Unity Simple Character Controller Script not working as expected

Im scratching my head over this one, really cant figure it out.
Im trying to implement the player movement from this example:
https://www.youtube.com/watch?v=LNidsMesxSE
Starts at minute 4:25 and ends at minute 5:20
This script tries translating all that to unity.So I started all the way over from scratch and just want to make a simple movement script.
You can plug this into any Unity version, throw the script onto and object with a CharacterController component, add a child object with a mesh that will tilt, the main object will rotate around its Y axis and move.
I do recommend using a simple T pose character or atleast a long capsule so you can better see what is happening than when you would be using a cube to test this.
The weird glitches im having is that the object randomly spasms out even though im always only adding extremely small rotations and movements every frame. And 95% of the time it doesnt happen, so I havent been able to pinpoint exactly what is causing this.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class CharacterMove : MonoBehaviour
{
public float speed = 200f;
public float rotationSpeed = 180f;
public float tiltFactor = 8f;
public bool normalizeVelocity = false;
CharacterController cc;
Vector3 velocity;
Transform armatureBody;
void Start()
{
cc = GetComponent<CharacterController>();
armatureBody = transform.GetChild(0);
}
void Update()
{
velocity = new Vector3(Input.GetAxis("Horizontal"), 0,
Input.GetAxis("Vertical"));
}
void FixedUpdate()
{
if ((velocity != Vector3.zero))
{
var ccVelocity = cc.velocity; // CharacterController velocity. This might be the problem, but without it I cannot rotate the object towards the actual forward velocity.
Quaternion toRotation;
toRotation = Quaternion.LookRotation(ccVelocity, Vector3.up);
transform.rotation = Quaternion.RotateTowards(transform.rotation, toRotation, rotationSpeed * Time.deltaTime);
if (Input.GetKey(KeyCode.S)) print("new toRotation: " + toRotation);
armatureBody.localEulerAngles = new Vector3(velocity.z * tiltFactor, 0, -velocity.x * tiltFactor); // Tilt Body towards velocity This causes the weirdest and most consistest twitching bugs when the tilt is backwards so the object is moving backwards, maybe because im using LookRotation to look backwards?
}
velocity = Quaternion.Euler(0, transform.eulerAngles.y, 0) * velocity; // forward is always forward
cc.SimpleMove(velocity * Time.deltaTime * speed);
}
}
This script does 4 things,
get the velocity from player input.
rotate the main Object(this script) towards the velocity
add tilt towards the velocity, to the child armatureBody, this is a t Pose character in my case.
move the main Object this script is on.
Any help would be appreciated.
I tried removing the vector3 != Zero check, I tried normalizing the vectors, and I tried using a different Quaternion rotation method, but all with the same faulty results.
Check in Update() if Input.forward > threshold if so rotate to velocity. Dont rotate to velocity when only going sideways or backwards, so we can now strafe sideways and walk backwards when standing still or run and rotate to our velocity with the AD keys when running.
void Update()
{
velocity = new Vector3(Input.GetAxis("Horizontal"), 0,
Input.GetAxis("Vertical"));
if (velocity.z > 0.2f)
{
forwardVelocityThreshold = true;
}
else forwardVelocityThreshold = false;
}
Then in our FixedUpdate() we check for that bool and apply the rotateToVelocity if true.
Adjust the following if statement:
if (ccVelocity != Vector3.zero && forwardVelocityThreshold)
{
toRotation = Quaternion.LookRotation(ccVelocity, Vector3.up);
transform.rotation = Quaternion.RotateTowards(transform.rotation, toRotation, rotationSpeed * Time.fixedDeltaTime);
}
Now it works as intended, I also changed the deltaTime to FixedDeltaTime as suggested by Voidsay in the comments, although I have heard conflicting things about this. Some say FixedUpdate always uses fixedDeltaTime even if you are using deltaTime, other say no, always use fixedDeltaTime in FixedUpdate.

FlyCamera with collision

How to create collisions for a flying camera in Unity 3d? to prevent the camera from falling into objects on the scene. My camera script snippet:
public class FlyCamera : MonoBehaviour
{
void FixedUpdate()
{
if (!isAlternative)
SetCameraMovement();
}
private void SetCameraMovement()
{
lastMouse = Input.mousePosition - lastMouse;
lastMouse = new Vector3(-lastMouse.y * camSens, lastMouse.x * camSens, 0);
lastMouse = new Vector3(transform.eulerAngles.x + lastMouse.x, transform.eulerAngles.y + lastMouse.y, 0);
if (Input.GetMouseButton(1))
transform.eulerAngles = lastMouse;
lastMouse = Input.mousePosition;
GetBaseInput();
transform.position = Vector3.Lerp(transform.position, NewPosition, Time.deltaTime * movementTime);
}
private void GetBaseInput()
{
Speed = Input.GetKey(KeyCode.LeftShift) ? superSpeed : mainSpeed;
if (Input.GetKey(KeyCode.W))
NewPosition += transform.forward * Speed;
if (Input.GetKey(KeyCode.S))
NewPosition += transform.forward * -Speed;
if (Input.GetKey(KeyCode.A))
NewPosition += transform.right * -Speed;
if (Input.GetKey(KeyCode.D))
NewPosition += transform.right * Speed;
}
}
If you want to achieve a RTS-like flying camera, you can set the camera to a parent dolly-like object and keep it looking at that object:
Object (Camera Dolly) -> this is moved by wasd and is rotated to the desired view angle
Child object: Camera -> only the camera's position.y is ever changed
Then, on a custom script on the dolly in Update(), send a LineCast from the dolly to the camera. When the cast hits a collider (important to use e.g. tags here so it does not collide with anything, like e.g. units) in the world, gradually (over time) reduce the camera's position.y and if nothing is hit, gradually increase it to the desired height. It will not entirely prevent the camera from clipping trough bigger objects but move it so it doesn't stay "inside" a collider. Something like that is also typically used in RPG third person cameras.
Please let me know if more clarification is needed!
Edit: I'd do that only for really big view-blocking objects though, not for the terrain or smaller buildings/units - at least if your goal is more of an RTS or sim game.
Edit2: In a solar system setting, it is a bit more complicated. A few options:
Before translating the camera, do a SphereCast (in the desired (final) movement direction with sphere radius of minimum allowed distance to any object) against all celestial object SphereColliders and set your "NewPosition" to the nearest hitPoint minus the desired minimum allowed distance to a celestial object. Also add some margin here, so the camera doesn't get stuck. This would be a continuous collision detection approach.
Everytime after translating the camera , do a CheckSphere (sphere radius is allowed minium distance to any object) against all celestial objects and as long as there is any hitpoint, lerp the camera position out of it over time. This is a "softer" looking approach, but if you fly very fast, it can still clip into something.
You can savely do both in LateUpdate().
Better put you camera movement in the LateUpdate() as adviced in the docs.
With a rigidbody and a collider properly set for the collision detection. Check docs so that you can detect the collisions properly.
Check that " Notes: Collision events are only sent if one of the colliders also has a non-kinematic rigidbody attached", so your camera could be one gameObject with no rigidbody, so that you can fly free and collide.
I case you might need physics behaviour for yout camera and you want it also to behave as a rigidbody I would set the camera movement with rigidbody.SetPosition instead of with transform.position = new Vector3(), as you need to choose to set the transform in the geometric or the physics world.
Also you would need to uncheck the gravity option not to fall.

Unity3D Player walking through and on the Stone

Hello guys my Player is walking on the Stone and through the Stone. The Player called Champ has a Box Collider and the Stone has a Mesh Collider. Also the Player has Rigidbody. I tried everthing i found but nothing helped me with my problem.
MovePlayer.cs Script
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MovePlayer : MonoBehaviour
{
Rigidbody rb;
public float speed = 10f;
private Vector3 moveDirection;
public float rotationSpeed = 0.05f;
void Start()
{
rb = GetComponent<Rigidbody>();
}
void Update()
{
moveDirection = new Vector3(Input.GetAxisRaw("Horizontal"), 0f, Input.GetAxisRaw("Vertical")).normalized;
}
void FixedUpdate()
{
rb.MovePosition(rb.position + transform.TransformDirection(moveDirection * speed * Time.deltaTime));
RotatePlayer();
}
void RotatePlayer()
{
if (moveDirection != Vector3.zero)
{
transform.rotation = Quaternion.Slerp(transform.rotation, Quaternion.LookRotation(moveDirection.normalized), rotationSpeed);
}
transform.Translate(moveDirection * speed * Time.deltaTime, Space.World);
}
}
Player Settings in Inspector
Stone Settings in Inspector
Scene Preview
Thank you for help guys! :)
So guys i found out the Solution with the help of the guys posted above.
The problem was that my player speed was too high in the Code the speed was on float 10, but i changed the velocity in the Unity Inspector of Player to float 50.
So my first step to solve the problem was to set the speed down to float 10, but i still wanted to move with a speed of 50f...
The Solution for this problem was that in Unity 2020.3.24f1 and higher (probably lower) you can go to Edit>Project Settings>Physics and set the "Default Max Depenetration Velocity" to the speed you want the objects stopping and not going through. In my case i wanted to move with speed = 50f so i needed to change Default Max Depenetration Velocity to 50.
I hope i can help someone with this Answer in future!
Best Wishes
Max G.
Tested your code and collisions seem to be working fine on my end.
Tested it by adding the script to a GameObject with box collider and creating a small level using cubes. Also made a wall that I modified to use mesh-collider instead of box collider. Player collided normally with objects in the scene.
You should double check your Layer collision matrix from Project Settings > Physics whether you've set layers player and wall to collide.
You could also try adding new cube to the scene and setting its layer to wall to see if player collides with it. If it does then the there might be issues with the mesh of the stone.
If not then I would disable animator and Gravity Body components from the player to make sure they're not interfering with the collisions
Rigidbody.MovePosition basically makes the player teleport which can cause unexpected behaviors. It's generally recommended to use Rigidbody.AddForce instead. For precise movement ForceMode.VeloictyChange can be used.
public float maxVelocityChange = 5.0f;
void moveUsingForces(){
Vector3 targetVelocity = moveDirection;
// Doesn't work with the given RotatePlayer implementation.
// targetVelocity = transform.TransformDirection(targetVelocity);
targetVelocity *= speed;
// Apply a force that attempts to reach our target velocity
Vector3 velocity = rb.velocity;
Vector3 velocityChange = (targetVelocity - velocity);
velocityChange.x = Mathf.Clamp(velocityChange.x, -maxVelocityChange, maxVelocityChange);
velocityChange.z = Mathf.Clamp(velocityChange.z, -maxVelocityChange, maxVelocityChange);
velocityChange.y = 0;
rb.AddForce(velocityChange, ForceMode.VelocityChange);
}
In this code you have applied motion twice and the problem is that transform.Translate is used. Remember that Rigidbody class methods are sensitive to colliders and recognize them, but transform is not the same and only applies a point-to-point shift. To solve the problem, I think you will not need a duplicate motion code with translate in the rotate section.
void RotatePlayer()
{
if (moveDirection != Vector3.zero)
{
transform.rotation = Quaternion.Slerp(transform.rotation, Quaternion.LookRotation(moveDirection.normalized), rotationSpeed);
}
// removed translate
}

I have a cube that spins all over the place when I hit an object.(the camera and character spins) UNITY

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.

Unity2D Enemy Patrol, weird sprite rotation

Needed help here, I've been following this tutorial about Enemy Patrolling, https://www.youtube.com/watch?v=KKU3ejp0Alg
The tutorial tell us to set 2 Empty Game Objects and the coordinates so the sprite will walk from one direction to another, the walking does working, however the rotation of the sprite became really weird, the 'Worm' sprite is suppose to move left and right now it change into facing upward
Please look at this image,
When moving from left to right
When moving from right to left
public Transform[] patrolPoints;
public float speed;
Transform currentPatrolPoint;
int currentPatrolIndex;
// Use this for initialization
void Start()
{
currentPatrolIndex = 0;
currentPatrolPoint = patrolPoints[currentPatrolIndex];
}
// Update is called once per frame
void Update()
{
transform.Translate(Vector3.up * Time.deltaTime * speed);
if (Vector3.Distance(transform.position, currentPatrolPoint.position) < .1f) {
if (currentPatrolIndex + 1 < patrolPoints.Length)
currentPatrolIndex++;
else
currentPatrolIndex = 0;
currentPatrolPoint = patrolPoints[currentPatrolIndex];
}
Vector3 patrolPointDir = currentPatrolPoint.position - transform.position;
float angle = Mathf.Atan2(patrolPointDir.y, patrolPointDir.x) * Mathf.Rad2Deg - 90f;
Quaternion q = Quaternion.AngleAxis(angle, Vector3.forward);
transform.rotation = Quaternion.RotateTowards(transform.rotation, q, 180f);
}
This is the code
Thank you
You can pass the optional parameter Space.World to your translation to move your object relative to world space instead of object space. That should prevent your object from rotating.
transform.Translate(Vector3.up * Time.deltaTime * speed, Space.World);
You can read more about it in the documentation.
You probably rotated the enemy sprite by 90 degrees. Try placing all your scripts into empty game object with no rotation, than place the enemy sprite as child of the empty game object and rotate as you need. This way your logic won't collide with your graphics.

Categories

Resources