2D Game, calculate the value for transform.Rotate out of 2 vectors - math

first I wanna say I am really new to unity3d. I have done some tutorials and now I playing around a bit. So here is my problem. I have a 2D scene with a gravity source in the middle (lets say its a planet). I have a spaceship in his orbit. The gravity is simulated with:
var myVector = GameObject.Find("middle").transform.position - transform.position;
rigidbody2D.velocity += 0.2 * Time.deltaTime * myVector;
I can rotate the spaceship with:
if(Input.GetKey(moveLeft)) {
transform.Rotate(Vector3.back * -turnSpeed * Time.deltaTime);
//this value is something like (0, 0, -8)
}
if(Input.GetKey(moveRight)) {
transform.Rotate(Vector3.back * turnSpeed * Time.deltaTime);
//this value is something like (0, 0, 8)
}
What I want is that the spaceship automaticly rotates when it changes the angle to the planet. So that if it is in his orbit the same side allways looks forward. I have done a small sketch for that:
http://snag.gy/AGJMR.jpg
(The Arrow is the spaceship with his direction, it should rotate while the angle between the spaceship and the planet changes)
Basicly: when the spaceship flies around the planet 1 time it also makes a 360° rotation.
I have the old Vector (from spaceship to planet) saved and also have the actual vector:
var myVector = GameObject.Find("middle").transform.position - transform.position;
lastVector = myVector;
//for example:
myVector is (-1, 1, 0)
lastVector is (-1, -1, 0)
Out of this 2 value I should be able to get the value for transform.Rotate (something like (0, 0, 2). But I have no idea how I get there.

The solution is pretty easy:
var angle = Vector3.Angle(lastVector, myVector);
var cross = Vector3.Cross(lastVector, myVector);
if(cross.z >0) {
angle = -angle;
}
transform.Rotate(Vector3.back * angle);

Related

When using an instanced scene, the light source used in it does not work

I have an asteroid scene and a planet scene. When I run the asteroid scene separately, the child lights work, and when I generate them in the planet scene, the glow disappears. Moreover, I checked if this source is in the asteroid when it is already instanced as a variable, but has not yet been added to the scene. At this moment, the asteroid's child light source is absent.Eventually asteroid changes illumination (to no illumination lol) but ofc it shouldn't
Here are ready and process functions:
func _ready():
#THERE ARE ONLY MOVEMENT AND COLOR SETTINGS
random_color()
scale = Vector2(0.2, 0.2)
var go = true
rand_generate.randomize()
var delta_speed = rand_generate.randf_range(-0.5, 0.5)
angle_speed = 3 + delta_speed
angle_speed *= speed_scale
life_time = 2 * PI / angle_speed
rand_generate.randomize()
radius = rand_generate.randf_range(min_rad, max_rad)
position = Vector2(0, radius) + rotate_point
radius = Vector2(0, -radius)
func _physics_process(delta):
if PLAY:
#FUNCTION ONLY FOR DEBUG
position = get_global_mouse_position()
if not go:
#CONTROLS SHOULD IT MOVE
return
#THIS THREE IF'S ARE USED THAT THE ASTEROID
#FIRST SWIM OUT SMOOTHLY, THEN MOVE UNIFORMALLY
#THEN GENTLY REMOVE
if time < life_time * 0.3:
time += delta
var count_scale = lerp(0.01, 3, time / life_time)
scale = Vector2(count_scale,count_scale)
elif time > life_time * 0.7:
time += delta
var count_scale = lerp(3, 0.01,time / life_time)
scale = Vector2(count_scale,count_scale)
else:
time += delta
if time > life_time:
queue_free()
#DATS A CIRCULAR MOVEMENT AROUND A PLANET
position = rotate_point + radius.rotated(angle_speed*time + PI)
I solved my problem. In the Light2D settings, I set the Layer Min and Layer Max properties to -1 and 1, respectively. Everything works now

What is the fast way to constraint an float angle in a range?

For example, I have an angle with value 350 degree, and I want to constraint it in a range with max positive offset of 30 and a max negative offset of 40.
As a result, the angle value should be in a range of (310, 360) and (0, 20). If the computed angle value is 304, the angle value should be constrainted to 310, and if the computed angle value is 30, the angle value should be constrainted to 20.
I have already implemented a method, but it's not efficient enough(Most of the effort is to solve the issue when the angle value is near 360~0 ). What is the fast way to achieve this please?
Function:
// All values are in the range [0.0f, 360.0f]
// Output: the angle value after constraint.
float _KeepAngleValueBetween(float originalAngle, float currentAngle, float MaxPositiveOffset, float MaxNegativeOffset).
For example:
KeepAngleValueBetween(350.0f, 302.0f, 30.0f, 40.0f)
result: 310.0f
KeepAngleValueBetween(350.0f, 40.0f, 30.0f, 40.0f)
result: 20.0f
KeepAngleValueBetween(140.0f, 190.0f, 45.0f, 40.0f)
result: 185.0f
I couldn't come up with a solution that doesn't use if. Anyway, I handle the problem around 0/360 by translating the values before checking if currentAngle is in the desired range.
Pseudo code (Ok, it's C. It is also valid Java. And C++.):
float _KeepAngleValueBetween(float originalAngle, float currentAngle, float MaxPositiveOffset, float MaxNegativeOffset) {
// Translate so that the undesirable range starts at 0.
float translateBy = originalAngle + MaxPositiveOffset;
float result = currentAngle - translateBy + 720f;
result -= ((int)result/360) * 360;
float undesiredRange = 360f - MaxNegativeOffset - MaxPositiveOffset;
if (result >= undesiredRange) {
// No adjustment needed
return currentAngle;
}
// Perform adjustment
if (result * 2 < undesiredRange) {
// Return the upper limit because it is closer.
result = currentAngle + MaxPositiveOffset;
} else {
// Return the lower limit
result = currentAngle - MaxNegativeOffset + 360f;
}
// Translate to the range 0-360.
result -= ((int)result)/360 * 360;
return result;
}

Offset Clock Hands Angle Calculation

I have an interesting mathematical problem that I just cant figure out.
I am building a watch face for android wear and need to work out the angle of rotation for the hands based on the time.
Ordinarily this would be simple but here's the kicker: the hands are not central on the clock.
Lets say I have a clock face that measures 10,10
My minute hand pivot point resides at 6,6 (bottom left being 0,0) and my hour hand resides at 4,4.
How would I work out the angle at any given minute such that the point always points at the correct minute?
Thanks
Ok, with the help Nico's answer I've manage to make tweaks and get a working example.
The main changes that needed to be incorporated were changing the order of inputs to the atan calculation as well as making tweaks because of android's insistence to do coordinate systems upside down.
Please see my code below.
//minutes hand rotation calculation
int minute = mCalendar.get(Calendar.MINUTE);
float minutePivotX = mCenterX+minuteOffsetX;
//because of flipped coord system we take the y remainder of the full width instead
float minutePivotY = mWidth - mCenterY - minuteOffsetY;
//calculate target position
double minuteTargetX = mCenterX + mRadius * Math.cos(ConvertToRadians(minute * 6));
double minuteTargetY = mCenterY + mRadius * Math.sin(ConvertToRadians(minute * 6));
//calculate the direction vector from the hand's pivot to the target
double minuteDirectionX = minuteTargetX - minutePivotX;
double minuteDirectionY = minuteTargetY - minutePivotY;
//calculate the angle
float minutesRotation = (float)Math.atan2(minuteDirectionY,minuteDirectionX );
minutesRotation = (float)(minutesRotation * 360 / (2 * Math.PI));
//do this because of flipped coord system
minutesRotation = minutesRotation-180;
//if less than 0 add 360 so the rotation is clockwise
if (minutesRotation < 0)
{
minutesRotation = (minutesRotation+360);
}
//hours rotation calculations
float hour = mCalendar.get(Calendar.HOUR);
float minutePercentOfHour = (minute/60.0f);
hour = hour+minutePercentOfHour;
float hourPivotX = mCenterX+hourOffsetX;
//because of flipped coord system we take the y remainder of the full width instead
float hourPivotY = mWidth - mCenterY - hourOffsetY;
//calculate target position
double hourTargetX = mCenterX + mRadius * Math.cos(ConvertToRadians(hour * 30));
double hourTargetY = mCenterY + mRadius * Math.sin(ConvertToRadians(hour * 30));
//calculate the direction vector from the hand's pivot to the target
double hourDirectionX = hourTargetX - hourPivotX;
double hourDirectionY = hourTargetY - hourPivotY;
//calculate the angle
float hoursRotation = (float)Math.atan2(hourDirectionY,hourDirectionX );
hoursRotation = (float)(hoursRotation * 360 / (2 * Math.PI));
//do this because of flipped coord system
hoursRotation = hoursRotation-180;
//if less than 0 add 360 so the rotation is clockwise
if (hoursRotation < 0)
{
hoursRotation = (hoursRotation+360);
}
This also included a small helper function:
public double ConvertToRadians(double angle)
{
return (Math.PI / 180) * angle;
}
Thanks for your help all
Just calculate the angle based on the direction vector.
First, calculate the target position. For the minute hand, this could be:
targetX = radius * sin(2 * Pi / 60 * minutes)
targetY = radius * cos(2 * Pi / 60 * minutes)
Then calculate the direction vector from the hand's pivot to the target:
directionX = targetX - pivotX
directionY = targetY - pivotY
And calculate the angle:
angle = atan2(directionX, directionY)

How to set transform origin for QPainter In Qt

I am using PyQt and more accurate QPainter for drawing a line. I need to rotate this line around an origin point (like clock handles), but setting it is not possible, I think!
I found setTransformOriginPoint but it doesn't work for QPainter object. Setting origin point is not possible for QTransform and rotate that could affect QPainter object.
Also I tried rotating the line manually, using rotation equation and ..., this is the code:
def rotateLine(x, y, d):
d = math.radians(d)
x2 = x * math.cos(d) - y * math.sin(d)
y2 = x * math.sin(d) + y * math.cos(d)
return x2, y2
des = QPoint(400, 0)
for k in range(0, 10):
paint.drawLine(center, des)
newLine = rotateLine(des.x(), des.y(), 45)
des = QPoint(newLine[0], newLine[1])
logging.warning(des)
But it doesn't work correctly!
What should I do?
I think one typical solution is to translate, rotate, and then draw. Here's a sample in C++ that will draw lines like hands on a clock with center at (50, 50) and extending from radius=0 to radius=400, with 45° between them.
QPainter painter(this);
painter.save();
painter.translate(50, 50); // Center
for (int k = 0; k < 10; k++) {
painter.drawLine(0, 0, 400, 0);
painter.rotate(45); // Degrees
}
painter.restore();
Side note: Your rotateLine() function is correct for rotating the given point about the origin but it looks like you wanted it to rotate it about center. You could also get the desired effect by changing your call to drawLine to paint.drawLine(center, center + des).

How to adjust player sprite speed correctly? (Basically a math question?)

Background: I have a bird view's JavaScript game where the player controls a space ship by touching a circle -- e.g. touch to the left of the circle center, and the ship will move left, touch the top right and it will move to the top right and so on... the further away from the circle center of pseudo joystick, the more speed in that direction. However, I'm not directly adjusting the ship's speed, but rather set a targetSpeed.x and targetSpeed.y value, and the ship will then adjust its speed using something like:
if (this.speed.x < this.targetSpeed.x) {
this.speed.x += this.speedStep;
}
else if (this.speed.x > this.targetSpeed.x) {
this.speed.x -= this.speedStep;
}
... and the same for the y speed, and speedStep is a small value to make it smoother and not too abrupt (a ship shouldn't go from a fast leftwards direction to an immediate fast rightwards direction).
My question: Using above code, I believe however that the speed will be adjusted quicker in diagonal directions, and slower along the horizontal/ vertical lines. How do I correct this to have an equal target speed following?
Thanks so much for any help!
var xdiff = targetSpeed.x - speed.x;
var ydiff = targetSpeed.y - speed.y;
var angle = Math.atan2(ydiff, xdiff);
speed.x += speedStep * Math.cos(angle);
speed.y += speedStep * Math.sin(angle);
Assuming you already checked that the touch is inside the circle, and that the edge of the circle represents max speed, and that the center of the circle is circleTouch == [0, 0]
In some C++-like pseudo code:
Scalar circleRadius = ...;
Scalar maxSpeed = ...;
Scalar acceleration = ...;
Vector calculateTargetSpeed( Vector circleTouch ) {
Vector targetSpeed = maxSpeed * circleTouch / circleRadius;
return targetSpeed;
}
Vector calculateNewSpeed( Vector currentSpeed, Vector targetSpeed ) {
Vector speedDiff = targetSpeed - currentSpeed;
Vector newSpeed = currentSpeed + acceleration * normalized(speedDiff);
return newSpeed;
}
// Divide v by its length to get normalized vector (length 1) with same x/y ratio
Vector normalized( Vector v ) {
return v / length(v);
}
// Pythagoras for the length of v
Scalar length( Vector v ) {
Scalar length = sqrt(v.x * v.x + v.y * v.y); // or preferably hypot(v.x, v.y)
return length;
}
This is just off the top of my head, and i haven't tested it. The other answer is fine, i just wanted to give an answer without trigonometry functions. :)

Resources