Is there a way to move a gameobject with a rigidbody - c#

Reference the picture for easier understanding of the case.
.
I'm making a 3D game and want to be able to move the board up and rotate it on the Z axis using a single finger. If the finger is slid up - the board goes up. If the finger is slid left or right, the board tilts left or right.
The whole point is so that the board brings the ball that sits on top of it upwards, and when the board is tilted/rotated to the side, the ball starts sliding and falling off to the side.
The board and the ball have rigidbodies attached.
What I've tried so far:
Using a slider that, when the value is changed the board rotates with
Quaternion.Euler.
Using the IDragHandler interface and changing the board position to
the EventData received when a touch is registered.
Tried it with buttons that modify the board position vertically by
some distance - it happens instantaneously and the ball falls through
the board.
Created a UI image/joystick and used touch/event data (from
IDragHandler) to move the board transform whenever the UI joystick is
moved.
I've tried some more variants, unfortunately I can't recall them right now and none of what I have already tried works.

I figured it out. I added a image(UI) game object to an empty game object so it can move from 0 on the X and 0 on the Y axis. Added 3 transforms - 1 tilted to the left, 1 tilted to the right and 1 in the middle of the top of the screen to serve as guides in the game and then disabled them so they don't show up in the actual game. Attached a script to my Image UI gameobject and assigned the necessary transforms in the inspector and voila, it works.
using UnityEngine;
using UnityEngine.EventSystems;
public class MoveStick : MonoBehaviour, IDragHandler, IEndDragHandler {
public Transform leftTarget;
public Transform rightTarget;
public float rotateSpeed;
[Space]
Vector2 joyStartPosition;
public Transform stick;
public Transform topTarget;
public float speed;
bool goingUp;
void Start()
{
joyStartPosition = transform.position;
goingUp = false;
}
public void OnDrag(PointerEventData eventData)
{
transform.position = eventData.position;
if (transform.localPosition.y > 80f || transform.localPosition.x > 50 || transform.localPosition.x < -50)
{
goingUp = true;
var step = speed * Time.deltaTime;
stick.position = Vector3.MoveTowards(stick.position, topTarget.position, step);
Debug.Log("Going up: " + goingUp);
}
else if (transform.localPosition.y < 80f)
{
goingUp = false;
Debug.Log("Going up: " + goingUp);
}
if (transform.localPosition.x > 80 && transform.localPosition.y > 80)
{
stick.rotation = Quaternion.RotateTowards(stick.rotation, rightTarget.rotation, rotateSpeed * Time.deltaTime);
}
else if (transform.localPosition.x < -80 && transform.localPosition.y > 80)
{
stick.rotation = Quaternion.RotateTowards(stick.rotation, leftTarget.rotation, rotateSpeed * Time.deltaTime);
}
}
public void OnEndDrag(PointerEventData eventData)
{
transform.position = joyStartPosition;
eventData.position = joyStartPosition;
Debug.Log("Joystick is not moving");
goingUp = false;
}
}
There is still a lot to smooth and improve, however as a base code it works fine.

Related

Why the object doesn't switch sides when collides from one side unity

I'm trying to change the direction of the enemy when collides with a wall or the character. However, it doesn't work for the wall that the enemy bumps into, but only stays where it is.
Here's what I mean:
In this picture, the goomba switches the direction when bumps into Mario, however the same does not happen when the wall is hit.
What happens instead is this:
The Goomba stands still.
Here's the code of the goomba:
public class GoombaController : MonoBehaviour
{
public float speed = 1f;
private Vector2 force = Vector2.left;
void Update()
{
transform.Translate(force * Time.deltaTime * speed);
}
void OnCollisionEnter2D(Collision2D coll) {
if ((this.transform.position.x - coll.collider.transform.position.x) < 0) {
force = Vector2.left;
} else if ((this.transform.position.x - coll.collider.transform.position.x) > 0) {
force = Vector2.right;
}
}
}
Also, I use a tile map to generate the level, and the ground and the walls are on the same tile map.
If anything else is needed as info, just leave a comment below the question.
How can I solve this?

My Player Movement is presenting some Issues

I'm starting to learn C# with Unity and I guess my code present some issues, the movement of my player works but not that good. Let me explain, I have a player at the bottom of the screen, moving only from left to right by itself, using transform.translate (I didn't used rigidbody) because on collision with the sides it stops, and is not a constant movement, the idea is that, once collides with the sides, it changes of direction, but same velocity.
The issue happens when the player colides with the walls (removed the mesh renderer to keep them transparent) but if at the same time you press the key to trigger also the change of direction the player gets stuck at the corner, as shown on this gif example:
Wait for the Player to get stuck at the corners, the gif takes like 15 secs.
And here's my actual Script for the Player
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PMovement : MonoBehaviour
{
public float playerSpeed = 8.0f;
void Update()
{
float moveX = playerSpeed * Time.deltaTime;
transform.Translate(moveX, 0, 0);
if (Input.GetKeyUp(KeyCode.Space))
{
playerSpeed = playerSpeed * -1;
}
}
void OnCollisionEnter(Collision target)
{
if (target.gameObject.tag.Equals("SideWalls") == true)
{
playerSpeed = playerSpeed * -1;
}
}
}
Your code looks ok for what you want to achieve. Unfortunately, in Unity it may not be enough to pin point the problem, as the code heavily depends on the setting from the editor. One possible solution to this or similar problems:
If you still have blocking colliders, (The collision functions need some sort of rigidbody.), or if you clamp your player's position, to stop overflow, the following can happen:
Collider on right side is hit
Player direction change to left
Space is hit while colliders are still touching
Player direction change to right again
There is no collider on right side left to start the colliderEnter event again.
In this case block your space recognition while the player is touching one side.
If you change direction when you hit the wall, but you press Space at just the right time, you'd end up inside the wall a bit most likely. Then it'd keep thinking it was entering the wall collision and reversing direction over and over. Here's what I'd do.
public class PMovement : MonoBehaviour
{
private List<GameObject> Collisions = new List<GameObject>();
public float playerSpeed = 8.0f;
void Update()
{
float moveX = playerSpeed * Time.deltaTime;
transform.Translate(moveX, 0, 0);
if (Collisions.Count <= 0 && Input.GetKeyUp(KeyCode.Space))
{
playerSpeed = playerSpeed * -1;
}
}
void OnCollisionEnter(Collision target)
{
if (!Collisions.Contains(target.gameObject) && target.gameObject.tag.Equals("SideWalls") == true)
{
Collisions.Add(target.gameObject);
playerSpeed = playerSpeed * -1;
}
}
void OnCollisionExit(Collision target)
{
if (Collisions.Contains(target.gameObject)) {
Collisions.Remove(target.gameObject);
}
}
}
By keeping a list of wall objects you're inside, you can disallow the space bar if you're inside a wall. Keep in mind there's probably better ways to do the things you're doing, but this should fix the issue you're having for now.

When using Unity and c#, how do I make an objects movement less choppy and more fluid?

I'm trying to make a simple snake game on unity that can be played on a mobile device. I got to the point where the snakes head is able to move continuously in the direction that the user swiped in, but the movement of the snake's head is kind of choppy and I'd like it to be more fluid.
I have this in the public class:
Vector2 dir = Vector2.right;
My start function looks like this:
void Start() {
dragDistance = Screen.height * 5 / 100; //dragDistance is 5% height of the screen
InvokeRepeating("Move", 0.3f, 0.075f);
}
Inside of my Update function I have this:
if (Mathf.Abs(lp.x - fp.x) > dragDistance || Mathf.Abs(lp.y - fp.y) > dragDistance)
{//It's a drag
//check if the drag is vertical or horizontal
if (Mathf.Abs(lp.x - fp.x) > Mathf.Abs(lp.y - fp.y))
{ //If the horizontal movement is greater than the vertical movement...
if ((lp.x > fp.x)) //If the movement was to the right)
{ //Right swipe
dir = Vector2.right;
}
else
{ //Left swipe
dir = -Vector2.right;
}
}
else
{ //the vertical movement is greater than the horizontal movement
if (lp.y > fp.y) //If the movement was up
{ //Up swipe
dir = Vector2.up;
}
else
{ //Down swipe
dir = -Vector2.up;
}
}
}
And after the Update function I have:
void Move()
{
// Move head into new direction
transform.Translate(dir);
}
Thanks for your help.
This is simply due to how you are currently moving.
Using InvokeRepeating to move your character will be super choppy as you are just moving "forward" by a certain amount every time InvokeRepeating repeats.
You really shouldn't be using that to move your character. Typically you want to you some form of Rigidbody and physics to move. Perhaps try something like this :
public Rigidbody2D rb;
void FixedUpdate() {
rb.MovePosition((rb.position + dir) * Time.fixedDeltaTime);
}
That could be a very simple answer. Check out some more details on that method here.
Also just try looking up some tutorials on movement in Unity.
The problem is you aren't moving every frame. You could fix this by moving in the update() like so:
transform.Translate(dir * speed * Time.deltaTime);
Instead of doing InvokeRepeating and Move().
But what if you want to make the snake stop at each square like it does now, but move smoothly from square to square? You would need to save the snake's next position in your move() function and then smoothly move the snake there in Update(). It would look something like this:
void Move()
{
// Move head to next position
prevSquare = transform.position; // keep track of the previous square
// so we can use lerp() later on
nextSquare = transform.position + dir;
progress = 0; // progress is the percent distance between the two squares
isMoving = true; //we probably need isMoving so we can decide what to do if they
//swipe while snake is moving, I'll leave it to you to figure
//out
}
update()
{
...
if(isMoving)
{
progress = progress + time.deltaTime;
transform.position = Vector2.Lerp(prevSquare, nextSquare, progress);
if(progress > 1.0f)
{
isMoving = false;
}
}
}

Unity - make character walk towards touch/drag position? In 3D space?

Ok, I have a 3D Unity game built for iOS where these controls will be implemented (in a first person shooter manner):
Camera follows just behind character
Keeping finger on screen makes character walk, finger up makes it stop
THIS is the problem: wherever the user has started touching the screen, whatever direction they drag (forward, backwards, left right) the character will walk indefinitely in that direction.
This must have done already but I cant find anything anywhere. I have the camera as a child of the character, so that's taken care of but for char movement all I have is:
void Update()
{
if (Input.touchCount == 1 && Input.GetTouch(0).phase == TouchPhase.Moved)
{
Vector3 target = Camera.main.ScreenToWorldPoint(new Vector3(Input.mousePosition.x, Input.mousePosition.y, -10f));
transform.Translate(Vector3.MoveTowards(transform.position, target, speed * Time.deltaTime) - transform.position);
}
Which doesn't work as needed. What can I do here?
You can just try to use any king of UI joysticks (https://assetstore.unity.com/packages/tools/input-management/joystick-pack-107631) for example
And access its parameters something like this:
public class TestMovement : MonoBehaviour
{
public float Speed;
public FloatingJoystick Joystick; //Set in the inspector, prefab from the asset
private void Update()
{
transform.Translate(new Vector2(Joystick.Horizontal, Joystick.Vertical) * Speed * Time.deltaTime);
}
}

XNA/Monogame: Platformer Jumping Physics and Collider Issue

I have a sprite, Player. I update Player's position the following way:
_position += (_direction * _velocity) * (float)gameTime.ElapsedGameTime.TotalSeconds;
Where _position, _direction and _velocity are Vector2s.
I have a simple collider(BoxCollider) which simply generates a rectangle (BoundingBox) given the position and dimensions of the collider.
In Initialize(), I create a new List<BoxCollider> and fill it with colliders for the level.
On Update(), I pass the list to Player to check for collisions.
The collision check method:
public void CheckPlatformCollision(List<BoxCollider> colliders, GameTime gameTime)
{
var nextPosition = _position + (_direction * _velocity) * (float)gameTime.ElapsedGameTime.TotalSeconds;
Rectangle playerCollider = new Rectangle((int)nextPosition.X, (int)nextPosition.Y, BoundingBox.Width, BoundingBox.Height);
foreach(BoxCollider collider in colliders)
{
if(playerCollider.Intersects(collider.BoundingBox))
{
nextPosition = _position;
}
}
Position = nextPosition;
}
Right now, every way I've tried to implement gravity has failed. If Player is dropped from too high, nextPosition becomes too far away from Player and leaves it stuck in mid-air.
I'm also having problems with horizontal collisions as well, the issue being similar: Player stops too soon, leaving a space between. Sometimes I've had Player stick to the side of the collider.
What I would like to know is:
How do I properly implement gravity & jumping with _position, _direction, and _velocity? How do I properly handle collisions both horizontally and vertically?
For gravity, add this just before you update _position:
_velocity += gravity * (float)gameTime.ElapsedGameTime.TotalSeconds;
Where gravity is something like new Vector2(0, 10).
For jumping, you need to set the vertical component of the velocity when the player presses the jump button:
if (jumpPressed && jumpAvailable)
{
_velocity.Y = -10; // Numbers are example. You need to adjust this
jumpAvailable = false;
}
And you need to reset jumpAvailable when the player touches the floor.
Colliding is a much complicated thing. But if you look for "XNA implement collision" on the internet you will find a lot of answers.
There are many ways. One of them is pushing back the player to the border of the boxcollider, instead of not letting him move, like you did in your code. The code would be:
if (IntersectsFromTop(playerCollider, collider.BoundingBox))
{
_position.Y = collider.BoundingBox.Y - BoundingBox.Height;
}
else if (IntersectsFromRight(playerCollider, collider.BoundingBox))
{
_position.X = collider.BoundingBox.X + collider.BoundingBox.Width;
}
// And so on...
The helper methods can implemented like:
private static bool IntersectsFromTop(Rectange player, Rectangle target)
{
var intersection = Rectangle.Intersect(player, target);
return player.Intersects(target) && intersection.Y == target.Y && intersection.Width >= intersection.Height;
}
private static bool IntersectsFromRight(Rectange player, Rectangle target)
{
var intersection = Rectangle.Intersect(player, target);
return player.Intersects(target) && intersection.X + intersection.Width == target.X + target.Width && intersection.Width <= intersection.Height;
}
// And so on...
The rationnale behind that code can be explained with a picture:
In that picture width and height correspond to the intersection, in purple.

Categories

Resources