- Home /
Moving an object on keypress
Hello everybody. In my quest to solve the problem i previously had with moving objects using boolean flags(that turned out to be how i was referencing the objects instead..) i have rewritten my code to use raycast instead, then assign a variable equals to the raycast, and directly change the object position instead of using a method inside the object script. The problem i have is that instead of moving objects of one unit, my code move objects of 1.19 instead (sometimes 1.22, sometimes 1.31..never the same amount). This is how i manipulate the object and it's position:
if ((hit) && hit.collider.name == "rock" && Input.GetKey(KeyCode.Space))
{
_object = hit.collider.gameObject;
_objectDestination = _object.transform.position;
_objectCurrentPosition = _object.transform;
Debug.Log("gameobject" + _object.name);
if(_objectCurrentPosition.position == _objectDestination)
{
switch (direction)
{
case up:
_objectDestination += Vector3.up;
break;
case down:
_objectDestination += Vector3.down;
break;
case right:
_objectDestination += Vector3.right;
break;
case left:
_objectDestination += Vector3.left;
break;
}
}
}
if (_object)
{
_object.transform.position = Vector3.MoveTowards(_object.transform.position, _objectDestination, Time.deltaTime * speed);
}
Does anyone know why it's moving of 1+something instead of one unit (as it should while using vector3.up/down/left/right)? Thank you. Ps: i have the same code that moves my player, and there it works perfectly!
if (Input.GetKeyDown(KeyCode.D) && currentPos.position == targetPos) //if we press the right key and we reached destination
{
hit = Physics2D.Raycast(startR, Vector2.right, checkLenght,collisionmask); //raycast in the direction of the key pressed only on the layer 11 defined with the collisionmask
manager.checkSolidTile(hit); //we process the "hit" object using the checkname function of the class collisionmanager
if (hit) //if hit exist
{
Debug.Log("colliding with " + hit.collider.name); //the name of the collider is printed
}
if(manager.solidTile==false) //if the collision manager set the solid tag to false, basically if the tile we checked is solid or not
{
targetPos += Vector3.right; //the destination is updated to the next destination in the direction of the key pressed
}
}
Answer by RudyTheDev · Jan 02, 2015 at 12:04 AM
Because the actual movement is done via _object.transform.position = Vector3.MoveTowards(_object.transform.position, _objectDestination, Time.deltaTime * speed);
The new position is not _objectDestination
, but an amount of Time.deltaTime * speed
between its current object.transform.position
and the desired _objectDestination
.
Time.deltaTime * speed
is a way of saying that you want to move the object a certain amount per second and Time.deltaTime
provides the current frame's time, so the movement is proportional to the FPS. This works well if you move something continuously, like holding down a button. This isn't useful if you want movement to happen once.
It would move instantly if you just did _object.transform.position = objectDestination
. speed
would become irrelevant.
Hello, thank you for your answer. I don't want the object to suddenly jump at the new destination, but i want it to move with a smooth movement, thats why i used time.deltatime. What i don't understand is why, ins$$anonymous$$d of going to the desired location (dictated by the use of vector3.right) it moves a little bit more than one unit, making my grid movement impossible. $$anonymous$$y player moves through the same code perfectly fine, once i press a key it goes, smoothly, from point to point of one unit at time ( a grid like movement). $$anonymous$$y objects, once they have been "grabbed" by the raycast, do move, but a bit more than one unit. I am pretty sure it's something trivial, possibly how i do the logic (again!) but so far i can't grasp it.
I solved the problem. Ins$$anonymous$$d of having the movement code inside the player object i have moved it into the object that i wanted to move; i have set up some more raycasts that seek for a colliding object named "player" (in my case kiwi) and if i press the space button at the time of colliding it changes the destination, exactly as i have done for my player. (Still don't understand what i was doing wrong before though...i sometimes get lost in nested loops!). Here is the new code, inside the "rock" object: void Update() { _setRayStart(); _raycastHit(); $$anonymous$$ove(); }
void $$anonymous$$ove()
{
transform.position = Vector3.$$anonymous$$oveTowards(transform.position, destination, Time.deltaTime * speed);
}
private void _raycastHit()
{
_downHit = Physics2D.Raycast(Down, -Vector2.up, 0.5f);
_upHit = Physics2D.Raycast(Up, Vector2.up, 0.5f);
_rightHit=Physics2D.Raycast(Right, Vector2.right, 0.5f);
_leftHit = Physics2D.Raycast(Left, -Vector2.right, 0.5f);
if(Input.Get$$anonymous$$ey($$anonymous$$eyCode.Space) && currentPos.position == destination)
{
if((_downHit) && _downHit.collider.name=="kiwi")
{
destination += Vector3.up;
}
if((_upHit) && _upHit.collider.name=="kiwi")
{
destination += Vector3.down;
}
if((_rightHit) && _rightHit.collider.name=="kiwi")
{
destination += Vector3.left;
}
if((_leftHit) && _leftHit.collider.name=="kiwi")
{
destination += Vector3.right;
}
}
}
private void _setRayStart()
{
Up = new Vector2(transform.position.x, transform.position.y + 0.6f);
Down = new Vector2(transform.position.x, transform.position.y - 0.6f);
Right = new Vector2(transform.position.x + 0.6f, transform.position.y);
Left = new Vector2(transform.position.x - 0.6f, transform.position.y);
}
It also made more sense that it would be the object itself to dictate it's own movement in one of its methods: i don't think few raycasts more will make a difference in performance.
You had Input.Get$$anonymous$$eyDown($$anonymous$$eyCode.D)
, so I assumed you wanted to "jump" instantly, because Get$$anonymous$$eyDown
only happens once per press. Your new code has Input.Get$$anonymous$$ey($$anonymous$$eyCode.Space)
, so it would be continuous now.
Thank you. I also haven't noticed that i used .get$$anonymous$$eyDown.