Update 'Analog Clock'
parent
4df544a236
commit
a485d145a0
123
Analog-Clock.md
123
Analog-Clock.md
@ -56,3 +56,126 @@ We will do this in `OnUserUpdate()`:
|
||||
[[***Try it out!***]](https://pgetinker.com/s/9PzMu2bRS6b "Click to try it out!")
|
||||
|
||||
[<img src="https://pit.pgetinker.com/SaoLD897rXSC.png" width="256" height="240">](https://pgetinker.com/s/9PzMu2bRS6b "Click to try it out!")
|
||||
|
||||
**Notice:**
|
||||
> Usage of `GetScreenSize()` and dividing by 2 here means we don't have to use magic numbers to figure out what the center of the screen is. It returns a vector with the width and height for us.
|
||||
|
||||
## Clock Numbers
|
||||
|
||||
Generating the numbers displayed around the clock will involve a little maths.
|
||||
|
||||
We want to generate one number every 30 degrees on the clock. This is because there are 12 numbers and `360/12 == 30`.
|
||||
|
||||
We can use the `olc::vf2d` class which is a vector class that stores an `x` and a `y` component. Instead of using it to store **cartesian** coordinates, let's use it to store **polar** coordinates.
|
||||
|
||||
In the polar coordinate system, points have a magnitude and an angle. We can use these to our advantage to traverse around the clock's outline while placing numbers at each point.
|
||||
|
||||
### Attempting the Problem
|
||||
|
||||
Let's first try to draw some reference dots to get a better idea of what we are doing here.
|
||||
|
||||
So for `i` in 12 times, we will draw a pixel at `angle * i` degrees from the center. Let's use a radius of `80` this time so it doesn't overlap the circle.
|
||||
|
||||
```cpp
|
||||
bool OnUserUpdate(float fElapsedTime) override
|
||||
{
|
||||
Clear(olc::VERY_DARK_GREEN);
|
||||
|
||||
DrawCircle(GetScreenSize()/2,100);
|
||||
|
||||
for(int i{0};i<12;i++){
|
||||
olc::vf2d drawVec{80,float(i*30)};
|
||||
Draw(drawVec);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
```
|
||||
|
||||
And...This isn't quite right.
|
||||
<img src="https://pit.pgetinker.com/AKfdbyb9ThAj.png" width="256" height="240">
|
||||
|
||||
**What happened?**
|
||||
> If we intend to represent a olc::vf2d in the polar coordinate space, we need to convert it back to cartesian coordinates to get a sensible result for the screen. olc::vf2d comes with a built-in function called `cart()` to do this for us.
|
||||
```cpp
|
||||
for(int i{0};i<12;i++){
|
||||
olc::vf2d drawVec{80,float(i*30)};
|
||||
Draw(drawVec.cart());
|
||||
}
|
||||
```
|
||||
<img src="https://pit.pgetinker.com/jyDH5FGPrMWv.png" width="256" height="240">
|
||||
|
||||
Still not quite right, but starting to look a little like something. We have to remember that these are just representations of a grid from the origin of (0,0).
|
||||
**Tip:**
|
||||
> After converting a polar coordinate to cartesian coordinates, add back in your origin to offset the entire circle.
|
||||
```cpp
|
||||
for(int i{0};i<12;i++){
|
||||
olc::vf2d drawVec{80,float(i*30)};
|
||||
Draw(GetScreenSize()/2+drawVec.cart());
|
||||
}
|
||||
```
|
||||
Surely everything is great now, righ-...?
|
||||
<img src="https://pit.pgetinker.com/hncED6BAIC9j.png" width="256" height="240">
|
||||
|
||||
One more fundamental issue here. Maybe you have caught on by now. The angles are incorrect. C++ deals with angles in **radians**, not degrees! Therefore we must convert to radians each time we attempt to calculate our angles.
|
||||
|
||||
A little revisit to trigonometry class! Conversion from degrees to radians is `deg * (π/180)`. Therefore we can write a small utility conversion function.
|
||||
|
||||
```cpp
|
||||
const float degToRad(const float deg){
|
||||
using namespace std::numbers;
|
||||
return deg*(pi/180);
|
||||
}
|
||||
|
||||
bool OnUserUpdate(float fElapsedTime) override
|
||||
{
|
||||
Clear(olc::VERY_DARK_GREEN);
|
||||
|
||||
DrawCircle(GetScreenSize()/2,100);
|
||||
|
||||
for(int i{0};i<12;i++){
|
||||
olc::vf2d drawVec{80,degToRad(i*30)};
|
||||
Draw(GetScreenSize()/2+drawVec.cart());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
```
|
||||
|
||||
Great! Another way to think about this is if π is half a revolution, then dividing it into sixths would also give us the correct result in radians. So alternatively we can do without the extra function and just multiply by `π/6` for each number. That would look like this:
|
||||
|
||||
```cpp
|
||||
bool OnUserUpdate(float fElapsedTime) override
|
||||
{
|
||||
Clear(olc::VERY_DARK_GREEN);
|
||||
|
||||
DrawCircle(GetScreenSize()/2,100);
|
||||
|
||||
for(int i{0};i<12;i++){
|
||||
using namespace std::numbers;
|
||||
olc::vf2d drawVec{80,float(i*(pi/6))};
|
||||
Draw(GetScreenSize()/2+drawVec.cart());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
```
|
||||
|
||||
A little cleaner, and an alternative solution! Choose the one you like the most. The new result looks good! The angles are now correct.
|
||||
[[***Try it out!***]](https://pgetinker.com/s/Y50E2kQVebK "Click to try it out!")
|
||||
|
||||
[<img src="https://pit.pgetinker.com/bnXBYvs1tzb0.png" width="256" height="240">](https://pgetinker.com/s/Y50E2kQVebK "Click to try it out!")
|
||||
|
||||
### Rendering the Numbers
|
||||
|
||||
Now that we have determined how to draw around the clock via code, we still need to draw the numbers themselves. If we just attempt to draw them, they will all be left-aligned to their corresponding dots.
|
||||
```cpp
|
||||
for(int i{0};i<12;i++){
|
||||
using namespace std::numbers;
|
||||
olc::vf2d drawVec{80,float(i*(pi/6))};
|
||||
const olc::vf2d drawPos{GetScreenSize()/2+drawVec.cart()};
|
||||
Draw(drawPos);
|
||||
DrawString(drawPos,std::format("{}",i+1));
|
||||
}
|
||||
```
|
||||
|
||||
I've moved the final rendered drawing coordinate to a variable so we can keep the dots around as a reference point. I am also adding 1 to `i` so the numbers start at 1, not 0.
|
||||
|
||||
<img src="https://pit.pgetinker.com/I32IJlyR5GSV.png" width="256" height="240">
|
Loading…
x
Reference in New Issue
Block a user