Hello friends! Is it possible to direct a point along the coordinates of a circle knowing the radius? Maybe there is some kind of formula?
Maybe have a look at the code of my game āSquare Noseā. It has rotations with the character Squiddy and its ball.
Thanks for the tip, but unfortunately this is not enough. I guess I did not explain well what I want to achieve ā¦
The radius can be different, so the point must go in different coordinates, depending on the size of the radius. I want to understand if it is possible to achieve this using some method or formula, so as not to write coordinates for each individual radius.
So ⦠if you know the starting point and you know the radius, canāt you just use COS & SIN to work out the coordinates?
To speed thinks up, you might want to have the SIN / COS tables pre-defined.
Some links >
as far as i remember from school X^2+Y^2=R^2 so |Y|=sqrt(R^2-X^2)
but if you need to make jumping game hero youāll better to follow filmoteās advice )
This is true ⦠however, I think the OP will have a radius and an angle so can calculate X / Y using Sin / Cos.
@filmote @ESPboy
Thanks for answers! To clarify the situation a little. Ultimately I need to bend a line that is always different in length. The top of this line is the point I mentioned earlier. I want to do something like this: drawLine (32, 0, X, Y). Tell me, did I choose the right strategy? Thanks for the links, but itās too difficult for me, Iām afraid I canāt figure it out without an example. If possible, could you please demonstrate this method? Or can you tell the game where this is implemented? Thank you anyway!
This will definitely not be superfluous, thanks! somehow I didnāt think of the clockwise
If you want to draw part of a circle that has specific length l, you can do it like:
- Compute the circumfence of the circle c = 2 * pi * r.
- Compute what fraction of this circumfence has the length you want: x = l / c.
- Draw the circle with sin/cos to which you feed values from 0 to x * 2 * pi. (2 * pi draws the whole circle).
Or is this like a racing game where youāre drawing a straight line that suddenly starts to curve and the goes straight again? Iād do this by keeping track of the point coordinates (which should be in some fractions of a pixel) as well as its direction angle, then at each step you shift the point to a new position and draw a line from previous position to the new position. Keeping the angle the same will be drawing a straight line, changing the angle will be curving it.
Next time I will immediately throw off the video of what I want to achieve This will be a remake of this wonderful and addictive game. I thought I would do it in a day, but I got stuck on lowering the bridge ā¦I hope I can extract the necessary piece of code from the example with the clock
so you have constant R and angle changing from 90 grad to 0 grad
letās angle is A so it could be like this:
uint8_t radius=20;
for (int8_t A=90; A>0; A--)
drawline (0, 0, radius*cos(radians(A)), radius*sin(radians(A)), COLOR);
and to make it faster itās better to take sin and cos in grads (with radians transformation) from the precalculated tables
with precalculated sin/cos and fixed point math i think it should be like this
uint8_t sintabl[90];
uint8_t costabl[90];
//sin and cos values are always less than 1 so we have to use float but it slow. so we use fixed point math with integers. we can *100 and then /100 but it's faster to devide by 2,4,8,16,32,64,128... so we use *128
for (uint8_t i=0; i<90; i++){
sintabl[i]=sin(radians(i))*128;
costabl[i]=cos(radians(i))*128;
};
uint8_t radius=50;
for (int8_t A=90; A>0; A--){
drawLine (0, 0, radius*costabl[A]>>7, radius*sintabl[A]>>7, COLOR);
// right shift is like deviding. >>7 is equal to /128 but >> maybe faster then /
}
Here you have a complete working code, try it here:
#include <Arduboy2.h>
#define ANIMATION_FRAMES 60 // how many frames bridge animation has, lower => faster animation
#define PI_HALF (3.1415 / 2)
Arduboy2 arduboy;
void setup() {
arduboy.begin();
arduboy.setFrameRate(30);
}
// Draws bridge of given length starting at pixel [x,y], frame is the frame for animation.
void drawBridge(int x, int y, int length, int frame)
{
if (frame < ANIMATION_FRAMES / 2) // rising the bridge: draw growing vertical line
arduboy.drawLine(x,y,x,y - (frame * 2 * length) / ANIMATION_FRAMES);
else if (frame < ANIMATION_FRAMES) // bridge falling: draw rotating line
{
float phase = ((frame - ANIMATION_FRAMES / 2) * PI_HALF) / ((float) ANIMATION_FRAMES / 2); // by reordering the operations here we avoid using float :)
arduboy.drawLine(x,y,x + sin(phase) * length,y - cos(phase) * length);
}
else // bridge on the ground: just draw a horizontal line
arduboy.drawLine(x,y,x + length,y);
}
void loop() {
if (!(arduboy.nextFrame()))
return;
arduboy.clear();
drawBridge(10,40,30,arduboy.frameCount);
if (arduboy.frameCount >= 20)
drawBridge(40,50,21,arduboy.frameCount - 20);
arduboy.display();
}
This is probably the easiest way to do it, with just one function and without global state, sin/cos is only computed when the bridge is falling.
You donāt really need sin/cos tables here because youāre not calling these functions very often ā basically 2x a frame ā precalculated values wonāt produce any noticeable speedup here. You should only consider this with orders of magnitude larger number of sin/cos calls, like each frame for every pixel.
A drive-by solution that might be half-bakedā¦
(Completely untested, no warranties, Iām a programmer not a mathematician et ceteraā¦)
// If you use int16_t for this then you can just use the one from Arduboy2,
// otherwise, if you want to use float components, you'll have to have your own Point type
struct Point
{
float x;
float y;
};
struct Line
{
Point start;
Point end;
};
Arduboy2 arduboy;
Line bridge;
void draw()
{
arduboy.drawLine(bridge.start.x, bridge.start.y, bridge.end.x, bridge.end.y, WHITE);
}
float bridgeAngle = 0;
// 90 Degrees (top/negative Y)
constexpr float raisedBridgeAngle = 1.0f;
// 0 Degrees (right/positive X)
constexpr float loweredBridgeAngle = 0.0f;
// Adjust as required
constexpr float bridgeAngleStep = -0.1f;
// Completely untested, purely theoretical.
void step()
{
if(bridgeAngle > loweredBridgeAngle)
{
// Adjust the angle of the line
bridgeAngle += bridgeAngleStep;
// Then recalculate the end of the bridge with the new angle
recalculateBridgeEnd()
}
}
// Move the bridge
void setBridge(Point position)
{
bridge.start = position;
bridgeAngle = raisedBridgeAngle;
recalculateBridgeEnd();
}
void recalculateBridgeEnd()
{
// If the range might exceed int16_t's limits,
// it might be better to promote to float here
const int16_t vectorX = (bridge.end.x - bridge.start.x);
const int16_t vectorY = (bridge.end.y - bridge.start.y);
// I can't remember if sqrt returns float or double,
// so I'll let the compiler figure it out for me
const auto length = sqrt(vectorX * vectorX + vectorY * vectorY);
// Again, can't remember the return types.
const auto baseX = cos(bridgeAngle);
const auto baseY = sin(bridgeAngle);
bridge.end.x = baseX * length;
bridge.end.y = baseY * length;
}
Some resources for understanding the theory (since I canāt explain myself at the moment)ā¦
Vectors:
https://www.mathsisfun.com/algebra/vectors.html
The Unit Circle:
A good Youtube series about video game physics including vectors and angles (mostly 2D):
A sneaky link to my āResource Collectionā (which has a link to the above video series among other things):
@ESPboy @filmote @drummyfish @Pharap @JuiceLizard
Guys, thank you so much for your help! Every time I am surprised at the responsiveness of this communityš
With you, any idea can be brought to life, I really appreciate it!
Not sure if itās exactly what youāre looking for, but Iāve been working on a game with a similar mechanic and Iāve got a demo on GitHub of just how to rotate one point around another on Arduboy: GitHub - poevoid/RotatingBodyDemo: very simple demo demonstrating how to rotate one point around another, for arduboy
thanks for the example! Iāve already used the tips above, but your example will definitely come in handy in future projects, thanks!