I have a small piece of code to make a sprite (in a 3D world) always face the camera (It has to be in 3D space).
public class CS_CameraFacingBillboard : MonoBehaviour {
private Camera m_Camera;
private void Start()
{
m_Camera = Camera.main;
}
void Update()
{
transform.LookAt(transform.position + m_Camera.transform.rotation *
Vector3.forward, m_Camera.transform.rotation * Vector3.up);
}
}
This code ensures the sprite is always facing the camera, causing it to lean backwards as the camera in above the sprite facing down in a 45 degree agle. When I put a rigidbody on the sprite, the sprite moves on its own towards the direction its leaning. The rigidbody works fine without this code attached.
How can I have a sprite that always faces the camera, and has a rigidbody attached?
It seems you've left the rigidbody as Dynamic, you should set it to Kinematic.
EDIT: After you comments, I checked myself inside Unity, and probably I've recreated the behaviour you described. It happens to me too IF I use a Box Collider on the sprite without locking its rigidbody rotation.
So you have three possible solutions:
Use a Box Collider and under Constraints of the rigidbody freeze the rotation:
Use a Sphere Collider (or another one that doesn't behave like the box one, you can check them out in play mode).
Split the components over two game object, a parent and a child. The parent will have all the components except the sprite renderer and the camera script, which will be on the child. This option is the most flexible and less restraining. You can have the box collider without freezing rotations, etc.
Another thing, you can avoid the use of the LookAt method, by simply using:
transform.rotation = m_Camera.transform.rotation;
they have the same outcome.
Related
I'm trying my first test-game with Unity, and struggling to get my bullets to move.
I have a prefab called "Bullet", with a RigidBody component, with these properties:
Mass: 1
Drag: 0
Angular drag: 0,1
Use grav: 0
Is Kinematic: 0
Interpolate: None
Coll. Detection: Discrete
On the bullet prefab, I have this script:
public float thrust = 10;
private Rigidbody rb;
void Start()
{
rb = GetComponent<Rigidbody>();
rb.AddForce(transform.forward * 100, ForceMode.Impulse);
}
On my playerController script (not the best place for this, I know):
if (Input.GetAxisRaw("Fire1") > 0)
{
var proj = Instantiate(projectile, transform.position, Quaternion.identity);
}
When I click my mouse, the bullet gets created, but doesn't move. I've added velocity to the rigidbody, which works, but I can't get it to move in the right direction. After googling around, it seems I need to be using rigidBody.AddForce(), which I did, but still can't get my bullet to move.
I've seen the other solution, but this did not work for me either.
Any advice would be appreciated.
Screenshot:
When you're working with 2D in Unity, the main camera basically becomes an orthographic camera (no perspective effects) looking sideways at the game scene along the z-axis. Incidentally, the "forward" direction of a non-rotated object is also parallel to the z-axis.
This means that when you apply a force along transform.forward, you're sending the object down the z-axis - which will not be visible to an orthographic camera looking in the same direction. The quick fix here would be to use a direction that translates to an x/y-axis movement, like transform.up or transform.right.
As derHugo also mentioned in the comments, you might want to look into using Rigidbody2D. There are some optimizations that will allow it to behave better for a 2D game (though you may not notice them until you scale up the number of objects).
I am trying to learn unity, and made my first own game and stucked at the beginning. The first idea was to drop a box (cube) to the mouse position. There are many videos and posts about getting the mouse position, and i tried to use them. My problem is, the mouse position i got is the camera's position, instead of the plane.
As you can see, it is kinda works, but it isn't fall to the plane.
https://prnt.sc/lmrmcl
My code:
void Update()
{
Wall();
}
void Wall()
{
if (Input.GetMouseButtonDown(0))
{
if (Input.GetMouseButtonDown(0))
{
wall = GameObject.CreatePrimitive(PrimitiveType.Cube);
Rigidbody wallsRigidbody = wall.AddComponent<Rigidbody>();
wall.transform.localScale = new Vector3(0.6f, 0.6f, 0.6f);
wallsRigidbody.mass = 1f;
wallsRigidbody.angularDrag = 0.05f;
wallsRigidbody.useGravity = true;
wallsRigidbody.constraints = RigidbodyConstraints.FreezeRotation;
wall.transform.position = Camera.main.ScreenToWorldPoint(Input.mousePosition);
}
Debug.Log(Camera.main.ScreenToWorldPoint(Input.mousePosition));
BoxCollider wallsCollider = wall.AddComponent<BoxCollider>();
wallsCollider.size = new Vector3(1f, 1f, 1f);
}
}
How should i change my code to get the right position?
This isn't a direct answer to your question, but I'm hoping it'll still get you where you need to go.
Prefabs are your friends! I'd highly recommend leveraging them here instead of constructing a cube directly in code.
But first, make sure everything else is set up right. Go ahead and construct a cube by hand in the Editor and make sure that when you hit Play, it falls as you expect. It should, provided it has a Rigidbody, collider, and you have gravity enabled (true by default).
If that works, drag that cube from your Hierarchy view into a folder in the Project view. This creates a prefab. You can now delete the cube from the Hierarchy view.
Update your script to have a public GameObject field, e.g.
public GameObject cubeToCreate;
Then, in the Inspector pane for whatever gameobject has that script attached, you should get a new field, "Cube To Create". Drag your prefab cube into that slot.
Lastly...update your code to wall = Instantiate(cubeToCreate). You'll still need to update the position, but you should be able to drop the rest of the initialization logic you have above, e.g. setting mass and drag.
As for the actual problem, the first thing that concerns me is how do you plan on turning a 2d mouse click into a 3d point? For the axis going "into" the screen...how should the game determine the value for that?
Camera.main.ScreenToWorldPoint accepts a Vector3, but you're passing it a Vector2 (Input.mousePosition, which gets converted to a z=0 Vector3), so the point is 0 units from the camera -- so in a plane that intersects with the camera.
I haven't done this, but I think you'll need to do raycasting of some sort. Maybe create an invisible 2d plane with a collider on it, and cast a physics ray from the camera, and wherever it hits that plane, that's the point where you want to create your cube. This post has a couple hints, though it's geared toward 2D. That might all be overkill, too -- if you create a new Vector3 and initialize it with your mouse position, you can set the z coordinate to whatever you want, but then your cube creation will be in terms of distance from the camera, which is not the best idea.
Hope this helps.
I know this is quite the noob question, but whatever, there's only one way to learn.
I've created an empty GameObject in Unity, attached a script that is supposed to move a cube(my player) and gave my cube the tag "Player". After creating the cube, I was hoping to be able to move the cube without having to put the script on the cube itself. When the script is on the cube, it moves without a problem (I know this is how it probably should be done, but for trying to learn new things I wanted to do it this way).
Player Controller script
Cube properties
After failing to find the answer through Google, any insight at all is greatly appreciated!
Thank you
Update!
Here's the code as text now, since it was asked for.
public class GameCoreController : MonoBehaviour {
private GameObject PlayerMove;
public Rigidbody rb;
void Start ()
{
PlayerMove = GameObject.FindGameObjectWithTag("Player");
rb = GetComponent<Rigidbody>();
}
void Update()
{
// character movement
if (Input.GetKey(KeyCode.W))
{
PlayerMove.transform.Translate(0, 0, 0.25f);
}
if (Input.GetKey(KeyCode.S))
{
PlayerMove.transform.Translate(0, 0, -0.25f);
}
if (Input.GetKey(KeyCode.A))
{
PlayerMove.transform.Translate(-0.25f, 0, 0);
}
if (Input.GetKey(KeyCode.D))
{
PlayerMove.transform.Translate(0.25f, 0, -0);
}
}
I've updated the code from before to include PlayerMove.transform.Translate but I still have the same issue with the cube note moving. I've also included screenshots of my scene with the cube and the GameCoreController; the empty GameObject holding the script that is supposed to control the cube.
Thanks again for the help guys.
Update 2!
After deleting the cube and re-insert it into the scene it now moves. Thanks for the help everyone.
The reason that the cube won't move because in your code you didn't move its transform but you move the transform of the gameobject that you attached this script to.
transform.Translate move the transform of the gameobject that this script attach to. So if you want to move the cube, all you need to do is change from transform.Translate to PlayerMove.transform.Translate which will move the transform of PlayerMove gameobject which is your cube with "Player" tag on it
^ All of the above. Plus, in the screenshot, your rigidbody is not set to "is kinomatic". This means that physics will still be applied to it (like gravity). Rule of thumb: If you have a moving object where collision is important, it will need a rigidbody and a collider. If the object is not moved with physics commands (eg rigidbody.AddForce()) but rather manipulating the transform as you are, set the rigidbody "isKinomatic" property to true.
So I have this mesh that I generate using perlin noise
What I want to do is to be able to click to place an object in the game. My ultimate goal is to have a menu so you can place different objects but I want to just try to get a cube to work. I tried RayCasting:
public class Raycast : MonoBehaviour
{
Ray myRay; // initializing the ray
RaycastHit hit; // initializing the raycasthit
public GameObject objectToinstantiate;
// Update is called once per frame
void Update()
{
myRay = Camera.main.ScreenPointToRay(Input.mousePosition);
if (Physics.Raycast(myRay, out hit))
{
if (Input.GetMouseButtonDown(0))
{
Instantiate(objectToinstantiate, hit.point, Quaternion.identity);
Debug.Log(hit.point);
}
}
I could not get this to work... I had no real idea how to use this script either (like what object to place it on) I tried just making a cube and putting the script on that but It did not work. I got no errors it just did not work.
I also had a mesh collider on my mesh and a box collider on my cube.
I see that you are following the tutorial on YouTube "Procedural Landmass Generation", which I would say is an excellent way to understand the basics of procedural content generation.
For your question I would suggest you add a camera on the top of the terrain, from where you will be able to point with your mouse where you want to instantiate the object (the cube for example). You would need a function which raycasts to the your land tiles. Check if its gameobject's tag is "Terrain" and check if there is no water at that current location. If terrain check returns true and water check returns false, then instantiate your desired object at the "hit" position of the raycast.
You can put the script on any object you want. I'd propose the camera. After adding this script-component to the camera, drag your mesh (that you want to instantiate) into the "objectToinstantiate" slot you see in the script.
Then see if it works, and for performance move the if (Input.GetMouseButtonDown(0)) up in your code, before you do the raycast, like #Basile said.
Note: This script will work in play-mode on the game-view - not in the editor scene-view.
If you'd like this to work too, you should add [ExecuteInEditMode] above the public class ... line. But be careful with those, it's sometimes hard to stop those scripts :P
i am totally new to c# scripting and unity... i was trying something on unity and created this code and it's woring fine but some times it's just overlapping "wall" tagged object or even getting out of that circle i am using Edge collider 2D on it and polygon collider 2D on my shooter object and this script is attached to shooter object. check the screen shot for the bug.
void OnCollisionEnter2D (Collision2D collider){
if (collider.gameObject.tag == "wall") {
StartCoroutine (shooterscale());
collider.gameObject.GetComponent<bgAnimater> ().animateBg ();
if (turn) {
turn = false;
}
else {
turn = true;
}
}
}
I assume you are using Rigidbody2D on the shooter.
Make sure that Collision detection mode is set to Continous to avoid objects passing through each other.
From Docs:
When the Collision Detection is set to Continuous, GameObjects with
Rigidbody 2Ds and Collider 2Ds do not pass through each other during
an update. Instead, Unity calculates the first impact point of any of
the Collider 2Ds, and moves the GameObject there. Note that this takes
more CPU time than Discrete.
and
When you set the Collision Detection to Discrete, GameObjects with
Rigidbody 2Ds and Collider 2Ds can overlap or pass through each other
during a physics update, if they are moving fast enough. Collision
contacts are only generated at the new position.
Hope this helps