Unity2D - Side scroller: Teleport player a fixed distance inside a predefined "cone" (Katan Zero style)?

104 Views Asked by At

I'm very new to Unity (it hasn't been a full week since I started). For my first project I have decided to create a small game for mobile. It's kind of a way to get warm with the engine and eventually do something bigger. Anyway, I'm trying to do the following (and I try my best to explain it as good as possible):

The game will be an infinite runner. It's a 2D side scroller. If the player touches and holds the screen, the game runs in slow motion for a short duration. So far this works.

Now I want to add a cone or circle that appears when holding the button/screen. This cone indicates the travel distance. The player can move his fingers up or down to determine where exactly the character will be teleported to (indicated by a line). If the player lifts the finger/button the character should be teleported to the point where the line and circle cross each other and every enemy in his path takes damage / dies. It doesn't matter if the Player get's teleported or dashes at a high speed.

Here is a YouTube video of Katana Zero which is approximately what I want to achieve (00:21 min): https://www.youtube.com/watch?v=33L04ZSzYvY

I've tried stuff like applying force, but the player just jumps in an arc and not really in a straight line. Also I couldn't set a maximum distance to travel.

Maybe I should also note, that the movement speed of the player increases over time.

If anyone has a nice source so learn Unity I would be happy to soak all the wisdom in haha. So far I'm just modifying scripts I find online and mixing them together. Therefore it's really hard to do this.

This is my script, which also includes the slow motion trigger. So far I've been obviously testing this with keyboard buttons, in this case Jump / space.

public TimeManager timeManager;

[SerializeField] private float force = 5f; //Force that is implied to move the character forward

void Update()
{
    if (Input.GetButtonDown("Jump"))
    {
        timeManager.DoSlowmotion();
        Rigidbody2D rb = GetComponent<Rigidbody2D>();

        // Gets the position of the mouse cursor in world space
        Vector3 direction = Camera.main.ScreenToWorldPoint(Input.mousePosition);

        rb.AddForce(direction * force, ForceMode2D.Impulse);
    }

}

}

I also tried this:

public class Mouse : MonoBehaviour { public GameObject MousePosGameObject;

void Update()
{
    Vector3 mousePos = Input.mousePosition;
    mousePos.z = MousePosGameObject.transform.position.z - Camera.main.transform.position.z ;

    MousePosGameObject.transform.position = Camera.main.ScreenToWorldPoint(mousePos);
}

}

It resulted in the Player just following the mouse without ever stopping.

3

There are 3 best solutions below

3
On

Ok, try making an empty gameobject variable in your player script like this

//you can name your gameobject anything
//now you can put a refrence to the circle or line renderer using this variable
public GameObject LineRenderer;

Now deactivate your gameobject by default

void Start(){
    LineRenderer.setActive(false);
}    

After you have done this you can now activate it through an If Statement

void Update(){
     //replace holding down with your own bool
    if(holdingDown){
        LineRenderer.setActive(true);
    }else if(!holdingDown){
       LineRenderer.setActive(false);
    }
}

after writing this script and you feel a lit unresponsive try changing Update to FixedUpdate finally in your player inspector window you can drag the empty gameobject your line and circle collider are attached to. now when you hold the screen your line renderer should appear! then when you release it dissapears!

now you can get the position of your cursor Using the last step in my previous answer

Hope This Helps, And have fun with your game!

0
On

So, positive update incoming!

I did it! The Circle Collider 2D AND the line both appear when holding the mouse button and disappear when releasing it. The Line also follows my mouse correctly!

In case someone stumbles upon this post, this is how I did it:

I used a SpriteRenderer instead and created a copy of the "Square" which I then stretched and made thin so it looks like a line. I then changed the pivot point to left instead of the center and attached the pivot point to the player.

This is my Script:

{ public TimeManager timeManager; // for the slow motion effect

public bool holdingScreen = false;

private Camera mainCam;

private Vector3 mousePos;

public GameObject SpriteRenderer;

public GameObject CircleRenderer;

void Start()
{
    mainCam = GameObject.FindGameObjectWithTag("MainCamera").GetComponent<Camera>(); // Make sure the main camera is Tagged as "MainCamera"
}


void Update()
{
    if (Input.GetMouseButton(0))
    {
        holdingScreen = true;
        timeManager.DoSlowmotion(); // For the slow motion
    }
    else
    {
        holdingScreen = false;
    }    

    if (holdingScreen == true)
    {
        SpriteRenderer.SetActive(true); // This contains the sprite for the line, aka the modified square
        CircleRenderer.SetActive(true);
        
        mousePos = mainCam.ScreenToWorldPoint(Input.mousePosition);
        Vector3 rotation = mousePos - transform.position;
        float rotZ = Mathf.Atan2(rotation.y, rotation.x) * Mathf.Rad2Deg;
        SpriteRenderer.transform.rotation = Quaternion.Euler(0, 0, rotZ);
    }
    else if(!holdingScreen)
    {
        SpriteRenderer.SetActive(false);
        CircleRenderer.SetActive(false);
    }
    }

}

Now what remains is to actually teleport the player when something hits the circle collider 2D / the line and then regulate the speed of the player so he falls back into his original position (since this game is a infinite runner und you can't move the character himself).

I don't know what to do about that because my level accelerates up to a max speed and to me it's really complicated to factor that in. But first the teleport or dash should work haha.

1
On
public TimeManager timeManager;
public bool holdingScreen = false;

void Update()
{
    if (Input.GetMouseButton(0))
    {
        holdingScreen = true;
        timeManager.DoSlowmotion();
    }
    else
    {
        holdingScreen = false;
    }    

    if (holdingScreen == true)
    {
        Debug.Log("holdingScreen = true");

    }

}

This is what I came up with...