In Godot, how to limit vector.x, if vector.y has reached maximum? - 2d

I'm new at godot engine. I'm trying to make a space shooter game and I've encountered a little problem.
I am moving my ship with that code:
if button_up.is_pressed():`
velocity += Vector2(acceleration, 0).rotated(rotation + deg2rad(-90))
move_and_slide(velocity)
I made it so ship moves to where it's pointing and it works pretty fine. However when I'm moving to degrees between 1 and 89, 91 and 179 etc., both velocity.x and velocity.y keep rising until it reaches max_speed and that results in my ship moving directly 45, 135, 225 or 315 degrees and not where it's pointing.
I want to make it so when for example velocity.x reaches max_speed, velocity.y gets limited to its current value. Is it possible?
Thank you in advance and excuse me for my english

Before move_and_slide, do velocity = velocity.clamped(max_speed)
This won't have any effect if it's less than the max, but will set it to the max if it is over.

Related

Some Random Blender 2.82 question about measure tool

I was using blender 2.82 and actually i am pretty new to it and learning it and messing around with tools in it, and when i was using measure tool, i tried to measure angles on monkey face and tried to sum up all the interior angles of one face with 4 sides, but i was not getting that why the sum was coming out to be 355 degrees not 360 degrees as i know that sum of interior angles for polygons with n sides is (n-2)*180 degrees which means it should be 360 degrees as it has four sides but it was rather 355 degrees. I don't if this is some bug and i should report this bug or like i am doing something wrong in this and i need to know something that i don't know. Here are some pictures of the above described situation. Thanks in advance for your reply.
That's because you're in 3D space and you're looking at a non-planar face. If you select that face and go to Mesh > Clean up > Make Planar Faces and then re-snap your rulers on the angles, you will get 359, which is still 1° less but that's only due to the fact that the angles don't have decimals.

How can I determine angular velocity from a fixed heading while dealing with the wrap around

I am trying to determine angular velocity in degrees per second of an object.
I have only the heading of that object in degrees updated every 1/60th of a second (with 0 being North and 90 being East)
The specific issue I have is one of handling the wrap around when the object goes from say 355 degrees to 5 degrees passing over 0/360.
I'm currently thinking that perhaps I can average readings over time, excluding the outliers however that will add unnecessary lag to the system and reduce accuracy over that region.
Simple example code where degreesIn is the source and degreesPerSecondOut is the result
degreesPerSecondOut = (degreesIn or 0 - degreesInOld) * 60
degreesInOld = degreesIn
Expected results include a smooth and accurate transition whilst passing over 0 degrees
Additional Thought: The object I am calculating the angular velocity of should never exceed 1 revolution per second (or even per 1/60th of a second). Im not sure why but I feel this is useful.
My take:
function velocity(ain,aout)
ipersec = 60
raw = aout - ain
turn = math.min((-math.abs(raw))%360,math.abs(raw)%360)
direction = math.abs(raw)/raw
return direction*turn*ipersec
end
print(velocity(5,355),velocity(355,5),velocity(20,40),velocity(40,20))
--[[600 -600 1200 -1200--]]
My take - you have three components:
Wrap around, simply handled with a %360. math.mod will work for 5.0.
Even with wrap around, there are two ways you could have turned - we always want the minimal turn.
A sign portion which indicates direction.
Once you handle the wrap around, you realize that 355->5 or backward is no different then 10->20 - you could have taken 10 degrees, or 350, but we assume the shortest.
I think I have found a solution to my answer. Unfortunately I dont think it is necessarily the best solution, as with this solution only up to a maximum of ~180 degrees per tick (10800 degrees per second/1800RPM) but I believe it solves my problem and is accurate enough for my application.
Here it is:
"angularVelocity" is the velocity calculated
"rotationInDegrees" is the input rotation/heading
"rotationInDegreesOld" is the previous rotation/heading
if (rotationInDegrees - rotationInDegreesOld > 180) then
angularVelocity = rotationInDegrees - rotationInDegreesOld - 360 * 60
elseif (inputRotation - inputRotationOld < 180) then
angularVelocity = rotationInDegrees- rotationInDegreesOld + 360 * 60
else
angularVelocity= rotationInDegrees - rotationInDegreesOld * 60
end
To explain what is happening, when the rate is so high that I assume it has wrapped around (like when you go from 355 degrees to 5 degrees where the measurement that tick would be -350 * 60 degrees per second) 360 is added to it making it the more reasonable option of 10 degrees.
The same applies in the other direction but with subtracting 360 rather than adding.

Rotating between 21 positions counterclockwise?

I'm building an Arduino-based control system for a model railway turntable and I need to be able to rotate it clockwise or counterclockwise at will. I have 21 positions on the turntable, which I currently have numbered 0-20. I need to figure out how many "clicks" counterclockwise it will take to get to a given track number. How on earth can I go about finding this?
If there's a math-y way I can do it, that would be fantastic. I don't want to have an endless series of IF statements if I can avoid it.
Never mind. I found a very simple, elegant way.
Let's take my turntable for example. 21 positions, numbered 0-20.
If we are at track 0, and we have 20 tracks total, and we want to go to track 16 counterclockwise, we could do:
moves = 0 + ((20 + 1) - 16)
This yields 5, meaning if we move the turntable counterclockwise 5 tracks, we end up at track 16.
Simple, elegant, and extends to fit an infinite number of possible positions.

Maths Concept: Draw line to follow mouse, with a radius limit

This is not a question specific to one programming language, more of a mathematically conceptual, though just in case, I'm using C++ on Visual Studio.
Basically, my current code draws a line, that starts at the centre (of the window), and ends at my mouse position at any time, every frame - I end up with a line that follows my mouse, starting from the centre.
My question is, how would I end up with the exact same system, except that no matter how far my mouse goes from the centre, the line will still follow the direction of the vector 'centerToMouse', but its length will only ever be 100 units (once the distance between MousePos and centre exceeds 100), such that I end up with a line that follows (extends/shrinks) my mouse, but once I reach above 100 units away from the centre, the line stays 100 units long as long as my mouse is further than 100 away.
I'm sorry if the question is badly phrased, in my head it makes sense, and I don't know how else to word it.
I don't necessarily need a code answer for C++, just the concept. I've tried a few methods involving normalizing, unit vectors etc. But I'm just stuck.
Thanks a lot for taking the time!
Paraphrasing from my above comment:
radius = 100;
angle = atan2(mouse_position.y-center.y, mouse_position.x-center.x);
if (distance(center, mouse_position) < radius){
line_position = mouse_position;
}
else{
line_position = center + Vector(radius*cos(angle), radius*sin(angle));
}

2D Spaceship movement math

I'm trying to make a top-down spaceship game and I want the movement to somewhat realistic. 360 degrees with inertia, gravity, etc.
My problem is I can make the ship move 360° with inertia with no problem, but what I need to do is impose a limit for how fast the engines can go while not limiting other forces pushing/pulling the ship.
So, if the engines speed is a maximum of 500 and the ship is going 1000 from a gravity well, the ship is not going to go 1500 when it's engines are on, but if is pointing away from the angle is going then it could slow down.
For what it's worth, I'm using Construct, and all I need is the math of it.
Thanks for any help, I'm going bald from trying to figure this out.
Take a page from relative physics, where objects cannot exceed the speed of light:
(See below for my working C++ code snippet and running demo [Windows only].)
Set the constant c to the maximum speed an object can reach (the "speed of light" in your game).
If applying a force will increase the speed of the object, divide the acceleration (change in velocity) by the Lorentz factor. The if condition is not realistic in terms of special relativity, but it keeps the ship more "controllable" at high speeds.
Update: Normally, the ship will be hard to maneuver when going at speeds near c because changing direction requires an acceleration that pushes velocity past c (The Lorentz factor will end up scaling acceleration in the new direction to nearly nothing.) To regain maneuverability, use the direction that the velocity vector would have been without Lorentz scaling with the magnitude of the scaled velocity vector.
Explanation:
Definition of Lorentz factor, where v is velocity and c is the speed of light:
This works because the Lorentz factor approaches infinity as velocity increases. Objects would need an infinite amount of force applied to cross the speed of light. At lower velocities, the Lorentz factor is very close to 1, approximating classical Newtonian physics.
Graph of Lorentz factor as velocity increases:
Note: I previously tried to solve a similar problem in my asteroids game by playing with friction settings. I just came up with this solution as I read your question^^
Update: I tried implementing this and found one potential flaw: acceleration in all directions is limited as the speed of light c is approached, including deceleration! (Counter-intuitive, but does this happen with special relativity in the real world?) I guess this algorithm could be modified to account for the directions of the velocity and force vectors... The algorithm has been modified to account for directions of vectors so the ship does not "lose controllability" at high speeds.
Update: Here is a code snippet from my asteroids game, which uses the Lorentz factor to limit the speed of game objects. It works pretty well!
update:* added downloadable demo (Windows only; build from source code for other platforms) of this algorithm in action. I'm not sure if all the dependencies were included in the zip; please let me know if something's missing. And have fun^^
void CObject::applyForces()
{
// acceleration: change in velocity due to force f on object with mass m
vector2f dv = f/m;
// new velocity if acceleration dv applied
vector2f new_v = v + dv;
// only apply Lorentz factor if acceleration increases speed
if (new_v.length() > v.length())
{
// maximum speed objects may reach (the "speed of light")
const float c = 4;
float b = 1 - v.length_squared()/(c*c);
if (b <= 0) b = DBL_MIN;
double lorentz_factor = 1/sqrt(b);
dv /= lorentz_factor;
}
// apply acceleration to object's velocity
v += dv;
// Update:
// Allow acceleration in the forward direction to change the direction
// of v by using the direction of new_v (without the Lorentz factor)
// with the magnitude of v (that applies the Lorentz factor).
if (v.length() > 0)
{
v = new_v.normalized() * v.length();
}
}
Well, lets consider the realistic problem first and see why this doesn't work and how we have to differ from it. In space as long as your engines are firing, you will be accelerating. Your speed is only limited by your fuel (and in fact you can accelerate faster once you've spent some fuel because your moving less mass).
To give this model an effective maximum speed, you can consider particles in space slowing you down and causing friction. The faster you go, the more particles you're hitting and the faster you're hitting them, so eventually at some fast enough speed, you will be hitting enough particles the amount of decelerating they do exactly cancels out the amount of accelerating your engine is doing.
This realistic model does NOT sound like what you want. The reason being: You have to introduce friction. This means if you cut your engines, you will automatically start to slow down. You can probably count this as one of the unintended forces you do not want.
This leaves us with reducing the effective force of your engine to 0 upon reaching a certain speed. Now keep in mind if your going max speed in the north direction, you still want force to be able to push you in the east direction, so your engines shouldn't be cut out by raw velocity alone, but instead based on the velocity your going in the direction your engines are pointing.
So, for the math:
You want to do a cross dot product between your engine pointing vector and your velocity vector to get the effective velocity in the direction your engines are pointing. Once you have this velocity, say, 125 mph (with a max speed of 150) you can then scale back the force of your engines is exerting to (150-125)/150*(Force of Engines).
This will drastically change the velocity graph of how long it will take you to accelerate to full speed. As you approach the full speed your engines become less and less powerful. Test this out and see if it is what you want. Another approach is to just say Force of Engines = 0 if the dot product is >=150, otherwise it is full force. This will allow you to accelerate linearly to your max speed, but no further.
Now that I think about it, this model isn't perfect, because you could accelerate to 150 mph in the north direction, and then turn east and accelerate to 150 mph going in that direction for a total of 212 mph in the north east direction, so not a perfect solution.
I really do like Wongsungi's answer (with the Lorentz factor), but I wanted to note that the code can be simplified to have fewer floating-point operations.
Instead of calculating the Lorentz factor (which itself is a reciprocal) and then dividing by it, like this:
double lorentz_factor = 1/sqrt(b);
dv /= lorentz_factor;
simply multiply by the reciprocal of the Lorentz factor, like this:
double reciprocal_lorentz_factor = sqrt(b);
dv *= reciprocal_lorentz_factor;
This eliminates one floating-point operation from the code, and also eliminates the need to clamp b to DBL_MIN (it can now be clamped to 0 because we're not dividing anymore). Why divide by the reciprocal of x when you can just multiply by x?
Additionally, if you can guarantee that the magnitude of v will never exceed c, then you can eliminate the testing of b being less than zero.
Finally, you can eliminate two additional sqrt() operations by using length_squared() instead of length() in the outer if statement:
if (new_v.length_squared() > v.length_squared())
{
const float c = 4;
float b = 1 - v.length_squared()/(c*c);
if (b < 0) b = 0;
double reciprocal_lorentz_factor = sqrt(b);
dv *= reciprocal_lorentz_factor;
}
This may only make a 0.1% difference in speed, but I think the code is simpler this way.
You need to have three variables for your ship, which you update at each physics time step based on the forces that are acting on it. These will be mass, position, and velocity. (note that position and velocity are single numbers but vectors). At each physics time step you update the position based on the velocity, and the velocity based on the acceleration. you calculate the acceleration based on the forces acting on the ship (gravity, friction, engines)
Newton's equation for force is F = M*A We can rearrange that to A = F/M to get Acceleration. Basically you need to figure out how much the ship should accelerate, and in which direction (vector), then add that acceleration to the ship's velocity, and add the ship's velocity to its position.
Here is the code you should execute each physics time step (I hope you can fill in the blanks) please ask if this is not enough detail
gravity = //calculate force of gravity acting on ship from Newton's law of universal gravitation
friction = //ten percent of the ship's velocity vector, in the opposite direction
engines = 0
if (engines_are_firing)
engines = 500
forces = gravity + friction + engines
acceleration = forces / ship.mass
ship.velocity += acceleration
ship.position += velocity
redraw()
Your question is difficult for me to understand but it seems like you're not using real physics for this game. Have you considered using real physics equations such as velocity, acceleration, force, etc?
Edit:
After your edits, I think I have a better understanding. You are simply keeping track of the current velocity (or something similar) but you don't keep track of the force where that velocity comes from. The ship should not be storing any of that information (other than engine thrust) -- it should come from the environment the ship is in.
For instance, the environment has a gravity vector (directional force) so you would need to take that into account when calculating the directional force provided by the engine.
Your ship should be storing its own engine force, acceleration, and velocity.

Resources