I'm coding a space-invaders like game, and I want to be able to move the player controlled ship with both mouse and keyboard. There is a speed constant that is being used, when moving the ship with the keyboard. When moving the ship with the mouse, only the position of the ship is changed. When moving the ship with the keyboard, the position of the mouse is also changed, to be consistent with the position of the ship.
The constant I mentioned is not an int value, but a float one. The reason behind this is that I want to add a powerup to increase the speed of the ship, and that may or may not be of type int. Also, I wish to be able to fine tune the speed, if requested by players or by game being to difficult. Problem is, the MouseState gives me a pair of int coordinates, but the position of the ship is a pair of float ones. So herein lies the problem :
Each frame, I need to move the ship to the mouse position (mouse controlled), and each frame I need to move the mouse position to the ship (keyboard controlled). Since the mouse gives me int coordinates, the float ones from the ship's position must be converted to int, which destroyes the idea I described earlier. Is there any way I can force the mouse to use float coordinates, either a workaround in XNA or some other API (DirectX or WINAPI)? I'm also toying with the idea of virtual coordinates and screen coordinates, with conversion between them.
Cheers,
Alex
EDIT : Added code snippet :
if (_keybState.IsKeyDown(Keys.Right))
{
Mouse.SetPosition(
(int)(_player1.GetPlayerPosition().X + Constants.HorizontalMovementSpeed),
(int)(_player1.GetPlayerPosition().Y));
}
if (_keybState.IsKeyDown(Keys.Left))
{
Mouse.SetPosition(
(int)(_player1.GetPlayerPosition().X - Constants.HorizontalMovementSpeed),
(int)(_player1.GetPlayerPosition().Y));
}
if (_keybState.IsKeyDown(Keys.Up))
{
Mouse.SetPosition(
(int)(_player1.GetPlayerPosition().X ),
(int)(_player1.GetPlayerPosition().Y - Constants.VerticalMovementSpeed));
}
if (_keybState.IsKeyDown(Keys.Down))
{
Mouse.SetPosition(
(int)(_player1.GetPlayerPosition().X),
(int)(_player1.GetPlayerPosition().Y + Constants.VerticalMovementSpeed));
}
if (_keybState.IsKeyDown(Keys.Space) && _shootKeyPressed == false)
{
_player1.Shoot();
_shootKeyPressed = true;
}
_shoboState = Mouse.GetState();
_player1.MovePlayerShipToPosition(new Vector2(_shoboState.X, _shoboState.Y));
Instead of tying the mouse and ship positions together like this:
_shoboState = Mouse.GetState();
_player1.MovePlayerShipToPosition(new Vector2(_shoboState.X, _shoboState.Y));
Try something along these lines:
Find unit vector between mouse and ship. This will give you a 1 unit step from your ship to your mouse. (You should be able to find tutorials for this fairly easily)
Multiply the unit vector by your movement amount. This gives you a direction and distance for you to move your ship.
Apply new vector to your ship.
Move the mouse as close as you can to your ship's new position.
Related
Hi2,
This seems to be an easy problem to fix.,
but i still cannot figure it on my own.
I need to be able to find the position of my mouse click at the 3D plane at world space which corresponding to plane's scale.
For example:
if i click the point a in my game view., it should return me 0,0f
The MainCamera however, can do move around.
and then if click point C it should return me a Vector2 which (i believe) should correspond with the scaling of the 3d object
and clicking inside the 3D plane, should once again return me a Vector2 according to the Object's scaling.
I know that i can use Input.mousePosition but it just return me the mouse position without any relation to the plane object itself.
There is " Camera.ScreenToWorldPoint" that converts to in game position.
here:
https://docs.unity3d.com/2018.4/Documentation/ScriptReference/Camera.ScreenToWorldPoint.html
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).
What I am trying to achieve at this point, is the following:
Let's say that we have a Cube game object and a SteamVR player.
The Cube object is on position y = 100 and the SteamVR player is on position y = 0.
I want to make it possible that the player can zoom in on the game object by doing the following:
-> Pressing both triggers and bringing the controllers close to each other will zoom in.
-> Pressing both triggers and bringing the controllers away from each other will zoom out.
I think u understand the effect that I want to create.
For my project I am using the SteamVR Unity plugin.
Could someone say me if this is possible and give me some insight on how to do this?
Thanks in forward.
Have an if statement checking for two inputs and move the camera position in the forward direction close and closer to the target. If you want to save the original camera position before zooming just store the Camera.main.forward before incrementing it.
pseudocode
public SteamVR_Input_Sources LeftInputSource = SteamVR_Input_Sources.LeftHand;
public SteamVR_Input_Sources RightInputSource = SteamVR_Input_Sources.RightHand;
public Vector3 currentZoom;
public Vector3 zoomAmount;
void update(){
if( SteamVR_Actions._default.Squeeze.GetAxis(LeftInputSource) && SteamVR_Actions._default.Squeeze.GetAxis(RightInputSource)){
currentZoom.forward += zoomAmount.forward; //increment zoom by whatever amount while
triggers are held
Camera.main.transform.forward = currentZoom;
}
}
I have not tested this, hence why I labeled it pseudocode, however, I hope this helps!
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.
I have been working on and off of a certain game I'm making (trying to get it finished!) and a problem that has been unsolved for a while in it is the collision detection between a ball and a square.
Basically what I want to happen eventually is depending on the angle/way the rectangle is facing, I want the ball to bounce of it accordingly (I know I could just inverse the ball direction before/as it hit the square).
At the moment though, my current problem is trying to inverse the correct X and Y components depending on the side/face that the ball collides with the square, e.g. if the ball hits the right side of the square, then I need to inverse the ball's X component.
This doesn't seem to work and I was wondering if I could somehow label each side of the rectangle, in terms of for the top of it label that 'face 1' or something, then for the right side of it 'face 2' or 'side 2', etc...
I have provided some code below (this is the code I'm using now):
//(collision with right side of square)
if (theBall.GetRectangle.Left <= thePaddle.GetRectangle.Right)
{
theBall.pVelocity.X = -theBall.pVelocity.X;
}
//(collision with bottom of square)
if (theBall.GetRectangle.Top <= thePaddle.GetRectangle.Bottom)
{
theBall.pVelocity.Y = -theBall.pVelocity.Y;
}
I have written the code for the other 2 sides of the rectangle but they are just the opposite of the two above, i.e. for collision with top of rectangle = opposite of bottom, etc.
EDIT: the object I am checking against if the ball has collided with DOES NOT move, I mean it only rotates... so I don't know if this is important (it probably is, therefore I apologise for missing this info out at the start).
EDIT # 23:36: ok, I have tried something.... and it hasn't worked... :(
public Vector2 DistBetweenBallAndBlock(Paddle thePaddle, Ball theBall)
{
Vector2 centreOfBall = new Vector2(theBall.Texture.Width / 2, theBall.Texture.Height / 2);
float distX = thePaddle.Position.X - centreOfBall.X;
float distY = thePaddle.Position.Y - centreOfBall.Y;
if (distX < 0)
{
distX = -distX;
}
if (distY < 0)
{
distY = -distY;
}
return new Vector2(distX, distY);
}
I have then tried to just print the result just to get an idea of what's going on and what sort of values are being output:
Vector2 a = ball.DistBetweenBallAndBlock(paddle1, ball);
angleOfPaddle = Math.Atan2(a.Y, a.X);
I then just print this value to screen, however I am getting the same result of 0.63...
To detect a collision between Rectangles you could use Rectangle.Intersect method, instead of checking the objects' sides.
And to detect which side of the rectangle is hit, you can compute the Vector2 between the ball center and the rectangle center. Getting its angle with Math.Atan2 you can easily know which face of the rectangle has been hit.
Looked up some Vector stuff, based on my comment.
Collision Style
The optimal way of colliding with a circular object is to collide using a vector between it and the nearest point of the object you're checking against. If the distance is less than or equal to the radius of the circle, there is a collision. The advantages of this method are that you don't have to keep track of a rectangle, you get circular collision, and you get the angle of the collision from the vector.
How You Do It
I'll assume you have some strategy to keep from considering every object every frame, and keep to the basic problem. Your paddle has 4 vertices, one for each corner. Because your ball is essentially a vertex with a picture drawn over it, you can easily check the distance between the ball and each corner of your paddle. Two will be nearest. From there, it's just a matter of finding out if that edge collides. I found a solution to that here, which includes a nice formula.
Does that help?