XNA Monogame Mouse Projectile Click - c#

I am coding for a game and I have it running fine and all, but I ran into the issue of projectiles. I have no idea of how to calculate the mouse position and send a projectile over. I've looked though many stackoverflow tutorials and many youtube videos, but they are either too vague or very very complex. Could someone please explain the process? I have been coding in C# for 2 years now, so I do have background knowledge. Please Help!

Well, you don't tell what kind of game you are working on and what the projectile you want to "send over", whatever that means but here are a few pointers, maybe one will help:
#1: If you are doing a 2D game, and you want to send a projectile from some point toward the mouse cursor, then you simply get the position of the mouse by calling GetState() on your MouseState instance, and reading it's X and Y properties, then get the direction of the projectile by subtracting the location of the origin of the projectile from the mouse position. Then you can move the projectile along that line by storing the time you launched it, subtracting that every frame from the actual time to get how long it has been on its way and then adding that many times it's speed times the normalized direction to its origin coordinates.
Example:
For this I assume you have a Projectile class that has Vector2 field called origin, one called direction, one called position, a float called speed and an int called startTime and you have an instance of it with origin and speed already set. Modify as necessary for your actual code.
MouseState ms = new MouseState();
in your Update method:
ms.GetState();
projectile.direction = new Vector2(ms.X, ms.Y) - projectile.origin;
projectile.direction.Normalize();
projectile.position = projectile.origin + projectile.speed * (gameTime.TotalGameTime.TotalMilliseconds - projectile.stratTime) * projectile.direction;
And then in the Draw method you just draw the projectile to the coordinates in projectile.position.
#2: You are doing a 3D game and want to shoot a projectile originating from your camera and directed toward whatever your mouse is pointing at. You will need to generate a Ray with something like this:
private Ray getClickRay(Vector2 clickLocation, Viewport viewport, Matrix view, Matrix projection)
{
Vector3 nearPoint = viewport.Unproject(new Vector3(clickLocation.X, clickLocation.Y, 0.0f), projection, view, Matrix.Identity);
Vector3 farPoint = viewport.Unproject(new Vector3(clickLocation.X, clickLocation.Y, 1.0f), projection, view, Matrix.Identity);
Vector3 direction = farPoint - nearPoint;
direction.Normalize();
return new Ray(nearPoint, direction);
}
From there you can get the position of your projectile the same way as above, only using Vector3-s instead of Vector2-s.
#3: You want to simulate some sort of launcher and do a physical simulation on the trajectory of the projectile. Since I find this less likely than the first two I'll just describe the idea: you set a minimum and maximum rotation for your launcher along 2 axes, link each rotation to the ratio of the full width and length of your screen to the mouse position, and then use the angles and whatever other variables you have to calculate the direction and speed of the projectile at launch, then simulate physics each frame.
I hope one of these will help.

Related

Make GameObject's Y Rotation be the same as the camera's

I have a Cinemachine Freelook camera and i want it similar to Skyrim, where the character's rotation follows where the camera is pointing, but only on the Y axis so that i can move my mouse and look at the character from up and down;
This video demonstrates how MrKrabs can move in 3 dimensions, but won't turn.
I already tried creating a blank object and putting it at the center of the character, then using transform.LookAt(Camera) to make it point to where the camera is, and finally getting the Y value of the object's rotation, inverting it with -transform.position.y and applying it to MrKrabs, but it didn't work: it was jittery and overall just a bad user experience, is there a way to turn the gameobject based on the camera's rotation? (having the camera always watching his back)
Something like this should do the trick.
transform.rotation = Quaternion.Euler(0, Camera.main.transform.eulerAngles.y, 0);
Beware that if your camera is a child of your object it will rotate with it.

Grappling hook ray cast direction problems in Unity

Hey team I'm currently working on a 3rd person game where I would like to fire grappling hooks from the player to a point that is offset from the center of the camera.
I have a screen overlay canvas with Ui images for crosshairs. When the left shift is held down the crosshairs move outward from center along the x axis and return to center once shift is released, a bit like crosshair spread in games except I want to trigger the spread via the shift key. These crosshairs are meant to dictate the location the anchors of the grappling hook land, originating from the player and hitting whatever object is directly forward of the crosshairs. (imagine attack on titan ODM gear if you've seen it). I am looking for a way to ray cast from the player to the point forward of these crosshairs while they're offset from the center.
So far I have the grappling system set up and working but am having trouble with the direction parameter when I use the crosshair spread. It separates fine but where the hooks land in relation to the cross hairs are obviously out as I'm trying to use angle calculations at the moment instead of what is forward of these reticles.
I'm basically wondering if it is possible to use these screen overlay UI images to cast forward from or if there's a better way to accomplish the same thing. I have my doubts because they're screen overlay so I imagine their coordinates wont be attached to the camera as they appear.
Thanks in advance for your help.
What I would do is determine the location of the reticleson the screen, then (as Aybe suggested) use ScreenPointToRay or ViewportToRay (depending on if it's easier to get a pixel position or a fractional position of each reticle) to Physics.Raycast that ray from the camera into the scene to find where the rays collide. At this point, you have two world positions the player seems to want to shoot the hooks.:
Vector3 hookTarget1;
Vector3 hookTarget2;
So, now you actually have to fire the hooks - but as you know the hooks aren't being shot from the camera, they are being shot from the player, and they maybe offset by a bit. Let's call the originating points (which may have the same value):
Vector3 hookOrigin1;
Vector3 hookOrigin2;
So, then you can create Rays that originate from the hook origins and point at the targets:
Ray hookShot1 = new Ray(hookOrigin1, hookTarget1 - hookOrigin1);
Ray hookShot2 = new Ray(hookOrigin2, hookTarget2 - hookOrigin2);
Using these rays, you can do another Physics.Raycast if you would like, to confirm that there aren't any trees or other obstacles that are between the player and the target location - and if there are, that may be where the anchor should actually sink:
Vector3 anchorPoint1;
Vector3 anchorPoint2;
The segment between the origin of these rays and these anchor points would be appropriate for rendering the cable, calculating physics for how to move the player, as well as checking for collisions with world geometry that might cause the anchor to release.

Control player z axis with mouse x axis

I'm trying to move the player to the position of the mouse in my game.
Right now movement along the x axis works fine, but I want the mouse y axis to control the characters movement along the z axis (because of my top-down camera's y being world z).
Right now mouse y controls player y, which looks like this in game.
And the code for it looks like this:
public Vector2 mousePos;
private Vector3 playerPos;
void update()
{
// Get mouse position from player
mousePos = Input.mousePosition;
// Move player with mouse
playerPos = new Vector3(mousePos.x, 0, mousePos.y);
transform.position = Camera.main.ScreenToWorldPoint(playerPos);
}
I then tried to just swap the y and z like this
playerPos = new Vector3(mousePos.x, mousePos.y, 0);
But instead of allowing me to control the z axis this snippet instead causes the player to lose all movement.
I'm very new to coding so I might be missing something completely obvious. What am I doing wrong?
Unity version: 2018.4.21f1
The example you gave isn't working because you're providing a z coordinate of 0 and when called on a perspective camera, Camera.ScreenToWorldPoint does some vector math, so in your scene view, your player is probably floating right on top of your camera. I can't explain the actual math because I don't understand it, but luckily for both of us, we don't need to! Essentially, the z coordinate is saying how far away from the camera to place the point, and since the view frustum of a perspective camera gets narrower closer to the camera, placing it at 0 means there's nowhere for it to go. how moving the object farther from the camera requires it to move farther to match the mouse position.
The bigger problem is that your method is wrong and there's a better way. Camera.ScreenToWorldPoint converts a mouse coordinate to a world space coordinate depending on what the camera is looking at, so you're essentially flippng the y and z coordinate, then feeding it into a method that figures out what coordinates need to be flipped.
It looks like this script is attached to your player gameObject, so it should look like this:
Camera cam;
[Range(1,10)] //this just creates a slider in the inspector
public int distanceFromCamera;
void Start()
{
//calling Camera.main is a shortcut for
//FindGameObjectsWithTag("MainCamera")
//so you should avoid calling it every frame
cam = Camera.main;
}
void Update()
{
//This will work for both perspective and orthographic cameras
transform.position = cam.ScreenToWorldPoint(
Input.mousePosition + new Vector3(0,0,distanceFromCamera));
}
If your camera is going to move closer or farther from the plane, make sure to add something that keeps the distance from camera updated.
That said, for most games having the player tied to the mouse cursor isn't usually what you're looking for. Generally you want some kind of input to move the player in some direction a certain amount. If that's what you're looking for, this part of the space shooter tutorial is a good introduction to player movement (though the code itself may be outdated).

How can I do this kind of 3D camera movement in Unity?

This is a school project. I have a big cube which is like a planet. I have a small cube that can move on every side of the cube planet. The player moves forward automatically on its local z axis and I rotate it by 90 or -90 degrees to move left or right- but the player can control it like it's an up-down-left-right movement (made a script so they don't have to rotate the cube with 2 keys). It's like a Tron game so if I press the up key, I can't press down immediately because I leave a trail so I have to press the left or right keys. I have a problem with my camera movement. The camera follows the little cube from above, but I want it to lean a little when the little cube player gets close to the edge of a side so it lets me see the other side - where I'm planning to go.
I have a script where I use the center of the cube planet and the player's center as the direction vector and multiply it with the camera-player distance.
Vector3 direction = (target.position - center.position).normalized;
transform.position = target.position + direction * distance;
Then I point my camera's forward vector to the player cube's direction. I tried two codes but none of them worked perfectly. First I tried to rotate the camera with:
transform.rotation = Quaternion.LookRotation(-direction);
Shown in video. The problem with this is that since I don't tell the program the Up and Right vectors (I think), it sets them for itself to some random numbers so the camera sometimes do its own thing like it does a pirouette.
Next I tried this:
Quaternion rot = Quaternion.FromToRotation(transform.forward, -direction);
transform.Rotate(rot.eulerAngles, Space.World);
Shown in video. It's almost good but as the little cube moves, the camera starts steering slightly in the beginning and it gets worse and worse.
Do you have any ideas how can I make it work? I hope you understand what I would like to achieve. I'm trying to set the camera as to always show that when I press Up, my cube moves upward, when I press Right my cube always goes right etc. and when I reach the edge of my side the camera leans a bit towards the side I'm moving to.
Use dot product to find which orthogonal direction of your cube is closest to the camera's current up.
Vector3 closestToUp;
float greatestDot = 0f;
foreach (Vector3 dir in new Vector3[]{
target.forward, target.right, -target.forward, -target.right})
{
float curDot = Vector3.Dot(dir,transform.up);
if (curDot > greatestDot)
{
greatestDot = curDot;
closestToUp = dir;
}
}
Than, use that direction as the second parameter of Quaternion.LookRotation. This will keep its local up direction as aligned with the cube's "top" as possible given whatever new forward direction:
transform.rotation = Quaternion.LookRotation(-direction, closestToUp);

Projectile Not Correctly Inheriting Parent Velocity (Unity3D)

I am trying to fire projectiles from a player who is moving at very high speeds. The issue is that the bullets do not seem to inherit the angular velocity. If the player is moving in a straight line at 500 U/s, then the bullet correctly inherits that velocity and adds its own speed onto that:
GameObject bullet = Instantiate(projectile, gun.transform.position, gun.transform.rotation);
bullet.GetComponent<Rigidbody>().velocity = r.velocity + bullet.transform.forward *bulletSpeed;
However, if the player is turning really quickly, it does not inherit the rotational velocity, and the bullet looks like it veers off to the side.
How can I implement this? I tried assigning the angular velocity of the player to the bullet, but this just caused the bullet to spin while moving in the same direction.
Some extra details:
I am using rigidbody.MoveRotation() to rotate my player, but I manually calculated angularVelocity to assign it to the bullet
I tried moving the player with AddTorque(), but could not produce any results with the bullets
The immediate problem is that the projectile isn't part of the physics simulation until the moment you create and launch it, meaning the rotation of the player up to that point will not be able to influence its movement. I suppose this could work if you created the projectile at the start, attached it to the gun with a weak joint, then broke the joint and added to its velocity when it was fired - but it really would be simpler if you just "faked" it.
Applying Circular Motion
This is similar to a classic circular motion example you'd find in a physics textbook. When your bullet travels in a circle around the player (inside the gun), its normal path (if released) would be tangent to the circular path around the player. So when the bullet is fired (and hence released from the circular path), that angular velocity of the player would translate into a linear velocity of the bullet. Here's a simple diagram I put together that represents the situation with a ball on a string, being spun in a circle:
Getting the Tangential Velocity of the Bullet
You don't want to be applying any kind of angular velocity to the projectile after it has been launched - as you saw, this will only spin the projectile on its own axis. Rather, you want to apply an additional velocity vector to the projectile, which is tangent to the rotation of the player (and perpendicular to the facing of the bullet). So how do we do this?
Well, as per this website, the formula for tangential velocity at any point on something spinning in a circle is:
velocity = angularVelocity x radius
A key point to remember is that the angularVelocity is in radians, not degrees.
So, let's put this all together. Here's a general idea of how you might code this:
FireGun() {
// Assumes the current class has access to the rotation rate of the player
float bulletAngularVelocityRad = Mathf.Deg2Rad(rotationRateDegrees)
// The radius of the circular motion is the distance between the bullet
// spawn point and the player's axis of rotation
float bulletRotationRadius =
(r.transform.position - gun.transform.position).magnitude;
GameObject bullet =
Instantiate(projectile, gun.transform.position, gun.transform.rotation);
// You may need to reverse the sign here, since bullet.transform.right
// may be opposite of the rotation
Vector3 bulletTangentialVelocity =
bulletAngularVelocityRad * bulletRotationRadius * bullet.transform.right;
// Now we can just add on bulletTangentialVelocity as a component
// vector to the velocity
bullet.GetComponent<Rigidbody>().velocity =
r.velocity + bullet.transform.forward * bulletSpeed + bulletTangentialVelocity;
}
Hope this helps! It's never a bad idea to read up on some basic kinematics/mechanics when you're working with game physics, since sometimes relying on the game physics is actually more complicated than just devising your own solution.

Categories