Unity 2D: как столкнуться с краем экрана

Сейчас я работаю над 2D-игрой для Android. В моей сцене есть игрок, и если пользователь наклоняет свое устройство, объект игрока движется по земле. Но он просто выходит за пределы экрана слева и справа. Я пытался сделать «стену», но безуспешно. У моего player-Gameobject есть краевой коллайдер. Теперь мой вопрос: как мой игровой объект игрока может столкнуться с боковой стороной экрана?

Это мой код:

public GameObject player;
    
    
    // Use this for initialization
    void Start () {
        
    }
    
    // Update is called once per frame
    void Update () {
        Vector3 dir = Vector3.zero;
        dir.y = Input.acceleration.x;

        player.transform.Translate(new Vector2(dir.y, 0) * Time.deltaTime * 2000f);  

    }

Большое спасибо! :)

Июл

Обновлено:

Изображение 1 - моя стена, а изображение 2 - мое игрока.

Пытаюсь решить стеной сбоку от экрана. Это изображения Unity 2D: как столкнуться с краем экрана

Unity 2D: как столкнуться с краем экрана


Решено

Код решения:

Vector3 position = player.transform.position;
        translation = Input.acceleration.x * movementSpeed * 50f;

        if (player.transform.position.x + translation < LeftlimitScreen)
        {
            position.x = -LeftlimitScreen;
        } 
        else if (transform.position.x + translation > RightlimitScreen)
        {
            position.x = RightlimitScreen;
        }
        else
        {
            position.x += translation;
            player.transform.position = position;
        }

Этот код у меня работает! :)

Вы можете сделать это без коллайдеров, просто напишите код, который вы используете для перемещения вашего персонажа, и я объясню вам, как вы можете программно установить границы.

Ignacio Alorre 21.05.2018 13:53

Vector3 dir = Vector3.zero; dir.y = Input.acceleration.x; player.transform.Translate (новый Vector2 (dir.y, 0) * Time.deltaTime * 2000f);

Jul 21.05.2018 14:59

Извините за плохое форматирование. Я новичок в stackoverflow. :)

Jul 21.05.2018 15:04

Это код в моей функции обновления.

Jul 21.05.2018 15:05
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
4
8 320
4
Перейти к ответу Данный вопрос помечен как решенный

Ответы 4

Ответ принят как подходящий

Вы можете разместить в своей сцене за пределами области, которая будет отображаться на вашем устройстве, 2 пустых игровых объекта с коллайдером, чтобы игрок столкнулся с ними.

Вы также можете ограничить с помощью кода границы, которые игрок может перемещать. Вы применяете это с помощью Mathf.Clamp (), и там вам нужно будет установить границы в координате x для вашей сцены.

Вы увидите, что вместо изменения положения игрока с помощью его преобразования мы используем вместо этого твердое тело.

public class PlayerController : MonoBehaviour
{
    public float speed;
    public float tilt;
    public Boundary boundary;

    void FixedUpdate ()
    {
        float moveHorizontal = Input.GetAxis ("Horizontal");
        float moveVertical = Input.GetAxis ("Vertical");

        Vector3 movement = new Vector3 (moveHorizontal, 0.0f, moveVertical);
        rigidbody.velocity = movement * speed;

        rigidbody.position = new Vector3 
        (
            Mathf.Clamp (rigidbody.position.x, boundary.xMin, boundary.xMax), 
            0.0f, 
            5.0f 
        );

    }
}

Вы можете просмотреть весь учебник здесь: https://unity3d.com/earn/tutorials/projects/space-shooter/moving-the-player?playlist=17147

Обновлять Другие варианты:

//You select here the speed you consider
float speed = 1.0f; 

void Update () {

    Vector3 dir = Vector3.zero;

    float InputValue = Input.acceleration.x * speed;

    //You need to set the values for this limits (max and min) based on your scene
    dir.y = Mathf.Clamp(InputValue, 0.5f, 50.5f);

    player.transform.position = dir;  

}

Обновление 2:

Без зажима, просто устанавливая ограничения на скрипт

void Update () {
     Vector3 position = player.transform.position ;
     translation = Input.acceleration.x * speed;
     if ( player.transform.position.y + translation < leftLimitScreen )
         position.y = -leftLimitScreen ;
     else if ( myTransform.position.x + translation > rightLimitScreen )
         position.y = rightLimitScreen ;
     else
         position.y += translation ;
     player.transform.position = position ;
 }

Спасибо за Ваш ответ! Я добавил код к своему ответу.

Jul 21.05.2018 15:07

@Jul Попробуйте мой обновленный ответ сейчас.

Ignacio Alorre 21.05.2018 15:11

@Jul Кстати, вы должны проверить единицы на своем экране, я использую магическое число 0 и 50 для левого и правого предела, но вам может потребоваться добавить туда что-то еще

Ignacio Alorre 21.05.2018 15:12

Этот код работает. Но если я проведу со своим плеером в сторону экрана, мой игрок застрянет, и я больше не смогу его двигать. Как я могу исправить эту проблему?

Jul 21.05.2018 16:10

@Jul Я обновил свой ответ. Я также добавлю учебник, который может быть вам интересен

Ignacio Alorre 21.05.2018 19:21

Я пробовал этот код, но безуспешно. Поскольку у меня есть 2D-игра, я добавил Rigidbody2D в свой Player-GameObject. Но я не совсем понял ваш код наверху. И это не сработало, потому что к нему не прикреплено (нормальное) Rigidbody. Я попытался решить эту проблему со стеной сбоку, но твердое тело моего игрока не сталкивается. Что я могу сделать сейчас? :)

Jul 22.05.2018 13:46

@Jul вы также добавили к стенам твердое тело и коллайдеры?

Ignacio Alorre 22.05.2018 13:59

Я обновил свой вопрос. «Пожалуйста, взгляните на изображения», - добавил я.

Jul 22.05.2018 14:59

@Jul и все еще не обнаружен? так что именно происходит? Игрок игнорирует стены и продолжает двигаться дальше?

Ignacio Alorre 22.05.2018 15:03

Игрок просто движется сквозь стену и вроде ничего не происходит.

Jul 22.05.2018 15:21

Нужно ли мне изменить какие-то настройки в моем rigdbody2D или Box / Edge Collider2D?

Jul 22.05.2018 15:21

@Jul Хорошо, это может быть способ перемещения игрока, который игнорирует коллайдеры. Попробуйте изменить Update () для сценария, который я только что добавил в свой ответ.

Ignacio Alorre 22.05.2018 15:48

Спасибо за попытку мне помочь. Я попытался реализовать этот код в своей игре. Но это не сработало. Игрок все еще висел в моей «нулевой» точке, и я не мог его сдвинуть. Этот код в порядке? :) И кстати: извините за поздний ответ.

Jul 22.05.2018 22:42

@Jul Это код, который я использовал некоторое время назад, но вводом было положение мыши, а не ускорение телефона

Ignacio Alorre 23.05.2018 06:52

@Jul Я добавил новый комментарий с новой опцией. Вам необходимо проверить и изменить левый и правый предел, а также скорость. Я не могу установить это для вас, так как это зависит от того, чего вы пытаетесь достичь. Также вам необходимо убедиться, что вы используете ось «y». В своем первоначальном вопросе вы используете его, не зная, правильно ли он или это ось «x». Но на всякий случай оставил букву «у».

Ignacio Alorre 23.05.2018 07:08

Спасибо за Ваш ответ. Завтра попробую. :)

Jul 23.05.2018 23:14

Спасибо за Ваш ответ. Похоже, работает. Отличная работа! Большое спасибо! :)

Jul 24.05.2018 13:37

В прототипе я создаю решение, к которому пришел, создавая «стены» с объектами без спрайтов в границах и проверяя, есть ли там что-то с Raycast с помощью такого скрипта:

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;

    public class PlayerController : MonoBehaviour {
        RaycastHit2D[] hit;
        Vector2[] directions;
        private Vector2 targetPosition;
        private float moveSpeed;
        private float moveHDir;
        private float wallPos;
        private bool hitLeft;
        private bool hitRight;

        // Use this for initialization
        void Start () {
            directions = new Vector2[2] {Vector2.right, Vector2.left};
            hitLeft = false;
            hitRight = false;
        }

        // Update is called once per physics timestamp
        void FixedUpdate () {
            foreach (Vector2 dir in directions) {
                hit = Physics2D.RaycastAll(transform.position, dir);
                Debug.DrawRay(transform.position, dir);

                if (hit[1].collider != null) {

                    // Keyboard control
                    if (Input.GetAxisRaw("Horizontal") != 0) {
                        moveHDir = Input.GetAxisRaw("Horizontal");

                        // I have found that a 5% of the size of the object it's a 
                        // good number to set as a minimal distance from the obj to the borders
                        if (hit[1].distance <= (transform.localScale.x * 0.55f)) {

                            if (dir == Vector2.left) {
                                hitLeft = true;
                            } else {
                                hitRight = true;
                            }

                            wallPos = hit[1].collider.transform.position.x;

                            // Condition that guarantee that the paddle do not pass the borders of the screen
                            // but keeps responding if you try to go to the other side
                            if ((wallPos > this.transform.position.x && moveHDir < 0) ||
                                (wallPos < this.transform.position.x && moveHDir > 0)) {
                                    moveSpeed = gControl.initPlayerSpeed;
                            } else {
                                moveSpeed = 0;
                            }
                        } else {
                            if (dir == Vector2.left) {
                                hitLeft = false;
                            } else {
                                hitRight = false;
                            }

                            if (!hitRight && !hitLeft)
                            {
                                moveSpeed = gControl.initPlayerSpeed;
                            }
                        }
                    }
                }
            }
            targetPosition = new Vector2((transform.position.x + (moveSpeed * moveHDir)), transform.position.y);
        }
    }

Может быть, это не лучшее решение или не самое короткое, но оно творит чудеса для меня.

Удачи.

Спасибо за Ваш ответ. Выглядит слишком большим для меня. Но в любом случае спасибо за ответ :) Если другого решения нет, я постараюсь ввести его в ваш код.

Jul 22.05.2018 14:16

Это создаст краевые коллайдеры вокруг экрана (для 2d):

void GenerateCollidersAcrossScreen()
    {
     Vector2 lDCorner = camera.ViewportToWorldPoint(new Vector3(0, 0f, camera.nearClipPlane));
     Vector2 rUCorner = camera.ViewportToWorldPoint(new Vector3(1f, 1f, camera.nearClipPlane));
     Vector2[] colliderpoints;

    EdgeCollider2D upperEdge = new GameObject("upperEdge").AddComponent<EdgeCollider2D>();
    colliderpoints = upperEdge.points;
    colliderpoints[0] = new Vector2(lDCorner.x, rUCorner.y);
    colliderpoints[1] = new Vector2(rUCorner.x, rUCorner.y);
    upperEdge.points = colliderpoints;

    EdgeCollider2D lowerEdge = new GameObject("lowerEdge").AddComponent<EdgeCollider2D>();
    colliderpoints = lowerEdge.points;
    colliderpoints[0] = new Vector2(lDCorner.x, lDCorner.y);
    colliderpoints[1] = new Vector2(rUCorner.x, lDCorner.y);
    lowerEdge.points = colliderpoints;

    EdgeCollider2D leftEdge = new GameObject("leftEdge").AddComponent<EdgeCollider2D>();
    colliderpoints = leftEdge.points;
    colliderpoints[0] = new Vector2(lDCorner.x, lDCorner.y);
    colliderpoints[1] = new Vector2(lDCorner.x, rUCorner.y);
    leftEdge.points = colliderpoints;

    EdgeCollider2D rightEdge = new GameObject("rightEdge").AddComponent<EdgeCollider2D>();

    colliderpoints = rightEdge.points;
    colliderpoints[0] = new Vector2(rUCorner.x, rUCorner.y);
    colliderpoints[1] = new Vector2(rUCorner.x, lDCorner.y);
    rightEdge.points = colliderpoints;
}

Работает как шарм. Благодаря тонну!

Eldoïr 17.03.2019 20:53

Если камера движется (и эта функция должна запускаться в FixedUpdate), я полагаю, это будет загружать процессор?

thathurtabit 12.08.2020 19:38

Да, это может быть полезно, когда ваша камера неподвижна. Вы можете попробовать заставить коллайдеры следовать за камерой, и это может дать вам тот же эффект.

Amit Matsil 06.09.2020 16:34

В случае, если вы хотите сгенерировать коллайдер на границах холста (2D)

Прикрепите этот скрипт к основному объекту холста.

using UnityEngine;

public class BorderCollider: MonoBehaviour 
{
    private EdgeCollider2D _edgeCollider2D;
    private Rigidbody2D _rigidbody2D;
    private Canvas _canvas;
    private float y, x;
    private Vector2 _topLeft, _topRight, _bottomLeft, _bottomRight;

    private void Start() {
        //Adding Edge Collider
        _edgeCollider2D = gameObject.AddComponent<EdgeCollider2D>();
        
        //Adding Rigid body as a kinematic for collision detection
        _rigidbody2D = gameObject.AddComponent<Rigidbody2D>();
        _rigidbody2D.bodyType = RigidbodyType2D.Kinematic;
        
        //Assigning canvas
        _canvas = GetComponent<Canvas>();
        
        GetCanvasDimension(); // Finds height and width fo the canvas
        GetCornerCoordinate(); // Finds co-ordinate of the corners as a Vector2
        DrawCollider(); // Draws Edge collide around the corners of canvas
    }

    public void GetCornerCoordinate() {
        // Assign corners coordinate in the variables
        
        _topLeft = new Vector2(-x,y); // Top Left Corner
        _topRight = new Vector2(x,y); // Top Right Corner
        _bottomLeft = new Vector2(-x,-y); // Bottom Left Corner
        _bottomRight = new Vector2(x,-y); // Bottom Right Corner
        
    }

    void GetCanvasDimension(){
        y = (_canvas.GetComponent<RectTransform>().rect.height) / 2;
        x = (_canvas.GetComponent<RectTransform>().rect.width) / 2;
    }

    void DrawCollider() {
        _edgeCollider2D.points = new[] {_topLeft, _topRight, _bottomRight, _bottomLeft,_topLeft};
    }

}

Другие вопросы по теме