So basically what I am trying to do is when I move my character via joystick I want to calculate the current angle the character is rotating and the new angle in which he should rotate. for example: i am moving the joystick to 45 degrees so my character is rotating at 45 degrees to right. now I move the joystick to 90 degrees. So basically I want to calculate the difference between the current and new angle and than rotate at that specific angle. In this case it would be 45 degrees to left and my character should rotate 45 degrees to left.
Whats the best way to do it?
void Update()
{
// move
_rigidbody.MovePosition(transform.position + (transform.forward * leftController.GetTouchPosition.y * Time.deltaTime * speedMovements) +
(transform.right * leftController.GetTouchPosition.x * Time.deltaTime * speedMovements) );
if (myX != leftController.GetTouchPosition.x || myY != leftController.GetTouchPosition.y) { //checks if player changed position.
myX = leftController.GetTouchPosition.x;
myY = leftController.GetTouchPosition.y;
double rad = Mathf.Atan2(leftController.GetTouchPosition.y, leftController.GetTouchPosition.x); // In radians
double deg = rad * (180 / System.Math.PI); // values from up right to up left : +0 to +180 and from down left to down right: -180 to -0
// double difference =....; here i want to calc the angle my char. should rotate
// transform.Rotate(Vector3.up,(float)difference * Time.deltaTime);
}
Related
I have a problem and although I serached everywhere I couldn't find a solution.
I have a stacked sprite and I'm rotating this sprite around the center of the screen. So I iterate over a list of sprites (stacked) and increase the y-coordinate by 2 every loop (rotation is increased step by step by 0.01f outside of the loop):
foreach(var s in stacked)
{
Vector2 origin = new Vector2(Basic.width / 2, Basic.height / 2);
Rectangle newPosition = new Rectangle(position.X, position.Y - y, position.Width, position.Height);
float angle = 0f;
Matrix transform = Matrix.CreateTranslation(-origin.X, -origin.Y, 0f) *
Matrix.CreateRotationZ(rotation) *
Matrix.CreateTranslation(origin.X, origin.Y, 0f);
Vector2 pos = new Vector2(newPosition.X, newPosition.Y);
pos = Vector2.Transform(pos, transform);
newPosition.X = (int)pos.X;
newPosition.Y = (int)pos.Y;
angle += rotation;
s.Draw(newPosition, origin, angle, Color.White);
y += 2;
}
This works fine. But now my problem. I want not only to rotate the sprite around the center of the screen but also around itself. How to achieve this? I can only set one origin and one rotation per Draw. I would like to rotate the sprite around the origin 'Basic.width / 2, Basic.height / 2' and while it rotates, around 'position.Width / 2, position.Height / 2'. With different rotation speed each. How is this possible?
Thank you in advance!
Just to be clear:
When using SpriteBatch.Draw() with origin and angle, there is only one rotation: the final angle of the sprite.
The other rotations are positional offsets.
The origin in the Draw() call is a translation, rotation, translate back. Your transform matrix shows this quite well:
Matrix transform = Matrix.CreateTranslation(-origin.X, -origin.Y, 0f) *
Matrix.CreateRotationZ(rotation) *
Matrix.CreateTranslation(origin.X, origin.Y, 0f);
//Class level variables:
float ScreenRotation, ScreenRotationSpeed;
float ObjectRotation, ObjectRotationSpeed;
Vector2 ScreenOrigin, SpriteOrigin;
// ...
// In constructor and resize events:
ScreenOrigin = new Vector2(Basic.width <<1, Basic.height <<1);
// shifts are faster for `int` type. If "Basic.width" is `float`:
//ScreenOrigin = new Vector2(Basic.width, Basic.height) * 0.5f;
// In Update():
ScreenRotation += ScreenRotationSpeed; // * gameTime.ElapsedGameTime.Seconds; // for FPS invariant speed where speed = 60 * single frame speed
ObjectRotation+= ObjectRotationSpeed;
//Calculate the screen center rotation once per step
Matrix baseTransform = Matrix.CreateTranslation(-ScreenOrigin.X, -ScreenOrigin.Y, 0f) *
Matrix.CreateRotationZ(ScreenRotation) *
Matrix.CreateTranslation(ScreenOrigin.X, ScreenOrigin.Y, 0f);
// In Draw() at the start of your code snippet posted:
// moved outside of the loop for a translationally invariant vertical y interpretation
// or move it inside the loop and apply -y to position.Y for an elliptical effect
Vector2 ObjectOrigin = new Vector2(position.X, position.Y);
Matrix transform = baseTransform *
Matrix.CreateTranslation(-ObjectOrigin.X, -ObjectOrigin.Y, 0f) *
Matrix.CreateRotationZ(ObjectRotation) *
Matrix.CreateTranslation(ObjectOrigin.X, ObjectOrigin.Y, 0f);
foreach(var s in stacked)
{
Vector2 pos = new Vector2(ObjectOrigin.X, ObjectOrigin.Y - y);
pos = Vector2.Transform(pos, transform);
float DrawAngle = ObjectRotation;
// or float DrawAngle = ScreenRotation;
// or float DrawAngle = ScreenRotation + ObjectRotation;
// or float DrawAngle = 0;
s.Draw(pos, SpriteOrigin, DrawAngle, Color.White);
}
I suggest moving the Draw() parameter away from destinationRectangle and use the Vector2 position directly with scaling. Rotations within square rectangles can differ up to SQRT(2) in aspect ratio, i.e. stretching/squashing. Using Vector2 incurs a cost of higher collision complexity.
I am sorry for the ors, but without complete knowledge of the problem...YMMV
In my 2D projects, I use the vector form of polar coordinates.
The Matrix class requires more calculations than the polar equivalents in 2D. Matrix operates in 3D, wasting cycles calculating Z components.
With normalized direction vectors (cos t,sin t) and a radius(vector length),in many cases I use Vector2.LengthSquared() to avoid the square root when possible.
The only time I have used Matrices in 2D is display projection matrix(entire SpriteBatch) and Mouse and TouchScreen input deprojection(times the inverse of the projection matrix)
I can move object (star) around cube’s corner using accelerometer. Object move following the orbit (green circle). Control inverted, if I tilt right object go left and vise versa.
While spinning cube around corner object move perfect. But when I stop spinning cube, object on one of the cube’s edges, cause of inverted control start jittering.
For example if I try to stop object between red and blue planes, it begins jumping from one plane to another.
Code for object movement
new accelX = abi_MTD_GetFaceAccelX(object.plane);
new accelY = abi_MTD_GetFaceAccelY(object.plane);
object.angle -= accelX - accelY;
if (object.angle >= 90) {
object.plane = GetRightPlane(object.plane);
object.angle -= 90;
} else if (object.angle <= 0) {
object.plane= GetBottomPlane(object.plane);
object.angle = 90 + spaceship.angle;
}
MovePointAlongCircle(OUT object.posX, OUT object.posY, object.orbit, object.angle);
Find coordinate on plane
const OBJECT _ORBIT_CENTER = 260;
new objectOrbit = 150;
MovePointAlongCircle(&posX, &posY, objectOrbit, anglePhi) {
posX = OBJECT_ORBIT_CENTER - (objectOrbit * cos(anglePhi));
posY = OBJECT _ORBIT_CENTER - (objectOrbit * sin(anglePhi));
}
I can get accelerometer values individually on each plane or like the cube is a one thing.
Trigonometric functions like sin and cos use fixed point and look up table.
I've got atan function, which return angle [-45; 45].
Atan(x) {
return ((PI_4_FIXED * x >> FP) - ((x * (ABS(x) - 256) >> FP) * (62 + (17 * ABS(x) >> FP)) >> FP)) * RAD_2_DEG >> FP;
}
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);
}
}
video game link
I'm trying to make a game (see link above) , and I need to have the stick rotate around himself to maintain the orientation face to center of the circle.
this is how I declare the Sprite, and how I move it around the circle:
declaration:
line = new Sprite(new Texture(Gdx.files.internal("drawable/blockLine.png")));
line.setSize(140, 20);
lineX = Gdx.graphics.getWidth()/2 - line.getWidth()/2;
lineY = (Gdx.graphics.getHeight()/2 - line.getHeight()/2) + circle.getHeight()/2;
movement:
Point point = rotatePoint(new Point(lineX, lineY), new Point(Gdx.graphics.getWidth()/2, Gdx.graphics.getHeight()/2), angle+= Gdx.graphics.getDeltaTime() * lineSpeed);
line.setPosition(point.x, point.y);
rotatePoint function:
Point rotatePoint(Point point, Point center, double angle){
angle = (angle ) * (Math.PI/180); // Convert to radians
float rotatedX = (int) (Math.cos(angle) * (point.x - center.x) - Math.sin(angle) * (point.y-center.y) + center.x);
float rotatedY = (int) (Math.sin(angle) * (point.x - center.x) + Math.cos(angle) * (point.y - center.y) + center.y);
return new Point(rotatedX,rotatedY);
}
Any sugestions ?
I can't test right now but I think the rotation of the line should simply be:
Math.atan2(rotatedPoint.getOriginX() - middlePoint.getOriginX(), rotatedPoint.getOriginY() - middlePoint.getOriginY()));
Then you'll have to adjust rad to degrees or whatever you'll use. Tell me if it doesn't work!
I would take a different approach, I just created a method that places n Buttons around a click on the screen. I am using something that looks like this:
float rotation; // in degree's
float distance; //Distance from origin (radius of circle).
vector2 originOfRotation; //Center of circle
vector2 originOfSprite; //Origin of rotation sprite we are calculating
Vector2 direction = new vector2(0, 1); //pointing up
//rotate the direction
direction.rotate(rotation);
// add distance based of the direction. Warning: originOfRotation will change because of chaining method.
// use originOfRotation.cpy() if you do not want to init each frame
originOfSprite = originOfRotation.add(direction.scl(distance));
Now you have the position of your sprite. You need to increment rotation by x each frame to have it rotate. If you want the orientation of the sprite to change you can use the direction vector, probably rotated by 180 again. Efficiency wise I'm not sure what the difference would be.
I try to make a clock, in swift, but now i want to make something strange. I want make border radius settable. This is the easy part (is easy because I already did that). I drew 60 ticks around the clock. The problem is that 60 ticks are a perfect circle. If I change the border radius I obtain this clock:
All ticks are made with NSBezierPath, and code for calculate position for every tick is :
tickPath.moveToPoint(CGPoint(
x: center.x + cos(angle) * point1 ,
y: center.y + sin(angle) * point1
))
tickPath.lineToPoint(CGPoint(
x: center.x + cos(angle) * point2,
y: center.y + sin(angle) * point2
))
point1 and point2 are points for 12 clock tick.
My clock background is made with bezier path:
let bezierPath = NSBezierPath(roundedRect:self.bounds, xRadius:currentRadius, yRadius:currentRadius)
currentRadius - is a settable var , so my background cam be, from a perfect circle (when corner radius = height / 2) to a square (when corner radius = 0 ).
Is any formula to calculate position for every tick so, for any border radius , in the end all ticks to be at same distance to border ?
The maths is rather complicated to explain without recourse to graphics diagrams, but basically if you consider a polar coordinates approach with the origin at the clock centre then there are two cases:
where the spoke from the origin hits the straight side of the square - easy by trigonometry
where it hits the circle arc at the corner - we use the cosine rule to solve the triangle formed by the centre of the clock, the centre of the corner circle and the point where the spoke crosses the corner. The origin-wards angle of that triangle is 45º - angleOfSpoke, and two of the sides are of known length. Solve the cosine equation as a quadratic and you have it.
This function does it:
func radiusAtAngle(angleOfSpoke: Double, radius: Double, cornerRadius: Double) -> Double {
// radius is the half-width of the square, = the full radius of the circle
// cornerRadius is, of course, the corner radius.
// angleOfSpoke is the (maths convention) angle of the spoke
// the function returns the radius of the spoke.
let theta = atan((radius - cornerRadius) / radius) // This determines which case
let modAngle = angleOfSpoke % M_PI_2 // By symmetry we need only consider the first quadrant
if modAngle <= theta { // it's on the vertical flat
return radius / cos(modAngle)
} else if modAngle > M_PI_2 - theta { // it's on the horizontal flat
return radius / cos(M_PI_2 - modAngle)
} else { // it's on the corner arc
// We are using the cosine rule to solve the triangle formed by
// the clock centre, the curved corner's centre,
// and the point of intersection of the spoke.
// Then use quadratic solution to solve for the radius.
let diagonal = hypot(radius - cornerRadius, radius - cornerRadius)
let rcosa = diagonal * cos(M_PI_4 - modAngle)
let sqrTerm = rcosa * rcosa - diagonal * diagonal + cornerRadius * cornerRadius
if sqrTerm < 0.0 {
println("Aaargh - Negative term") // Doesn't happen - use assert in production
return 0.0
} else {
return rcosa + sqrt(sqrTerm) // larger of the two solutions
}
}
}
In the diagram OP = diagonal, OA = radius, PS = PB = cornerRadius, OS = function return, BÔX = theta, SÔX = angleOfSpoke