Force mode working only on Y axis Unity3D - c#

I'm learning how to use Unity3D.
I have this scene where the elements are two PNG images (two black circles) to which I have associated the Rigidbody property (without gravity).
With a script I have associated the controller of the horizontal axis and it works: I can control the central circle with the keyboard.
Now I'm trying to associate a constant force. My script is as follows. But it only works along the Y axis. I can not make it work along the horizontal axis.
The script is:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class CircleController : MonoBehaviour {
float MaxSpeed = 10f;
Rigidbody rigid2D;
public Vector3 tensor;
// Use this for initialization
void Start()
{
rigid2D = GetComponent<Rigidbody>();
rigid2D.AddForce(new Vector3(0,10,0), ForceMode.Force);
}
// Update is called once per frame
void FixedUpdate()
{
float move = Input.GetAxis("Horizontal");
rigid2D.velocity = new Vector2(move * MaxSpeed, rigid2D.velocity.y);
}
}
Can someone help me to understand why I can not put a force along that axis?
In particular, when I execute the script with this instruction: rigid2D.AddForce(new Vector3(0,10,0), ForceMode.Force);, I see the central circle moving towards the other. This is right.
Instead, when I execute it with this instruction rigid2D.AddForce(new Vector3(10,0,0), ForceMode.Force); the central circle remains stationary.

You call the following line in the Start function (executed once)
rigid2D.AddForce(new Vector3(10,0,0), ForceMode.Force);
It applies a force to the rigidbody to the right by the given value (10). The Physics engine computes the acceleration to apply to the rigidbody and will automatically compute the velocity (speed) and new positions each frame.
However, in the FixedUpdate, you call the following lines
float move = Input.GetAxis("Horizontal");
rigid2D.velocity = new Vector2(move * MaxSpeed, rigid2D.velocity.y);
Here, you force the velocity of the rigidbody on the horizontal axis, overriding the value computed by the Physics engine. If you don't press the buttons defined in the Input manager, the circle will remain still on the horizontal axis since move is equal to 0.
When calling rigid2D.AddForce(new Vector3(0,10,0), ForceMode.Force);, the circle moves up, because rigid2D.velocity = new Vector2(move * MaxSpeed, rigid2D.velocity.y); keeps the velocity on the vertical axis.

Related

Unity: RigidBody2D, how to move GameObject in straight lines (no curves)

Hello all, I'm very new to and very confused by Unity.
I'm creating a top-down, gravity-free test game, similar to PacMan (i.e. think of the movement of characters in straight lines).
Currently, I'm trying to move an object in straight lines (without curvature) (see image).
My GameObject has RigidBody2D attached, as well as Linear, Angular and Gravity set to 0.
I'm currently controlling my GameObject by adding force:
private Rigidbody2D _playerRB2D;
public float _speed;
private void FixedUpdate()
{
float moveHorizontal = Input.GetAxis("Horizontal");
float moveVertical = Input.GetAxis("Vertical");
Vector2 movement = new Vector2(moveHorizontal, moveVertical);
_playerRB2D.AddForce(movement * _speed);
}
The idea is that the game object won't get to slow down, so is constantly in motion (in straight lines). Collision with objects is obviously important too!
Any help or information to look at will help a lot, thank you!
Unity has a built-in physics engine that calculates movement based on velocity (and collisions, etc.) By using Rigidbody2D.AddForce, you are adding to your rigidbody's velocity. This means that if you press the up arrow and then the right arrow, the velocity from pressing the up arrow remains, causing a diagonal velocity and curved path. If you want straight lines, you can use Rigidbody2D.velocity or just use Transform.translate.
_playerRB2D.velocity = movement * _speed;
Edit: You said that collisions were important, so keep the rigidbody
or remove the rigidbody2D component and use
transform.Translate(movement * _speed);
The idea is basically to reset the force being applied on the rigidBody2D on each changed direction.
In fact, you would have to test if the direction input from horizontal is greater than vertical for x axis, and the inverse for y axis , and thus if it is true, change the opposite to 0f.
You would have normally:
Vector2 movement = new Vector2(moveHorizontal < moveVertical ? moveHorizontal: 0f, moveVertical < moveHorizontal ? moveVertical: 0f);
_playerRB2D.velocity = movement * speed;
Edit: By testing the input value, you can move your RigidBody2D with a analogic controller, and thus being straight as you wished !

Unity enemy move forward

I have an enemy on Unity, the enemy follows the player and when player is at a specific distance i want the enemy run X units without stopping. The idea is that the enemy run, then he gets tired and the Player can attack him from behind.
How can i make enemy run X distance forward without stopping?
How can i make enemy run X distance forward without stopping?
Depends on a lot of things, how is the movement handled in your game? is it 2D? 3D? etc. ...
If you use a character controller on your Enemy GameObject for example (in 2D)
Vector2 moveDirection = Vector2.zero;
void Update(){
CharacterController player = GetComponent<CharacterController>();
if (player.isGrounded)
{
// constantly move horizontally
moveDirection.x = valuespeed;
player.Move(moveDirection * Time.deltaTime);
}
}
This is just some basic theory. FOr 3D, you add a dimension and choose the direction by using the current forward vector or so.
As for checking the X value, what you could do is that in your Enemy class, when the "running mode" is triggered, you save the origin position and in the update, you check the distance between CurrentPosition and Origin (Vector3.Distance(......)) and as long as the distance is smaller than X, you let him run. If not, you are not in "running mode".

Generating GameObject in front of player infinitely

I have a 'player' 3D Object and a 'circle' 3D Object. The player can move towards the circles one by one already.
I need the circles to generate randomly in front of the player when spacebar is pressed, e.g spacebar pressed then one circle generated, spacebar pressed again then another circle generated and so on.
As in randomly generated, it needs to spawn on the radius of the existing circle, e.g 2 units away from the circle anywhere in front that is not behind (180 degree)
All this text may make the question seem complicated but all I really need is another circle created in front of the existing one.
It would also be helpful if you could use some sort of random rotation of the player in order to generate in front of the player.
This is my code so far, feel free to completely wipe my original code in the answer:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class CreateObject : MonoBehaviour
{
public Vector3 playerPos;
public GameObject yourObject;
// Use this for initialization
void Start()
{
playerPos = playerPos.transform.position;
Instantiate(yourObject, new Vector3(playerPos.transform.position.x + 5, playerPos.transform.position.y, playerPos.transform.position.z), Quaternion.identity);
}
// Update is called once per frame
void Update()
{
}
}
Thanks in advance!
you can rotate your player around your Up Vector between your max and min angle then use your distance and direction to find the new position
for the random angle part you can generate a random number with
RandomAngle=Random.Range(MinAngle,MaxAngle);
then use it with
Quaternion.AngleAxis(RandomAngle, playerUpVector)
to rotate it around your players Upvector, I dont know what you used for your Up vector but normally it is Vector3.up
then multiply it by your players direction(playerLocalDirection) that which normally is Vector3.forward
Vector3 newPos= myPos + Quaternion.AngleAxis(RandomAngle, playerUpVector) * playerLocalDirection * DistanceFromPlayer;

Colliding with Rigidbodies throwing player object in the air

I have a Rigidbody attached to my character controller and my enemies. I want the enemies to be able to surround me and have me trapped without me being able to move, so I set the mass property accordingly.
There's just a small problem - if I don't set my mass high enough, the moment the enemies collide with me, my player will go flying into the air. If I don't set my enemies' mass high enough, I will be able to walk right through them. How can I fix this issue? Here is the movement code for the player:
using UnityEngine;
using System.Collections;
public class CharController : MonoBehaviour {
public float speed;
void Start () {
Cursor.lockState = CursorLockMode.Locked;
}
void Update () {
float translation = Input.GetAxis ("Vertical") * speed;
float strafe = Input.GetAxis ("Horizontal") * speed;
translation *= Time.deltaTime;
strafe *= Time.deltaTime;
transform.Translate (strafe, 0, translation);
if (Input.GetKeyDown ("escape")){
Cursor.lockState = CursorLockMode.None;
}
}
}
The problem here is that you're using Transform.Translate() to move your player object. As a result, the player is being moved into clipping with your enemy objects in between physics calculations - so when the next physics calculation comes around, there will be a massive repulsing force to correct this. This is what's sending your player flying.
A better alternative is to use Rigidbody.AddForce() (or one of its variants) to indirectly move your player object. This allows the player object's movement to be taken into account during physics calculations, so it can collide with and be stopped by enemy objects before it starts clipping into them.
If you retrieve and store a reference to the player's Rigidbody in a variable, then you can replace Translate() with something like:
rigidbody.AddRelativeForce(strafe, 0, translation);
Hope this helps! Let me know if you have any questions.
Make sure IsKinematic is checked. UseGravity can be checked or not depend on your situation.
That way, you rigidbody will not be affected by force, collision or joint and is under full control of your script. But maybe they will lose the ability to detect collision as well but I'm not so sure, I haven't tested it yet.
If that was the case, uncheck the IsKinematic and instead, check FreezeRotation and FreezePosition as well. That way, you revoke control of the physics from affecting your position and rotation. You will manually manipulate position & rotation from your script (using CharacterController).
References:
https://docs.unity3d.com/ScriptReference/Rigidbody-isKinematic.html
https://docs.unity3d.com/Manual/class-Rigidbody.html

C# and XNA -- How to make 3d model follow another 3d model using lerp

I am writing the enemy class of a 3d game I am making and am working on making the enemy follow the player. I want the enemy to basically rotate itself in the direction of the player a little bit every frame and move forward a bit every frame. I tried to use Lerping to accomplish this as seen in the code below, but I can't seem to get it to work. When playing, the enemies don't even appear in my field of view or chase me at all. Here is my code from my enemy class below.
Note: p is a reference to a player object that I am chasing, world is the enemy object's world matrix, quaternion is this enemy object's quaternion.
My current strategy is finding the direction vector in between the forward vector of my enemy and the location vector3 of the player and then lerping that by an amount determined by the velocity variable. Then, I try to find the perpendicular vector to the plane determined by the enemy's forward vector and that new lerped vector I call midVector.Then, I update my quaternion for the player to be rotated about that perpendicular vector. Here is the code below:
//here I get the direction vector in between where my enemy is pointing and where the player is located at
Vector3 midVector = Vector3.Lerp(Vector3.Normalize(world.Forward), Vector3.Normalize(Vector3.Subtract(p.position,this.position)), velocity);
//here I get the vector perpendicular to this middle vector and my forward vector
Vector3 perp=Vector3.Normalize(Vector3.Cross(midVector, Vector3.Normalize(world.Forward)));
//here I am looking at the enemy's quaternion and I am trying to rotate it about the axis (my perp vector) with an angle that I determine which is in between where the enemy object is facing and the midVector
quaternion = Quaternion.CreateFromAxisAngle(perp, (float)Math.Acos(Vector3.Dot(world.Forward,midVector)));
//here I am simply scaling the enemy's world matrix, implementing the enemy's quaternion, and translating it to the enemy's position
world = Matrix.CreateScale(scale) * Matrix.CreateFromQuaternion(quaternion) * Matrix.CreateTranslation(position);
//here i move the enemy forward in the direciton that it is facing
MoveForward(ref position, quaternion, velocity);
}
private void MoveForward(ref Vector3 position, Quaternion rotationQuat, float speed)
{
Vector3 addVector = Vector3.Transform(new Vector3(0, 0, -1), rotationQuat);
position += addVector * speed;
}
My question is both, what is wrong with my current strategy/implementation and is there an easier way for me to accomplish this (the first part is more important)?
You aren't storing your object's orientation from frame to frame. I think you are thinking that the quaternion you are creating is oriented in the objects new direction. But actually, it's just a quaternion that only represents the rotational difference between last frame and the current frame, not the overall orientation.
So what needs to happen is your new quat has to be applied to last frame's orientation quaternion to get a current frame orientation.
In other words, you are creating an inter-frame update quaternion, not the final orientation quaternion.
You need to do something like this:
enemyCurrentOrientation = Quaternion.Concatenate(lastFrameQuat, thisNewQuat);
There's probably is an easier way but if this way's working for you, no need to change it.

Categories

Resources