2013-03-26 12 views
5

Sto scrivendo un Platform in 2D in Unity e sto cercando di far rimanere il giocatore su una piattaforma mobile. Ho cercato e armeggiato per un giorno o due adesso, e non ho avuto fortuna.Rimanere su piattaforme mobili

Fondamentalmente, mi è stato detto di provare a mantenere il personaggio in movimento con la piattaforma quando stanno toccando. In primo luogo, se utilizzo qualsiasi cosa correlata a OnTriggerEnter(), il lettore passa direttamente attraverso la piattaforma. Se faccio OnCollisionEnter() (con un CharacterController sul giocatore e un BoxCollider sulla piattaforma), non succede nulla. Queste sono due cose che ho trovato suggerite di più. L'altro è genitore del giocatore con la piattaforma, ma questo a quanto pare causa "problemi" (spesso affermato, mai spiegato).

Quindi, come posso far rimanere il giocatore sulla piattaforma mobile? Ecco il codice per la piattaforma mobile:

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); 
} 

E qui è il codice per il movimento del giocatore (in aggiornamento):

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: Penso che potrebbe avere a che fare con il modo in I' Sto definendo il giocatore e la piattaforma, ma ho provato diverse combinazioni. Se la piattaforma è un innesco (sul suo collisore), il giocatore lo attraversa in modo coerente. In caso contrario, non posso utilizzare le funzioni di OnTrigger. Ho un corpo rigido collegato sia al giocatore che alla piattaforma, ma non sembra influenzare nulla. Quando il giocatore sale sulla piattaforma in alcune situazioni, fa tremare e spesso finisce per cadere.

+0

Non ho mai usato Unity3D, ma è possibile fare qualcosa di simile 'moveDirection + = thePlatform.moveDirection' quando il personaggio si trova su una piattaforma? – mbeckish

+0

L'ho provato, ma mi sembra di imbattersi in problemi con le funzioni OnTrigger e OnCollision, che sarebbero responsabili della parte "quando il giocatore è sulla piattaforma". Penso che abbia a che fare con il modo in cui sto definendo i miei oggetti, ma non sono sicuro del modo corretto per definirli in modo che funzioni. – muttley91

+0

Inoltre, dovrai assicurarti che moveDirection.y del personaggio non sia mai inferiore alla funzione moveDirection.y della tua piattaforma, altrimenti potresti fallire (a meno che il framework Unity3D lo gestisca automaticamente per te?) – mbeckish

risposta

1

Che cosa è necessario sembra essere una seconda collisore sulla piattaforma. Il collisore principale ha isTrigger = false per assicurarsi che il controller di caratteri funzioni. Il secondo viene eseguito con isTrigger = true e la sua unica funzione è quella di rilevare che il lettore è in qualche modo collegato alla piattaforma quando viene chiamato OnTriggerEnter e lascia la piattaforma su OnTriggerExit.

Poiché non è possibile avere 2 raccoglitori dello stesso tipo (penso che siano necessari collettori di scatole), creare un bambino vuoto sotto l'oggetto di gioco della piattaforma e assegnargli il collettore di riquadri. Di solito prendo un materiale di fisica speciale chiamato ActionMaterial solo per avere le mie cose pulite. Se stai usando i livelli e hai una matrice di collisione ottimizzata, assicurati che la tua collisione sia gestita da PhysX.

+0

Posso utilizzare due collettori diversi (una scatola, una capsula) sullo stesso oggetto per lo stesso effetto, piuttosto che avere 2 oggetti e avere entrambi bisogno dello script di movimento? Inoltre, non sto usando i livelli e non ho una matrice di collisione ottimizzata. – muttley91

+0

Sono consentiti collettori diversi. Ma tieni presente che un collettore di capsule è molto più costoso. Quindi, se hai una forma cubica, è meglio usare la soluzione oggetto figlio. Nessun livello, nessuna manipolazione della matrice di collisione => nessuna complessità aumentata;) Hai solo bisogno di quella roba quando ti imbatti in problemi di prestazioni. Sto sviluppando per iOS quindi le prestazioni sono sempre un problema per me – Kay

+0

Ah abbastanza giusto! Quindi, per essere chiari, vuoi dire avere due oggetti di gioco nella scena? Come fai in modo specifico a rendere un oggetto figlio di un altro? – muttley91

1

Questo non è il modo migliore per farlo, ma è possibile eseguire un RayCast dal lettore alla piattaforma mobile. Se RayCast colpisce "MovingPlatform", puoi verificare la differenza sull'asse Y per determinare se il giocatore è abbastanza vicino da essere considerato "OnThePlatform". Quindi puoi semplicemente regolare la posizione dei giocatori normalmente.

Un esempio potrebbe essere:

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

Solo per curiosità, visto che sto per provare questo, il minimo, il massimo e l'offset, si riferiscono alla dimensione della piattaforma? – muttley91

+0

Non necessariamente. Min e max sono solo intervalli in modo da sapere dove il giocatore è rilevante per la piattaforma. Ad esempio, se il valore Y dei giocatori è 5 sopra il massimo, è chiaro che non è sulla piattaforma e viceversa. Cambia gli intervalli finché non ottieni una buona coppia di galleggianti. In teoria potrebbero derivare dall'altezza della piattaforma ma non devono. –

0

This Unity Answers page potrebbe aiutare.

+0

È davvero piuttosto buono. Ma dovresti postarlo come commento o fornire maggiori informazioni. Le risposte contenenti solo un collegamento verranno eliminate su SO (ne ho appena perse alcune) – Kay

0

Si potrebbe anche semplicemente rendere il giocatore oggetto di gioco trasformi genitore uguale alla trasformazione della piattaforma. Ciò consente al giocatore di continuare a muoversi mentre è su di esso. Per quanto riguarda il rilevamento, Raycast è un po 'lento, ma ha il compito di farlo.

Problemi correlati