Unity2D: How do I move the player to the touch position - visual-studio

I can't figure it out, how do I move the Player slowly, scaleable with a speed value to the point, where the touch happens?
My Camera is attached to the player.

You should use Vector2.Lerp, Input.GetTouch, and Touch.Position. Here is a code example that prints the current touch position:
if (Input.touchCount > 0 && Input.GetTouch(0).phase == TouchPhase.Began)
{
Debug.Log(Input.GetTouch(0).position);
}
Now, we should add this to a certain position in the world. We can use Camera.ScreenPointToRay for this part:
if (Input.touchCount > 0 && Input.GetTouch(0).phase == TouchPhase.Began)
{
Ray ray = Camera.main.ScreenPointToRay(Input.GetTouch(0).position);
RaycastHit2D hit;
Physics2D.Raycast(ray, out hit);
Debug.Log(hit.point);
}
Here, we actually get the position in the world that you have pressed. We can then use this along with Lerp to move an object to the position:
public float scaleFactor = 0.2f; //how fast to move object.
public GameObject moving // drag the object you want to move in this slot.
public Vector2 Lerped;//Vector3 if you’re working in 3D.
public float time = 0f;
public bool lerping = false;
private Vector2 newPos = new Vector2();
//Vector3 if you’re working in 3D.
RaycastHit2D hit;//remove the 2D after RaycastHit if you are in 3D. If you are in 2D, leave it.
float dist;
...
if (Input.touchCount > 0 && Input.GetTouch(0).phase == TouchPhase.Began)
{
Ray ray = Camera.main.ScreenPointToRay(Input.GetTouch(0).position);
Physics2D.Raycast(ray, out hit);//same with this one. Remove the 2D if you are in 3D.
Debug.Log(hit.point);
dist = Vector2.Distance(moving.transform.position, hit.point);
//Vector3 if you’re in 3D.
lerping = true;
}
if (lerping)
{
time += Time.deltaTime * dist * scaleFactor;
lerp(hit.point.x, hit.point.y, hit.point.z);
//remove hit.point.z if you are in 2D.
}
else
{
time = 0f;
}
if (moving.transform.position == new Vector3(hit.point.x, hit.point.y, hit.point.z);
//remove hit.point.z if in 2D, and switch Vector3 to Vector2 if in 2D.
{
lerping = false;
}
moving.transform.position = newPos;
And then in another part of the script:
public void lerp(float x, float y, float z)
//remove the float z and the comma before it if you are in unity 2d.
{
Vector3 pos = new Vector3(x, y, z);
//Vector2 and no z if you’re in 2D.
newPos = Vector2.Lerp(moveObj, pos, time);
//Vector3 if in 3D.
}
This is a pretty large script, and it’s pretty hard to explain, so I will say this: do what the comments tell you, and tell me if you get any errors. I haven’t actually tested the script, so if anyone notices them, please tell me.
Now, what the script does: basically, it gets the point of where you touched, and makes the player slowly go towards it (the speed changes by the distance and scaleFactor variable of which you can change.)

Related

bounce after collision doesnt work and object clips through terrain

EDIT I changed my code to the one below but it still clips through the terrain sometimes. It also likes to bounce on corners where it should slide off.
I tried implementing my own collision for a little game I am making. This is the code for my ball class.
class Ball {
//config
float gforce = 1;
float friction = 0.8;
float elasticity = 0.5;
//vars
PVector position;
PVector velocity = new PVector(0, 0);
Ball(PVector p) {position = p;}
void render(){fill(255, 255, 0); noStroke(); circle(position.x, height-position.y, 16);}
PVector bounce(PVector v, PVector n){ //calculate velocity after bounce
PVector u = PVector.mult(n,v.dot(n)/n.dot(n));
PVector w = PVector.sub(v, u);
return PVector.sub(PVector.mult(w, friction), PVector.mult(u, elasticity));
}
Boolean intersect(PVector c, PVector p1, PVector p2, float r){
if (c.dist(p1)<=r || c.dist(p2)<=r){return true;}
float len = p1.dist(p2);
float dot = ( ((c.x-p1.x)*(p2.x-p1.x)) + ((c.y-p1.y)*(p2.y-p1.y)) )/(len*len);
PVector closest = PVector.add(p1, PVector.mult(PVector.sub(p2, p1), dot));
float d1 = closest.dist(p1);
float d2 = closest.dist(p2);
if (d1+d2>=len-0.1 && d1+d2<=len+0.1){if(closest.dist(c)<=r){return true;}}
return false;
}
Boolean intersect(PVector p1, PVector p2, PVector p3, PVector p4){ //if the line p1p2 intersects line p3p4
float uA = ((p4.x-p3.x)*(p1.y-p3.y) - (p4.y-p3.y)*(p1.x-p3.x))/((p4.y-p3.y)*(p2.x-p1.x) - (p4.x-p3.x)*(p2.y-p1.y));
float uB = ((p2.x-p1.x)*(p1.y-p3.y) - (p2.y-p1.y)*(p1.x-p3.x))/((p4.y-p3.y)*(p2.x-p1.x) - (p4.x-p3.x)*(p2.y-p1.y));
if (uA>=0 && uA<=1 && uB>=0 && uB<=1){return true;}else{return false;}
}
void moveBall(){
//if the ball is stationary
if(velocity.mag()==0 || velocity.mag()==1 || velocity.mag()==2){
PVector v = new PVector(min(280, max(-280, mX-mouseX)), min(280, max(-280, mouseY-mY))).div(28);
int n = int(max(abs(v.x), abs(v.y)));
v.normalize().mult(25);
//render arrow
if(mX!=0 && mousePressed){
strokeWeight(5); stroke(#75D5FD); line(mX, mY, mouseX, mouseY);
for (int i=0; i<n+1; i++){
noStroke(); fill(510*(float)i/12, 510*(1-(float)i/12), 0, 55+200*(1-(float)i/12)); circle(mX+(v.x*i), mY-(v.y*i), 15);
}
}
if(mX==0 && mouseP){mX=mouseX; mY=mouseY; mouseP=false;}
if(mX!=0 && mouseR){b.velocity = new PVector(min(280, max(-280, mX-mouseX)), min(280, max(-280, mouseY-mY))).div(8); mX=0; mouseR=false;} //apply velocity
}else {
//if the ball is still, do not allow additional movement
if(mX!=0 && mousePressed){stroke(200); line(mX, mY, mouseX, mouseY);}
if(mX==0 && mouseP){mX=mouseX; mY=mouseY; mouseP=false;}
if(mX!=0 && mouseR){mX=0; mouseR=false;}
}
}
void collision(){
//test collision with terrain
for (int i=1; i<l.points.length; i++){
PVector centerout = PVector.div(velocity, velocity.mag()).mult(8);
strokeWeight(5); stroke(255,0,0); line(position.x, height-position.y, position.x+centerout.x+velocity.x, height-position.y-centerout.y-velocity.y);
if(intersect(position, l.points[i-1], l.points[i], 7) || intersect(position, PVector.add(position,velocity,centerout), l.points[i-1], l.points[i])){
velocity = bounce(velocity, l.normals[i-1]);
}
}
}
void move() {
moveBall();
collision();
position.add(velocity);
if(velocity.y>-10){velocity.y-=gforce;}
if(velocity.mag()<0.5){velocity.x=0; velocity.y=0;}
}
}
There is another object, l (which is the terrain), and it stores the array points[] which contains all the coordinates for the terrain. There is a line connecting each point and the ball detects if its velocity vector intersects that line, or if the ball itself intersects that line.
When i drag and release my mouse, it changes the velocity to whatever vector the mouse was dragged in. It then detects for a collision and it changes the velocity based on its current velocity and the normal of the terrain. However, when it does that, it flies in the opposite direction and flings itself through the floor.
How can I fix my code so that the collision and bouncing works as expected? Additionally it will be nice if the velocity eventually became 0 after bouncing a while.
Oh and usually the y position goes up the further you go down but I changed it so that the y position goes down the further you go down. SO at the very bottom, the y position is 0 instead of the height of the canvas.
Regarding your current problem, I actually have 2 different suggestions I decided to offer only the first one after consideration, as the second one can throw you into recursive madness, but I'm willing to expand on it if needed. I cannot really test them or offer you real code without a working example, though, so I'll stay on pseudocode level.
Solution 1: easy and robust
This one is pretty straightforward: save the pre-bounce vector. When the ball actually bounce, if the rebound has clipping, forget about it and inverse the initial vector. Since the ball came from this exact direction, you can be pretty damn sure that it can go back that way.
The algo would go like this:
if ValidateMove(CurrentVector):
Move(CurrentVector)
else:
NewVector = CalculateNewVector
if ValidateMove(NewVector):
Move(NewVector)
else:
Move(CurrentVector.Invert)
There's a possible problematic edge case, though. If another object is in movement, it may block the ball's inverted path. Honestly, I wouldn't care about the chance that this happens unless your game is specifically prone to this.
Hope this'll help!

Unity 2D - Rotate object and limiting the rotation

I'm trying to do a rotating cannon which rotates back and forward.
I want to limit the rotation from -55 to 55 (i mean transform.position.z), but i can't make it work.
For the moment my code is:
public class Cannon : MonoBehaviour
{
bool hit = false;
void Update ()
{
float angle = transform.rotation.z;
if (angle > -55 & angle < 55 & !hit)
{
transform.Rotate(Vector3.back * Time.deltaTime);
}
if (angle <= -55)
{
transform.Rotate(Vector3.back * Time.deltaTime);
hit = true;
}
if (angle >= 55)
{
transform.Rotate(Vector3.forward * Time.deltaTime);
hit = true;
}
}
}
The only think that is working is the first rotation which I've done for the object to start rotating, so it just rotates back and don't stop, it seems to be ignoring "angle"
I've also tried to put the last 2 If statements, inside the first one but still not working.
I want to make it rotate until it hit -55, then start rotating until it hits +55 and repeat this.
The first thing you need to do is to use Euler Angles rather than Quarternions to find the rotation in degrees.
Then, since it doesn't report negative angles but rather angles from 0 to 360, you will need to subtract 360 whenever greater than 180 to get the negative angle equivalent.
From there you can apply your test to keep it in bounds:
public class Cannon : MonoBehaviour {
public float direction = 1f; // initial direction
public float speed = 20f; // speed of rotation
void Update ()
{
float angle = transform.eulerAngles.z;
if (angle > 180f) angle -= 360f;
if ((angle < -55f) || (angle > 55f)) direction *= -1f; // reverse direction (toggles between 1 & -1)
transform.Rotate (0, 0, speed * direction * Time.deltaTime);
}
}

How to rotate the ball in the direction its moving?I try to use the rotate function but that throws everything off?

//declaringglobalvaribales
float dia1=50;
//diameteroftheface
float x=400;
float y=400;
float speedX=4;
float speedY=0;
//setup
void setup() {
size(810, 810);
} //draw
void draw() {
background(225);
fill(225, 0, 0);
stroke(0);
ellipse(x, y, dia1, dia1);
fill(0, 225, 0);
//a nose
triangle(x, y, x+10, y+10, x-10, y+10);
//movingtheballXway
x=x+speedX;
//movingtheballYway
y=y+speedY;
//if it hits the left or right corners it will turn around
if (x>width-dia1/2 || x<2+dia1/2) {
speedX=speedX*-1;
}
// it its hits the top or bottom it will turn around
if (y>height-dia1/2 || y<2+dia1/2) {
speedY=speedY*-1;
}
// this code to move it according to the keys W S D A
void keyPressed() {
if (keyCode=='W') {
speedX=0;
speedY=-4;
}
if (keyCode=='S') {
speedX=0;
speedY=4;
}
if (keyCode=='A') {
speedX=-4;
speedY=0;
}
if (keyCode=='D') {
speedX=4;
speedY=0;
}
}
I made this ball with a nose, which moves around the screen with the keys W S D A. If it hits the edges it will bounce back.
I'm trying to change the direction the ball is facing to make it face the same way as it's moving. I wanted to use rotate for this, but once I use rotate it throws all the coordinates off. Rotating it back doesn't help either.
I have commented out the stuff I have tried to do. For example, I tried to translate it to 250,250 and then rotate it afterwards, but then the X and Y coordinates are switched. Also, the ball won't go all the way to the corners and it moves out (since it's translated down).
What kind of rotation/translation logic do I need to change?
It is likely that using the rotate function on your triangle is wreaking havoc as you are performing the rotate on several variables in your draw loop because you're not telling processing exactly which object you want to transform. One way to do this is to look up the pushMatrix and popMatrix functions (google "processing pushMatrix" to see helpful info for how to use the type and associated functions). It would be cumbersome to implement this into your code as the triangle is created in your draw loop every frame. An easy way to make transformations to a specific shape you have (in your instance, a triangle) is to store it as a PShape and then make transformations as you need to. Since PShape's can easily be transformed using PShape functions you don't need to worry about your transformations effecting other variables (so no need to use push/popmatrix. Here is a commented version of your code that implements your Triangle as a PShape.
//declaringglobalvaribales
float dia1=50;
//diameteroftheface
float x=400;
float y=400;
float speedX=4;
float speedY=0;
//Initialize PShape which we can later store a triangle in
PShape tri;
void setup() {
size(810, 810);
//Initialize triangle - this triangle faces right
tri = createShape(TRIANGLE, 0, 10, 0, -10, 10, 0);
}
void draw() {
background(225);
fill(225, 0, 0);
stroke(0);
ellipse(x, y, dia1, dia1);
fill(0, 225, 0);
//Draw the stored PShape at x and y coordinate
shape(tri,x,y);
//movingtheballXway
x=x+speedX;
//movingtheballYway
y=y+speedY;
//if it hits the left or right corners it will turn around
if (x>width-dia1/2 || x<2+dia1/2) {
speedX=speedX*-1;
//Flip PShape rotation
tri.rotate(PI);
} // it its hits the top or bottom it will turn around
if (y>height-dia1/2 || y<2+dia1/2) {
speedY=speedY*-1;
//Flip PShape rotation
tri.rotate(PI);
}
}
// this code to move it according to the keys W S D A
void keyPressed() {
if (keyCode=='W') {
speedX=0;
speedY=-4;
//reset triangle orientation (transformation matrix) to original then rotate to face UP
tri.resetMatrix();
tri.rotate(-PI/2);
}
if (keyCode=='S') {
//reset triangle orientation (transformation matrix) to original then rotate to face DOWN
speedX=0;
speedY=4;
tri.resetMatrix();
tri.rotate(PI/2);
}
if (keyCode=='A') {
//reset triangle orientation (transformation matrix) to original then rotate to face LEFT
tri.resetMatrix();
tri.rotate(PI);
speedX=-4;
speedY=0;
}
if (keyCode=='D') {
//reset triangle orientation (transformation matrix) to original - it is already pointing right
tri.resetMatrix();
speedX=4;
speedY=0;
}
}
I suspect your next step, or a more efficient way to write this piece of code might be to begin to implement PVectors (google processing PVectors to see helpful info for how to use the type and associated functions) for position and direction of your 'ball'. Here is some commented code that begins to show you how you might implement this in your current code. Although there are many improvements that can be made on this. For more information on how vectors work in processing follow this tutorial - http://natureofcode.com/book/chapter-1-vectors/
//declaringglobalvaribales
//diameteroftheface
float dia1=50;
//initialize position PVector and tell it where you want it to be - in this case 400,400
PVector position = new PVector(400, 400);
//how many steps you want your position to move per frame
float speed=4;
//initialize direction vector as 0,0 - the ellipse will not move until you give it a
//direction as it is initialized with no direction
PVector direction = new PVector(0, 0);
void setup() {
size(810, 810);
}
void draw() {
background(225);
fill(225, 0, 0);
stroke(0);
//draw ellipse at your position PVector using the PVectors x and y values
ellipse(position.x, position.y, dia1, dia1);
fill(0, 225, 0);
//drawing a line to indicate what direction the ellipse is heading in using the position coordinates and the position plus direction
line(position.x, position.y, position.x+direction.x*4, position.y+direction.y*4);
// add the direction to the position to make it move
position =position.add(direction);
//if the position PVector is close to sketch edges invert its direction by multiplying direction PVector by -1
if (position.x>width-dia1/2 || position.x<2+dia1/2) {
direction.mult(-1);
}
if (position.y>height-dia1/2 || position.y<2+dia1/2) {
direction.mult(-1);
}
}
// this code to move it according to the keys W S D A
void keyPressed() {
//set the direction coordinates based on keypresses
//also multiply the direction by speed variable so it moves at a speed set at top of script
if (keyCode=='W') {
direction.y = -1*speed;
direction.x = 0;
}
if (keyCode=='S') {
direction.y = 1*speed;
direction.x = 0;
}
if (keyCode=='A') {
direction.x = -1*speed;
direction.y = 0;
}
if (keyCode=='D') {
direction.x = 1*speed;
direction.y = 0;
}
}
If you have a center point, an angle you want to face, and a distance from that center, you can use cos() and sin() to calculate the end point. Here's a simple example:
float angle = 0;
float distance = 25;
void draw(){
angle += .01;
float startX = width/2;
float startY = height/2;
float endX = startX + cos(angle)*distance;
float endY = startY + sin(angle)*distance;
background(255);
line(startX, startY, endX, endY);
}
In the future, please try to narrow your question down to an MCVE like this before posting.

flying around 3D obj

I'm making a game space simulator. My spacesheep has to fly around the Earth in 3D.
I've made a simple controller for spacesheep:
public GameObject objToMove=GameObject.Find("Player");
public GameObject zeroPoint=GameObject.Find("Earth");
public float farFromZero=10;
void Update(){
Vector2 Ldirection;
Ldirection.x = Input.GetAxis ("Horizontal");
Ldirection.y = Input.GetAxis ("Vertical");
MoveObj (objToMove, Ldirection.x, Ldirection.y);
}
I also made a separated class just because i want to get control from another class (touchscreen)
public void MoveObj(GameObject LobjToMove, float AxsHoriz, float AxsVert){
AxsHoriz = AxsHoriz * speed;
AxsVert = AxsVert * speed;
AxsHoriz *= Time.deltaTime;
AxsVert *= Time.deltaTime;
LobjToMove.transform.Translate(AxsHoriz, AxsVert, 0);
//spase has to look at the earth
LobjToMove.transform.LookAt (zeroPoint.transform.position);
ZeroPointMagnitude (LobjToMove);
}
//fixing the distance between earth and spacesheep
void ZeroPointMagnitude(GameObject LobjToMove)
{
Vector3 direction = zeroPoint.transform.position - LobjToMove.transform.position;
float distance = direction.magnitude;
if (distance > farFromZero||distance < farFromZero) {
LobjToMove.transform.position += direction.normalized * (distance - farFromZero);
}
}
I've put camera in the spacesheep.
It looks good and spacesheep flies around the earth but it looks like it flying around the pivot, just making radius smaller when it reaches poluses and it can't go around if I press up or down - it stops at the bottom and upstairs
I've tried to make my it fly well for 3 months, I used Raycast or Quaternions and it doesn't work as I want it.
Looks like it going to take few months more and I ask you to help me with flying player around the object without stopping on puluses (or camera flipping)
so here we go
Vector3 rotDir=new Vector3(AxsVert,AxsHoriz,0);
float gypotenuse=Mathf.Sqrt(AxsHoriz*AxsHoriz+AxsVert*AxsVert);
gypotenuse=(gypotenuse>1)?1:gypotenuse;
objToMove.transform.RotateAround (zeroPoint.transform.position,
objToMove.transform.TransformDirection(rotDir),
gypotenuse
);

Unity: rotating object around Z axis with Lerp/Slerp

Im trying to rotate my player to face where I last clicked. I've acutally manged to do this, but now I want to see the player rotate at a set speed instead of the sprite just changing rotation instantly.
Ive tried several methods I've found online, but none of them work for me. Here's what I have
void Update()
{
if (Input.GetMouseButtonDown (0))
{
Vector3 diff = Camera.main.ScreenToWorldPoint(Input.mousePosition) - transform.position;
diff.Normalize();
float rot_z = Mathf.Atan2(diff.y, diff.x) * Mathf.Rad2Deg;
transform.rotation= Quaternion.Euler(0f, 0f, rot_z - 90);
Instantiate(ProjectilePrefab, transform.position, transform.rotation);
}
}
The code above works fine, but it shows no movement. I have tried to do this but the position is wrong and the rotation is instant as well:
Vector3 diff = Camera.main.ScreenToWorldPoint(Input.mousePosition) - transform.position;
var newRotation = Quaternion.LookRotation(diff);
newRotation.y = 0.0f;
newRotation.x = 0.0f;
transform.rotation = Quaternion.Slerp(transform.rotation, newRotation, Time.deltaTime * 30);
ANy ideas?
Two problems here. First, the Slerp function is only called once after the user pressed the mouse button. You have to move it outside the if part or use a coroutine. Second, Slerp expects a float from 0 to 1 to indicate the progress and not time or deltaTime. The official examples covering the lerp functions are just bad, because using the time value would work only during the first second the game is running.
You need something like this
if (Input.GetMouseButtonDown (0)) {
// your other stuff here
float starTime = Time.time;
}
float t = Time.time - startTime;
transform.rotation = Quaternion.Slerp(transform.rotation, newRotation, t);
The rotation would finish after one second. If you want it faster or slower just multiply t with a factor.
I found the answer. This is how I made it work
if (Input.GetMouseButtonDown (0)) {
target = Camera.main.ScreenToWorldPoint (Input.mousePosition);
rotateToTarget = true;
print ("NEW TARGET: " + target);
}
if (rotateToTarget == true && target != null) {
print ("Rotating towards target");
targetRotation = Quaternion.LookRotation (transform.position - target.normalized, Vector3.forward);
targetRotation.x = 0.0f;//Set to zero because we only care about z axis
targetRotation.y = 0.0f;
player.transform.rotation = Quaternion.Slerp (transform.rotation, targetRotation, Time.deltaTime * rotationSpeed);
if (Mathf.Abs (player.transform.rotation.eulerAngles.z - targetRotation.eulerAngles.z) < 1) {
rotateToTarget = false;
travelToTarget = true;
player.transform.rotation = targetRotation;
print ("ROTATION IS DONE!");
}
}

Resources