2013-03-26 3 views
5

Я пишу 2D-платформер в Unity, и я пытаюсь заставить игрока оставаться на движущейся платформе. Сейчас я искал и переделывал день или два, и мне не повезло.Пребывание на движущихся платформах

В принципе, мне сказали, чтобы я старался, чтобы персонаж двигался с платформой, когда они касаются друг друга. Во-первых, если я использую что-либо, связанное с OnTriggerEnter(), игрок идет прямо через платформу. Если я делаю OnCollisionEnter() (с помощью CharacterController на проигрывателе и BoxCollider на платформе), ничего не происходит вообще. Это две вещи, которые я нашел больше всего. Другой - воспитывать игрока на платформе, но это, по-видимому, вызывает «проблемы» (часто заявляемые, никогда не объясняемые).

Итак, как я могу заставить игрока оставаться на движущейся платформе? Вот код для движущейся платформы:

public class MovingPlatform : MonoBehaviour 
{ 
private float useSpeed; 
public float directionSpeed = 9.0f; 
float origY; 
public float distance = 10.0f; 

// Use this for initialization 
void Start() 
{ 
    origY = transform.position.y; 
    useSpeed = -directionSpeed; 
} 

// Update is called once per frame 
void Update() 
{ 
    if(origY - transform.position.y > distance) 
    { 
     useSpeed = directionSpeed; //flip direction 
    } 
    else if(origY - transform.position.y < -distance) 
    { 
     useSpeed = -directionSpeed; //flip direction 
    } 
    transform.Translate(0,useSpeed*Time.deltaTime,0); 
} 

И вот код для движения игрока (в Update):

CharacterController controller = GetComponent<CharacterController>(); 
    float rotation = Input.GetAxis("Horizontal"); 
    if(controller.isGrounded) 
    { 
     moveDirection.Set(rotation, 0, 0); //moveDirection = new Vector3(rotation, 0, 0); 
     moveDirection = transform.TransformDirection(moveDirection); 

     //running code 
     if(Input.GetKey(KeyCode.LeftShift) || Input.GetKey(KeyCode.RightShift)) //check if shift is held 
     { running = true; } 
     else 
     { running = false; } 

     moveDirection *= running ? runningSpeed : walkingSpeed; //set speed 

     //jump code 
     if(Input.GetButtonDown("Jump")) 
     { 
      //moveDirection.y = jumpHeight; 
      jump(); 
     } 
    } 
    moveDirection.y -= gravity * Time.deltaTime; 
    controller.Move(moveDirection * Time.deltaTime); 

EDIT: Я думаю, что это, возможно, придется делать с тем, как я m определяя игрока и платформу, но я пробовал разные комбинации. Если платформа является триггером (на коллайдере), игрок проходит последовательно. Если нет, я не могу использовать функции OnTrigger. У меня есть жесткий диск, прикрепленный как к игроку, так и к платформе, но, похоже, это ничего не влияет. Когда игрок находится на платформе в некоторых настройках, он дрожит и часто просто падает.

+0

Я никогда не использовал Unity3D, но это можно сделать что-то вроде 'moveDirection + = theplatform.moveDirection', когда персонаж находится на платформе? – mbeckish

+0

Я пробовал это, но у меня, похоже, возникают проблемы с функциями OnTrigger и OnCollision, которые будут отвечать за часть «когда игрок находится на платформе». Я думаю, что это связано с тем, как я определяю свои объекты, но я не уверен, как правильно их определить, чтобы это могло работать. – muttley91

+0

Кроме того, вам необходимо убедиться, что движок moveDirection.y не меньше, чем moveDirection.y вашей платформы, иначе вы бы провалились (если только инфраструктура Unity3D не будет автоматически обрабатывать это для вас автоматически) – mbeckish

ответ

1

Что вам нужно, кажется, второй коллайдер на платформе. Основной коллайдер имеет isTrigger = false, чтобы гарантировать, что ваш контроллер символов работает. Второй работает с isTrigger = true, и его единственная функция - обнаружить, что игрок относится к платформе, когда вызывается OnTriggerEnter и покидает платформу на OnTriggerExit.

Поскольку у вас не может быть 2 коллайдера одного типа (я думаю, вам нужны коллайдеры), создайте пустого ребенка под игровым объектом платформы и назначьте ему коллайдер. Обычно я беру специальный физический материал под названием ActionMaterial, чтобы очистить свой материал. Если вы используете слои и модифицировали матрицу столкновений, убедитесь, что ваше столкновение выполняется с помощью physX.

+0

Могу ли я использовать два разных коллайдера (один ящик, одна капсула) на одном и том же объекте для одного и того же эффекта, вместо того, чтобы иметь 2 объекта и им обоим нужен сценарий перемещения? Кроме того, я не использую слои и не имею исправленной матрицы столкновений. – muttley91

+0

Разрешены разные коллайдеры. Но имейте в виду, что коллайдер капсулы намного дороже. Поэтому, если у вас есть кубическая фигура, вам лучше использовать решение дочернего объекта. Никаких слоев, никаких манипуляций с матрицей конфликтов => нет повышенной сложности;) Вам нужно только это, когда вы сталкиваетесь с проблемами производительности. Я разрабатываю для iOS, поэтому производительность всегда является для меня проблемой – Kay

+0

Ах, справедливо! Итак, чтобы быть понятным, вы имеете в виду наличие двух игровых объектов на сцене? Как конкретно вы делаете один объект ребенком другого? – muttley91

1

Это не лучший способ сделать это, но вы можете выполнить RayCast от игрока к движущейся платформе. Если RayCast попадает на «MovingPlatform», вы можете проверить разницу по оси Y, чтобы определить, достаточно ли близок игрок, чтобы он считался «OnThePlatform». Затем вы можете просто настроить положение игроков как обычно.

Примером может быть:

private bool isOnMovingPlatform; 
private float offsetToKeepPlayerAbovePlatform = 2.2f; 
private float min = 0.2f; 
private float max = 1.2f; 

private void Update() 
{ 
RaycastHit hit; 
if(Physics.Raycast (player.position, player.TransformDirection(Vector3.down), out hit)) 
{ 
    if(hit.transform.name.Contains("MovingPlatform")) 
    { 
     Transform movingPlatform = hit.collider.transform; 

     if(movingPlatform.position.y - player.position.y <= min && movingPlatform.position.y - player.position.y >= max) 
     { 
      isOnMovingPlatform = true; 
     } 
     else 
     { 
      isOnMovingPlatform = false; 
     } 
    } 

    if(isOnMovingPlatform) 
    { 
     player.position = new Vector3(hit.transform.x, hit.transform.y + offsetToKeepPlayerAbovePlatform, 0); 
    } 
} 
} 
+0

Просто интересно, как я собираюсь попробовать это, мин, макс и смещение, они вообще относятся к размеру платформы? – muttley91

+0

Не обязательно. Мин и макс - только диапазоны, поэтому вы знаете, где игрок имеет отношение к платформе. Если, например, значение игрока Y равно 5, то, как видно, он не на платформе и наоборот. Измените диапазоны, пока не получите хорошую пару поплавков. Теоретически они могут основываться на высоте платформы, но им этого не нужно. –

0

This Unity Answers page может помочь.

+0

Это действительно очень хорошо. Но вы должны опубликовать его как комментарий или предоставить дополнительную информацию. Ответы, содержащие только ссылку, будут убиты на SO (я просто проиграл) – Kay

0

Вы также можете просто заставить игрока gameobjects преобразовать родителя равным преобразованию платформы. Это позволяет игроку продолжать движение, пока он на нем. Что касается обнаружения, Raycast немного медленнее, но выполняет свою работу.

0

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

http://spacelizardstudio.com/devblog/index.php/2016/03/02/unity-a-guide-to-moving-platforms/

+0

Вы должны добавить релевантную информацию из этой ссылки, чтобы ответ по-прежнему был полезен и уместен, даже если связь умирает. – drneel

Смежные вопросы