I have a problem with the Translate function. What I'm trying to do is to open doors by clicking on them. I succeeded in doing this with all the doors, but now I've added a new one and when I close it, it doesn't go back to its position.
I'll try to explain the problem better showing the code:
public override void OpeningDoor() {
Vector3 movement = new Vector3 (2.006f, 0.0f,1.793f);
Vector3 rotate = new Vector3 (0.0f, 108.3f, 0.0f);
transform.Translate (movement);
transform.Rotate (rotate);
toClose = true;
}
public override void ClosingDoor() {
Debug.Log ("Closing Door");
Vector3 movement = new Vector3 (-2.006f, 0.0f,-1.793f);
Vector3 rotate = new Vector3 (0.0f, -108.3f, 0.0f);
transform.Translate (movement);
transform.Rotate (rotate);
toClose = false;
}
The rotation is okay, no problem with that. Also when I open the door it goes to
the right position, but when I close it, it doesn't go back to its position and it translates to a wrong one. Theoretically I just apply a certain movement on the X axis and Z axis, and when I close the door I decrement them of the same value.
I hope I've clearly explained the problem, if not please tell me.
Try changing the order of the transform.Rotate and transform.Translate lines in your ClosingDoor function.
Because the translation is relative to the orientation of the door, translating it before it's rotated will move it to the wrong place.
public override void OpeningDoor() {
Vector3 movement = new Vector3 (2.006f, 0.0f,1.793f);
Vector3 rotate = new Vector3 (0.0f, 108.3f, 0.0f);
transform.Translate (movement);
transform.Rotate (rotate);
toClose = true;
}
public override void ClosingDoor() {
Debug.Log ("Closing Door");
Vector3 movement = new Vector3 (-2.006f, 0.0f,-1.793f);
Vector3 rotate = new Vector3 (0.0f, -108.3f, 0.0f);
transform.Rotate (rotate);
transform.Translate (movement);
toClose = false;
}
Related
I want to move my player character(human) on a curved surface. But at the same time character shall stay perpendicular to the surface normals and it should face in the movement direction and can handle collisions(if there is a wall ahead, shall not be able to go through it).
I tried to make a parent stay over normals and change the child local rotation towards direction of motion of its parent. But it has several limitations as of now.
Here is the code what i was using:
[SerializeField] float raycastLength = 1f;
bool canPlayerMove = true;
public float speed = 2f;
public Vector3 offset; //object's position offset to ground / surface
public Quaternion childDirection;
private void Update()
{
float moveHorizontal = SimpleInput.GetAxis("Horizontal");
float moveVertical = SimpleInput.GetAxis("Vertical");
Ray ray = new Ray(transform.position, -transform.up);
RaycastHit hitInfo;
if (Physics.Raycast(ray, out hitInfo, raycastLength))
{
transform.rotation = Quaternion.LookRotation(Vector3.up, hitInfo.normal);
transform.position = hitInfo.point + offset;
Debug.DrawLine(ray.origin, hitInfo.point, Color.red);
}
if (canPlayerMove)
{
Vector3 movement = new Vector3(moveHorizontal, 0, moveVertical);
if (movement != Vector3.zero)
{
childDirection = Quaternion.Slerp(transform.GetChild(0).localRotation, Quaternion.LookRotation(movement), 0.15F);
transform.GetChild(0).localRotation = childDirection;
}
transform.Translate(movement * speed * Time.deltaTime, Space.Self);
}
}
first to not make your player go thru walls you want to add a collider to your walls and not set it as trigger, you will also need a rigidbody on your player and this will help in the next steps.
Secondly you will need to acces the rigidBody in code using this: (if you Check Use Gravity it will also stay on your terrain that you made)
private Rigidbody rb;
private float speed = 7.5f;
private void Start()
{
//this gets the rigidbody on the gameObject the script is currently on.
rb = this.GetComponent<Rigidbody>();
}
private void Update()
{
float hor = Input.GetAxis("Horizontal");
float vert = Input.GetAxis("Vertical");
//this will move your player frame independent.
rb.MovePosition(this.transform.position + new Vector3(hor, 0, vert) * speed *
Time.deltaTime);
}
Also make sure that you have a rigidBody on your player, else it will throw an error.
In my project I currently have 1 script, 1 camera, and 1 object. I wrote a code (see below) that will rotate the camera around the object but X axis is not always left and right, and Y axis is not always up and down.
What I mean by this is, if for example, we load into unity with the camera axis being Y = up, X = left, Z being forward as the transform position and the object having the same orientation as the camera. I can click and drag left or right/ up or down and the camera will rotate with it correctly, but as soon as I rotate it 90 DEG any direction, the opposite axis will not rotate as I want it to.
I know there is a term for this "perfect rotation" but I do not know the term , thus it is very difficult for me to explain. Sorry. Please feel free to enter the code into a C# script and play around with it. add the script to the camera, make sure the camera is looking at the object, and the object needs to be added to the gameobject on the script.
can someone please help me so that when I swipe left, the object will always rotate left, right for right, up for up and down for down.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class FocusObject : MonoBehaviour
{
public GameObject target;//the target object
private Vector3 point;//the coord to the point where the camera looks at
float f_lastX = 0.0f;
float f_difX = 0.0f;
float f_lastY = 0.0f;
float f_difY = 0.0f;
void Start()
{//Set up things on the start method
point = target.transform.position;//get target's coords
transform.LookAt(point);//makes the camera look to it
}
void Update()
{
if (Input.GetMouseButtonDown(0))
{
f_difX = 0.0f;
f_difY = 0.0f;
}
else if (Input.GetMouseButton(0))
{
f_difX = Mathf.Abs(f_lastX - Input.GetAxis("Mouse X"));
f_difY = Mathf.Abs(f_lastY - Input.GetAxis("Mouse Y"));
if (f_lastX < Input.GetAxis("Mouse X"))
{
transform.RotateAround(point, new Vector3(0.0f, 1.0f, 0.0f), f_difX);
}
if (f_lastX > Input.GetAxis("Mouse X"))
{
transform.RotateAround(point, new Vector3(0.0f, -1.0f, 0.0f), f_difX);
}
if (f_lastY < Input.GetAxis("Mouse Y"))
{
transform.RotateAround(point, new Vector3(1.0f, 0.0f, 0.0f), f_difY);
}
if (f_lastY > Input.GetAxis("Mouse Y"))
{
transform.RotateAround(point, new Vector3(-1.0f, 0.0f, 0.0f), f_difY);
}
f_lastX = -Input.GetAxis("Mouse X");
f_lastY = -Input.GetAxis("Mouse Y");
}
}
}
I'm watching unity tutorials and in the control code of the ship I would like to make it rotate on its axis, that is, it can rotate 360 degrees continuously while I press the right key for example.
playerController:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[System.Serializable]
public class Boundary
{
public float xMin, xMax, zMin, zMax;
}
public class PlayerController : MonoBehaviour {
[Header("Movement")]
public float speed;
public float tilt;
public Boundary boundary;
private Rigidbody rig;
[Header("Shooting")]
public GameObject shot;
public Transform shotSpawn;
public float fireRate;
private float nextFire;
void Awake () {
rig = GetComponent<Rigidbody>();
}
void Update () {
if (Input.GetButton ("Fire1") && Time.time > nextFire) {
nextFire = Time.time + fireRate;
Instantiate (shot, shotSpawn.position, Quaternion.identity);
}
}
void FixedUpdate () {
float moveHorizontal = Input.GetAxis ("Horizontal");
float moveVertical = Input.GetAxis ("Vertical");
Vector3 movement = new Vector3(moveHorizontal, 0f, moveVertical);
rig.velocity = movement * speed;
rig.position = new Vector3 (Mathf.Clamp (rig.position.x, boundary.xMin, boundary.xMax), 0f, Mathf.Clamp (rig.position.z, boundary.zMin, boundary.zMax));
rig.rotation = Quaternion.Euler (0f, 0f, rig.velocity.x * -tilt);
}
}
How can I edit it to do what I want?
example:
You can use Transform.Rotate()
Your code would look like this, with the example you provided:
void FixedUpdate () {
float moveHorizontal = Input.GetAxis ("Horizontal");
float moveVertical = Input.GetAxis ("Vertical");
Vector3 movement = new Vector3(moveHorizontal, 0f, moveVertical);
rig.velocity = movement * speed;
rig.position = new Vector3 (Mathf.Clamp (rig.position.x, boundary.xMin, boundary.xMax), 0f, Mathf.Clamp (rig.position.z, boundary.zMin, boundary.zMax));
if(moveHorizontal > 0){ //if your "right key" is pressed
// Rotate the object around its local X axis at 1 degree per second
transform.Rotate(Vector3.right * Time.deltaTime);
}
}
For faster Rotation you can simply multiply the Vector3.right with some value.
To Rotate around another Axis, use other Vector directions, like Vector3.up.
For example:
transform.Rotate(Vector3.Up * moveHorizontal * Time.deltaTime);
transform.Rotate(Vector3.Forward * moveHorizontal * Time.deltaTime);
When you multiply the Vector3.Right with your moveHorizontal it should also work when you press the "left key" and that should result in rotating in the other direction.
transform.Rotate(Vector3.right * moveHorizontal * Time.deltaTime);
Notes:
That only works if your PlayerController is attached to your ship gameobject. If it is not attached you have to use the transform of your ship of course.
World Space vs Local Space
When you click on your object in the scene view, you should see the transform and the 3 arrows (red, green, blue) pointing on different directions (the 3 axis). When you use the method with the parameters provided above, you are using these arrows as rotation axis.
You can also rotate arround the WorldSpace axis.
transform.Rotate(Vector3.up, Time.deltaTime, Space.World);
When to use transform.Rotate?
When you change position or rotation of a transform, using the transforms
methods, it will be applied at the end of the frame. These changes ignore physics.
-> Use transforms methods if you don't care about collisions
When to use rigidbody.MoveRotation?
When you change rigidbody.position or rigidbody.MoveRotation using rigidbodies methods, it will be applied at the end of the next physics step. These changes care about physics (collisions and stuff)
-> Use rigidbodies methods if you care about collisions
Thanks to Helium for that hint.
The third possibility:
Instead of directly calling transform.Rotate or rigidbody.MoveRotation, you can also rotate your Object, using an animation, which changes the transforms rotation.
Example of Transform.Rotate()
You can clearly see, that the collision checks are ignored on that object while it's rotating through the ground. (I packed that gif into a spoiler to reduce noise. You'll need to hover over it, if you want to see it)
This will be the speed and axis of your rotation.
public Vector3 eulerAngleVelocity = new Vector3(0f,0f,1000f);
Since you want to rotate a rigidbody so use MoveRotation
Quaternion deltaRotation = Quaternion.Euler(-moveHorizontal * eulerAngleVelocity * Time.deltaTime);
rig.MoveRotation(rig.rotation * deltaRotation);
Final code will look like this
// NEW CODE BEGIN------
public Vector3 eulerAngleVelocity = new Vector3(0f,0f,1000f);
// NEW CODE END------
void FixedUpdate () {
float moveHorizontal = Input.GetAxis ("Horizontal");
float moveVertical = Input.GetAxis ("Vertical");
// NEW CODE BEGIN------
Vector3 movement = new Vector3(0f, 0f, moveVertical); // Notice I have removed moveHorizontal, this will make sure your gameobject doesnt go left and right. We will use move horizontal for rotating the gameobject.
// NEW CODE END------
rig.velocity = movement * speed;
rig.position = new Vector3 (Mathf.Clamp (rig.position.x, boundary.xMin, boundary.xMax), 0f, Mathf.Clamp (rig.position.z, boundary.zMin, boundary.zMax));
// NEW CODE BEGIN------
Quaternion deltaRotation = Quaternion.Euler(-moveHorizontal * eulerAngleVelocity * Time.deltaTime);
rig.MoveRotation(rig.rotation * deltaRotation);
// NEW CODE END------
}
You can play with eulerAngleVelocity to get the desired speed. Hope this helps. ;)
I have a little problem with this code:
private void Update()
{
if (Input.GetMouseButtonDown(0) && canClick)
{
Vector3 mouseWorldPosition = Camera.main.ScreenToWorldPoint(Input.mousePosition);
mouseWorldPosition.z = player.transform.position.z;
directionVector = player.transform.position - mouseWorldPosition;
player.GetComponent<Rigidbody2D>().AddForce(directionVector.normalized * speed);
Quaternion InstanceRotation = Quaternion.Euler(mouseWorldPosition.x - 90f, 0f, 0f);
GameObject effect = Instantiate(SteamFx, mouseWorldPosition, InstanceRotation);
effect.transform.LookAt(directionVector);
}
}
The problem is that when instantiating the object, it has a z rotation. So I have an effect that when I click on the screen, it should instantiate, and blow in the player direction. It has different rotation, how to make the rotation correct.
Thks!!!
I've created a simple drag script. This will be the main input of my game and that's how I'll control the player. The script can be seen below:
public void OnMouseDown() {
offset = gameObject.transform.position - Camera.main.ScreenToWorldPoint (new Vector3 (Input.mousePosition.x, Input.mousePosition.y, screenPoint.z));
if (gameController.GetCurrentState () != GameStates.INGAME){
gameController.StartGame();
}
}
public void OnMouseDrag() {
if (gameController.GetCurrentState () == GameStates.INGAME) {
Vector3 curScreenPoint = new Vector3 (Input.mousePosition.x, Input.mousePosition.y, screenPoint.z);
Vector3 curPosition = Camera.main.ScreenToWorldPoint (curScreenPoint) + offset;
transform.position = curPosition;
}
}
This script is attached to my player. Also attached to my player is a RigidBody 2D and Circle Collider 2D. I've created some walls and at game start, I'm repositioning it outside of the camera using mainCam.ScreenToWorldPoint. This is done with:
var mainCam : Camera;
var topWall : BoxCollider2D;
var bottomWall : BoxCollider2D;
var leftWall : BoxCollider2D;
var rightWall : BoxCollider2D;
//Reference the players
function Start () {
//Move each wall to its edge location:
topWall.size = new Vector2 (mainCam.ScreenToWorldPoint (new Vector3 (Screen.width * 2f, 0f, 0f)).x, 1f);
topWall.center = new Vector2 (0f, mainCam.ScreenToWorldPoint (new Vector3 ( 0f, Screen.height, 0f)).y + 0.5f);
bottomWall.size = new Vector2 (mainCam.ScreenToWorldPoint (new Vector3 (Screen.width * 2, 0f, 0f)).x, 1f);
bottomWall.center = new Vector2 (0f, mainCam.ScreenToWorldPoint (new Vector3( 0f, 0f, 0f)).y - 0.5f);
leftWall.size = new Vector2(1f, mainCam.ScreenToWorldPoint(new Vector3(0f, Screen.height*2f, 0f)).y);;
leftWall.center = new Vector2(mainCam.ScreenToWorldPoint(new Vector3(0f, 0f, 0f)).x - 0.5f, 0f);
rightWall.size = new Vector2(1f, mainCam.ScreenToWorldPoint(new Vector3(0f, Screen.height*2f, 0f)).y);
rightWall.center = new Vector2(mainCam.ScreenToWorldPoint(new Vector3(Screen.width, 0f, 0f)).x + 0.5f, 0f);
}
Like the player, this walls also have RigidBody 2D and Box Collider 2D attached to it. My problem is that I'm not able to detect any kind of collision. Not even when I drag the ball up to the walls. Mine intend with this script is detect if, while dragging, you touched the walls. By doing that, I'll be able to call my game state "GameOver" and end the game.
Any idea about WHY, I'm not able to detect this collisions? I'm sure that the walls are in the right position and the ball is indeed touching the walls.
Are you just asking how to detect a collision? Make sure all of your objects (the walls and the player object) have Collider2D components. On those colliders, set IsTrigger to true. Then in your player controller:
void OnTriggerEnter2D(Collider2D other) {
// check if "other" is a wall
if (other.transform.GetComponent<Wall>())
this.gameState = GameStates.GAMEOVER;
}
Note that you need a RigidBody2D on at least one of the collidable GameObjects. Just put a RigidBody2D on everything and don't use gravity.
you didnt wrote how you made screenPoint so here is how just incase
public void OnMouseDown() {
screenPoint = Camera.main.WorldToScreenPoint(gameObject.transform.position);