I have such a problem, maybe someone will help. I am making a game and I need to make a dice that goes in the direction opposite to the click. For example, clicking on the back of a cube moves it forward, etc. Gravity must act on the cube as shown in the figure below. Unfortunately, the cube does not change height, but only the position of X and Z. Please help.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MoveCube : MonoBehaviour
{
Vector3 movePosition;
public float time = 0.02f;
[HideInInspector]
public bool blockClick = false;
private void Start()
{
movePosition = transform.position;
}
private void Update()
{
blockClick = false;
if (Input.GetMouseButtonDown(0))
{
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
RaycastHit raycastHit;
if (Physics.Raycast(ray, out raycastHit))
{
string hitName = raycastHit.transform.name;
if (hitName == "MoveCube")
{
move(raycastHit);
blockClick = true;
}
}
}
transform.position = Vector3.Lerp(
transform.position,
movePosition,
time);
}
public void move(RaycastHit raycastHit)
{
Vector3 incomingVec = raycastHit.normal - Vector3.up;
// South
if (incomingVec == new Vector3(0, -1, -1))
{
movePosition = movePosition + new Vector3(0, 0, 1);
return;
}
// North
if (incomingVec == new Vector3(0, -1, 1))
{
movePosition = movePosition + new Vector3(0, 0, -1);
return;
}
// West
if (incomingVec == new Vector3(-1, -1, 0))
{
movePosition = movePosition + new Vector3(1, 0, 0);
return;
}
// East
if (incomingVec == new Vector3(1, -1, 0))
{
movePosition = movePosition + new Vector3(-1, 0, 0);
return;
}
}
}
From what I know, changing the transform.position of a gameObject with a rigidbody will mess with Unity's physics, and it won't work as intended. I suggest trying to apply a force from the position of the mouse's click instead of moving the cube's position manually (if this makes sense to do for your purposes). Here is the documentation for Rigidbody.AddForce
Related
i'm trying to make a game on unity using C# for a games dev course. the course is: https://www.youtube.com/watch?v=b8YUfee_pzc and at 51:55 is where i am experiencing the error. the error is NullReferenceException: Object reference not set to an instance of an object player.FixedUpdate () (at Assets/scripts/player.cs:32)
i have checked and it seems to be letter by letter (including caps) perfect, unless i'm jsut stupid.
it may be because of outdated code, something in unity or me just copying something down wrong. anyhow, here's the code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[RequireComponent(typeof(BoxCollider2D))]
public class player : MonoBehaviour
{
private BoxCollider2D boxCollider;
private RaycastHit2D hit;
private Vector3 moveDelta;
private void start(){
boxCollider = GetComponent<BoxCollider2D>();
}
private void FixedUpdate()
{
float x = Input.GetAxisRaw("Horizontal");
float y = Input.GetAxisRaw("Vertical");
// reset move delta
moveDelta = new Vector3(x, y, 0);
// swap sprite direction
if(moveDelta.x > 0)
transform.localScale = Vector3.one;
else if (moveDelta.x < 0)
transform.localScale = new Vector3(-1,1,1);
hit = Physics2D.BoxCast(transform.position, boxCollider.size, 0, new Vector2(0, moveDelta.y), Mathf.Abs(moveDelta.y * Time.deltaTime), LayerMask.GetMask("actor", "blocking"));
if (hit.collider == null)
{
transform.Translate(0, moveDelta.y * Time.deltaTime, 0);
}
hit = Physics2D.BoxCast(transform.position, boxCollider.size, 0, new Vector2(moveDelta.x, 0), Mathf.Abs(moveDelta.y * Time.deltaTime), LayerMask.GetMask("actor", "blocking"));
if (hit.collider == null)
{
transform.Translate( moveDelta.x * Time.deltaTime, 0, 0);
}
}
}```
Found a comment on that video that worked for me: "changing "private BoxCollider2D boxCollider;" to "public BoxCollider2D boxCollider;" then dragging the box collider in to the tab on the script under your npc"
I'm currently trying to use a Physics2D.BoxCast() to manually detect collisions in a test project. I got everything set up with the help of a tutorial I watched a while ago but for some reason the box cast seems to be above the Box Collider that I attached its size to. I'm not the best a writing issues out so Ill have a gif bellow that better shows what the problem is, as well as I'll attach the code I used to detect the collisions.
This is when I try to collide from +y on the axis
This is when I try to collide from -y on the axis:
I've tried looking up more on how Physics2D.BoxCast work and why it would seem to be pushed down but I havent found anything helpful just yet.
Here's the code I use for movement and manual collision detection.
using UnityEngine;
public class Player : MonoBehaviour {
public float speed = 2f;
private BoxCollider2D boxCollider;
private SpriteRenderer sprite;
private Vector3 moveDelta;
private RaycastHit2D hit2D;
protected virtual void Awake() {
boxCollider = GetComponent<BoxCollider2D>();
sprite = GetComponent<SpriteRenderer>();
}
protected virtual void Update() {
float x = Input.GetAxisRaw("Horizontal");
float y = Input.GetAxisRaw("Vertical");
moveDelta = new Vector3(x, y, 0);
// Flips the sprite based on the direction its moving on the X
if (moveDelta.x > 0)
{
sprite.flipX = false;
}
if (moveDelta.x < 0)
{
sprite.flipX = true;
}
// Manual detection for collisions
hit2D = Physics2D.BoxCast(transform.position, boxCollider.size, 0, new Vector2(moveDelta.x, 0), Mathf.Abs(moveDelta.x * Time.deltaTime), LayerMask.GetMask("Blocking", "Actor"));
if (hit2D.collider == null)
{
transform.Translate(moveDelta.x * Time.deltaTime, 0, 0);
}
hit2D = Physics2D.BoxCast(transform.position, boxCollider.size, 0, new Vector2(0, moveDelta.y), Mathf.Abs(moveDelta.y * Time.deltaTime), LayerMask.GetMask("Blocking", "Actor"));
if (hit2D.collider == null)
{
transform.Translate(0, moveDelta.y * Time.deltaTime, 0);
}
}
}
The transform.position used in the box cast was not at the center of the collider. Thus casting the BoxCast above where the collider was. The solution was to place an empty game object in the center of the collider. Again I'm sorry about the way I explain things I hope the pictures bellow can help you understand better..
Code wise it was a simple fix that took me too long to figure out..
using UnityEngine;
public class Player : MonoBehaviour {
public float speed = 2f;
public GameObject boxcastCenter;
private BoxCollider2D boxCollider;
private SpriteRenderer sprite;
private Vector3 moveDelta;
private RaycastHit2D hit2D;
protected virtual void Awake() {
boxCollider = GetComponent<BoxCollider2D>();
sprite = GetComponent<SpriteRenderer>();
}
protected virtual void Update() {
float x = Input.GetAxisRaw("Horizontal");
float y = Input.GetAxisRaw("Vertical");
moveDelta = new Vector3(x, y, 0);
// Flips the sprite based on the direction its moving on the X
if (moveDelta.x > 0)
{
sprite.flipX = false;
}
if (moveDelta.x < 0)
{
sprite.flipX = true;
}
// Manual detection for collisions changes were made in the transform.position bellow
hit2D = Physics2D.BoxCast(boxcastCenter.transform.position, boxCollider.size, 0, new Vector2(moveDelta.x, 0), Mathf.Abs(moveDelta.x * Time.deltaTime), LayerMask.GetMask("Blocking", "Actor"));
if (hit2D.collider == null)
{
transform.Translate(moveDelta.x * Time.deltaTime, 0, 0);
}
hit2D = Physics2D.BoxCast(boxcastCenter.transform.position, boxCollider.size, 0, new Vector2(0, moveDelta.y), Mathf.Abs(moveDelta.y * Time.deltaTime), LayerMask.GetMask("Blocking", "Actor"));
if (hit2D.collider == null)
{
transform.Translate(0, moveDelta.y * Time.deltaTime, 0);
}
}
}
I have a bullet object, that needs to glide to the mouse when the mouse is pressed (but should stop when it is released). I have tried multiple approaches, but every time the bullet accelerates, and makes circles around the mouse in a ellipse form (I also have gravity). How can I get it to just move towards the mouse at a constant speed?
This is my code:
using UnityEngine;
public class Bullet : MonoBehaviour {
public Rigidbody rigidbody;
void Start() {
rigidbody = GetComponent<Rigidbody>();
rigidbody.useGravity = false;
rigidbody.velocity = new Vector3(0, -0.3F, 0);
}
float getX(Vector3 transform_pos, Vector3 mouse_pos) {
float tx = transform_pos.x;
float mx = mouse_pos.x;
if (tx == mx) { return 0;
} else if (tx > mx) { return -1;
} else if (tx < mx ) { return 1;
}else { return 0; }
}
void Update() {
if (Input.GetMouseButton(0)) {
Vector3 mouse_pos = Camera.main.ScreenToWorldPoint(Input.mousePosition);
transform.LookAt(mouse_pos);
float x = getX(transform.position, mouse_pos);
float y = transform.position.y > mouse_pos.y ? -0.03F : 0.03F;
rigidbody.AddForce(new Vector3(x, 0, transform.position.z), ForceMode.VelocityChange);
Debug.Log(x.ToString() + y.ToString());
}
if (transform.position.y < -5 | transform.position.y > 5) {
Destroy(transform.gameObject);
}
rigidbody.AddForce(Vector3.down, ForceMode.Force);
}
}
I tried a bit more, and found out, that using rigidbody.velocity() is better than rigidbody.AddForce(), so replace rigidbody.AddForce(new Vector3(x, 0, transform.position.z), ForceMode.VelocityChange); with rigidbody.velocity = new Vector3(x, y, transform.position.z); (replace x and y with the velocity and it should work. Note that this replaces the velocity, so all the movement will be stopped)
I've been trying to create a road mechanic but when I instantiate a mesh, it fails to even create.
I have a version where it's a mesh created in the script(commented) and it works as intended, but when i switch to the instantiated, the roadStart ray and roadend ray both work. I followed a tutorial by quill18 to get a sense of where to go. But I got to a point where I got so frustrated I just copy and pasted and it still failed to work.
bool ClickLoc(out Vector3 point)
{
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
print(ray);
RaycastHit hit;
if (Physics.Raycast(ray, out hit))
{
point = hit.point;
return true;
}
point = Vector3.zero;
return false;
}
void CreateRoad(Vector3 roadStart, Vector3 roadEnd)
{
float width = 1;
float length = Vector3.Distance(roadStart, roadEnd);
if (length < .5)
{
return;
}
GameObject road = (GameObject)Instantiate(prefabRoad);
// GameObject road = new GameObject ("road", typeof(MeshRenderer),typeof(MeshFilter));
road.transform.position = roadStart + new Vector3(0, 0.01f, 0);
road.transform.rotation = Quaternion.FromToRotation(Vector3.right, roadEnd - roadStart);
Debug.Log(road.transform.rotation.eulerAngles);
Vector3[] vertices = {
new Vector3(0, 0, -width/2),
new Vector3(1, 0, -width/2),
new Vector3(1, 0, width/2),
new Vector3(0, 0, width/2)
};
int[] triangles = {
1, 0, 2, // triangle 1
2, 0, 3 // triangle 2
};
Vector2[] uv = {
new Vector2(0, 0),
new Vector2(1, 0),
new Vector2(1, 1),
new Vector2(0, 1)
};
Vector3[] normals = {
Vector3.up,
Vector3.up,
Vector3.up,
Vector3.up
};
Mesh mesh = new Mesh();
mesh.vertices = vertices;
mesh.triangles = triangles;
mesh.uv = uv;
mesh.normals = normals;
MeshFilter mesh_filter = road.GetComponent<MeshFilter>();
MeshRenderer mr = road.GetComponent<MeshRenderer>();
mesh_filter.mesh = mesh;
}
Vector3 roadStart;
Vector3 roadEnd;
void Update()
{
if (yes == true & Input.GetMouseButtonDown(0) )
{
ClickLoc(out roadStart);
}
if (Input.GetMouseButtonUp(0))
{
ClickLoc(out roadEnd);
print(click);
if (roadStart.magnitude != 0)
{
CreateRoad(roadStart, roadEnd);
}
// if (click == false)
// {
// CreateRoad(roadStart, roadEnd);
// mid = true;
//}
}
if (Input.GetMouseButtonUp(1))
{
click = false;
}
}
}
The road created will start at the center of the map and end at my mouse position
I tried and copy your CreateRoad() method and took a quad, cleared the mesh from meshfilter and used that as the roadPRefab and it works. Think it might be as derHugo says; that some portion of your code does not get called.
I have a camera that I control it with the (W,A,S,D) keys...
What I want to do is that when press left mouse click ("Fire1") the camera turns back to the first position animatedly.
Is it possible to do it with Mecanim and create a dynamic animation file to do it?!
That's my code:
void Update ()
{
if (Input.GetKey(KeyCode.W))
{
Cam.transform.Rotate (0, 0, 2);
}
if (Input.GetKey(KeyCode.S) )
{
Cam.transform.Rotate (0, 0, -2);
}
if (Input.GetKey(KeyCode.D))
{
Cam.transform.Rotate (0, 2, 0);
}
if (Input.GetKey(KeyCode.A))
{
Cam.transform.Rotate (0, -2, 0);
}
My camera position and rotation at the start is (0,0,0) but when I control my camera these parameters change so I want my camera to turns back to the first position (0,0,0) animatedly when I press left mouse button...
Something like:
if (Input.GetButtonDown("Fire1"))
{
Cam.GetComponent<Animation> ().Play ();
}
Instead of the animation, you could smooth out the camera movement:
Add the following variables to your script, the first one is used to control the amount of smoothness you want:
public float smoothTime = 0.2f;
private Vector3 velocity = Vector3.zero;
And then:
if (Input.GetButtonDown("Fire1")) {
Vector3 targetPosition = new Vector3(0,0,0);
Cam.transform.position = Vector3.SmoothDamp(Cam.transform.position, targetPosition, ref velocity, smoothTime);
}
From your code, I can see that you are only changing rotation of the Camera. Following is my solution to it.
It saves the starting rotation at the start and later lerps to the start rotation when "Fire1" is pressed.
However, position is not handled here, as there's no position change in your code. But the concept is same. You can change the position in a similar way.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class CamTest : MonoBehaviour {
public float animSpeed = 1.0f;
public Camera Cam;
private Quaternion startRotation;
private bool doRotate = false;
// Use this for initialization
void Start () {
//Cam = GetComponent<Camera> ();
startRotation = transform.rotation;
}
void Update () {
if (Input.GetKey(KeyCode.W))
{
Cam.transform.Rotate (0, 0, 2);
}
if (Input.GetKey(KeyCode.S) )
{
Cam.transform.Rotate (0, 0, -2);
}
if (Input.GetKey(KeyCode.D))
{
Cam.transform.Rotate (0, 2, 0);
}
if (Input.GetKey(KeyCode.A))
{
Cam.transform.Rotate (0, -2, 0);
}
if (Input.GetButtonDown("Fire1")) {
Debug.Log ("Fire1");
doRotate = true;
}
if(doRotate) DoRotation ();
}
void DoRotation(){
if (Quaternion.Angle(Cam.transform.rotation, startRotation) > 1f) {
Cam.transform.rotation = Quaternion.Lerp(Cam.transform.rotation, startRotation,animSpeed*Time.deltaTime);
} else {
Cam.transform.rotation = startRotation;
doRotate = false;
}
}
}