Vector2 mousePos = Input.mousePosition;
// motion core
if (GameObject.Find("Camera").GetComponent<room>().playerNum == 1)
{
if (Input.GetMouseButtonDown(0))
{
// move script not working
}
}
So, I have mostly every possible solution I could find but none of them worked. I cannot get it to smoothly move with AddForce because I could not figure out a working algorithm to make the force move toward the MousePosition.
The position you're getting out of Input.mousePosition are the coordinates on the screen, not the position in the world. To transform between the two, you can use Camera.ScreenToWorldPoint().
if (Input.GetMouseButtonDown(0))
{
Vector3 mousePos = Input.mousePosition
mousePos = new Vector3(mousePos.x, mousePos.y, Camera.main.nearClipPlane)
Vector3 worldPos = Camera.main.ScreenToWorldPoint(new Vector3())
// move script
}
You might need to edit the z coordinate in the mousePos to the current transform.position.z of the object you're trying to move, or another value that makes most sense here. It acts as a kind of wall, where it'll create the point exactly that far from the camera on your mouse position. This should be a lot cheaper than raycasting, and still works if there's nothing to hit where you're clicking.
I have a script that did this same movement to the handle of a wrecking ball, but I don't have the code with me at the moment. I can't remember exactly how it worked, but I think the idea was that when the mouse was clicked, drag would be set to a very high number and gravity would be set to 0. Then an extremely strong force would be added to counter the drag so that the object would fly towards the mouse without orbiting. When the mouse was released, the drag and gravity would be set back to normal.
I can't test this at the moment because I'm on a chromebook and my PC with Unity on it is in another building, but this code should do the trick if I don't make any errors.
using UnityEngine;
public class ExampleClass : MonoBehaviour
{
float prevDrag, prevGrav;
bool mousedown;
Plane plane;
Rigidbody2D r;
void Start()
{
r = GetComponent<Rigidbody2D>(); // assuming this script is attached to the object being moved.
plane = new Plane(Vector3.up, Vector3.zero);
}
void Update()
{
if(mousedown)
{
float enter;
if (plane.Raycast(ray, out enter))
{
var hitPoint = ray.GetPoint(enter);
var mouseDir = hitPoint - gameObject.transform.position;
rb.AddForce(mouseDir * 9999999);
}
}
}
void OnMouseDown()
{
mousedown = true;
prevDrag = r.drag;
prevGrav = r.gravity;
r.drag = 99999;
r.gravity = 0;
}
void OnMouseUp()
{
mousedown = false;
r.drag = prevDrag;
r.gravity = prevGrav;
}
}
Related
I would like to develop a 3d game. An "air hockey" simulator. I would like to control the paddle with the mouse but at the same time, I would like to use the physics engine to handle collisions with the puck and the borders of the table.
I tried the following:
If I use a Kinematic paddle I lose the property to handle the physics by the engine.
If I use static object the same.
If I use a dynamic rigidbody I am not able to control smoothly the paddle.
What is the best way to handle this scenario?
Thank you.
What makes a air-puck feel good is the sliding effect it has. Ofcourse it doesn't continue forever, but still feels nice.
Here is what you can do:
Create an Paddle & Puck
Create two physics materials for both.
Decrease the friction on the material that both feels slidey, the puck a little more than the paddle.
For both:
Freeze the x & z rotation
Freeze the y position
Now the part that makes the paddle use physics & RigidBody correctly. Create a new script for moving the paddle:
public class PaddleMovement : MonoBehaviour
{
private RigidBody rb;
public float speed = 5;
public float minDist = 0;
public float maxDist = 5;
public LayerMask layers;
void Start()
{
rb = GetComponent<RigidBody>();
}
void Update()
{
// Paddle will only move if we hold down the mouse button
paddleGrabed = Input.GetInput(KeyCode.Mouse0);
}
void FixedUpdate()
{
if (paddleGrabed)
{
HandleMovement();
}
}
void HandleMovement()
{
Ray ray = Camera.main.ScreenToWorldPoint(Input.MousePosition);
RaycstHit hit;
if (Physics.Raycast(ray, out hit, 100f, layers))
{
// Calculate the slow effect as paddle comes close to the point;
float dist = Vector3.Distance
(
new Vector3(transform.position.x, 0 transform.position.z),
new Vector3(hit.point.x, 0, hit.point.z)
);
dist = Mathf.Clamp(dist, minDist, maxDist);
var slowEffect = dist / maxDist;
// Now move move the rigid body appropriately
var dir = new Vector3(hit.point.x, 0, hit.point.z) -new Vector3(transform.position.x, 0 transform.position.z);
dir.Normalize();
rb.MovePosition(transform.position + dir * slowEffect * speed * Time.deltaTime);
}
}
}
That should move the Paddle to a certain position with a bit of a lag and sliding effect.
Following this question How to align sprites of smaller sizes to a moving gameobject sprite?, I'm trying to redraw my sprites to avoid rendering transparent pixels and try to maximize performance, and as I try starting this process with the sword sprites, I need to change the way the Sword game object follows the Player, which before was handled simply by using transform.position = hero.transform.position; because since both objects use sprites that are perfect squares they would have the same pivot point despite their size difference.
At first, it seemed to me the problem lied in how the pivots are different, thus I would need to update the transform position of the Sword every time its attack animation changes sprites. For that, I made a function which updates variables that influence the position as that gets updated:
here, heroTransform is a variable which gets sent the Player's transform property on the script's Start function as heroTransform = hero.transform;, where hero is defined right above it as hero = GameObject.Find("Hero");.
I would have expected this to make the Sword which is equipped with this script, called WieldablePosition to follow the player position, but it seems stuck in the same position as it starts:
I'm not sure, but I don't think I changed anything that would stop the Sword from moving. In what cases could a GameObject remain in a single place even as the transform.position is modified? For reference, please view the script:
using UnityEngine;
public class WieldablePosition : MonoBehaviour {
GameObject hero;
HeroMovement heroMovementScript;
private Transform heroTransform;
protected Animator anim;
private bool isAirAttackSingle;
private bool isFacingLeft;
private float x = 0;
private float y = 0;
void Start() {
hero = GameObject.Find("Hero");
heroTransform = hero.transform;
heroMovementScript = hero.GetComponent<HeroMovement>();
anim = GetComponent<Animator>();
isAirAttackSingle = heroMovementScript.isAirAttackSingle;
isFacingLeft = heroMovementScript.isFacingLeft;
}
void Update() {
UpdatePosition();
isAirAttackSingle = heroMovementScript.isAirAttackSingle;
isFacingLeft = heroMovementScript.isFacingLeft;
anim.SetBool("isAirAttackSingle", isAirAttackSingle);
if (isFacingLeft) {
transform.localScale = new Vector3(-1, 1, 1);
} else {
transform.localScale = Vector3.one;
}
}
public void SetPosition(AnimationEvent eventParams) {
string[] eventPositions = eventParams.stringParameter.Split(',');
x = float.Parse(eventPositions[0]);
y = float.Parse(eventPositions[1]);
}
private void UpdatePosition() {
transform.position = new Vector2(heroTransform.position.x + x, heroTransform.position.y + y);
}
}
I have this code:
public class MoveCard : MonoBehaviour
{
public float speed = 1f;
public Rigidbody2D rb;
public Vector2 pos = new Vector2(6.8f,0);
public bool move = false;
void FixedUpdate(){
if (move){
//Stops Rigidbody
if (rb.position == pos){
move = false;
}
rb.transform.position += -rb.transform.right * speed * Time.fixedDeltaTime;
}
}
public void CardMovement(){
move = true;
}
}
I have it set as so when a button is pressed, CardMovement() initiates and in FixedUpdate I have a if statement that turns move off when the Rigidbody reaches a certain position. The rb moves but it doesn't stop when it reaches the Vector2. I am new to Unity so I don't know if this is the way to do it.
Well your Rb doesn't pass exactly for each point between the initial position and Vector2.
It's prtty unlikely to have rb.position == pos because one frame it will not enough, and the next one will be too much :)
Try with MoveTowards. Some like this:
rb.position = Vector3.MoveTowards(rb.position, pos, speed * Time.fixedDeltaTime);
You dont need a statement to stop it because it will do it when reaches pos.
PD: You can do this with transform instead of rigidbody if u are not going to use physics and you only want a movement.
Don't compare the 2 vector2D values like this:
if(rb.position == pos)
Rather compare the distance between them with a value that is very small, like this:
if(Vector2.Distance(rb.position,pos) <= 0.01)
Additionally, you can set the position like this rb.postion = pos; if it is close enough so that it snaps to the right location.
Hi I'm making a little 3D platformer with a player controller like zelda/mario64.
I want to add the possibility to reset the camera behind the player. It ok, not really hard, but I wanted to do this smoothly and with the camera rotating around the player.
I discovered the Slerp method of Vector3 that almost do what I want. But I don't know if it's possible to force the Slerp method to make a trajectory only on the x,z plan. I dont want the camera to go above the player but turn arround it.
Someone know of it's possible to Vector3.Slerp() only on some axis ?
Or maybe Vector3.Slerp() is not the solution, so what can I do ?
My guess is your looking for Transform.localEulerAngles (you can find out more about it here). What I would do in your situation is keep the axis you don't want to move and use Slerp on this other(s) :
Vector3 currentLocalEulerAngles = transform.localEulerAngles;
Vector3 targetLocalEulerAngles = /*What you want*/ Vector3.zero;
float slerpSpeed;
transform.localEulerAngles = Vector3.Slerp(transform.localEulerAngles, new Vector3(currentLocalEulerAngles.x, targetLocalEulerAngles.y, targetLocalEulerAngles.z), slerpSpeed * Time.deltaTime);
EDIT : To be clear I suggested this way of doing things having in mind that in those kind of situations, the Camera is often placed as a child of a GameObject located on the player. This way you simply have to rotate what can be called the CameraHolder : Player (doing what you want) > CameraHolder (rotating along local axis) > Camera (fixed or getting shaked or what you want) :)
EDIT2 : Here's a small script that will do what you're looking for (hopefully) : you simply have to set your Camera as child of your Player, place it so it "looks" at your Player with desired distance/angle, and finally add this CameraHolder script to your Camera.
using UnityEngine;
[RequireComponent(typeof(Camera))]
public class CameraHolder : MonoBehaviour
{
[Range(0.0f, 10.0f)]
[SerializeField]
private float m_CameraResetSpeed = 4.0f;
[Range(0.0f, 10.0f)]
[SerializeField]
private float m_MinAngleToStopReseting = 2.0f;
private Transform m_CameraHolderTransform;
private Vector3 m_CameraHolderWorldEulerAngles;
private bool m_ResetingCamera;
void Start()
{
GameObject cameraHolder = new GameObject("CameraHolder");
m_CameraHolderTransform = cameraHolder.transform;
m_CameraHolderTransform.SetParent(transform.parent);
m_CameraHolderTransform.localPosition = Vector3.zero;
m_CameraHolderTransform.localRotation = Quaternion.identity;
m_CameraHolderTransform.localScale = Vector3.one;
transform.SetParent(cameraHolder.transform);
m_CameraHolderWorldEulerAngles = m_CameraHolderTransform.eulerAngles;
m_ResetingCamera = false;
}
void LateUpdate()
{
if(m_ResetingCamera)
{
m_CameraHolderTransform.localEulerAngles = new Vector3(0.0f,
Mathf.LerpAngle(m_CameraHolderTransform.localEulerAngles.y, 0.0f, m_CameraResetSpeed * Time.deltaTime), 0.0f);
if(Mathf.Abs(m_CameraHolderTransform.localEulerAngles.y) < m_MinAngleToStopReseting)
{
Debug.Log("Reset done...");
m_ResetingCamera = false;
m_CameraHolderWorldEulerAngles = m_CameraHolderTransform.eulerAngles;
}
}
else
{
m_CameraHolderTransform.eulerAngles = m_CameraHolderWorldEulerAngles;
}
}
public void ResetCamera()
{
Debug.Log("Reseting camera...");
m_ResetingCamera = true;
}
}
I have this code here ,i am trying to move an object from one position to another ,on mouse click ,but everytime i run it it justs instantiate the projectile object in a specific position while it had to instantiate it in a the ffor object position
using UnityEngine;
using System.Collections;
public class Shoot : MonoBehaviour
{
public GameObject projectile;
public GameObject foot;
public GameObject mouse;
void Start()
{
}
void Update()
{
if (Input.GetMouseButtonDown(0))
{
Vector2 Target = Input.mousePosition;
Vector2 pos1 = Camera.main.ScreenToWorldPoint(Target);
GameObject newObj = (GameObject)GameObject.Instantiate(projectile);
Vector2 pos2 = foot.transform.position;
transform.position=Vector2.Lerp(pos2,pos1,Time.deltaTime);
}
}
There are several issues here, I'll address them one at a time. First, the code for moving the projectile is wired up wrong:
transform.position=Vector2.Lerp(pos2,pos1,Time.deltaTime);
You are moving the object that "Shoot" is attached to, not the new game object (newObj, as you have named it.)
Second, it's important to understand the Update pattern and how to properly use it. Update is run every frame. Time.deltaTime is how much time has passed between the last frame render and this one. This number is usually very small. Lastly, Input.GetMouseButtonDown is true only on the first frame that the mouse is pressed.
The current code you have only attempts to (but fails, due to other code problems) move the projectile the one frame the mouse is clicked. What we want is the mouse click to spawn a projectile, and the projectile to move forward EVERY update.
This will be best accomplished with two classes. I will call them Gun and SeekerBullet. The Gun class will be responsible for creating a bullet every time the mouse button is pressed. The SeekerBullet class will be responsible for moving the bullet to it's target.
Gun
public SeekerBullet ProjectilePrefab;
void Update()
{
if (Input.GetMouseButton(0))
{
Vector2 target = Camera.main.ScreenToWorldPoint(Input.mousePosition);
FireBullet(target);
}
}
void FireBullet(Vector2 target)
{
GameObject projectile = (GameObject)GameObject.Instantiate(ProjectilePrefab, transform.position, Quaternion.Identity);
projectile.GetComponent<SeekerBullet>().Target = target;
}
SeekerBullet
public float MoveSpeed = 5;
public Vector2 Target { get; set; }
public void Update()
{
transform.position = Vector3.MoveTowards(transform.position, Target, MoveSpeed * Time.deltaTime);
if (transform.position == Target)
OnReachTarget();
}
void OnReachTarget()
{
// Do whatever you want here
Destroy(gameObject); // delete this seekerbullet
}
The main Idea I'm trying to stress is isolating your code to perform it's one function well. The gun shouldn't be responsible for moving the projectile, just creating it and telling it where to go.
Also, note that the projectile is starting wherever the Gun is. See this line
GameObject projectile = (GameObject)GameObject.Instantiate(ProjectilePrefab, transform.position, Quaternion.Identity);
The transform.position is the position of the gun object. If you want it to start at the foot, like you have in your code, you can re-implement that just like you have in your example.
Why don't you use Raycast. It's pretty simple. Here's an example (Moves the object (transform) in the direction and distance of translation.):
var obj:Transform;
var hit:RaycastHit;
var move: boolean = false;
var moveSpeed:float;
var moveTime:float;
private var startTime:float;
function Update ()
{
if (Input.GetButtonDown ("Fire1"))
{
var ray = Camera.main.ScreenPointToRay (Input.mousePosition);
if (Physics.Raycast (ray, hit, 10000)){
move = true;
startTime = Time.time;
}
}
if(move){
var curTime = Time.time;
var elapsedTime = curTime - startTime;
var amountToMove = elapsedTime / moveTime;
print(amountToMove);
obj.transform.position = Vector3.Lerp(obj.transform.position, hit.point, amountToMove);
if(obj.transform.position == hit.point){
move = false;
}
This code creates a plane, and a cube. Assign the above code to the plane, assign the cube to the obj var in the inspector. Click on the plane, and watch the fun.
This is pretty simple. You can use the Vector3.Lerp function to achieve this. Use raycasting to get the mouse click position or the touch position. Then use the initial and the final position in the lerp function. The initial position being the position that the gameobject is at now and the final position being the click / touch position.
You can find the article by The Game Contriver on the same here
Move to Touch / Click Position - The Game Contriver