Stop sprite from bouncing - c#

I am making a simple puzzle game on the Unity platform. First, I tested some simple physics on scratch and then wrote it in C#. But for some reason, some of the code isn't producing the same effect. In scratch, the code makes the sprite do exactly what I want; go towards the mouse, slow down, then stop on the mouse. However, (what I presume to be) the same code in Unity makes the sprite go crazy and never stop.
UPDATE
It definitely is cause #2. It turns out the sprite is bouncing off other bounding boxes, causing the velocity to change drastically. It would work with smaller values, except I have gravity. My new question is there any way to stop the sprite from bouncing?
Vector2 CalcHookPull(){
//code for finding which hook and force
//find if mouse pressed
if (Input.GetMouseButton(0))
{
//check if new hook needs to be found
if (!last){
Vector2 mypos = new Vector2(transform.position.x, transform.position.y);
Vector2 relmousepos = new Vector2(Camera.main.ScreenToWorldPoint(Input.mousePosition).x-transform.position.x, Camera.main.ScreenToWorldPoint(Input.mousePosition).y-transform.position.y);
//player is on layer 8, don't want to check itself
int layermask = ~(1<<8);
RaycastHit2D hit = Physics2D.Raycast(mypos, relmousepos, Mathf.Infinity, layermask);
maybeHook = hit.collider.gameObject;
}
if(maybeHook.tag == "hook"){
float hookx = maybeHook.transform.position.x;
float hooky = maybeHook.transform.position.y;
float myx = transform.position.x;
float myy = transform.position.y;
//elasticity = 30
float chx = (hookx - myx) / (5f + 1f/3f);
float chy = (hooky - myy) / (5f + 1f/3f);
float curchx = GetComponent<Rigidbody2D> ().velocity.x;
float curchy = GetComponent<Rigidbody2D> ().velocity.y;
Vector2 toChange = new Vector2 (curchx * 0.3f + chx, curchy * 0.3f + chy);
Debug.Log(toChange);
last = Input.GetMouseButton (0);
return toChange;
} else{
last = Input.GetMouseButton (0);
return new Vector2(0,0);
}
} else {
last = Input.GetMouseButton (0);
return new Vector2 (0, 0);
}
}
Possible differences:
Vectors work differently that xy changes (doubtful)
The bounding box is not allowing the sprite to go all the way to the center of the hook object. (likely, but don't know how to fix)
I copied the code wrong (unlikely)
Any help is appreciated, thanks!

I was being stupid. There is already something for this. Should have thought it through more. http://docs.unity3d.com/Manual/class-PhysicsMaterial2D.html

Related

Why isn't my attempt at making an FPS shooter zoom working?

OBJECTIVE
I am using this script I got from Unity's forums to move my camera around. It works perfectly and this is exactly the style of camera I want. Here it is in action:
https://streamable.com/j7ozps
I wanted to create a zoom effect when the user holds the right mouse button.
PROBLEM
After zooming in, the aim is off by a lot. Here's what happens:
https://streamable.com/8aiil0
MY ATTEMPT
void Update () {
if (Input.GetMouseButton(1))
{
int layerMask = 1 << CombatManager.GROUND_LAYER; // -> public const int GROUND_LAYER = 8;
Ray mouseClick = Camera.main.ScreenPointToRay(Input.mousePosition);
RaycastHit[] hitInfos;
float maxDistance = 100.0f;
hitInfos = Physics.RaycastAll(mouseClick, maxDistance,
layerMask, QueryTriggerInteraction.Ignore);
mainCamera.fieldOfView = 10;
mainCamera.transform.LookAt(hitInfos[0].point);
}
else
mainCamera.fieldOfView = startingFieldOfView;
I also tried swapping the order of the LookAt and field of view assignment.
What am I doing wrong?
Seems that what you want is to zoom towards the cursor position, not towards where the ray hits which are likely not the same point. To check that out you can draw a debug cube where the ray hits, to check if the point you are looking at is the one you need, like so:
GameObject cube = GameObject.CreatePrimitive(PrimitiveType.Cube);
cube.transform.position = hitInfos[0].point;
Check Camera.ScreenToWorldPoint that gives you the worldspace point created by converting the screen space point at the provided distance z from the camera plane.
What I would try:
Vector3 point = Camera.main.ScreenToWorldPoint(Input.mousePosition);
//check if this is the point you want to look at
GameObject cube = GameObject.CreatePrimitive(PrimitiveType.Cube);
cube.transform.position = point;
//look at it
mainCamera.transform.LookAt(point);
It should not mind if you are using the cam.nearClipPlane or the cam.farClipPlane in the ScreenToWorldPoint function, but I would play with that in case something is not working as intended.
Vector3 screenPoint = Input.mousePosition;
screenPoint.z = Camera.main.farClipPlane;
Vector3 worldPoint = Camera.main.ScreenToWorldPoint(screenPoint);

My characters won't strafe or move left to right

I even checked my project settings about horizontal and vertical. It is correct and it is set to WASD, but my character wont move or strafe from left to right.
I put my character set to animation though like he just walk straight with a lil curve here and there but that wont conflict with this script right?
public class Player : MonoBehaviour {
[SerializeField] float controlSpeed = 10f;
void Update()
{
float horizontalThrow = Input.GetAxis("Horizontal");
float VerticalThrow = Input.GetAxis("Vertical");
Debug.Log(horizontalThrow);
Debug.Log(VerticalThrow);
float xoffSet = horizontalThrow * Time.deltaTime * controlSpeed;
float newXpos = transform.localPosition.x + xoffSet;
transform.localPosition = new Vector3(newXpos, transform.localPosition.y, transform.localPosition.z);
}
}
try
transform.localPosition += new Vector3(xoffSet, transform.localPosition.y, transform.localPosition.z);, that is just adding the offset directly to the existing position of your player instead of computing the final value with newXPos. that seems a bit unnecessary.
Also, In your animator component on the player, make sure Apply Root Motion is not checked. applying root motion on an animator whilst trying to also move it externally generally causes issues like these, because their positions are being overridden by each other, causing conflict.

Unity - Using a rigidbody for motorcycle - how do I turn?

I'm new to Unity and rigidbodies, and I thought I'd learn by trying to make a 3D Tron Light-cycle game. I've made my player vehicle using a combination of cylinders, spheres, and rectangles, seen below:
I used a rigid body on the elongated sphere, and used the following code:
public float accel = 1.0f;
// Use this for initialization
void Start () {
cycleSphere = GetComponent<Rigidbody>();
}
void FixedUpdate () {
cycleSphere.velocity = Vector3.forward * accel;
}
That moves the vehicle forwards. I'm not sure if there's a better way to do this, but if there is, please do say so.
I've attached the Main camera to the vehicle, and disabled X rotation to prevent it and the camera from rolling.
Now I would like to get it to turn by pressing the A and D buttons. Unlike the 90 degree turning of the original Tron light-cycles, I wanted it to turn like a regular vehicle.
So I tried this:
void Update () {
if (Input.GetKey (KeyCode.A)) {
turning = true;
turnAnglePerFixedUpdate -= turnRateAngle;
} else if (Input.GetKey (KeyCode.D)) {
turning = true;
turnAnglePerFixedUpdate += turnRateAngle;
} else {
turning = false;
}
}
void FixedUpdate () {
float mag = cycleSphere.velocity.magnitude;
if (!turning) {
Quaternion quat = Quaternion.AngleAxis (turnAnglePerFixedUpdate, transform.up);// * transform.rotation;
cycleSphere.MoveRotation (quat);
}
cycleSphere.velocity = Vector3.forward * accel;
}
While the above code does rotate the vehicle, it still moves in the last direction it was in - it behaves more like a tank turret. Worse, pressing either A or D too much would cause it to rotate in the desired direction and, after a short while, go nuts, rotating this way and that, taking the camera with it.
What did I do wrong and how can I fix it?
First of all I would recommend you to change from Input.GetKey to Input.GetAxis which will gracefully increase or decrease it's value when the key is pressed. This will give you the option to normalize the force vector applied as your velocity. Then based on that vector you have to adapt your force input so that the "front wheel" will "drag" the rest of the body to some other direction ( left or right ). This is not the ideal "real world physics behavior" because the forward force is slightly bigger than the side ( left or right ) force.
code example :
// member fields
float sideForceMultiplier = 1.0f;
float frontForceMultiplier = 2.0f;
Vector3 currentVeloticy = Vector3.zero;
void Update()
{
Vector3 sideForce = (sideForceMultiplier * Input.GetAxis("horizontal")) * Vector3.right;
Vector3 frontForce = frontForceMultiplier * Vector3.forward;
currentVelocity = (sideForce + fronForce).Normalize;
}
void FxedUpdate()
{
cycleSphere.velocity = currentVelocity * accel;
}

Unity Move rotating object

I have a ball which rotates around the point 0,0,0 in the Z-axis. When the space button is pressed, the ball has to go inside the large circle. Now my code looks like this. When you press space, the ball does not behave as they should. I want to know how to make a balloon down exactly down
that's how the ball should behave ->
behavior image
my code:
void Update () {
if (Input.GetKeyDown (KeyCode.Space)) {
transform.position = new Vector3 (transform.position.x - 1, transform.position.y - 1, 0);
} else {
transform.RotateAround(new Vector3(0,0,0), new Vector3(0,0,1), 2);
}
}
Your code to 'jump' the orbit doesn't do what you want because Transform.RotateAround modifies both the rotation and the position of the object's transform.
So jumping to (position - 1,1,0) in the world is going to return wildly different results every time.
What you want to do instead is calculate the (Vector) direction from the object to the centre of orbit (the difference), then scale that down to how far you want it to move, then apply it to the position.
private Vector3 _orbitPos = Vector3.zero;
private float _orbitAngle = 2f;
private float _distanceToJump = 2f;
void Update()
{
if (Input.GetKeyDown(KeyCode.Space))
{
var difference = (_orbitPos - transform.position).normalized * _distanceToJump;
transform.Translate(difference);
}
transform.RotateAround(_orbitPos, Vector3.forward, _orbitAngle);
}
This will move the object to be orbiting 2 units closer when space is pressed immediately.
If you wanted to have a smooth transition instead of a jump, look into using Mathf.Lerp, Vector3.Lerp and the routines involved.

Accurate Pinch Zoom

I'm trying to figure out how to create an accurate pinch zoom for my camera in Unity3D/C#. It must be based on the physical points on the terrain. The image below illustrates the effect I want to achieve.
The Camera is a child of a null which scales (between 0,1 and 1) to "zoom" as not to mess with the perspective of the camera.
So what I've come up with so far is that each finger must use a raycast to get the A & B points as well as the current scale of the camera parent.
EG: A (10,0,2), B (14,0,4), S (0.8,0.8,0.8) >> A (10,0,2), B (14,0,4), S (0.3,0.3,0.3)
The positions of the fingers will change but the hit.point values should remain the same by changing the scale.
BONUS: As a bonus, it would be great to have the camera zoom into a point between the fingers, not just the center.
Thanks so much for any help or reference.
EDIT:
I've come up with this below so far but it's not accurate the way I want. It incorporates some of the ideas I had above and I think that the problem is that it shouldn't be /1000 but an equation including the current scale somehow.
if (Input.touchCount == 2) {
if (!CamZoom) {
CamZoom = true;
var rayA = Camera.main.ScreenPointToRay (Input.GetTouch (0).position);
var rayB = Camera.main.ScreenPointToRay (Input.GetTouch (1).position);
int layerMask = (1 << 8);
if (Physics.Raycast (rayA, out hit, 1500, layerMask)) {
PrevA = new Vector3 (hit.point.x, 0, hit.point.z);
Debug.Log ("PrevA: " + PrevA);
}
if (Physics.Raycast (rayB, out hit, 1500, layerMask)) {
PrevB = new Vector3 (hit.point.x, 0, hit.point.z);
Debug.Log ("PrevB: " + PrevB);
}
PrevDis = Vector3.Distance (PrevB, PrevA);
Debug.Log ("PrevDis: " + PrevDis);
PrevScaleV = new Vector3 (PrevScale, PrevScale, PrevScale);
PrevScale = this.transform.localScale.x;
Debug.Log ("PrevScale: " + PrevScale);
}
if (CamZoom) {
var rayA = Camera.main.ScreenPointToRay (Input.GetTouch (0).position);
var rayB = Camera.main.ScreenPointToRay (Input.GetTouch (1).position);
int layerMask = (1 << 8);
if (Physics.Raycast (rayA, out hit, 1500, layerMask)) {
NewA = new Vector3 (hit.point.x, 0, hit.point.z);
}
if (Physics.Raycast (rayB, out hit, 1500, layerMask)) {
NewB = new Vector3 (hit.point.x, 0, hit.point.z);
}
DeltaDis = PrevDis - (Vector3.Distance (NewB, NewA));
Debug.Log ("Delta: " + DeltaDis);
NewScale = PrevScale + (DeltaDis / 1000);
Debug.Log ("NewScale: " + NewScale);
NewScaleV = new Vector3 (NewScale, NewScale, NewScale);
this.transform.localScale = Vector3.Lerp(PrevScaleV,NewScaleV,Time.deltaTime);
PrevScaleV = NewScaleV;
CamAngle();
}
}
Intro
I had to solve this same problem recently and started off with the same approach as you, which is to think of it as though the user is interacting with the scene and we need to figure out where in the scene their fingers are and how they're moving and then invert those actions to reflect them in our camera.
However, what we're really trying to achieve is much simpler. We simply want the to user feel like the area of the screen that they are pinching changes size with the same ratio as their pinch changes.
Aim
First let's summarise our goal and constraints:
Goal: When a user pinches, the pinched area should appear to scale to match the pinch.
Constraint: We do not want to change the scale of any objects.
Constraint: Our camera is a perspective camera.
Constraint: We do not want to change the field of view on the camera.
Constraint: Our solution should be resolution/device independent.
With all that in mind, and given that we know that with a perspective camera objects appear larger when they're closer and smaller when they're further, it seems that the only solution for scaling what the user sees is to move the camera in/out from the scene.
Solution
In order to make the scene look larger at our focal point, we need to position the camera so that a cross-section of the camera's frustum at the focal point is equivalently smaller.
Here's a diagram to better explain:
The top half of the image is the "illusion" we want to achieve of making the area the user expands twice as big on screen. The bottom half of the image is how we need to move the camera to position the frustum in a way that gives that impression.
The question then becomes how far do I move the camera to achieve the desired cross-section?
For this we can take advantage of the relationship between the frustum's height h at a distance d from the camera when the camera's field of view angle in degrees is θ.
Since our field of view angle θ is constant per our agreed constraints, we can see that h and d are linearly proportional.
This is useful to know because it means that any multiplication/division of h is equally reflected in d. Meaning we can just apply our multipliers directly to the distance, no extra calculation to convert height to distance required!
Implementation
So we finally get to the code.
First, we take the user's desired size change as a multiple of the previous distance between their fingers:
Touch touch0 = Input.GetTouch(0);
Touch touch1 = Input.GetTouch(1);
Vector2 prevTouchPosition0 = touch0.position - touch0.deltaPosition;
Vector2 prevTouchPosition1 = touch1.position - touch1.deltaPosition;
float touchDistance = (touch1.position - touch0.position).magnitude;
float prevTouchDistance = (prevTouchPosition1 - prevTouchPosition1).magnitude;
float touchChangeMultiplier = touchDistance / prevTouchDistance;
Now we know by how much the user wants to scale the area they're pinching, we can scale the camera's distance from its focal point by the opposite amount.
The focal point is the intersection of the camera's forward ray and the thing you're zooming in on. For the sake of a simple example, I'll just be using the origin as my focal point.
Vector3 focalPoint = Vector3.zero;
Vector3 direction = camera.transform.position - focalPoint;
float newDistance = direction.magnitude / touchChangeMultiplier;
camera.transform.position = newDistance * direction.normalized;
camera.transform.LookAt(focalPoint);
That's all there is to it.
Bonus
This answer is already very long. So to briefly answer your question about making the camera focus on where you're pinching:
When you first detect a 2 finger touch, store the screen position and related world position.
When zooming, move the camera to put the world position back at the same screen position.
This is a small example:
if (_Touches.Length == 2)
{
Vector2 _CameraViewsize = new Vector2(_Camera.pixelWidth, _Camera.pixelHeight);
Touch _TouchOne = _Touches[0];
Touch _TouchTwo = _Touches[1];
Vector2 _TouchOnePrevPos = _TouchOne.position - _TouchOne.deltaPosition;
Vector2 _TouchTwoPrevPos = _TouchTwo.position - _TouchTwo.deltaPosition;
float _PrevTouchDeltaMag = (_TouchOnePrevPos - _TouchTwoPrevPos).magnitude;
float _TouchDeltaMag = (_TouchOne.position - _TouchTwo.position).magnitude;
float _DeltaMagDiff = _PrevTouchDeltaMag - _TouchDeltaMag;
_Camera.transform.position += _Camera.transform.TransformDirection((_TouchOnePrevPos + _TouchTwoPrevPos - _CameraViewsize) * _Camera.orthographicSize / _CameraViewsize.y);
_Camera.orthographicSize += _DeltaMagDiff * _OrthoZoomSpeed;
_Camera.orthographicSize = Mathf.Clamp(_Camera.orthographicSize, _MinZoom, _MaxZoom) - 0.001f;
_Camera.transform.position -= _Camera.transform.TransformDirection((_TouchOne.position + _TouchTwo.position - _CameraViewsize) * _Camera.orthographicSize / _CameraViewsize.y);
}
In the second video of this tutorial explains it

Categories

Resources