How to drop a box to the mouse position? - c#

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.

Related

How would one add force to a rigidbody from a relative mouse position?

I have a game I am creating in Unity. It has a table with 30 cubes on it. I want a user to be able to shuffle the cubes on the table using their mouse/touch.
I am currently using a ray to get the initial table/cube hit point then accessing the rigidbody component on the cube to apply a force using AddForceAtPosition, happening in an OnMouseDrag. I am also pulling out my hair trying to figure out how to apply force in the direction from the mouse's last position to the hit point on the rigidbody of the cube.
Can someone please help me? An example would be great. I would share my code but I am a spaghetti code monster and fear criticism... Thanks much!
If I understood correctly, is something like this you want to achieve? https://www.youtube.com/watch?v=5Zli2CJGAtU&feature=youtu.be
If so, first you have to add your cubes and table to a new layermask, this step is only necessary if you don't want your ray to hit other colliders that might mess with your result.
After this you should add a tag to all the cubes you want to aplly the force, in my case I added a new tag called "Cubes".
You can search on youtube this if you don't know how to do it, there are plenty of tutorials to help you.
After that you create a new script and attach to the camera. Here is my script:
public class CameraForceMouse : MonoBehaviour
{
public LayerMask layerMask;
RaycastHit hit;
Vector3 lastPosition;
// Start is called before the first frame update
void Start()
{
lastPosition = new Vector3();
}
// Update is called once per frame
void Update()
{
if (Input.GetMouseButton(0))
{
if (Physics.Raycast(Camera.main.ScreenPointToRay(Input.mousePosition), out hit, 200f, layerMask))
{
if (hit.transform.CompareTag("Cubes"))
{
Rigidbody rb = hit.transform.GetComponent<Rigidbody>();
Vector3 force = (hit.point - lastPosition).normalized * 55f;
rb.AddForceAtPosition(force, hit.point);
}
lastPosition = hit.point;
}
}
}
}
Just want to say that there are a lot of ways to achieve the same thing, this is the way I decided to do, but there are probably other (maybe even better) ways of doing this.
Explaining the code:
The first thing is a public LayerMask that before you play the game you will have to select your camera in your scene and look for the script on the editor in the right side and select witch layerMask you added to your cubes and table.
If you don't know how raycast works, here is the documentation: https://docs.unity3d.com/ScriptReference/Physics.Raycast.html but you can also search on youtube.
The important thing here is the new vector being created to define the direction of the force.
First we declare a global variable called LastPosition, and for every frame that we are clicking, we will check for a collision, and if this collision happens, we will then create a new vector going out of the last position the mouse was to the position the mouse is now Vector3 force = (hit.point - lastPosition), than we normalize it because we only care about the direction and multiply it by the amount of force we want, you can make it as a nice variable but I just put it there directly.
Then, after you've applied the force to the position the ray hit the object, you have to define that this is now your last position, since you are going to the next frame. Remember to put it outside of the Tag check, because this is checking if the object we collided with is the cube we want to apply the force or if it is the table. If we add this line lastPosition = hit.point; inside of this check it will only assign a new lastPosition value when we hit the cube, and would lead to bugs.
I'm not saying my answer is perfect, I can think of a few bugs that can happen, when you click outside the table for example, but is a good start, and I think you can fix the rest.

Unity Sub Camera following Player with rotation problem

Here is an image of what I'm trying to achieve
As you can tell it's a split screen game, the player is on the left, computer on the right.
there are 3 cameras in the game, main and two player cameras
the player camera MUST be independent of the player and CAN NOT be a child object of the player object, because the ball bounces and rotates while moving, the cameras must not.
when the balls change direction the camera must remain behind the player so the visual appears to show the landscape rotating with the player.
I've searched high and low for anything to put me on the right path but nothing seems to work right.
It should be a smooth transition so lerp and slerp are to slow for instant moving. I know LateUpdate will help with this.
If anyone can point me in the right direction I'd appreciate it.
Many thanks,
Paul
Have a script which takes in an object's position, in this case the player's ball, so you can code the camera as if it was a child of the object.
An simple example code for having a following camera would be something like...
FollowObject.cs
public Transform exampleObject;
private int offset = 5; //How far back the camera will be
void LateUpdate()
{
transform.position = new Vector3(exampleObject.transform.position.x,
exampleObject.transform.position.y,
exampleObject.transform.position.z - offset)
}

Unity 2D tongue shooter

I would like to use a characters tongue so instead of shooting a bullet, it goes toward the enemy, licks it, and comes back. I got this wording from this question: Unity shooting with Tongue 2d game (hasn't been answered and is 4+ years old). The only difference is my character moves.
I have this code from looking at a shooting tutorial so when you click the tongue prefab generates and is at the correct angle. I need it to grow on click and shrink back.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class LineController : MonoBehaviour
{
public GameObject player;
private Vector3 target;
public GameObject crosshairs;
public GameObject tonguePrefab;
// Start is called before the first frame update
void Start()
{
Cursor.visible = false;
}
// Update is called once per frame
void Update()
{
target = transform.GetComponent<Camera>().ScreenToWorldPoint(new Vector3(Input.mousePosition.x, Input.mousePosition.y, transform.position.z));
crosshairs.transform.position = new Vector2(target.x, target.y);
Vector3 difference = target - player.transform.position;
float rotationZ = Mathf.Atan2(difference.y, difference.x) * Mathf.Rad2Deg;
if (Input.GetMouseButtonDown(0))
{
shootTongue(rotationZ);
}
}
IEnumerator shootTongue(float rotationZ)
{
GameObject t = Instantiate(tonguePrefab) as GameObject;
t.transform.position = new Vector2(target.x, target.y);
t.transform.rotation = Quaternion.Euler(0.0f, 0.0f, rotationZ);
yield return new WaitForSeconds(2000);
t.SetActive(false);
}
}
I was also trying to make it disappear after whatever time and with that it doesn't work at all?
If the prefab is just a line with a simple texture I suggest using a line renderer:
Create an empty transform that starts on the mouth and then it move untill it reaches the crosshair. The movement is done using Vector2.MoveTowards.
Your tongue will no be a line renderer component. This line renderer will have 2 points, the start which is static, and the end which you have to update on the Update() for example, to correspond to the positions of the empty transform in item 1.
If you really wish to expand a tongue gameobject instead, then you are going to need a bit of math, this answer has what you need but in 3D:
https://answers.unity.com/questions/473076/scaling-in-the-forward-direction.html
1) I suggest creating sprite/sprite sheet animations with Mecanim or relatively new Skeletal Animation with Anima2D. With these systems you can create nice animations, transitions, even animate the sphere collider to trigger collisions and actions, change active state of your objects, etc. and control the animation with very little code. This way you can get best effects in my opinion.
As tongue is not a bullet... :) You only need one. I don't think you want to Instantiate/Create prefabs every time you press the lick button. Instead you should just turn your tongue object on/off (gameObject.SetActive). You can also change your object active state within the animation. So if you don't know how to code it you can do most of it in the Animation window and use very simple code to play the animation when you press the lick button. Whenever a sphere collider touches something you can tell the Animator Controller to play a 'roll back' animation and it will transition nicely to the start position.
There are many tutorials about Mecanim, Animations, 2D Animations, Anima2D, Animator Controller out there.
2) If you need very good control over the tongue you could create a custom mesh and control it via script but this is far more difficult.
3) The reason why your object is not turning off is probably because you wrote WaitForSeconds(2000) so it will turn off after 2000 seconds - more than half an hour. You should also call it with StartCoroutine(shootTongue()) as it is a Coroutine. Again if you want to turn off the object don't create new ones every time. If you want to keep creating new objects you should Destroy the objects instead. Otherwise you will end up with a lot of deactivated tongues in your scene and I don't think you needs that many tongues.

Camera follow with a World Space Canvas gets weird result?

I want to follow the camera the player along (just the y axis, but this I will look later) for now I have the following problem:
I have a background image in a seperate canvas (World Space) with my Main Camera attached.
Now if I attach a camera follow script (simply transform.position = Player.transform.position) the background image follows.
This results to the following: Everything falls down.
I tried to use another camera but I don't know if I just did it wrong. I have no idea.
as I said, just:
void update()
{
transform.position = Player.transform.position
}
but the code isn't my problem. I expect that the camera follows the player on the y axis (but not 100% just smoothly a bit) but I will look up for that later
I want that the Background doesn't move. Is there another Way to have them background images as a world space, or something I don't know?
void update()
{transform.position = Player.transform.position}
this will make your camera follow your player whatever his direction.
while u didnt mention any details, I expect the reason why everything is falling bec your mainplayer is falling due to physics . and u need to fix this by adding rigibody to your mainplayer and make sure that any thing he walk on also has colliders.
if u want your camera only to follow player on Y axis only , it should be something like this
void update()
{ float y = player.transfor.position.y;
Vector3 newPos = new Vector3(transform.position.x,y,transform.position.z);
transform.position = newPos;
}
and I suggest you cach your transform varaibles too.
lastly about your image that you dont want it to move, just dont attach it to any moving gameobject and set it to static and it should never move at all.

How to place objects when clicking onto mesh Unity

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

Categories