So, I'm trying to make something similar to Super Mario Galaxy's planet traversal where the player has to jump from planet to planet but the difference here is that the player is orbiting around the player instead of walking on it. I've managed to do the jumping from planet to planet but I have a small problem on where the players up direction is facing.
While landing somewhere in the middle of the planet the player changes his up direction in the opposite way he was facing when he first made the jump, if he lands somewhere close to the edge my logic fails.
As you can see in the photo bellow the Y axis is facing the wrong direction and it should face in the direction where the X axis is facing right now.
What would be the right logic to follow for the player Y axis to face the correct way?
// Jump from a planet
void Update()
{
if (TouchListener.Instance.Tap)
{
isOrbiting = false;
_rb.AddForce(transform.up * jumpForce, ForceMode2D.Impulse);
}
}
// Rotating around the planet
private void FixedUpdate()
{
if (planet != null && isOrbiting)
transform.RotateAround(planet.transform.localPosition, transform.forward * -1, orbitSpeed * Time.deltaTime);
}
// Handling the player entering the orbit. Here's where I inverse the up direction of the player. Also stopping any kind of force or rotation
private void OnTriggerEnter2D(Collider2D other)
{
if (other.CompareTag("Planet"))
{
if (!isOrbiting)
score++;
planet = other.gameObject;
isOrbiting = true;
if (score > 0)
{
_rb.velocity = Vector2.zero;
_rb.angularVelocity = 0f;
_rb.rotation = 0f;
transform.up = transform.up * -1;
}
}
}
Use Quaternion.LookRotation to set the player's up to be facing away from the planet and its forward to be world forward (away from camera):
static void SetPlayerUp(Transform player, Transform planet)
{
player.rotation = Quaternion.LookRotation(Vector3.forward,
player.position - planet.position);
}
Consider calling this instead of _rb.rotation = 0f; and transform.up = transform.up * -1;
Related
I've made a code for the enemy where it will go left and right and stop at the ledge, but for some reason the enemy will just disappear into thin air, but the enemy can still hit you, when I am going near where the enemy is located.
Here is the code I've made for the Enemy AI:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PatrollingEnemy : MonoBehaviour
{
public float speed;
private bool movingRight = true;
public Transform groundDetection; //detects the ground if it is there...
// Update is called once per frame
void Update()
{
transform.Translate(Vector2.right * speed * Time.deltaTime);
RaycastHit2D groundInfo = Physics2D.Raycast(groundDetection.position, Vector2.down, 2f);
if (groundInfo.collider == false)
{
if(movingRight == true)
{
transform.eulerAngles = new Vector2(0, -200);
movingRight = false;
}
else
{
transform.eulerAngles = new Vector2(0, 0);
movingRight = true;
}
}
}
}
Here is the link if you want to see how it works with this code: Link for Bug
It occurs because the z-axis value of the enemy transform decreases by time until it's less than the CAMERA z-axis value and moves outside the camera view.
The main problem is that you set transform.eulerAngles = new Vector2(0, -200); when the enemy moves to the left direction and when you combine this code with the transform.Translate(Vector2.right * speed * Time.deltaTime);, the enemy moves in its right vector with -200 angle and so after some times, it goes outside the camera view (Because the camera z-index is probably set to -10 by default).
You need to set the local angle of the y axis value to 180:
...
if (groundInfo.collider == false)
{
if(movingRight == true)
{
transform.eulerAngles = new Vector2(0, 180); // Change -200 to 180
movingRight = false;
}
...
}
...
ANOTHER WAY: if you want to change the enemy face direction to the left side, you can set localScale.x to -1 instead of using rotation.
Here is a simple example:
// Change face direction to the right when Moving RIGHT
transform.localScale= new Vector3(transform.localScale.x, transform.localScale.y, transform.localScale.z);
// Change face direction to the left when Moving LEFT
transform.localScale= new Vector3(-transform.localScale.x, transform.localScale.y, transform.localScale.z);
I Have a gun that spawn a projectile that bounces of colliders (a Ricochet). It is supposed to be shooting to the direction of where the gun is facing but what I am getting is the projectile always shoots 45 degrees upwards to the right I know this is because of my constant declared vector 2.
I tried using Vector2.up but it prevents the projectile to do the ricochet effect because it always wants to go upwards.
How should I implement those things? I just want the projectile to shoot to the direction where my gun is facing and bounces of on colliders. This is a 2D game btw. I have my codes attached below so you can see. Thanks!
Projectile Script:
private Rigidbody2D rb;
public static bool canMove = true;
void Start()
{
rb = GetComponent<Rigidbody2D>();
rb.velocity = new Vector2(10f, 10f);
}
void Update()
{
//transform.Translate(Vector2.up * speed * Time.deltaTime);
if (canMove)
{
rb.isKinematic = false;
}
else if (!canMove)
{
rb.isKinematic = true;
}
}
Gun Script:
float offset = -90f;
public GameObject projectile;
public Transform shotPoint;
public GameObject child;
void Start()
{
}
void Update()
{
Vector3 diff = Camera.main.ScreenToWorldPoint(Input.mousePosition) - transform.position;
float rotZ = Mathf.Atan2(diff.y, diff.x) * Mathf.Rad2Deg;
transform.rotation = Quaternion.Euler(0f, 0f, rotZ + offset);
if (Input.GetMouseButtonDown(0))
{
Instantiate(projectile, shotPoint.position, transform.rotation);
Projectile.canMove = true;
}
}
The Rigodbody.velocity is in World-Space coordinates.
When you pass in
rb.velocity = new Vector2(10f, 10f);
it will go in world space 10 in X and 10 in Y direction.
In order to pass it in as local coordinates in general you can not always rely on Tramsform.InverseTransformDirection as suggested here since the Transform component. In this specific case it might work but in general you set velocities in FixedUpdate and in that moment the Transform component might not be updated yet!
But the Rigidbody2D component is so in general you can use Rigidbody2D.GetRelativeVector in order to convert a local vector relative to the Rigidbody into world coordinates:
// Might also be Vector.up depending on your setup
rb.velocity = rb.GetRelativeVector(Vector2.right * speed);
Note: it would be better you make
[SerializeField] private Rigidbody2D rb;
and already reference it via the Inspector. Then you can get rid of the expensive GetComponent call.
Because you are telling it to do so.
rb.velocity = new Vector2(10f, 10f);
10 to the right, and 10 upwards.
Unless your projectile has a constant force applied to it, like a missile, get rid of everything related to forces or velocity in the projectile script. It will do you no good.
Then, on the gun script:
//...
if (Input.GetMouseButtonDown(0)) {
var projectileInstance = Instantiate(projectile, shotPoint.position, transform.rotation);
var rigidbody = projectileInstance.GetComponent<Rigidbody2D>();
rigidbody.velocity = transform.TransformDirection(yourDirectionVector);
Projectile.canMove = true;
}
Where Transform.TransformDirection is what makes yourDirectionVector, which is a direction relative to the gun, be transformed into one relative to world-space.
I am developing a 3D game like "Stairs By Ketchapp" in Unity.
I am moving the stairs backward instead of moving the player forward by using "transform.Translate" and I am making the player(which is a ball) jump whenever it hit the ground.
The player can only move on the X-axis, Y-axis and I have frozen the Z coordinates for the player so that it cannot move forward or backward by hitting the edge of a stair. Whenever the player hits the ground it jumps back.
The problem is with the landing of the player.
I want the player to land right in the middle of the next stair regardless of its position on the X-axis. so that it can look like it traveled the distance of one stair in one jump.
Here is the stair script
public class Stairmovement : MonoBehaviour {
public float speed;
Vector3 destroyPos;
private void Start()
{
destroyPos = new Vector3(0, -0.5f, -2f);
}
// Update is called once per frame
void Update () {
transform.Translate(new Vector3(0, -0.5f, -2f) * Time.deltaTime * speed);
if(transform.position.z <= destroyPos.z)
{
//transform.position = new Vector3(0, 4f, 16);
transform.position = new Vector3(0, transform.position.y + 4.5f, transform.position.z + 18f);
}
}
}
And this is my player script
public class Player : MonoBehaviour {
private Rigidbody myRigidbody;
public bool grounded;
public float jumpSpeed;
public float forwardSpeed;
public float fallMultiplier;
// Use this for initialization
void Start () {
myRigidbody = GetComponent<Rigidbody>();
}
// Update is called once per frame
void Update () {
if (grounded)
{
myRigidbody.velocity = new Vector3(myRigidbody.velocity.x, jumpSpeed, forwardSpeed);
grounded = false;
}
if (this.gameObject.transform.position.y > 1f)
{
myRigidbody.velocity += Vector3.up * Physics.gravity.y * (fallMultiplier) * Time.deltaTime;
}
}
private void OnCollisionEnter(Collision other)
{
if (other.transform.tag == "Ground")
{
Debug.Log("Grounded");
grounded = true;
}
}
}
I need your help guys, I hope you guys can understand the problem, if not then please do let me know. I'll try to explain it better. I'll appreciate any kind of help, Thank you.
This is an image showing the difference between jumping position and landing position. [Note: please keep it in mind that I am moving the stairs.]
![Image]: https://i.stack.imgur.com/VW9FK.png
The idea is you need to play with the stair's backward movement speed so that each stair will only move "1 stair length" through the duration of time that ball is on air. So lets say if each stair's movement taking 1 second, then the ball should also be on air exaclty 1 second and land on the stair.
So I have these two circles. The white one is supposed to jump away from the coloured one in the direction that it's turned. It works sometimes, but sometimes it jumps at the wrong angle or barely moves at all. This is the code I have:
void Update () {
if (Input.GetKeyDown(KeyCode.Space)) {
jumpDirection = transform.parent.rotation * Vector3.up;
transform.parent = null;
go1.AddComponent();
go2.AddComponent();
}
if(transform.parent == null) {
Vector3 rrotation = jumpDirection;
transform.Translate(rrotation * Time.deltaTime, Space.World);
}
}
void OnCollisionEnter2D(Collision2D col) {
if (col.collider.tag == "sun") {
Destroy(gameObject);
}
if(col.collider.tag == "border") {
Destroy(gameObject);
}
transform.SetParent(col.gameObject.transform);
transform.rotation = transform.parent.rotation;
}
I'm on mobile so sorry if the formatting is a little off. Does anyone know how to fix this?
There is no need to rotate Vector3.up / Vector3.forward by transform.rotation, transform class offers getters that calculate the correct vector for you
Vector3 forward=transform.forward;
Gives you this objects forward, use transform.parent.forward to get parent heading
I've got a quick question regarding 2D Sprite animations that I haven't been able to find specifically answered anywhere:
I have a sprite with walk animations to the right. However, I obviously want to flip the animation to the left when he walks left (2D side-scroller).
I can easily flip the sprite itself, using transform.localscale.x, however, that only flips the sprite. Not the animation clip. (This no longer happens in Unity)
So, while the sprite flips, the minute the animation clip begins playing, it flips back right (as the only animation clip I have is for the right facing sprite).
Is the only way to do this to flip the sprites in Photoshop, or is there a way to do it in Unity?
Thanks!
UPDATE: With the actual versions of unity if you scale the transform by multiplying it by -1, the animation frames are also scaled.
I finally figured it out by doing this:
void Flip()
{
// Switch the way the player is labelled as facing
facingRight = !facingRight;
// Multiply the player's x local scale by -1
Vector3 theScale = transform.localScale;
theScale.x *= -1;
transform.localScale = theScale;
}
This is from Unity's 2D Platformer example.
To implement some sort of checking which makes use of the Flip method, you can do something similar to the below example which is basic movement code. facingRight is set as a value on the class so that the other methods can use it, and it is defaulted to false.
void Update()
{
//On X axis: -1f is left, 1f is right
//Player Movement. Check for horizontal movement
if (Input.GetAxisRaw ("Horizontal") > 0.5f || Input.GetAxisRaw("Horizontal") < -0.5f)
{
transform.Translate (new Vector3 (Input.GetAxisRaw ("Horizontal") * moveSpeed * Time.deltaTime, 0f, 0f));
if (Input.GetAxisRaw ("Horizontal") > 0.5f && !facingRight)
{
//If we're moving right but not facing right, flip the sprite and set facingRight to true.
Flip ();
facingRight = true;
} else if (Input.GetAxisRaw("Horizontal") < 0.5f && facingRight)
{
//If we're moving left but not facing left, flip the sprite and set facingRight to false.
Flip ();
facingRight = false;
}
//If we're not moving horizontally, check for vertical movement. The "else if" stops diagonal movement. Change to "if" to allow diagonal movement.
} else if (Input.GetAxisRaw ("Vertical") > 0.5f || Input.GetAxisRaw("Vertical") < -0.5f)
{
transform.Translate (new Vector3 (0f, Input.GetAxisRaw ("Vertical") * moveSpeed * Time.deltaTime, 0f));
}
//Variables for the animator to use as params
anim.SetFloat ("MoveX", Input.GetAxisRaw ("Horizontal"));
anim.SetFloat ("MoveY", Input.GetAxisRaw ("Vertical"));
}
void FlipHorizontal()
{
animator.transform.Rotate(0, 180, 0);
}
You could also do that on transform itself (without animator). But in that case rotation value can be overriden by animator
This is how I did it - almost the same as the other technique by Jestus with unity script.
var facing : String = "right";
function updateFacing(curr : String){
if(curr != facing){
facing = curr;
var theScale : Vector3 = gameObject.transform.localScale;
theScale.x *= -1;
gameObject.transform.localScale = theScale;
}
}
//put to use
function controls(){
if(Input.GetKey (KeyCode.LeftArrow)){
updateFacing("left");
} else if(Input.GetKey (KeyCode.RightArrow)){
updateFacing("right");
}
}
If you're animating in Unity:
Copy all frames (sprites) of the animation that you want to flip over.
Paste those frames into your new animation and select everything on the first frame.
Change the x scale of the first frame from 1 to -1.
Do the same thing with the very last frame of your animation.
Now it should play facing the other direction!
This is my C# implementation. It uses a string as the direction facing to make it a little easier to debug.
public string facing = "right";
public string previousFacing;
private void Awake()
{
previousFacing = facing;
}
void Update()
{
// store movement from horizontal axis of controller
Vector2 move = Vector2.zero;
move.x = Input.GetAxis("Horizontal");
// call function
DetermineFacing(move);
}
// determine direction of character
void DetermineFacing(Vector2 move)
{
if (move.x < -0.01f)
{
facing = "left";
}
else if (move.x > 0.01f)
{
facing = "right";
}
// if there is a change in direction
if (previousFacing != facing)
{
// update direction
previousFacing = facing;
// change transform
gameObject.transform.Rotate(0, 180, 0);
}
}