want to make a game where there is a 2D ball which moves to the position of the cursor. To get the position of the cursor, I use this code:
Vector2 PixelPos = Input.mousePosition;
Then to convert the screen position to world position I use this code:
Vector2 Pos = Camera.main.ScreenToWorldPoint(PixelPos);
The problem is that the main camera move up so that if forces the player to move. But when it move I get some weird movement with the ball.(as the camera is moving up it is always moving the ball)
Is there an alternate way to make this work??
Or more simply can I replace this piece of code:
Vector2 Pos = Camera.main.ScreenToWorldPoint(PixelPos);
with some other things which does not require a camera to convert the screen positions to world position?
Thanks!
Since you want the cursor to be moved only by the player and to be updated relative to world space, not screen space, you need to implement a virtual cursor that exists in world space.
First, create your virtual cursor as a GameObject. On Update you can update its position with
float sensitivity = 1f;
transform.position += sensitivity * new Vector2(
Input.GetAxis("Mouse X"),
Input.GetAxis("Mouse Y")
);
Then, instead of using the camera to find the cursor position, you just check the `transform.position` of that virtual cursor `GameObject`.
Second, you'll need to lock the built-in cursor. You can do that with
Cursor.lockState = CursorLockMode.Locked;
If you need to undo that (for instance, if you bring up a menu, and need to use the regular cursor without moving the virual cursor around), then you can use:
Cursor.lockState = CursorLockMode.None;
or, if you need the cursor to stay in the window:
Cursor.lockState = CursorLockMode.Confined;
If you only want to move the ball to the last position clicked/touched then here is an easier solution.
Keep track of the goal position for the ball, and if one has been set yet:
private Vector2 moveGoalPos;
private bool moveGoalSet= false;
Only change moveGoalPos on frames where the mouse is clicked/the screen is touched.:
bool isTouched;
if (isMouseEnable) {
isTouched = Input.GetMouseButtonDown(0);
PixelPos = Input.mousePosition;
} else {
isTouched = Input.touchCount > 0;
Touch touch = Input.GetTouch(0);
PixelPos = touch.position;
}
if (isTouched) {
moveGoalPos= Camera.main.ScreenToWorldPoint(PixelPos);
moveGoalSet= true;
}
However, on every frame, you'll want to move the ball to the world space moveGoalPos (only if a goal has been set):
if (moveGoalSet) {
Vector2 OffsetPos = moveGoalPos + CursorOffSet;
GCursor.transform.position = OffsetPos;
print(OffsetPos);
Vector2 LerpPos = Vector2.Lerp(rb.transform.position, OffsetPos, 0.05f);
rb.MovePosition(LerpPos);
}
When you need to stop the ball from moving to the last touched/clicked position (for instance, if you change or reset a level), you'll need to reset moveGoalSet:
moveGoalSet = false;
Related
I am working on a simulation that takes place in the universe.
What I want to achieve is to move (by mouse or touch) an object around the planet at a fixed distance.
I've tried to use the RotateAround function that Unity provides, however I don't know how to take the mouse position into consideration when using that function.
So what I did is the following.
First I check if the mouse is pressed. If so I will get the mouse position and convert it to a position in the world space. I want to ignore the z because I don't want to move it in the z axis. But you could leave the z there if you want to move it in the z axis also.
Afterwards I check the direction from the planet to the mouse position. To keep it in orbit I will use the the fixed distance that is stored in maxDistance.
And finally if I want the object to look at the planet I will use LookAt.
public void Start()
{
maxDistance = Vector3.Distance(planet.position, transform.position);
}
public void Update()
{
if (Input.GetMouseButton(0))
{
var planetPos = planet.position;
var t = transform;
var mousePos = mainCamera.ScreenToWorldPoint(Input.mousePosition);
mousePos = new Vector3(mousePos.x, mousePos.y, planetPos.z);
var dir = (mousePos - planetPos).normalized;
t.position = planetPos + dir * maxDistance;
t.LookAt(planetPos, Vector3.right);
}
}
I have a sphere in that is moving foward and I need it to follow my finger smoothly when it swipes on the screen but only in the x axis.
I trying to make the exact movent like Rolling Sky, Color Road
The ball Should follow my finger when it swipes in the x axis and move smoothly.
Just like in the games I mention before.
I try OnMouseDrag and a lot of ways but it dont work correctly beacuse it dont dont follow the finger or it dont move while finger is swiping.
From what I understand, it seems you want to get the position of the user's finger and move the ball accordingly?
You could achieve this with Touch.position
Example:
private void Update()
{
Touch touch = Input.GetTouch(0); // Get the touch data for the first finger
Vector2 position = touch.position; // Get the position in screen-space
Vector3 worldPosition = Camera.main.ScreenToWorldPoint(position); // Convert the position to world space
Vector3 ballPosition = ball.transform.position;
ball.transform.position = new Vector3(worldPosition.x, ballPosition.y, ballPosition.z); // Move the ball
}
I think you should handle the input separately from the sphere.
Put this on a script to detect the swiping on the screen.
bool inputBegan = false;
Vector2 beganPosition;
void Update()
{
if (!inputBegan && Input.GetMouseButtonDown (0))
{
inputBegan = true;
beganPosition = Input.mousePosition;
}
else if (inputBegan && Input.GetMouseButtonUp (0))
{
//If you want a threshold you need to change this comparison
if (beganPosition.x > Input.mousePosition)
{
MoveBallLeft ();
}
else
{
MoveBallRight ();
}
inputBegan = false;
}
}
The movement of the balls you can achieve it adding or substracting Vector2.right * movingDistance to the sphere Transform if you want it to teleport or making the sphere move slowly using a targetPosition and currentPosition and each Update cycle add a little bit of transform distance.
I solved it doing this and setting the variable NavigationMultiplier to 10000
Goal: Detect when the cursor has entered a defined radius of the player.
Hello, I am in the process of trying to replicate the combat system from a game called CrossCode. The idea is that when the cursor is within a certain radius of the player, I will be able to switch to melee combat, and back to ranged once the cursor leaves this radius.
I have implemented one way I thought it could be done, however it feels slow or unreliable and I just wanted to know if there are any other methods I could possibly look into to achieve a smoother result.
Here is what I've done
attached to the player
void Update()
{
attackStyleSwitchRadius = colRef.radius;
playerCenter = colRef.transform.position;
if(Physics2D.OverlapCircle(playerCenter, attackStyleSwitchRadius, cursor))
{
meleeMode = true;
rangeMode = false;
}
else
{
meleeMode = false;
rangeMode = true;
}
}
And on a small 2D object I have this script so that it follows the cursor position.
void Update()
{
pos = Input.mousePosition;
gameObject.transform.position = Camera.main.ScreenToWorldPoint(pos);
}
when the small object enters the overlap circle it changes the bools around.
You can remove the collision detection overhead by doing something like this instead;
void Update ()
{
attackStyleSwitchRadius = colRef.radius;
playerCenter = colRef.transform.position;
var mouse = Input.mousePosition;
mouse.z = Vector3.Distance(Camera.main.transform.position, playerCenter);
var range = Vector2.Distance(Camera.main.ScreenToWorldPoint(mouse), playerCenter);
var inside = range < attackStyleSwitchRadius;
meleeMode = inside;
rangeMode = !inside;
}
Cursor
Make an object, name it cursor.
Add a small collider to the cursor object.
Add a script to the cursor object so its always at the mouses location.
Melee range zone
Add a GameObject as child of the player, name it MeleeRangeZone.
Add a collider to it, set it to be a Trigger. The size of this collider will be the players melee range,
Add a rigidbody to it so that collisions can be detected, but set the rigidbody to not rotate or change its position.
Add a script to the object and use the OnTriggerEnter and OnTriggerExit methods to detect whether or not the cursor has entered your melee zone.
You can now use the OnTriggerEnter and OnTriggerExit methods to switch between the players attack modes, meaning that when the cursor enters it changes to melee and when it exit it changes to ranged.
You can fire the ray to detect the location the cursor should have like this:
public LayerMask RaycastCollidableLayers;
public RaycastHit Hit;
public float CheckDistance = 200f;
public Transform Cursor;
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
{
//Move cursor to Hit.point;
Cursor.position = Hit.point;
}
}
I am creating a 2D game in Unity and wanted to see if anyone has any suggestion on how I can improve the script below which I am using to drag a paddle in a breakout/arkanoid style game. I know there are more complex ways to drag objects but this works ok for me but the only issue I encounter is that when I test my game on a mobile device the dragging is not 100% sharp and when I stop dragging the paddle seems to lag ever so slightly. I don’t have any issues with my mobile device as I have played other breakout games I downloaded from the Play store and the dragging is very crisp.
The script below is attached to the paddle.
Vector3 dist;
float posX;
float posY;
void OnMouseDown(){
dist = Camera.main.WorldToScreenPoint(transform.position);
posX = Input.mousePosition.x - dist.x;
posY = Input.mousePosition.y - dist.y;
}
void OnMouseDrag(){
Vector3 curPos = new Vector3(Input.mousePosition.x - posX, Input.mousePosition.y - posY, dist.z);
Vector3 worldPos = Camera.main.ScreenToWorldPoint(curPos);
transform.position = worldPos;
}
I would advise doing your translation of the x and y-axis values using the mouse's position as it's being dragged via the subtracted difference between what the mouse's position value was as it's first pressed down.
A summary of that would be:
Store a 2D vector as a private field, called previousPos (so
mousedown and mousemove can both access it) and set it's value to the result of the mouse's current position.
In the mouse drag function, get the mouse position again and assign the
value to a 2D vector called currentPos and subtract that from
the previousPos, which gives you the x and y-axis values to set the
paddle's transform position to.
Then update the previousPos at the end of the drag function, and
assign the value of currentPos to it so that next time around it
gives the new change and not the aggregated change.
*You probably want to have a boolean that you set to true when mouse is down and at the end of the drag set it to false. Use that bool in the drag as a check to see if you need to set the paddle position in the first place (only set paddle position if the boolean is true) -- Not sure if unity does this for you by only firing mouse dragged when the mouse is down or not.
An example in code:
private Vector2 _previousPos;
private bool _isMouseDown;
void OnMouseDown(){
_isMouseDown = true; //because we're in the on mouse down function
_previousPos = Input.mousePosition; //get the current mouse position
}
void OnMouseDrag(){
if(!_isMouseDown)
return;
Vector2 currentPos = Input.mousePosition; //get updated mouse pos
Vector2 paddlePos = currentPos - previousPos; //the delta change
transform.position = paddlePos; //new paddle position
_isMouseDown = false; //drag is complete, mouse btn is no longer down
_previousPos = currentPos; //reset previous pos for next mouse move
}
I have a class below that I attach to a object in order to make it rotate around its pivot. I sent the pivot of the sprite via the inspector.
This works exactly how I want it too, BUT the issue I am having is that whenever I touch and drag it, and then touch and drag it again, it snaps to a new position.
What I would like for it to do is, when it is rotated and then rotated again, the sprite stays in its same rotation and not snap to a new position and I would like the angle of the sprite to be reset to 0. The next then is that I want the angle to continually rotate. So if I rotate it in the positive direction, the angle should keep increasing in the positive direction and not change..Such as 0---> 360 ----> 720 -----> etc, etc. And then when the mouse is released, the sprite stays in the same position but the angle is now set back to 0. And then when clicked again to rotate, it rotates from that exact position.
Here is my code thus far which works well for rotating, but I would like to modify it to achieve the above scenario. Any help with this?
public class Steering : MonoBehaviour {
float prevAngle,wheelAngle,wheelNewAngle = 0;
public SpriteRenderer sprite;
void Start () {
}
void Update () {
}
public float GetAngle(){
return wheelAngle;
}
void OnMouseDrag(){
Vector3 mouse_pos = Input.mousePosition;
Vector3 player_pos = Camera.main.WorldToScreenPoint(this.transform.position);
mouse_pos.x = mouse_pos.x - player_pos.x;
mouse_pos.y = mouse_pos.y - player_pos.y;
wheelNewAngle = Mathf.Atan2 (mouse_pos.y, mouse_pos.x) * Mathf.Rad2Deg;
if (Input.mousePosition.x > sprite.bounds.center.x) {
wheelAngle += wheelNewAngle - prevAngle;
} else {
wheelAngle -= wheelNewAngle - prevAngle;
}
this.transform.rotation = Quaternion.Euler (new Vector3(0, 0, wheelAngle));
Debug.Log (wheelAngle);
prevAngle = wheelNewAngle;
}
void OnMouseUp(){
prevAngle = wheelNewAngle;
wheelAngle = 0;
}
}
By angle of the sprite, do you mean the rotation? I'm not sure how the position is changing if there's nothing in your code doing that. Does it always move to the same position? I'm having a little trouble visualizing how your system is supposed to look but I hope this helps.
It looks like you might want to store the previous mouse position so you can get the relative amount to rotate each frame.
At the top:
Vector3 prevMousePos = Vector3.zero;
This method will help get the position when the player pressed:
void OnMouseDown(){
prevMousePos = Input.mousePosition;
}
Then in OnMouseDrag() get the difference between the two mouse positions to get the relative position (if you moved the mouse left, right, up, or down since pressing):
Vector3 mouseDiff = Input.mousePosition - prevMousePos;
With this it will use the relative mouse position after pressing instead of the current one, which should smooth things out.