unity3d: shoot where mouse clicks on sceen - mouse

Looking at various bulletin boards, this is a common problem, yet I could not find any good answers online.
My project has a first-person car that moves via the arrow keys. I want a gun mounted on the car to be able to shoot via crosshair that can aim anywhere on the current screen. Right now the bullets just shoot right through the middle all the time, except for the times when I click on the screen and nothing happens (which is about 50%). Here is the code which I got via various scripts on the web:
var speed = 20;
var bullet: GameObject;
function Update () {
var hit : RaycastHit;
if(Input.GetButtonDown("Fire1")){
var ray = Camera.main.ScreenPointToRay (Input.mousePosition); //ray from
// through the mousePosition.
if(Physics.Raycast(ray, hit, 1000)) { //does the ray collide with
// anything.
//add stuff here for finding type of object and such.
Debug.Log("Hit Something at mouse position");
Debug.DrawRay (ray.origin, ray.direction * 10, Color.yellow);
//Display the ray.
var projectile:GameObject = Instantiate(bullet,transform.position,transform.rotation);
projectile.rigidbody.velocity = transform.forward * speed;
}
}
}
If anyone could help, it would be very much appreciated.

Your ray is correct (pointing to middle of screen), but it has nothing to do with the way your making the bullet travel. The bullet travels based on a transform.forward * speed. What you need to do is get the hit point of your ray, then get a direction from your bullets origin to that point.
Vector3 direction = hit.point - projectile.transform.position;
projectile.rigidbody.velocity = direction * speed;
1000 is pretty low for a screenPointToRay, so you might want to up that by a lot if you want to avoid future problems.
Also rigidbody has been deprecated, im not sure if you should be doing a (GameObject).rigidbody directly like that
http://docs.unity3d.com/ScriptReference/GameObject-rigidbody.html

Without actually posting you any code, I can tell you that what you should probably be looking into is why your projectile is setting its rotation from the transform's rotation instead of the rotation of your ray if I understand your attempt.
The projectile is clearly gaining all of it's properties (including those which are supposed to be detached from the origination) from the vehicle and just following along accordingly.
Try setting your projectile's rotation to that of your ray.
Also, your ray is more than likely only ever hitting half of the time because of your amount of distance to test. Try upping that number, or creating walls for it to collide with at shorter range.

Related

Can't make bullets land in the right spot

I'm making an FPS game, but the bullets are not hitting in the right spot sometimes the bullets are below the crosshair but the next time it will be way off to the left.
I tried moving the gun tip (aka the thing that spawned the bullets) to aim at the center of the screen but then the bullets just went way of track. The code for launching the bullets is simple. If you can help me make the bullets land where the crosshair is, thank you if not thanks for reading this.
The Code
if(Input.GetMouseButton(0) && Time.time >= nextTimeToFire)
{
Rigidbody rb = Instantiate(Bullet, GunTip.position, Quaternion.identity).GetComponent<Rigidbody>();
rb.AddForce(GunTip.forward * 500f, ForceMode.Impulse);
}
Difficult to tell what the problem is straight off the bat. Can you share the entire project somewhere? I tried to do this on my own computer and it seems to be working fine for me. One think which comes to my mind is that your GunTip may not necessarily point at the crosshair and so your bullets go off course.
If you draw a triangle (imaginary, right now) between the weapon tip, the crosshair (for simplicity, take it if the weapon tip is right under the crosshair), and the target at which the crosshair points, you'll see a different triangle when the target is 10m away, or 100m.
Based on that, I would do a Raycast "from the" crosshair (in this case, from camera position to camera forward). From that, you'll get where should your bullet arrive, and you can add the force something like that (half pseudo):
[SerializeField] private Transform _camera;
[SerializeField] private Transform _weaponTip;
[SerializeField] private LayerMask _bulletLayerMask;
[SerializeField] private float _range;
[SerializeField] private float _bulletInitSpeed;
private void Update()
{
if (<can shoot checks>)
{
if (Physics.Raycast(_camera.position, _camera.forward, out RaycastHit hit, _range, _bulletLayerMask)
{
Rigidbody bullet = <instantiate stuff>;
// calculating the direction from the weapon tip to the impact point
bullet.AddForce((hit.point - _weaponTip.position).normalized * _bulletInitSpeed, ForceMode.Impulse);
}
}
}

Unity - move the starting position of raycast slightly forward along its direction

I am still new to coding in unity, so please be gentle XD ... I want to make a raycast that is hitting a collider to start a new raycast with the same direction but not starting from the point where it has hit, but just slightly forward along its direction (like a few centimeters or so, or whatever that might be in unity units ^^) ... the code snippet shows the second raycast after the first hit:
Physics.Raycast(firsthit.point, direction, out var hit, distance, HitLayerMask, QueryTriggerInteraction.Ignore)
So I figure I need to change the "firsthit.point" value(s) somehow using the "direction", but I just cant figure out how exactly. Any help would be highly appreciated.
Thanks, ANB_Seth
Try:
float distance = 1f;
Vector3 newPosition = firsthit.point + direction.normalized * distance;
Physics.Raycast(newPosition, direction, out var hit, distance, HitLayerMask, QueryTriggerInteraction.Ignore);

How to determine turret rotation direction if rotation angle has to be limited, and target "passed behind"?

I started some programming in Unity just for fun a couple days ago.
So far my game (pretty much top-down shooter) consists of player flying in an asteroid field, in which lurk enemy ships. Player can shoot down asteroids and enemies, and enemy ships have missile turrets that "track" player.
Everything works fine until I decided that enemy ships shouldn't be able to rotate their turrets all the 360-way. Think of it as real-world battleship being unable to turn it's front turret (No.1) 180 degrees behind because turret No.2 is in the way.
Currently code for turret rotation is like this (this is not about making "gradual rotation", setting "rotation speed" or something, so please don't look at that!):
playerTarget = GameObject.FindGameObjectWithTag("Player");
chaseDirection = Quaternion.LookRotation(playerTarget.transform.position - transform.position);
newYaw = Mathf.Clamp(chaseDirection.eulerAngles.y, minYaw, maxYaw);
transform.rotation = Quaternion.Euler(0, newYaw, 0);
That works okay, until player flies behind enemy ship. As soon as player gets into turret's "possible rotation angle", it just snaps past "dead zone" to new direction if I don't turn it gradually with fixed angle, or is still stuck trying to rotate "past limit" until target (player) flies all around enemy ship so the angle to target is small enough for rotation direction to be calculated through "enabled" rotation zone, not through "dead zone".
An important thing is I am not looking for answer "how to make gradual rotation". I am looking about calculating rotation direction!
I thought about coding enemy to start rotating turret in counter-direction as soon as player passes "directly behind" the turret "forward facing" position. But the concept of how to do that eludes me.
Because as soon as turret rotates just a bit from limit, it's able to turn "towards" player again, and gets stuck at limit again.
Edited with the clarification in mind.
You need a function that will tell you if you should rotate clockwise or counter-clockwise, based on the enemy location.
First find the mid point, this will be:
var mid = (minYaw + maxYaw) / 2
In your example this will be 3 o'clock, straight right.
Now, if your current rotation is lower than mid, and the target is higher than mid, than you must rotate clockwise even if it's not the shortest rotation to get there.
If the target rotation is higher than mid, and the target is lower than mid, you must rotate counter-clockwise for the same reason. You may need to adjust for negative degrees.
Please note that this will create a secondary effect, where once the ship passes the half point of the dead zone (say moving from 10 o'clock to 8 o'clock in your example), the turret will start moving as if anticipating the flank. You may want to disable this movement in a special case.
I'll keep the second part of my answer as-is, for future references.
If you want it to move gradually, you need to use deltaTime or fixedDeltaTime in case of a fixed update. You can define how fast it will move by adding a speed property. Try something like this:
void update () {
var playerTarget = GameObject.FindGameObjectWithTag("Player");
var chaseDirection = Quaternion.LookRotation(playerTarget.transform.position - transform.position);
var newYaw = Mathf.Clamp(chaseDirection.eulerAngles.y, minYaw, maxYaw);
var currentRotation = transform.eulerAngles;
var desiredRotation= currentRotation;
var desiredRotation.y = newYaw;
transform.eulerAngles = Vector3.RotateTowards(currentRotation, desiredRotation, Time.deltaTime * RotationSpeed, 0.0f);
}

Unity2d Player rotate in accordance with mouse position

I've tried Atan2, I've tried whatever is euler angles, I've tried everything Unity3d's site, and I get three results:
I can move my mouse slowly, I can move it at the speed of light, the rotation of the player is fixed, either looking up, or down.
The player rotates, not looking at the mouse though. It's as though it's doing it's own thing.
It rotates on anything but the z axis.
I'm completely out of ideas, completely out. I've tried everything, including downloading several slither.io knockoff projects to figure out how they accomplish the task, but none of them work.
If you're having trouble grasping what I need to achieve, well, I have no code at this moment. But there's a website with the same thing I'm trying to accomplish.
Play surviv.io Look at how the player rotates in accordance with the mouse. That's what I'm trying to accomplish.
I didn't test this, but....
The code below should work if you have a background screen that can be raycasted against so the ray collides with it. Then play around a bit with the coordinates in the Transform.LookAt().
Basically it does these steps.
1 - Fire a ray from the screen to the mouse position, save a reference to whatever is hit in the 'Hit' variable.
2 - If anything was hit, rotate the players transform to look where it hit.
public LayerMask RaycastCollidableLayers;
public RaycastHit Hit;
public float CheckDistance = 200f;
public Transform Player;
void PerformRaycast(){
//Set up ray
ray = Camera.main.ScreenPointToRay(Input.mousePosition);
//Fire ray
Physics.Raycast(ray, out Hit, CheckDistance + 0.1f, RaycastCollidableLayers);
if (Hit.collider == null)
{
//Debug.Log("Raycast hit nothing");
return;
}
else //Ray hit something
{
//Look at Hit.point on x and y axes.
Player.LookAt(new Vector3(Hit.point.x, Hit.point.y, 0f), Vector3.up); //Ignoring z axis, may need to be another axis. Vector3.up sets the up direction.
}
}
Sources:
Transform.LookAt: https://docs.unity3d.com/ScriptReference/Transform.LookAt.html
Camera.ScreenPointToRay: https://docs.unity3d.com/ScriptReference/Camera.ScreenPointToRay.html
Let me know how it works for you.

How can i give soccer ball a trajectory?

I am a beginner and trying to make penalty shooter Game in unity.. I have just setup the scene and just trying to shoot the ball towards the goal post.
When i shoot the ball it goes toward the goal but does not come down, because i am shooting it through the script and its gravity is off and kinematic is on.
Currently i have the following script:
void Start () {
startTime = Time.time;
rb.GetComponent<Rigidbody>();
}
void Update () {
transform.position -= fakevel * Time.deltaTime;
transform.position += fakeGravity * Time.deltaTime;
fakevel *= 0.999f ;
}
void OnTriggerEnter( Collider other ) {
fakevel = new Vector3(0.01f, 0, 0) * 2000f;
fakeGravity = new Vector3 (0 ,0.01f, 0)* 200f;
y = -45.68312f;
}
}
I have tried enabling the gravity and disabling the kinematic at some specific position but i does so the gravity just pull it down at that position and it does not look realistic. Some screen shoots are attached.
Please help me in setting trajectory of the ball and stopping it when it collides with the goalpost,
I would suggest you use a non-kinematic rigidbody on your ball and add a force to it when you shoot it: GetComponent<Rigidbody>().AddForce(forceVector3, ForceMode.Impulse) (this is just an example, you should avoid calling GetComponent on a frequent basis, you are better off calling it for the rigidbody component once on Start and store it in a private variable)
This way Unity's physics engine can handle gravity and the balls' velocity over time. To modify the trajectory you can play around with the properties of the balls' rigidbody component.
If you want to have more control over the velocity, you can also set the rigidbody's velocity directly in the FixedUpdate() (which is called right before each physics update). When doing so, you have to consider that velocity is measured in m/s and the physics engine handles sub-steps for you (I am assuming that FixedUpdate() is called more than once per second), meaning you do not have to multiply your velocity with some delta time (but I am not 100% sure about this right now).
Seeing how it does work, just doesn't give the effect you want, you can either spend several hours fine tuning it, or like xyLe_ stated, use the built in physics. Using the built-in physics isn't a bad thing, you just gotta be smart with it. You can add a bouncy physics material also, which will help give the ball a well, ball feel.