Страница 1 из 2

(Проблема) движение на движущемся объекте

СообщениеДобавлено: 14 авг 2010, 08:07
Garu
персонаж - переделанный PlatformerController (лишь добавка осей)
корабль - ставил аналогичную управляху, так же пробовал нечто типа - А.transform.position = Б.transform.position
при статичном положении корабля - перемещение полностью адекватна, при движении - по плоским участкам корабля бегает нормально, но ступеньки дают следующий эффект:
при набеге на них по направлению движения корабля, словно упираюсь в стену и персонажа сильно дергает вперед и назад, если бежать против движения корабля - буквально телепортирует сквозь несколько кусков корабля. ступеньки и как чайлд крепил в общей модельке, и просто куском основной части - без разницы, при наклоне, даже небольшом, начинаются проблемы с движением, к примеру если плоскость с коллизией ставлю под углом градусов в 5, при движении вперед, двигаюсь назад. Ну а дальше по возрастанию угла, все сильнее глюки. Как лучше тогда поставить физику персонажа (и\или объекта), дабы сохранить возможность перемещения по всем осям на подвижном объекте?

Re: (Проблема) движение на движущемся объекте

СообщениеДобавлено: 14 авг 2010, 10:50
Zaicheg
Вряд ли многие тут помнят, как работает PlatformerController. Если сможете описать проблему на уровне стандартных компонентов юнити, то вероятность решения будет выше, в том числе и я подумаю над ним.

Re: (Проблема) движение на движущемся объекте

СообщениеДобавлено: 14 авг 2010, 11:38
Garu
Zaicheg писал(а):Вряд ли многие тут помнят, как работает PlatformerController. Если сможете описать проблему на уровне стандартных компонентов юнити, то вероятность решения будет выше, в том числе и я подумаю над ним.

ок, тогда попробую перефразировать проблему и потребность

Есть:
Персонаж и объект, объект движется по горизонтали, на объекте есть ступеньки и разница высот. Нужно что бы персонаж свободно перемещался по данному объекту, как обычный контроллер по земле, с сохранением возможности сойти\зайти на корабль и сохранение возможности прыжка. Опробованные варианты принесли 0 эффекта.
И да, забыл сказать, очень желательно ява а не шарп, ибо с шарпом не дружу.

Вот по позиции на объекте часть:

Код: Выделить всё
if (activePlatform != null) {
      var newGlobalPlatformPoint = activePlatform.TransformPoint(activeLocalPlatformPoint);
      var moveDistance = (newGlobalPlatformPoint - activeGlobalPlatformPoint);
      transform.position = transform.position + moveDistance;
      lastPlatformVelocity = (newGlobalPlatformPoint - activeGlobalPlatformPoint) / Time.deltaTime;
   } else {
      lastPlatformVelocity = Vector3.zero;   
   }

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

Re: (Проблема) движение на движущемся объекте

СообщениеДобавлено: 14 авг 2010, 12:32
Paul Siberdt
Ниччиво не понимаю, но, вероятно, двигать персонажа лучше в LateUpdate, а все остальные элементы сцены - в обычном Update. При этом персонаж учтёт все изменения за кадр вокруг себя.

Re: (Проблема) движение на движущемся объекте

СообщениеДобавлено: 14 авг 2010, 12:36
sp00n
Без остального кода тяжело судить, но в глаза сразу бросается строчка
transform.position = transform.position + moveDistance;
, я так понимаю moveDistance тоже вектор и тут мы имеем интересную ситуацию с векторной сумой, в результате которой персонаж и под землю уйдет и на небо взлетит, не говоря уже направо/налево. Тут дело не в шарпе или джаваскрипте, а в простом незнании векторной арифметики(гы, новый термин придумал:) ). Я могу помочь со скриптом, но нужно чуть больше информации - у тебя 2д или 3д платформер, какие ограничения по осям и все такое. Обращайся, наверное, в личку - а как сделаем, то выложим результат здесь или в исходниках :) Учить математику не направляю, так как понимаю что не твой профиль :)

Re: (Проблема) движение на движущемся объекте

СообщениеДобавлено: 14 авг 2010, 12:49
Paul Siberdt
Звиняйте, сама строчка ничего плохого в себе не несет :ymparty:
Все мои трансформы работают именно на кинетическом приращении дельты к текущей позиции :)

Кстати, термин-то придуман ужо, и звучит похоже - векторная алгебра :)

Re: (Проблема) движение на движущемся объекте

СообщениеДобавлено: 14 авг 2010, 13:14
sp00n
Про векторную алгебру я в курсе, также как и про аналитическую геометрию :) Просто для меня это какбэ елементарные знания на уровне арифметики для школьника))))
А насчет дельты - я так помню, что в юнити идет как раз сумма векторов, а не приращение дельты. Но, даже если не так и идет приращение - то приращение по каким осям? или же просто будет x+delta_x, y+delta_y, z+delta_z? В последнем случае мы имеем проблему в том, а где это считается? В Update, FixedUpdate, LateUpdate? Как я уже говорил - тут просто недостаток информации :)

Re: (Проблема) движение на движущемся объекте

СообщениеДобавлено: 14 авг 2010, 14:43
Neodrop
Garu писал(а):персонаж - переделанный PlatformerController (лишь добавка осей)
корабль - ставил аналогичную управляху, так же пробовал нечто типа - А.transform.position = Б.transform.position
при статичном положении корабля - перемещение полностью адекватна, при движении - по плоским участкам корабля бегает нормально, но ступеньки дают следующий эффект:
при набеге на них по направлению движения корабля, словно упираюсь в стену и персонажа сильно дергает вперед и назад, если бежать против движения корабля - буквально телепортирует сквозь несколько кусков корабля. ступеньки и как чайлд крепил в общей модельке, и просто куском основной части - без разницы, при наклоне, даже небольшом, начинаются проблемы с движением, к примеру если плоскость с коллизией ставлю под углом градусов в 5, при движении вперед, двигаюсь назад. Ну а дальше по возрастанию угла, все сильнее глюки. Как лучше тогда поставить физику персонажа (и\или объекта), дабы сохранить возможность перемещения по всем осям на подвижном объекте?


Это от того, что вы двигаете объект имеющий коллайдер, но не имеющий Rigidbody - а этим вы нарушаете корректность физики. Добавьте к кораблю ригидбоди и поставьте на нём галку isKinematic

Re: (Проблема) движение на движущемся объекте

СообщениеДобавлено: 14 авг 2010, 16:10
Paul Siberdt
Вона скока всего наговорили, и аналитическую геометрию вспомнили, и коллайдеры с апдейтами.
Лучше впредь более полно описывать проблему, а если больно много и сложно печатать - прикладывать пак с тестом. :D

Re: (Проблема) движение на движущемся объекте

СообщениеДобавлено: 15 авг 2010, 06:00
Garu
Нео - печально но факт, ригидбоди на кораблике и так было, масса 10000 драг 0 АнДраг0.05 гравитация 0 кинематика - торчит галка, Фриз ротейшен тоже стояло, но что с ним что без него, эффект такой же...
И даже на отдельных частях уже пробовал кидать ригидбоди (не на весь кораблик, а на палубную часть с ступеньками), эффекта не получил.

Вот собственно вся управляшка, сильно не пинать - расковырял дико (мне так удобнее ковыряться) и лишняк не сносил еще (как заработает уже сделаю адекватный внешний вид)
Код: Выделить всё
var canControl = true;
var myCamera: Transform;
var me: Transform;

class PlatformerControllerMovement {
   //var walkSpeed = 3.0;

   var gravity = 60.0;
   var maxFallSpeed = 20.0;

//   var speedSmoothing = 5.0;

   var rotationSmoothing = 10.0;

   @System.NonSerialized
   var direction = Vector3.zero;

   @System.NonSerialized
   var verticalSpeed = 0.0;

   @System.NonSerialized
   var speed = 0.0;

   
   var isMoving = false;
   var isMoving2 = false;
   
   @System.NonSerialized
   var collisionFlags : CollisionFlags;

   @System.NonSerialized
   var velocity : Vector3;
   
   @System.NonSerialized
   var inAirVelocity = Vector3.zero;

   @System.NonSerialized
   var hangTime = 0.0;
}

var movement : PlatformerControllerMovement;

class PlatformerControllerJumping {

   var enabled = true;


   var height = 1.0;

   var extraHeight = 4.1;

   @System.NonSerialized
   var repeatTime = 0.05;

   @System.NonSerialized
   var timeout = 0.15;


   @System.NonSerialized
   var jumping = false;
   
   @System.NonSerialized
   var reachedApex = false;
 

   @System.NonSerialized
   var lastButtonTime = -10.0;
   

   @System.NonSerialized
   var lastTime = -1.0;


   @System.NonSerialized
   var lastStartHeight = 0.0;
}


var jump : PlatformerControllerJumping;


var R2 : float;
var J2 : float;

var bulletGUI : GUIText;

private var Weapon : WeaponQ;

private var controller : CharacterController;

// Moving platform support.
private var activePlatform : Transform;
private var activeLocalPlatformPoint : Vector3;
private var activeGlobalPlatformPoint : Vector3;
private var lastPlatformVelocity : Vector3;

// This is used to keep track of special effects in UpdateEffects ();
private var areEmittersOn = false;

var SPDrot = 1;

var Using = 0;

function Awake ()

{

   Weapon = GetComponentInChildren(WeaponQ);
   moveDirection = new Vector3(Input.GetAxis("Horizontal"), 0, Input.GetAxis("Vertical"));
      moveDirection = transform.TransformDirection(moveDirection);
   controller = GetComponent (CharacterController);
   
}

function LateUpdate ()
{   
   UpdateGUI();
   tdt3 = Time.time;
}


function UpdateGUI ()
{
if (Weapon) {
      bulletGUI.text = Weapon.GetBulletsLeft().ToString();
   }

}

function UpdateSmoothedMovementDirection ()
   {   
   var h = Input.GetAxisRaw ("Vertical");
   var g = Input.GetAxisRaw ("Horizontal");
   
   var h2 = Input.GetButton("Fire1");
   
   var Stat = GetComponent(Stat);
   var R2 = Stat.RunSpd;
if (Using < 1)
{
   if (!canControl)
      h = 0.0;
      //g = 0.0;

   movement.isMoving = (Mathf.Abs (h) > 0.1);
   //movement.isMoving2 = (g > 0.1) || (g < -0.1);
   movement.isMoving2 = (Mathf.Abs (g) > 0.1);
   lineX = (Mathf.Abs (h) > 0.1) && (Mathf.Abs (g) > 0.1);
   
   //transform.forward= myCamera.forward;
      
   if (movement.isMoving)
   {
   //transform.eulerAngles.y = myCamera.eulerAngles.y;
      movement.direction = myCamera.forward * h;
      if(h<0)
      {
      movement.direction = -myCamera.forward * h*0.5;
      }
      
   }
   
   if (movement.isMoving2)
   {
   //transform.eulerAngles.y = myCamera.eulerAngles.y;
   movement.direction = myCamera.right * g;
   
   
   //transform.rotation.y = myCamera.rotation.y;
   }
   if (lineX)
   {
   movement.direction = (myCamera.right * g + myCamera.forward * h) *0.7;
   //if (movement.direction.sqrMagnitude > 0.01)
      
   if(h<0)
      {
      //movement.direction = -(myCamera.forward * h) *0.5;
      movement.direction = -(myCamera.right * g + myCamera.forward * h) *0.4;
      }
      
   //transform.rotation.y = myCamera.rotation.y;
   }






   
   // Grounded controls
   if (controller.isGrounded) {
      // Smooth the speed based on the current target direction
      //var curSmooth = movement.speedSmoothing * Time.deltaTime;
      
      // Choose target speed
      var targetSpeed = h || Mathf.Min (Mathf.Abs(g), 1.0);
   
      // Pick speed modifier
      if (Input.GetButton ("Speed") && canControl)
      {
         targetSpeed *= 0;
         movement.isMoving = false;
         movement.isMoving2 = false;
         }
      else
         targetSpeed *= R2;

      movement.speed = Mathf.Lerp (movement.speed, targetSpeed, 1);
      
      movement.hangTime = 0.0;
   }
   else {
      // In air controls
      movement.hangTime += Time.deltaTime;
   }
   }
}

















function ApplyJumping () {
   // Prevent jumping too fast after each other
   if (jump.lastTime + jump.repeatTime > Time.time)
      return;

   if (controller.isGrounded) {
      // Jump
      // - Only when pressing the button down
      // - With a timeout so you can press the button slightly before landing      
      if (jump.enabled && Time.time < jump.lastButtonTime + jump.timeout) {
         movement.verticalSpeed = CalculateJumpVerticalSpeed (jump.height);
         movement.inAirVelocity = lastPlatformVelocity;
         SendMessage ("DidJump", SendMessageOptions.DontRequireReceiver);
      }
   }
}

function ApplyGravity ()
{   var Stat = GetComponent(Stat);
   var J2 = Stat.jump;
   // Apply gravity
   var jumpButton = Input.GetButton ("Jump");
   
   if (!canControl)
      jumpButton = false;
   
   // When we reach the apex of the jump we send out a message
   if (jump.jumping && !jump.reachedApex && movement.verticalSpeed <= 0.0) {
      jump.reachedApex = true;
      SendMessage ("DidJumpReachApex", SendMessageOptions.DontRequireReceiver);
   }
   
   // * When jumping up we don't apply gravity for some time when the user is holding the jump button
   //   This gives more control over jump height by pressing the button longer
   var extraPowerJump =  jump.jumping && movement.verticalSpeed > 0.0 && jumpButton && transform.position.y < jump.lastStartHeight + J2 && !IsTouchingCeiling ();
   
   if (extraPowerJump)
      return;
   else if (controller.isGrounded)
      movement.verticalSpeed = -movement.gravity * Time.deltaTime;
   else
      movement.verticalSpeed -= movement.gravity * Time.deltaTime;
      
   // Make sure we don't fall any faster than maxFallSpeed.  This gives our character a terminal velocity.
   movement.verticalSpeed = Mathf.Max (movement.verticalSpeed, -movement.maxFallSpeed);
}

function CalculateJumpVerticalSpeed (targetJumpHeight : float) {
   // From the jump height and gravity we deduce the upwards speed
   // for the character to reach at the apex.
   return Mathf.Sqrt (2 * targetJumpHeight * movement.gravity);
}

function DidJump () {
   jump.jumping = true;
   jump.reachedApex = false;
   jump.lastTime = Time.time;
   jump.lastStartHeight = transform.position.y;
   jump.lastButtonTime = -10;
}

function Update ()
   {
   //if (Input.GetButtonUp("Horizontal"))
   
//transform.rotation.y = myCamera.rotation.y;


      if (Input.GetButtonDown ("Jump") && canControl)
      {
         jump.lastButtonTime = Time.time;
      }

   UpdateSmoothedMovementDirection();
   
   // Apply gravity
   // - extra power jump modifies gravity
   ApplyGravity ();

   // Apply jumping logic
   ApplyJumping ();
   
   // Moving platform support
   if (activePlatform != null) {
      var newGlobalPlatformPoint = activePlatform.TransformPoint(activeLocalPlatformPoint);
      var moveDistance = (newGlobalPlatformPoint - activeGlobalPlatformPoint);
      transform.position = transform.position + moveDistance;
      lastPlatformVelocity = (newGlobalPlatformPoint - activeGlobalPlatformPoint) / Time.deltaTime;
   } else {
      lastPlatformVelocity = Vector3.zero;   
   }
   
   activePlatform = null;
   
   // Save lastPosition for velocity calculation.
   lastPosition = transform.position;
   
   // Calculate actual motion
   var currentMovementOffset = movement.direction * movement.speed + Vector3 (0, movement.verticalSpeed, 0) + movement.inAirVelocity;
   
   // We always want the movement to be framerate independent.  Multiplying by Time.deltaTime does this.
   currentMovementOffset *= Time.deltaTime;
   
      // Move our character!
   movement.collisionFlags = controller.Move (currentMovementOffset);
   
   // Calculate the velocity based on the current and previous position. 
   // This means our velocity will only be the amount the character actually moved as a result of collisions.
   //movement.velocity = (transform.position - lastPosition) / Time.deltaTime;
   
   // Moving platforms support
   if (activePlatform != null) {
      activeGlobalPlatformPoint = transform.position;
      activeLocalPlatformPoint = activePlatform.InverseTransformPoint (transform.position);
   }
   

   // We are in jump mode but just became grounded
   if (controller.isGrounded) {
      movement.inAirVelocity = Vector3.zero;
      if (jump.jumping) {
         jump.jumping = false;
         SendMessage ("DidLand", SendMessageOptions.DontRequireReceiver);

         var jumpMoveDirection = movement.direction * movement.speed + movement.inAirVelocity;
         if (jumpMoveDirection.sqrMagnitude > 0.01)
            movement.direction = jumpMoveDirection.normalized;
      }
   }   
}

function OnControllerColliderHit (hit : ControllerColliderHit)
{
   if (hit.moveDirection.y > 0.01)
      return;
   
   // Make sure we are really standing on a straight platform
   // Not on the underside of one and not falling down from it either!
   if (hit.moveDirection.y < -0.9 && hit.normal.y > 0.9) {
      activePlatform = hit.collider.transform;   
   }
}

// Various helper functions below:
function GetSpeed () {
   return movement.speed;
}

function GetVelocity () {
   return movement.velocity;
}


function IsMoving () {
   return movement.isMoving;
}

function IsMoving2 () {
   return movement.isMoving2;
}


function IsJumping () {
   return jump.jumping;
}

function IsTouchingCeiling () {
   return (movement.collisionFlags & CollisionFlags.CollidedAbove) != 0;
}

function GetDirection () {
   return movement.direction;
}

function GetHangTime() {
   return movement.hangTime;
}

function Reset () {
   gameObject.tag = "Player";
}

function SetControllable (controllable : boolean) {
   canControl = controllable;
}

function USE (U1 : float)
{
   Using = U1;
}



// Require a character controller to be attached to the same game object
@script RequireComponent (CharacterController)
@script AddComponentMenu ("2D Platformer/Platformer Controller")


На счет - "Все мои трансформы работают именно на кинетическом приращении дельты к текущей позиции" - а можно чутку подробнее?

Re: (Проблема) движение на движущемся объекте

СообщениеДобавлено: 15 авг 2010, 11:27
Paul Siberdt
Подробность лишь в том, что я позьзую физику лишь для контроля взаимопроникновения триггеров и трассировки лучиков. У меня нет физических объектов, все перемещения делаю кинетически и вручную, высчитывая дельту. Да, приходится многое делать самому, но зато технология дубовая и лишена появления внезапнных артефактов физики. :)

Re: (Проблема) движение на движущемся объекте

СообщениеДобавлено: 16 авг 2010, 07:06
Garu
в общем единственный способ, который "хавается" ступеньками и всем кораблем нормально, это объект без управления, с ригидбоди (гравитация без разницы - обе ест), но обязательно что бы объект был чайлдом корабля, если объект из обычной сцены - при начале движения корабля, остается на своем месте, только чуть вертится (из-за задевания кораблем) и все, полностью игнорит параметр is kinematic на ригидбоде кораблика, но делать так, что бы персонаж при условии Х закидывался в чайлд корабля, мне кажется это не самое вкусное решение... Но пока другого не придумалось.

Re: (Проблема) движение на движущемся объекте

СообщениеДобавлено: 16 авг 2010, 21:16
warr11r
Физику чаще обновляйте. Таймстеп раза в 2 меньше сделайте.

Re: (Проблема) движение на движущемся объекте

СообщениеДобавлено: 17 авг 2010, 14:20
Garu
По сути все тоже, любые шаманства оканчиваются тем, что - предмет с коллайдером + ригидбоди в чаелде корабля дает сносный результат, тоже самое не являясь чаелдом корабля дает 0 эффекта. Про персонажа естественно даже молчу, при таких результатах. Да и очень уж не горю желанием, решать все через перекидывание объектов в чайлд корабля и обратно, топорно это как-то.

Re: (Проблема) движение на движущемся объекте

СообщениеДобавлено: 17 авг 2010, 19:44
warr11r
Насколько я знаю, это делается одной командой. Но, к сожалению, может повлечь за собой другие глюки