I'm trying to make a 2d fighting camera. I want the camera to focus on 2 fighters and then zoom in/out to make sure they are both on the screen. Using the post below, I was able to get this camera to work horizontally:
https://answers.unity.com/questions/126184/fighting-game-camera.html
The original script is the following
float margin = 1.5f; // space between screen border and nearest fighter
private float z0; // coord z of the fighters plane
private float zCam; // camera distance to the fighters plane
private float wScene; // scene width
private Transform f1; // fighter1 transform
private Transform f2; // fighter2 transform
private float xL; // left screen X coordinate
private float xR; // right screen X coordinate
public void calcScreen(Transform p1, Transform p2)
{
// Calculates the xL and xR screen coordinates
if (p1.position.x < p2.position.x)
{
xL = p1.position.x - margin;
xR = p2.position.x + margin;
}
else
{
xL = p2.position.x - margin;
xR = p1.position.x + margin;
}
}
public void Start()
{
// find references to the fighters
f1 = GameObject.Find("Fighter1").transform;
f2 = GameObject.Find("Fighter2").transform;
// initializes scene size and camera distance
calcScreen(f1, f2);
wScene = xR - xL;
zCam = transform.position.z - z0;
}
public void Update()
{
Vector3 pos = transform.position;
calcScreen(f1, f2);
float width = xR - xL;
if (width > wScene)
{ // if fighters too far adjust camera distance
pos.z = zCam * width / wScene + z0;
}
// centers the camera
pos.x = (xR + xL) / 2;
transform.position = pos;
}
Since on my game you can move horizontally and vertically, I modified the code to also adjust when the character moves vertically to this:
float margin = 1.5f; // space between screen border and nearest fighter
float marginY = 1.5f; // space between screen border and nearest fighter
private float z0; // coord z of the fighters plane
private float zCam; // camera distance to the fighters plane
private float wScene; // scene width
private float hScene; // scene height
private Transform f1; // fighter1 transform
private Transform f2; // fighter2 transform
private float xL; // left screen X coordinate
private float xR; // right screen X coordinate
private float yU; // up screen Y coordinate
private float yD; // down screen Y coordinate
public void calcScreen(Transform p1, Transform p2)
{
// Calculates the xL and xR screen coordinates
if (p1.position.x < p2.position.x)
{
xL = p1.position.x - margin;
xR = p2.position.x + margin;
}
else
{
xL = p2.position.x - margin;
xR = p1.position.x + margin;
}
if (p1.position.y < p2.position.y)
{
yD = p1.position.y - marginY;
yU = p2.position.y + marginY;
}
else
{
yD = p2.position.y - marginY;
yU = p1.position.y + marginY;
}
}
public void Start()
{
// find references to the fighters
f1 = GameObject.Find("Fighter1").transform;
f2 = GameObject.Find("Fighter2").transform;
// initializes scene size and camera distance
calcScreen(f1, f2);
wScene = xR - xL;
hScene = yU - yD;
zCam = transform.position.z - z0;
}
public void Update()
{
Vector3 pos = transform.position;
calcScreen(f1, f2);
float width = xR - xL;
float height = yU - yD;
if (width > wScene)
{ // if fighters too far adjust camera distance
pos.z = zCam * width / wScene + z0;
}
else if (height > hScene)
{ // if fighters too far adjust camera distance
pos.z = zCam * height / hScene + z0;
}
// centers the camera
pos.x = (xR + xL) / 2;
pos.y = (yU + yD) / 2;
transform.position = pos;
}
This works when the character only moves horizontally or vertically, if it moves both horizontally and vertically it doesn't work anymore. Also, the vertical movement doesn't work appropriately when the 2 fighters are far away. The camera zooms in even thought they are far from each other but they are close in terms of the height.
I feel like I need to change the code to look at both x and y at the same time. It feels like I'm considering and x separately.
I have been stuck on this for a while now. Any help would be appreciated.
Your else statement is the reason your vertical scaling is being removed. You should change your if block in Update to this.
if (width > wScene)
{ // if fighters too far adjust camera distance
pos.z = zCam * width / wScene + z0;
}
if (height > hScene)
{ // if fighters too far adjust camera distance
pos.z = Mathf.Max(zCam * height / hScene + z0, pos.z);
}
Related
So i am trying so to make a script for zooming in and out on a ui element(image), and so far i am doing it by scaling the image based on differences in magnitudes between touches from frame to frame, the only problem is that is zooms from where the pivot is.
The solution would be to move the pivot to the point the is the middle of the line that connects the touches. I tried but it puts my pivot way out of the screen due to the fact that i get values greater than 1 from the formula i used.
Basically, i don't know how to move the pivot so it matches the point the would be the middle of the line that connects the touches.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class Zoom : MonoBehaviour
{
public GameObject image1, image2;
public RectTransform tran1, tran2;
public float zoomSpeed = 0.0090f;
public bool startZooming = false;
void Start()
{
tran1 = image1.GetComponent<RectTransform>();
tran2 = image2.GetComponent<RectTransform>();
}
void Update()
{
if(Input.touchCount == 0)
{
//Remember if the player is zooming to be able to change pivot point
startZooming = false;
}
// If there are two touches on the device...
if (Input.touchCount == 2)
{
// Store both touches.
Touch touchZero = Input.GetTouch(0);
Touch touchOne = Input.GetTouch(1);
// Find the position in the previous frame of each touch.
Vector2 touchZeroPrevPos = touchZero.position - touchZero.deltaPosition;
Vector2 touchOnePrevPos = touchOne.position - touchOne.deltaPosition;
// Find the magnitude of the vector (the distance) between the touches in each frame.
float prevTouchDeltaMag = (touchZeroPrevPos - touchOnePrevPos).magnitude;
float touchDeltaMag = (touchZero.position - touchOne.position).magnitude;
// Find the difference in the distances between each frame.
float deltaMagnitudeDiff = prevTouchDeltaMag - touchDeltaMag;
//Find pivot point, the middle of the line that connects the touch points
if (deltaMagnitudeDiff < 0 && startZooming == false)
{
float xpivot, ypivot;
xpivot = (touchZero.position.x + touchOne.position.x) / 2;
ypivot = (touchOne.position.y + touchZero.position.y) / 2;
tran1.pivot = new Vector2(xpivot, ypivot);
tran2.pivot = new Vector2(xpivot, ypivot);
startZooming = true; // player is currently zooming, don't change the pivot point
}
float x, y;
x = tran1.localScale.x - deltaMagnitudeDiff * zoomSpeed;
y = tran1.localScale.y - deltaMagnitudeDiff * zoomSpeed;
// Make sure the localScale size never goes below 1 or above 5
x = Mathf.Clamp(x, 1.0f, 5.0f);
y = Mathf.Clamp(y, 1.0f, 5.0f);
// ... change the localScale size based on the change in distance between the touches.
tran1.localScale = new Vector3(x, y, tran1.localScale.z);
tran2.localScale = new Vector3(x, y, tran2.localScale.z);
}
}
}
The RectTrasnform.pivot you are trying to set is
The normalized position in this RectTransform that it rotates around.
this would be a vector between 0,0 and 1,1,!
You can use ScaleAroundRelative from this post
public static void ScaleAround(Transform target, Vector3 pivotInWorldSpace, Vector3 newScale)
{
// pivot
var localPivot = target.InverseTransformPoint(pivotInWorldSpace);
// diff from object pivot to desired pivot/origin
Vector3 pivotDelta = target.transform.localPosition - pivot;
Vector3 scaleFactor = new Vector3(
newScale.x / target.transform.localScale.x,
newScale.y / target.transform.localScale.y,
newScale.z / target.transform.localScale.z );
pivotDelta.Scale(scaleFactor);
target.transform.localPosition = pivot + pivotDelta;
//scale
target.transform.localScale = newScale;
}
then I would implement it using something like
private float initialTouchDistance;
private Vector2 pivot1;
private Vector2 pivot2;
private Vector2 initialScale1;
private Vector2 initialScale2;
void Update()
{
// If there are two touches on the device...
if (Input.touchCount == 2)
{
// Store both touches.
var touchZero = Input.GetTouch(0);
var touchOne = Input.GetTouch(1);
var touchZeroPosition = touchZero.position;
var touchOnePosition = touchOne.position;
var currentDistance = Vector2.Distance(touchZeroPosition, touchOnePosition);
// Is this a new zoom process? => One of the two touches was added this frame
if(touchZero.phase == TouchPhase.Began || touchOne.phase == TouchPhase.Began)
{
// initialize values
initialTouchDistance = currentDistance;
initialScale1 = tran1.localScale;
initialScale2 = tran2.localScale;
// get center between the touches
// THIS IS STILL IN PIXEL SPACE
var zoomPivot = (touchZeroPosition + touchOnePosition) / 2f;
// Get the position on the RectTransforms planes in WORLD SPACE
RectTransformUtility.ScreenPointToWorldPointInRectangle(tran1, zoomPivot, Camera.main, out pivot1));
RectTransformUtility.ScreenPointToWorldPointInRectangle(tran2, zoomPivot, Camera.main, out pivot2));
}
// Is this an already running zoom process and at least one of the touches was moved?
else if(touchZero.phase == TouchPhase.Moved || touchOne.phase == TouchPhase.Moved)
{
// Scale factor
var factor = (currentDistance / initialTouchDistance) * zoomSpeed;
factor = Mathf.Clamp(factor, 1, 5);
var scaleVector1 = Vector3.Scale(new Vector3(factor, factor, 1), initialScale1);
var scaleVector2 = Vector3.Scale(new Vector3(factor, factor, 1), initialScale2);
// apply scaled around pivot
ScaleAround(tran1, pivot1, scaleVector1);
ScaleAround(tran2, pivot2, scaleVector2);
}
}
}
Note: Typed on smartphone but I hope the idea gets clear
i want to rotate a cube around a 1x1 pipe with arrow keys. (left and right).
The problem is i cannot use built-in functions which sets transform's position and location directly. (Such as transform.lookAt, transform.Rotate or transform.RotateAround). Because I need the vector values of rotation's euler and position for multiple stuff before i modify the value of the transform i want to rotate.
I tried different techniques but no luck so far.
I tried using sin-cos for rotating but could not figure out how to make it work for both rotation and position.
_timer += Time.deltaTime * _larvaSpeed;
float x = -Mathf.Cos(_timer) * distanceBetweenCenter;
float y = Mathf.Sin(_timer) * distanceBetweenCenter;
Here is what i want to achieve. By pressing right or left, move and rotate the object around the pipe.
The result i want. (If i pressed right arrow key a litte bit).
I would appreciate any help. Thank you!
here is the solution using circle mathematics and I strongly recommended not use it, it's just to understand the circular move using circle equation as #FaTaLL ask in the comments
Circle equation...
(x1 - x2)^2 + (y1 - y2)^2 = r^2
x1, y1 is the cube position
x2, y2 is the pipe position
r is the distance between cube and pipe;
using UnityEngine;
public class Rotating : MonoBehaviour
{
public GameObject pipe;
public float Delta;
Vector3 nextpos;
bool compareY;
bool next;
int switchx;
float storeVarAxis;
float x, y, r;
private void Start()
{
next = true;
switchx = 1;
compareY = true;
x = transform.position.x - pipe.transform.position.x;
y = transform.position.y - pipe.transform.position.y;
storeVarAxis = y;
r = Mathf.Sqrt(x * x + y * y);
}
private void Update()
{
if (next)
{
if (compareY == true)
{
y -= Delta * Time.deltaTime;
if (y <= -storeVarAxis)
{
y = -storeVarAxis;
compareY = false;
switchx = -1;
}
}
else
{
y += Delta * Time.deltaTime;
if (y >= storeVarAxis)
{
y = storeVarAxis;
compareY = true;
switchx = 1;
}
}
float v = r * r - y * y;
x = Mathf.Sqrt(Mathf.Abs(v));
nextpos = new Vector3(pipe.transform.position.x + x * switchx, pipe.transform.position.y + y, transform.position.z);
next = false;
}
transform.position = Vector3.MoveTowards(transform.position, nextpos, 1f * Time.deltaTime);
if(Vector3.Distance(transform.position, nextpos) < .05) transform.position = nextpos;
if (transform.position.x.Equals(nextpos.x) && transform.position.y.Equals(nextpos.y)) next = true;
}
}
well, the recommended way is using this simple script
using UnityEngine;
public class Rotating : MonoBehaviour
{
public float speed;
public GameObject pipe;
float r, angle;
Vector3 startpos;
private void Start()
{
r = Mathf.Abs(transform.position.y - pipe.transform.position.y);
angle = 0;
transform.position = pipe.transform.position;
startpos = transform.position;
}
void Update()
{
angle = angle + speed * Time.deltaTime;
transform.rotation = Quaternion.EulerAngles(0,0, angle);
transform.position = startpos + (transform.rotation * new Vector3(r, 0, 0));
}
}
I think Quaternion * Vector3 is what you are looking for. Luckily the box's rotation in its own local coordinates is the same rotation you need to apply to the box's position.
public float speed; //how fast to rotate
public float radius; //radius of the cylinder
public float angle; //angle around it
void Update()
{
if (Input.GetKey(KeyCode.LeftArrow))
{
angle = angle + speed * Time.deltaTime;
}
if (Input.GetKey(KeyCode.RightArrow))
{
angle = angle - speed * Time.deltaTime;
}
//figure out the rotation (from euler angles i guess??)
var quat = Quaternion.EulerAngles(new Vector3(0, angle, 0));
//ok uh what is the box position?? lets just multiply
var unrotated_position = new Vector3(radius, 0, 0);
var rotated_position = quat * unrotated_position;
this.transform.position = rotated_position;
//oh yea and also rotate the box in its own local coordinates
this.transform.rotation = quat;
}
How do you adjust or otherwise set up a screenshot to have the exact dimensions of a particular sprite that is in 3D space (so, Gameobject with SpriteRenderer).
The render camera is set up directly above the sprite but has some blank space outside the boundaries of the sprite. I'm not sure how to precisely adjust the viewport of the rendercamera.
Here's what the scene looks like. (Actually this is a quick and simplified version of my current scene, to showcase my specific problem) And yes, I'm trying to take a specific screenshot at runtime. The main camera is at an arbitrary angle but the render camera can be centered to the sprite renderer. In other words, the screenshot I am taking looks like the one in the Camera Preview in bottom right corner in the pic below. How do I crop out (or adjust the viewport to exclude) the extra part beyond the size of the sprite renderer?
You can calculate the size of the frustum in world space:
float frustumHeight = 2.0f * distance * Mathf.Tan(camera.fieldOfView * 0.5f * Mathf.Deg2Rad);
float frustrumWidth = frustumHeight * camera.aspect;
Then if you know the painting's height and width in world units, you can calculate how big of the center piece of the screen it's occupying:
float widthPortion = paintingWidth / frustrumWidth;
float heightPortion = paintingHeight / frustrumHeight;
Then you know how much of the center of the renderTexture to hide:
float leftRightCrop = (1f-widthPortion)/2f;
float topBottomCrop = (1f-heightPortion)/2f;
So to copy it from your camera's render texture you can do this in OnPostRender:
RenderTexture currentRT = RenderTexture.active;
RenderTexture.active = Cam.targetTexture;
Cam.Render();
int croppedPixelWidth = widthPortion*camera.pixelWidth;
int croppedPixelHeight = heightPortion*camera.pixelHeight;
int leftPixelPadding = leftRightCrop*camera.pixelWidth;
int bottomPixelPadding = topBottomCrop*camera.pixelHeight;
Texture2D cropped = new Texture2D(croppedPixelWidth, croppedPixelHeight);
cropped.ReadPixels(new Rect(
leftPixelPadding,
bottomPixelPadding,
leftPixelPadding + croppedPixelWidth,
bottomPixelPadding + croppedPixelHeight), 0, 0);
cropped.Apply();
RenderTexture.active = currentRT;
Or as #ina used it,
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.IO;
public class SpritePerfectScreenshot : MonoBehaviour
{
bool ScreenshotIt;
float widthPortion; float heightPortion;
float leftRightCrop; float topBottomCrop;
Camera camera;
public void TakeScreencap(Camera c,float distance,float pw,float ph)
{
camera = c;c.enabled = true;
SetItUp(distance, pw, ph);
}
void SetItUp(float distance,float paintingWidth,float paintingHeight)
{
float frustrumHeight = 2.0f * distance * Mathf.Tan(camera.fieldOfView * 0.5f * Mathf.Deg2Rad);
float frustrumWidth = frustrumHeight * camera.aspect;
widthPortion = (paintingWidth / frustrumWidth);
heightPortion = (paintingHeight / frustrumHeight);
leftRightCrop = (1f - widthPortion) / 2f;
topBottomCrop = (1f - heightPortion) / 2f;
ScreenshotIt = true;
print("SetItUp " + distance);
}
private void OnPostRender()
{
if (ScreenshotIt)
{
int croppedPixelWidth =(int) (widthPortion * camera.pixelWidth);
int croppedPixelHeight =(int) (heightPortion * camera.pixelHeight);
int leftPixelPadding =(int)( leftRightCrop * camera.pixelWidth);
int bottomPixelPadding =(int)( topBottomCrop * camera.pixelHeight);
print(croppedPixelWidth + " " + croppedPixelHeight);
Texture2D cropped = new Texture2D(croppedPixelWidth, croppedPixelHeight);
cropped.ReadPixels(new Rect(
leftPixelPadding,
bottomPixelPadding,
leftPixelPadding + croppedPixelWidth,
bottomPixelPadding + croppedPixelHeight), 0, 0);
cropped.Apply();
string uuid = UUID.GetUUID(); string localPath = Application.persistentDataPath + "/" + uuid + ".png";
#if !UNITY_EDITOR
NativeGallery.SaveImageToGallery(cropped.EncodeToPNG(), "A Beautiful Letter",uuid);
#else
File.WriteAllBytes(localPath,cropped.EncodeToPNG());
print(localPath);
#endif
//TODO server (?)
ScreenshotIt = false;camera.enabled = false;
}
}
}
I'm trying to re-implement a pinch-to-zoom system in a Unity UI-based app. About six months ago I was able to hack one together by making the UI canvas a child of a regular GameObject, and manipulating that object's transform, but since updating to Unity 5.5+ I find this doesn't work. The closest I can get allows the pinch gesture to change the canvas' scaleFactor, which a) can make images, panels, etc resize improperly depending on their alignments, and b) won't allow me to pan once zoomed.
What I have so far is this:
public class PinchToZoomScaler : MonoBehaviour {
public Canvas canvas; // The canvas
public float zoomSpeed = 0.5f; // The rate of change of the canvas scale factor
public float _resetDuration = 3.0f;
float _durationTimer = 0.0f;
float _startScale = 0.0f;
void Start() {
_startScale = canvas.scaleFactor;
}
void Update()
{
// If there are two touches on the device...
if (Input.touchCount == 2) {
// Store both touches.
Touch touchZero = Input.GetTouch (0);
Touch touchOne = Input.GetTouch (1);
// Find the position in the previous frame of each touch.
Vector2 touchZeroPrevPos = touchZero.position - touchZero.deltaPosition;
Vector2 touchOnePrevPos = touchOne.position - touchOne.deltaPosition;
// Find the magnitude of the vector (the distance) between the touches in each frame.
float prevTouchDeltaMag = (touchZeroPrevPos - touchOnePrevPos).magnitude;
float touchDeltaMag = (touchZero.position - touchOne.position).magnitude;
// Find the difference in the distances between each frame.
float deltaMagnitudeDiff = prevTouchDeltaMag - touchDeltaMag;
// ... change the canvas size based on the change in distance between the touches.
canvas.scaleFactor -= deltaMagnitudeDiff * zoomSpeed;
// Make sure the canvas size never drops below 0.1
canvas.scaleFactor = Mathf.Max (canvas.scaleFactor, _startScale);
canvas.scaleFactor = Mathf.Min (canvas.scaleFactor, _startScale * 3.0f);
_durationTimer = 0.0f;
} else {
_durationTimer += Time.deltaTime;
if (_durationTimer >= _resetDuration) {
canvas.scaleFactor = _startScale;
}
}
}
}
As I said, this works to a degree, but doesn't give me a nice uniform zooming, not does it allow me to pan the canvas. Thanks in advance for any help.
Attach this script in canvas object which you want to zoom in and zoom out by pinch
using UnityEngine;
using UnityEngine.EventSystems;
public class ObjectScalling : MonoBehaviour, IPointerDownHandler, IPointerUpHandler
{
private bool _isDragging;
private float _currentScale;
public float minScale, maxScale;
private float _temp = 0;
private float _scalingRate = 2;
private void Start()
{
_currentScale = transform.localScale.x;
}
public void OnPointerDown(PointerEventData eventData)
{
if (Input.touchCount == 1)
{
_isDragging = true;
}
}
public void OnPointerUp(PointerEventData eventData)
{
_isDragging = false;
}
private void Update()
{
if (_isDragging)
if (Input.touchCount == 2)
{
transform.localScale = new Vector2(_currentScale, _currentScale);
float distance = Vector3.Distance(Input.GetTouch(0).position, Input.GetTouch(1).position);
if (_temp > distance)
{
if (_currentScale < minScale)
return;
_currentScale -= (Time.deltaTime) * _scalingRate;
}
else if (_temp < distance)
{
if (_currentScale > maxScale)
return;
_currentScale += (Time.deltaTime) * _scalingRate;
}
_temp = distance;
}
}
}
Reminder: This script only works in canvas objects
You can use this function ( just pass to it negative deltaMagnitudeDiff )
Also it is good to multiplay deltaMagnitudeDiff with a ratio like ( 0.05 )
float currentScale = 1f;
void Zoom (float increment)
{
currentScale += increment;
if (currentScale >= maxScale)
{
currentScale = maxScale;
}
else if (currentScale <= minScale)
{
currentScale = minScale;
}
rectTransform.localScale = new Vector3 (currentScale, currentScale, 1);
pan.ValidatePosition ();
}
For Panning,
you can use something like this :
public class Pan : MonoBehaviour
{
public float Speed;
Vector3 startDragPosition;
public void BeginDrag ()
{
startDragPosition = Input.mousePosition;
}
public void Drag ()
{
transform.localPosition += (Input.mousePosition - startDragPosition) * Speed;
startDragPosition = Input.mousePosition;
ValidatePosition ();
}
public void ValidatePosition ()
{
var temp = transform.localPosition;
var width = ((RectTransform)transform).sizeDelta.x;
var height = ((RectTransform)transform).sizeDelta.y;
var MaxX = 0.5f * width * Mathf.Max (0, transform.localScale.x - 1);
var MaxY = 0.5f * height * Mathf.Max (0, transform.localScale.y - 1);
var offsetX = transform.localScale.x * width * (((RectTransform)transform).pivot.x - 0.5f);
var offsetY = transform.localScale.y * width * (((RectTransform)transform).pivot.y - 0.5f);
if (temp.x < -MaxX + offsetX)
temp.x = -MaxX + offsetX;
else if (temp.x > MaxX + offsetX)
temp.x = MaxX + offsetX;
if (temp.y < -MaxY + offsetY)
temp.y = -MaxY + offsetY;
else if (temp.y > MaxY + offsetY)
temp.y = MaxY + offsetY;
transform.localPosition = temp;
}
Just call the functions ( BeginDrag & Drag ) from the Events Trigger component.
what i did to scale an object using pinch was this, it works on any touch screen when the object is in the middle of the screen:
if (Input.touchCount == 2)
{
//The distance between the 2 touches is checked and subsequently used to scale the
//object by moving the 2 fingers further, or closer form eachother.
Touch touch0 = Input.GetTouch(0);
Touch touch1 = Input.GetTouch(1);
if (isScaling)//this will only be done if scaling is true
{
float currentTouchDistance = getTouchDistance();
float deltaTouchDistance = currentTouchDistance - touchDistanceOrigin;
float scalePercentage = (deltaTouchDistance / 1200f) + 1f;
Vector3 scaleTemp = transform.localScale;
scaleTemp.x = scalePercentage * originalScale.x;
scaleTemp.y = scalePercentage * originalScale.y;
scaleTemp.z = scalePercentage * originalScale.z;
//to make the object snap to 100% a check is being done to see if the object scale is close to 100%,
//if it is the scale will be put back to 100% so it snaps to the normal scale.
//this is a quality of life feature, so its easy to get the original size of the object.
if (scaleTemp.x * 100 < 102 && scaleTemp.x * 100 > 98)
{
scaleTemp.x = 1;
scaleTemp.y = 1;
scaleTemp.z = 1;
}
//here we apply the calculation done above to actually make the object bigger/smaller.
transform.localScale = scaleTemp;
}
else
{
//if 2 fingers are touching the screen but isScaling is not true we are going to see if
//the middle of the screen is looking at the object and if it is set isScalinf to true;
Ray ray;
RaycastHit hitTouch;
ray = cam.ViewportPointToRay(new Vector3(0.5f, 0.5f, 0));
if (Physics.Raycast(ray, out hitTouch, 100f))
{
if (hitTouch.transform == transform)
{
isScaling = true;
//make sure that the distance between the fingers on initial contact is used as the original distance
touchDistanceOrigin = getTouchDistance();
originalScale = transform.localScale;
}
}
}
}
I am making clone of Circle pong game in xna. I am not able to get collision of rotating pad with ball. I can't use farseer physics in this game as it is in mono game.
I found one method for it but it also not seem to work.
private void EllasticCollisionPhysics(Ball ball, GoScreen pad)
{
//find normal vector
Vector2 normal = new Vector2(pad.padV.X - ball.ballRectangle.X, pad.padV.Y - ball.ballRectangle.Y);
//find normal vector's modulus, i.e. length
float normalmod = (float)Math.Sqrt(Math.Pow(normal.X, 2) + Math.Pow(normal.Y, 2));
//find unitnormal vector
Vector2 unitnormal = new Vector2((pad.padV.X - ball.ballRectangle.X) / normalmod, (pad.padV.Y - ball.ballRectangle.Y) / normalmod);
//find tangent vector
Vector2 unittan = new Vector2(-1 * unitnormal.Y, unitnormal.X);
//first ball normal speed before collision
float inormalspeedb = unitnormal.X * velocity.X + unitnormal.Y * velocity.Y;
//first ball tangential speed
float itanspeed = unittan.X * velocity.X + unittan.Y * velocity.Y;
//Calculate normal speeds after the collision
//Calculate first ball Velocity vector components (tangential and normal)
Vector2 inormala = new Vector2(unitnormal.X * inormalspeedb, unitnormal.Y * inormalspeedb);
Vector2 itana = new Vector2(unittan.X * itanspeed, unittan.Y * itanspeed);
//Add Vector components to each balls' Velocity
velocity = Vector2.Add(inormala, itana);
You don't need farseer physics for that, what you need is circle to rectangle collisition funciton.
// circle is object with x,y,r parameters
bool intersects(CircleType circle, RectType rect)
{
circleDistance.x = abs(circle.x - rect.x);
circleDistance.y = abs(circle.y - rect.y);
if (circleDistance.x > (rect.width/2 + circle.r)) { return false; }
if (circleDistance.y > (rect.height/2 + circle.r)) { return false; }
if (circleDistance.x <= (rect.width/2)) { return true; }
if (circleDistance.y <= (rect.height/2)) { return true; }
cornerDistance_sq = (circleDistance.x - rect.width/2)^2 +
(circleDistance.y - rect.height/2)^2;
return (cornerDistance_sq <= (circle.r^2));
}
Added CircleType and RectType
public class CircleType
{
public int x;
public int y;
public decimal r;
}
public class RectType
{
public int x;
public int y;
public int width;
public int height;
}