I am new to unity and I am trying to make a simple task: touch an object and then release your touch. when you release, I want to check in which side of the screen you released your touch and then move the object to that side of the screen.
So if I am pressing on my object, then swiping my finger to thr giht side, the object will move left and same for the right side...
This is my code, attached to the game object, and for some reason the object is just going to the right side of the screen. and it do it immidietly even though I used Lerp.
void OnMouseUp()
{
Vector3 pos = Input.mousePosition;
Debug.Log("press off");
if (pos.x < Screen.width / 2)
{
transform.position = Vector3.Lerp(transform.position, new Vector3(0,0,0), 2f * Time.deltaTime);
}
else
{
transform.position = Vector3.Lerp(transform.position, new Vector3(Screen.width, 0, 0), 2f * Time.deltaTime);
}
}
thank you!
So After a lot of trying this worked out for me:
public float smoothing = 7f;
IEnumerator MoveCoroutine(Vector3 target)
{
while (Vector3.Distance(transform.position, target) > 0.05f)
{
transform.position = Vector3.Lerp(transform.position, target, smoothing * Time.deltaTime);
yield return null;
}
}
void OnMouseUp()
{
Plane p = new Plane(Camera.main.transform.forward, transform.position);
Ray r = Camera.main.ScreenPointToRay(Input.mousePosition);
float d;
if (p.Raycast(r, out d))
{
Vector3 target = r.GetPoint(d);
if (target.x > 0)
{
Debug.Log("right:" + target.x + " total: " + Screen.width);
target.x = 5;
target.y = 0;
}
else
{
Debug.Log("left:" + target.x + " total: " + Screen.width);
target.x = -5;
target.y = 0;
}
StartCoroutine(MoveCoroutine(target));
}
}
not sure what the Ray casting does, I would be glad if someone can explain.
You code is almost right. You just need to define target positions and have Lerp called each time in update function.
A simple solution is to define two empty objects as position targets and pass them as parameters to the function.
using UnityEngine;
using System.Collections;
public class ClickTest : MonoBehaviour {
public Transform posLeft;
public Transform posRight;
private Vector3 destPos;
void Setup()
{
// default target is init position
destPos = transform.position;
}
// Update is called once per frame
void Update () {
// Define target position
if (Input.GetMouseButtonUp (0)) {
Vector3 pos = Input.mousePosition;
Debug.Log("press off : "+pos+ " scren : "+Screen.width);
if (pos.x < Screen.width / 2)
{
Debug.Log("left");
destPos = posLeft.position;
}
else
{
Debug.Log("right");
destPos = posRight.position;
}
}
// update position to target
transform.position = Vector3.Lerp(transform.position, destPos, 2f * Time.deltaTime);
}
}
Screenshot with empty objects as parameters
Related
I can write somehow this code for optimization?
If not use coroutines, when I click on space the next jump has more force and so on.
If use rb.MovePosition, the character will move as if 15 fps. I know, change Time in settings. But I want to know if exist another method...
private void Update() {
if(Input.GetKeyDown(KeyCode.Space)) {
StopAllCoroutines();
StartCoroutine(Jump());
}
}
private IEnumerator Jump() {
if(rb.bodyType != RigidbodyType2D.Dynamic) {
rb.bodyType = RigidbodyType2D.Dynamic;
}
rb.constraints = RigidbodyConstraints2D.FreezePositionY;
_pos = transform.position;
for (float t = 0; t < 1; t += Time.deltaTime * 4f)
{
transform.position = Vector3.Lerp(transform.position, new Vector3(transform.position.x, _pos.y + .35f, transform.position.z), t);
yield return null;
}
rb.constraints = RigidbodyConstraints2D.None;
}
Rigidbodies exist so you don't need to directly adjust an object's transform. Since you have a Rigidbody2d you can just set the velocity directly:
public float jumpSpeed = 5f; // Whatever feels right
private void FixedUpdate() {
if(Input.GetKeyDown(KeyCode.Space)) {
rb.velocity = Vector2.up * jumpSpeed;
}
}
(Edited to use velocity instead of AddForce)
I have a test 2D game where my player moved from left to right and when he reached the end of the screen it would just transform on the other side. I had a change of heart and made my player move diagonally. It did work, but I have no idea how to make the player stop when it hits the end of the screen. I don't want it to transform on the other side, but rather just stop. So far all my results are either some glitching on the edges or not stopping at all. I have provided my PlayerController script. Right now my player moves diagonally and he will just continue after the edge of the screen. If anyone can assist me I would be very grateful. I never thought I will deal with diagonal movement, but I really want to learn how to do it.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class PlayerController : MonoBehaviour {
public float speed = 7;
public float speedy = 7;
public event System.Action OnPlayerDeath;
float screenHalfWidthInWorldUnits;
Rigidbody2D rb;
void Start () {
rb = GetComponent<Rigidbody2D>();
float halfPlayerWidth = transform.localScale.x / 2f;
screenHalfWidthInWorldUnits = Camera.main.aspect * Camera.main.orthographicSize;
}
void Update()
{
float inputX = Input.GetAxisRaw("Horizontal");
float velocity = inputX * speed;
transform.Translate(Vector2.right * velocity * Time.deltaTime);
}
public void MoveRight()
{
rb.velocity = new Vector2(speed, speedy);
}
public void MoveLeft()
{
rb.velocity = new Vector2(-speed, -speedy);
}
public void Stop()
{
rb.velocity = Vector2.zero;
}
void OnTriggerEnter2D(Collider2D triggerCollider)
{
if (triggerCollider.tag =="Box")
{
if (OnPlayerDeath != null)
{
OnPlayerDeath();
}
Destroy(gameObject);
}
}
}
You can check if the player is at what you define as the border of the map.
If you check this for the x and y axis respectively, you can then lock his x or y axis to the border and not further.
Here is an example of a script I made earlier that does that.
If I understand you correctly you would like to be able to move diagonally. In my sample script below you can move both straight and diagonally, you can also warp between the edges or stop at the edges as you spoke of wanting to.
This script is a bit more advanced than what you need probably, so let me know if something about it confuses you.
Please note that if you set the boolean _ShouldWarp to false he will stop at the border, otherwise he will warp from edge to edge of the map.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Player : MonoBehaviour
{
public float _Speed = 5f;
public WorldBounds _WorldBounds;
public bool _ShouldWarp; //If _ShouldWarp is false, will block players movement instead.
void Update()
{
Move();
WarpIfAtBoundary();
}
void Move()
{
float horizontal = Input.GetAxisRaw("Horizontal");
float vertical = Input.GetAxisRaw("Vertical");
transform.Translate(Vector3.right * Time.deltaTime * _Speed * horizontal);
transform.Translate(Vector3.up * Time.deltaTime * _Speed * vertical);
}
void WarpIfAtBoundary()
{
//X Axis
//If player is at positive X boundary
if (transform.position.x > (_WorldBounds.xPlus + _WorldBounds.xBuffer))
{
if (_ShouldWarp) //Teleport/warp player is set to enabled
{
transform.position = new Vector3(_WorldBounds.xMinus, transform.position.y, transform.position.z);
}
else //Otherwise keep player in border position
{
transform.position = new Vector3(_WorldBounds.xPlus + _WorldBounds.xBuffer, transform.position.y, transform.position.z);
}
}
//Else if player is at negative X boundary
else if (transform.position.x < (_WorldBounds.xMinus - _WorldBounds.xBuffer))
{
if (_ShouldWarp)//Teleport/warp player is set to enabled
{
transform.position = new Vector3(_WorldBounds.xPlus, transform.position.y, transform.position.z);
}
else //Otherwise keep player in border position
{
transform.position = new Vector3(_WorldBounds.xMinus - _WorldBounds.xBuffer, transform.position.y, transform.position.z);
}
}
//Y Axis
//If player is at positive Y boundary
if (transform.position.y > (_WorldBounds.yPlus + _WorldBounds.yBuffer))
{
if (_ShouldWarp)//Teleport/warp player is set to enabled
{
transform.position = new Vector3(transform.position.x, _WorldBounds.yMinus, transform.position.z);
}
else //Otherwise keep player in border position
{
transform.position = new Vector3(transform.position.x, _WorldBounds.yPlus + _WorldBounds.yBuffer, transform.position.z);
}
}
//Else if player is at negative Y boundary
else if (transform.position.y < (_WorldBounds.yMinus - _WorldBounds.yBuffer))
{
if (_ShouldWarp)//Teleport/warp player is set to enabled
{
transform.position = new Vector3(transform.position.x, _WorldBounds.yPlus, transform.position.z);
}
else //Otherwise keep player in border position
{
transform.position = new Vector3(transform.position.x, _WorldBounds.yMinus - _WorldBounds.yBuffer, transform.position.z);
}
}
}
}
//Set as serializable so it displays correctly in Unity's inspector window.
[System.Serializable]
public class WorldBounds
{
[Header("Bounds")]
public float xMinus = -9.4f;
public float xPlus = 9.4f;
public float yMinus = -9.4f;
public float yPlus = 9.4f;
[Header("BufferZone")]
public float xBuffer = 1f;
public float yBuffer = 1f;
}
EDIT:
With your additions will I be able to assign the movement to my two buttons. One is up and right and the other is down and left.
void Move()
{
float horizontal = Input.GetAxisRaw("Horizontal");
transform.Translate(Vector3.right * Time.deltaTime * _Speed * horizontal);
transform.Translate(Vector3.up * Time.deltaTime * _Speed * horizontal);
}
This should work to move diagonally left and down as well as up and right.
The change i made is to use the Horizontal input for both X and Y movement.
I don't need the warp. Just to step at the defined borders
You can set the Warp boolean to false or remove the warp parts from the code then :-), should work.
I've got a hover tank and I'm working on a controller for it. The goal is to have the float above the ground, but I don't want it to tilt over more the a degree or two. I want it to basically stay level all the time.
I'm using a Rigidbody on the tank to control it with .MovePosition and .MoveRotation. You can see the FixedUpdate function below. I've got a section below to keep thinks level, where I check if there tank is tipping past its maxTilt amount. If it is, the keep it at the max.
This makes the tank very jittery all the time. It looks like it's bouncing up and down quickly. I think its due to the hover forces, but I'm not sure.
How can I keep the tank level while still letting it hoover?
FixedUdpate
void FixedUpdate () {
if (!isServer) {
return;
}
CheckGrounded ();
Hoover ();
if (_moveForward) {
float moveAmount = moveSpeed * Time.deltaTime;
_rigidbody.MovePosition(_rigidbody.position + _rigidbody.transform.forward * moveAmount);
}
if (_moveBackward) {
float moveAmount = (-moveSpeed * 0.6f) * Time.deltaTime;
_rigidbody.MovePosition(_rigidbody.position + _rigidbody.transform.forward * moveAmount);
}
if (_turnLeft) {
Quaternion rotateAmount = Quaternion.Euler(new Vector3(0f, -angularSpeed, 0f) * Time.deltaTime);
_rigidbody.MoveRotation(_rigidbody.rotation * rotateAmount);
}
if (_turnRight) {
Quaternion rotateAmount = Quaternion.Euler(new Vector3(0f, angularSpeed, 0f) * Time.deltaTime);
_rigidbody.MoveRotation(_rigidbody.rotation * rotateAmount);
}
if (_jump && _isGrounded) {
_isJumping = true;
}
if (_isJumping && _jumpTimeLeft > 0) {
float moveAmount = jumpSpeed * Time.deltaTime;
_rigidbody.MovePosition(_rigidbody.position + _rigidbody.transform.up * moveAmount);
_jumpTimeLeft -= Time.deltaTime;
} else if (_isJumping) {
_isJumping = false;
_jumpTimeLeft = jumpTime;
}
// Keep things level
Vector3 rotation = _rigidbody.rotation.eulerAngles;
if (rotation.x > maxTilt) {
rotation.x = maxTilt;
} else if (rotation.x < -maxTilt) {
rotation.x = -maxTilt;
}
if (rotation.y > maxTilt) {
rotation.y = maxTilt;
} else if (rotation.y < -maxTilt) {
rotation.y = -maxTilt;
}
if (rotation.z > maxTilt) {
rotation.z = maxTilt;
} else if (rotation.z < -maxTilt) {
rotation.z = -maxTilt;
}
Quaternion q = new Quaternion ();
q.eulerAngles = rotation;
_rigidbody.rotation = q;
}
Hoover
void Hoover() {
foreach (Transform hoverPoint in hooverPoints) {
Ray ray = new Ray (hoverPoint.position, -hoverPoint.up);
RaycastHit hitInfo;
if (Physics.Raycast (ray, out hitInfo, hooverHeight)) {
float distance = Vector3.Distance (hoverPoint.position, hitInfo.point);
if (distance < hooverHeight) {
_rigidbody.AddForceAtPosition (hoverPoint.up * hooverForce * (1f - distance / hooverHeight), hoverPoint.position, ForceMode.Force);
}
}
}
}
I'm thinking that the reason you are seeing 'jitters' is because...
All physics calculations and updates occur immediately after FixedUpdate.
https://docs.unity3d.com/Manual/ExecutionOrder.html
Because you are adjusting the tilt in FixedUpdate(), which is then immediately followed by the Physics Engine running its calculations this will sometimes alter the tilt value giving a 'jitter'. The reason I say sometimes is because FixedUpdate() can run multiple times per frame (FPS dependant), which potentially means the following call order for a single frame:
FixedUpdate() // start frame
PhysicsEngine
FixedUpdate() // end frame
In the case above, there would be no jitter because you re-correct the tilt after the physics engine has done its thing - by complete fluke. However when you don't get a second FixedUpdate() call on a frame, you will have:
FixedUpdate() // start frame
PhysicsEngine // end frame
Which will result in your jitter.
So my suggestion is to break up your FixedUpdate() and offset any tilt corrections to LateUpdate(). Becuase LateUpdate() is always the last update call prior to the rendering of the frame.
I am making a 2D game. I got a character and some tiles. The tiles are 1 x 1 unit, and placed in scene.
I used the following codes to move my character. Here is my character ("Hero")'s code:
public class Hero : MonoBehaviour {
private Vector2 speedX = new Vector2(1, 0);
private Vector2 speedY = new Vector2(0, 1);
void Update () {
if(Input.GetKey("left")) {
rigidbody2D.MovePosition(rigidbody2D.position - speedX * Time.deltaTime);
} else if(Input.GetKey("right")) {
rigidbody2D.MovePosition(rigidbody2D.position + speedX * Time.deltaTime);
} else if(Input.GetKey("up")) {
rigidbody2D.MovePosition(rigidbody2D.position + speedY * Time.deltaTime);
} else if(Input.GetKey("down")) {
rigidbody2D.MovePosition(rigidbody2D.position - speedY * Time.deltaTime);
}
}
}
It works, but it does not move as expected. It moves around 0.2 units when I press the arrow key once. How can I make the player moves 1 unit per key down ?
What did I miss?
Documentation: Rigidbody2D.MovePosition
From what I see, it looks like you want to achieve instant movement of character to new position once key is pressed. If so, you have two errors here:
You don't need to multiply speed (speedX or speedY) by Time.deltaTime.
Input.GetKey is not what you want to use, because it will return true in every frame where key is pressed (not once per key pressing). Instead, you need to use Input.GetKeyDown.
So, your code should look like this:
public class Hero : MonoBehaviour {
private Vector2 speedX = new Vector2(1, 0);
private Vector2 speedY = new Vector2(0, 1);
void Update () {
if(Input.GetKeyDown("left")) {
rigidbody2D.MovePosition(rigidbody2D.position - speedX);
} else if(Input.GetKeyDown("right")) {
rigidbody2D.MovePosition(rigidbody2D.position + speedX);
} else if(Input.GetKeyDown("up")) {
rigidbody2D.MovePosition(rigidbody2D.position + speedY);
} else if(Input.GetKeyDown("down")) {
rigidbody2D.MovePosition(rigidbody2D.position - speedY);
}
}
}
I created a object in unity
GameObject monsterclone =
(GameObject)Instantiate(monsterPrefab, floorPosition, Quaternion.identity);
This object should move in a wave style from a limit1 to limit2.
Then move back from limit2 to limit1.
Y position as well x position have to change in a specific way.
Vector3 nPos = mfloorPos + new Vector3(2f, 0f, 0f);
Vector3 oPos = mfloorPos + new Vector3(-2f, 0f, 0f);
How can I do it?
I can't exactly write the code without knowing more specific but i think this question is already asked any this link will help you out MOVE OBJECT as wave
EDIT:
I think the flat up and float down functionality will work for you for moving one point to another
example:
var floatup;
function Start(){
floatup = false;
}
function Update(){
if(floatup)
floatingup();
else if(!floatup)
floatingdown();
}
function floatingup(){
transform.position.y += 0.3 * Time.deltaTime;
yield WaitForSeconds(1);
floatup = false;
}
function floatingdown(){
transform.position.y -= 0.3 * Time.deltaTime;;
yield WaitForSeconds(1);
floatup = true;
}
example taken from
float amplitudeX = -25.0f;
float amplitudeY = 5.0f;
float omegaX = 0.5f;
float omegaY = 4.0f;
float index;
void Update () {
index += Time.deltaTime;
float x = amplitudeX*Mathf.Cos (omegaX*index);
float y = Mathf.Abs (amplitudeY*Mathf.Sin (omegaY*index));
if(transform.position.x > 24){
transform.eulerAngles = new Vector3(270, -90, 0);
}
if(transform.position.x < -24){
transform.eulerAngles = new Vector3(270, 90, 0);
}
transform.localPosition= new Vector3(x,y,20);
}
If this is a consitant wave and not dependant on speed I would use an animation to create a literal wave curve of the Position.Y value (much in the same principle as Ravindra Shekhawat has explained.) you can find out more about animation here.
Here is some code (untested) that you could go off. It is in c# so I hope it proves no issue with putting in to JavaScript.
bool monsterMoving = false;
void Update(){
//check monster moving to start updating position
if(monsterMoving == true){
//moving animation controls up and down "wave" movement
animation.CrossFade('moving');
//Lerp changes position
Transform.Lerp(transform.Position, oPos, Time.deltaTime);
if (transform.Position == oPos) {
//We are at destination, stop movement
monsterMoving = false;
}
} else {
// if monster stopped moving, return to idle animation (staying still)
animation.CrossFade('idle');
}
}
// function to send a new position to the monster object
void MoveTo(Vector3 newPos){
oPos = newPos;
monsterMoving = true;
}