基于EasyX和Raylib的别碰方块
基于 EasyX
// 根据《C和C++游戏趣味编程》第三章 别碰方块 写出
#include <graphics.h>
#include <conio.h> // _kbhit()
#include <stdio.h>
// 检测按下了空格键
void demo_3_1_3()
{
while (1)
{
if (kbhit()) // 当按键时
{
char input = getchar(); // 获得输入字符
if (input == ' ')
{
printf("按下了空格!\n");
}
}
}
}
// 按空格键控制小球起跳
void demo_3_2()
{
float width = 600;
float height = 400;
initgraph(width, height);
float gravity = 0.6;
float radius = 20;
float ball_x = width / 4;
float ball_y = height - radius;
float ball_vy = 0;
while (1)
{
if (kbhit())
{
//char input = getchar(); // getchar() 会等待按下回车
char input = _getch(); // 要想获得实时响应,用 _getch()
if (input == ' ')
{
ball_vy = -16; // 当按下空格键时, 给小球一个向上的初速度
}
else if (input == 'q')
{
break;
}
}
ball_vy = ball_vy + gravity; // 根据重力加速度,更新小球y方向速度
ball_y = ball_y + ball_vy; // 根据小球y方向速度更新其y坐标
if (ball_y >= height - radius) // 如果小球落到地面上
{
ball_vy = 0; // y 速度为0
ball_y = height - radius; // 规范其y坐标,避免落到地面下
}
cleardevice();
fillcircle(ball_x, ball_y, radius);
Sleep(10);
}
closegraph();
}
// 在绘制小球的同时,绘制静态方块
void demo_3_3_1()
{
float width = 600;
float height = 400;
initgraph(width, height);
float gravity = 0.6;
float radius = 20;
float ball_x = width / 4;
float ball_y = height - radius;
float ball_vy = 0;
float rect_height = 100; // 方块高度
float rect_width = 20; // 方块宽度
float rect_left_x = width * 3 / 4; // 方块左边 x 坐标
float rect_top_y = height - rect_height; // 方块顶部 y 坐标
while (1)
{
if (kbhit())
{
//char input = getchar(); // getchar() 会等待按下回车
char input = _getch(); // 要想获得实时响应,用 _getch()
if (input == ' ')
{
ball_vy = -16; // 当按下空格键时, 给小球一个向上的初速度
}
else if (input == 'q')
{
break;
}
}
ball_vy = ball_vy + gravity; // 根据重力加速度,更新小球y方向速度
ball_y = ball_y + ball_vy; // 根据小球y方向速度更新其y坐标
if (ball_y >= height - radius) // 如果小球落到地面上
{
ball_vy = 0; // y 速度为0
ball_y = height - radius; // 规范其y坐标,避免落到地面下
}
cleardevice();
fillcircle(ball_x, ball_y, radius);
fillrectangle(rect_left_x, height - rect_height, rect_left_x + rect_width, height);
Sleep(10);
}
closegraph();
}
// 绘制小球的同时, 绘制向左匀速移动的方块: 在 3_3_1 基础上增加 rect_vx
void demo_3_3_2()
{
float width = 600;
float height = 400;
initgraph(width, height);
float gravity = 0.6;
float radius = 20;
float ball_x = width / 4;
float ball_y = height - radius;
float ball_vy = 0;
float rect_height = 100; // 方块高度
float rect_width = 20; // 方块宽度
float rect_left_x = width * 3 / 4; // 方块左边 x 坐标
float rect_top_y = height - rect_height; // 方块顶部 y 坐标
float rect_vx = -3;
while (1)
{
if (kbhit())
{
//char input = getchar(); // getchar() 会等待按下回车
char input = _getch(); // 要想获得实时响应,用 _getch()
if (input == ' ')
{
ball_vy = -16; // 当按下空格键时, 给小球一个向上的初速度
}
else if (input == 'q')
{
break;
}
}
ball_vy = ball_vy + gravity; // 根据重力加速度,更新小球y方向速度
ball_y = ball_y + ball_vy; // 根据小球y方向速度更新其y坐标
if (ball_y >= height - radius) // 如果小球落到地面上
{
ball_vy = 0; // y 速度为0
ball_y = height - radius; // 规范其y坐标,避免落到地面下
}
rect_left_x = rect_left_x + rect_vx;
if (rect_left_x <= 0)
{
rect_left_x = width; // 在最右边重新出现
}
cleardevice();
fillcircle(ball_x, ball_y, radius);
fillrectangle(rect_left_x, height - rect_height, rect_left_x + rect_width, height);
Sleep(10);
}
closegraph();
}
// 基于demo_3_3_2(), 检测到小球和方块碰撞时,Sleep()一段时间实现类似慢动作的效果
void demo_3_4_2()
{
float width = 600;
float height = 400;
initgraph(width, height);
float gravity = 0.6;
float radius = 20;
float ball_x = width / 4;
float ball_y = height - radius;
float ball_vy = 0;
float rect_height = 100; // 方块高度
float rect_width = 20; // 方块宽度
float rect_left_x = width * 3 / 4; // 方块左边 x 坐标
float rect_top_y = height - rect_height; // 方块顶部 y 坐标
float rect_vx = -3;
while (1)
{
if (kbhit())
{
//char input = getchar(); // getchar() 会等待按下回车
char input = _getch(); // 要想获得实时响应,用 _getch()
if (input == ' ')
{
ball_vy = -16; // 当按下空格键时, 给小球一个向上的初速度
}
else if (input == 'q')
{
break;
}
}
ball_vy = ball_vy + gravity; // 根据重力加速度,更新小球y方向速度
ball_y = ball_y + ball_vy; // 根据小球y方向速度更新其y坐标
if (ball_y >= height - radius) // 如果小球落到地面上
{
ball_vy = 0; // y 速度为0
ball_y = height - radius; // 规范其y坐标,避免落到地面下
}
rect_left_x = rect_left_x + rect_vx;
if (rect_left_x <= 0)
{
rect_left_x = width; // 在最右边重新出现
}
if ( (rect_left_x <= ball_x + radius)
&& (rect_left_x + rect_width >= ball_x - radius)
&& (height - rect_height <= ball_y + radius))
{
Sleep(100); // 慢动作效果
}
cleardevice();
fillcircle(ball_x, ball_y, radius);
fillrectangle(rect_left_x, height - rect_height, rect_left_x + rect_width, height);
Sleep(10);
}
closegraph();
}
// 当方块重新出现时, 随机方块的速度和高度. 基于 demo_3_4_2
void demo_3_5_4()
{
float width = 600;
float height = 400;
initgraph(width, height);
float gravity = 0.6;
float radius = 20;
float ball_x = width / 4;
float ball_y = height - radius;
float ball_vy = 0;
float rect_height = 100;
float rect_width = 20; // 方块宽度
float rect_left_x = width * 3 / 4; // 方块左边 x 坐标
float rect_top_y = height - rect_height; // 方块顶部 y 坐标
float rect_vx = -3;
while (1)
{
if (kbhit())
{
//char input = getchar(); // getchar() 会等待按下回车
char input = _getch(); // 要想获得实时响应,用 _getch()
if (input == ' ')
{
ball_vy = -16; // 当按下空格键时, 给小球一个向上的初速度
}
else if (input == 'q')
{
break;
}
}
ball_vy = ball_vy + gravity; // 根据重力加速度,更新小球y方向速度
ball_y = ball_y + ball_vy; // 根据小球y方向速度更新其y坐标
if (ball_y >= height - radius) // 如果小球落到地面上
{
ball_vy = 0; // y 速度为0
ball_y = height - radius; // 规范其y坐标,避免落到地面下
}
rect_left_x = rect_left_x + rect_vx;
if (rect_left_x <= 0)
{
rect_left_x = width; // 在最右边重新出现
rect_height = rand() % int(height / 4) + height / 4; // 方块高度, 设置为随机的高度
rect_vx = rand() / float(RAND_MAX) * 4 - 7; // [0, 4] - 7 = [-7, -3]
}
if ( (rect_left_x <= ball_x + radius)
&& (rect_left_x + rect_width >= ball_x - radius)
&& (height - rect_height <= ball_y + radius))
{
Sleep(100); // 慢动作效果
}
cleardevice();
fillcircle(ball_x, ball_y, radius);
fillrectangle(rect_left_x, height - rect_height, rect_left_x + rect_width, height);
Sleep(10);
}
closegraph();
}
// 加入得分机制,并显示得分
// 在书上代码基础上, 增加得分的时机从“方块到达左边边界”改为:当前方块没有和小球发生碰撞,并且小球刚刚跳过方块时,得分增加
void demo_3_6()
{
float width = 600;
float height = 400;
initgraph(width, height);
float gravity = 0.6;
float radius = 20;
float ball_x = width / 4;
float ball_y = height - radius;
float ball_vy = 0;
float rect_height = 100;
float rect_width = 20; // 方块宽度
float rect_left_x = width * 3 / 4; // 方块左边 x 坐标
float rect_top_y = height - rect_height; // 方块顶部 y 坐标
float rect_vx = -3;
int score = 0;
bool first_time_being_left = false;
bool collision = false;
while (1)
{
if (kbhit())
{
//char input = getchar(); // getchar() 会等待按下回车
char input = _getch(); // 要想获得实时响应,用 _getch()
if (input == ' ')
{
ball_vy = -16; // 当按下空格键时, 给小球一个向上的初速度
}
else if (input == 'q')
{
break;
}
}
ball_vy = ball_vy + gravity; // 根据重力加速度,更新小球y方向速度
ball_y = ball_y + ball_vy; // 根据小球y方向速度更新其y坐标
if (ball_y >= height - radius) // 如果小球落到地面上
{
ball_vy = 0; // y 速度为0
ball_y = height - radius; // 规范其y坐标,避免落到地面下
}
rect_left_x = rect_left_x + rect_vx;
// 如果方块跑到最左边
if (rect_left_x <= 0)
{
rect_left_x = width; // 在最右边重新出现
first_time_being_left = false;
collision = false;
rect_height = rand() % int(height / 4) + height / 4; // 方块高度, 设置为随机的高度
rect_vx = rand() / float(RAND_MAX) * 4 - 7; // [0, 4] - 7 = [-7, -3]
}
// 如果小球碰到方块
if ( (rect_left_x <= ball_x + radius)
&& (rect_left_x + rect_width >= ball_x - radius)
&& (height - rect_height <= ball_y + radius))
{
Sleep(100); // 慢动作效果
score = 0; // 得分清零
collision = true;
}
// 如果方块没有和小球碰撞,那么方块刚刚处于小球左边时,增加得分
if (rect_left_x + rect_width < ball_x - radius && first_time_being_left == false && collision == false)
{
first_time_being_left = true;
score++; // 增加得分
}
cleardevice();
fillcircle(ball_x, ball_y, radius);
fillrectangle(rect_left_x, height - rect_height, rect_left_x + rect_width, height);
char s[20] = { 0 };
sprintf(s, "score: %d", score);
const int fontsize = 40;
settextstyle(fontsize, 0, _T("Consolas"));
settextcolor(LIGHTGRAY);
outtextxy(50, 30, s);
Sleep(10);
}
closegraph();
}
int main()
{
//demo_3_1_3();
//demo_3_2();
//demo_3_3_1();
//demo_3_3_2();
//demo_3_4_2();
//demo_3_5_4();
demo_3_6();
return 0;
}
基于 Raylib
// 根据《C和C++游戏趣味编程》第三章 别碰方块 写出
#include "raylib.h"
#include <stdio.h>
#include <stdlib.h>
// 检测按下了空格键
void demo_3_1_3()
{
InitWindow(600, 600, "don't touch the square");
SetTargetFPS(60);
while (!WindowShouldClose())
{
// 这种写法, 会在每一帧都输出。感觉不够灵敏。
// char input = getchar();
// if (input == ' ')
// if (IsKeyDown(KEY_SPACE))
// {
// printf("按下了空格!\n");
// }
// else
// {
// printf("不知道啥\n");
// }
// 只在检测到按键按下,并且按键为空格的情况下,才输出内容。符合预期。
if (GetKeyPressed() == ' ')
{
printf("按下了空格!\n");
}
// Draw
BeginDrawing();
{
ClearBackground(BLACK);
}
EndDrawing();
}
CloseWindow();
}
// 按空格键控制小球起跳
void demo_3_2()
{
float width = 600;
float height = 400;
InitWindow(width, height, "don't touch the square");
SetTargetFPS(60);
float gravity = 0.6;
float radius = 20;
float ball_x = width / 4;
float ball_y = height - radius;
float ball_vy = 0;
while (!WindowShouldClose())
{
// Update
if (GetKeyPressed() == ' ')
{
ball_vy = -16; // 当按下空格键时, 给小球一个向上的初速度
}
else if (GetKeyPressed() == 'q') // 对应到 ESC 键而不是q键,很奇怪
{
break;
}
ball_vy = ball_vy + gravity; // 根据重力加速度,更新小球y方向速度
ball_y = ball_y + ball_vy; // 根据小球y方向速度更新其y坐标
if (ball_y >= height - radius) // 如果小球落到地面上
{
ball_vy = 0; // y 速度为0
ball_y = height - radius; // 规范其y坐标,避免落到地面下
}
// Draw
BeginDrawing();
{
ClearBackground(BLACK);
DrawCircle(ball_x, ball_y, 20, WHITE);
}
EndDrawing();
}
CloseWindow();
}
// 在绘制小球的同时,绘制静态方块
void demo_3_3_1()
{
float width = 600;
float height = 400;
InitWindow(width, height, "don't touch the square");
SetTargetFPS(60);
float gravity = 0.6;
float radius = 20;
float ball_x = width / 4;
float ball_y = height - radius;
float ball_vy = 0;
float rect_height = 100; // 方块高度
float rect_width = 20; // 方块宽度
float rect_left_x = width * 3 / 4; // 方块左边 x 坐标
float rect_top_y = height - rect_height; // 方块顶部 y 坐标
while (!WindowShouldClose())
{
// Update
if (GetKeyPressed() == ' ')
{
ball_vy = -16; // 当按下空格键时, 给小球一个向上的初速度
}
else if (GetKeyPressed() == 'q') // 对应到 ESC 键而不是q键,很奇怪
{
break;
}
ball_vy = ball_vy + gravity; // 根据重力加速度,更新小球y方向速度
ball_y = ball_y + ball_vy; // 根据小球y方向速度更新其y坐标
if (ball_y >= height - radius) // 如果小球落到地面上
{
ball_vy = 0; // y 速度为0
ball_y = height - radius; // 规范其y坐标,避免落到地面下
}
// Draw
BeginDrawing();
{
ClearBackground(BLACK);
DrawCircle(ball_x, ball_y, 20, WHITE);
DrawRectangle(rect_left_x, height - rect_height, rect_width, rect_height, WHITE);
}
EndDrawing();
}
CloseWindow();
}
// 绘制小球的同时, 绘制向左匀速移动的方块: 在 3_3_1 基础上增加 rect_vx
void demo_3_3_2()
{
float width = 600;
float height = 400;
InitWindow(width, height, "don't touch the square");
SetTargetFPS(60);
float gravity = 0.6;
float radius = 20;
float ball_x = width / 4;
float ball_y = height - radius;
float ball_vy = 0;
float rect_height = 100; // 方块高度
float rect_width = 20; // 方块宽度
float rect_left_x = width * 3 / 4; // 方块左边 x 坐标
float rect_top_y = height - rect_height; // 方块顶部 y 坐标
float rect_vx = -3;
while (!WindowShouldClose())
{
// Update
if (GetKeyPressed() == ' ')
{
ball_vy = -16; // 当按下空格键时, 给小球一个向上的初速度
}
else if (GetKeyPressed() == 'q') // 对应到 ESC 键而不是q键,很奇怪
{
break;
}
ball_vy = ball_vy + gravity; // 根据重力加速度,更新小球y方向速度
ball_y = ball_y + ball_vy; // 根据小球y方向速度更新其y坐标
if (ball_y >= height - radius) // 如果小球落到地面上
{
ball_vy = 0; // y 速度为0
ball_y = height - radius; // 规范其y坐标,避免落到地面下
}
rect_left_x = rect_left_x + rect_vx;
if (rect_left_x <= 0)
{
rect_left_x = width; // 在最右边重新出现
}
// Draw
BeginDrawing();
{
ClearBackground(BLACK);
DrawCircle(ball_x, ball_y, 20, WHITE);
DrawRectangle(rect_left_x, height - rect_height, rect_width, rect_height, WHITE);
}
EndDrawing();
}
CloseWindow();
}
// 基于demo_3_3_2(), 检测到小球和方块碰撞时,Sleep()一段时间实现类似慢动作的效果
void demo_3_4_2()
{
float width = 600;
float height = 400;
InitWindow(width, height, "don't touch the square");
SetTargetFPS(60);
float gravity = 0.6;
float radius = 20;
float ball_x = width / 4;
float ball_y = height - radius;
float ball_vy = 0;
float rect_height = 100; // 方块高度
float rect_width = 20; // 方块宽度
float rect_left_x = width * 3 / 4; // 方块左边 x 坐标
float rect_top_y = height - rect_height; // 方块顶部 y 坐标
float rect_vx = -3;
while (!WindowShouldClose())
{
rect_vx = -3;
// Update
if (GetKeyPressed() == ' ')
{
ball_vy = -16; // 当按下空格键时, 给小球一个向上的初速度
}
else if (GetKeyPressed() == 'q') // 对应到 ESC 键而不是q键,很奇怪
{
break;
}
ball_vy = ball_vy + gravity; // 根据重力加速度,更新小球y方向速度
ball_y = ball_y + ball_vy; // 根据小球y方向速度更新其y坐标
if (ball_y >= height - radius) // 如果小球落到地面上
{
ball_vy = 0; // y 速度为0
ball_y = height - radius; // 规范其y坐标,避免落到地面下
}
// 由于 raylib 是一开始生成窗口时就指定了 FPS, 这里碰撞的效果不能像 easyx 一样直接调用 Sleep()
// 解决办法是,在更新 rect_left_x 之前判断和减小 rect_vx 的绝对值。
// 并且在每一帧的最初处理部分, 恢复 rect_vx = -3
if ( (rect_left_x <= ball_x + radius)
&& (rect_left_x + rect_width >= ball_x - radius)
&& (height - rect_height <= ball_y + radius))
{
rect_vx = -1;
}
rect_left_x = rect_left_x + rect_vx;
if (rect_left_x <= 0)
{
rect_left_x = width; // 在最右边重新出现
}
// Draw
BeginDrawing();
{
ClearBackground(BLACK);
DrawCircle(ball_x, ball_y, 20, WHITE);
DrawRectangle(rect_left_x, height - rect_height, rect_width, rect_height, WHITE);
}
EndDrawing();
}
CloseWindow();
}
// 当方块重新出现时, 随机方块的速度和高度. 基于 demo_3_4_2
void demo_3_5_4()
{
float width = 600;
float height = 400;
InitWindow(width, height, "don't touch the square");
SetTargetFPS(60);
float gravity = 0.6;
float radius = 20;
float ball_x = width / 4;
float ball_y = height - radius;
float ball_vy = 0;
float rect_height = 100; // 方块高度
float rect_width = 20; // 方块宽度
float rect_left_x = width * 3 / 4; // 方块左边 x 坐标
float rect_top_y = height - rect_height; // 方块顶部 y 坐标
float rect_vx = -3;
float old_rect_vx = -3; // 之前用于碰撞减速的trick,更新为使用变量记录前一次的速度
while (!WindowShouldClose())
{
rect_vx = old_rect_vx;
// Update
if (GetKeyPressed() == ' ')
{
ball_vy = -16; // 当按下空格键时, 给小球一个向上的初速度
}
else if (GetKeyPressed() == 'q') // 对应到 ESC 键而不是q键,很奇怪
{
break;
}
ball_vy = ball_vy + gravity; // 根据重力加速度,更新小球y方向速度
ball_y = ball_y + ball_vy; // 根据小球y方向速度更新其y坐标
if (ball_y >= height - radius) // 如果小球落到地面上
{
ball_vy = 0; // y 速度为0
ball_y = height - radius; // 规范其y坐标,避免落到地面下
}
// 由于 raylib 是一开始生成窗口时就指定了 FPS, 这里碰撞的效果不能像 easyx 一样直接调用 Sleep()
// 解决办法是,在更新 rect_left_x 之前判断和减小 rect_vx 的绝对值。
// 并且在每一帧的最初处理部分, 恢复 rect_vx = -3
if ( (rect_left_x <= ball_x + radius)
&& (rect_left_x + rect_width >= ball_x - radius)
&& (height - rect_height <= ball_y + radius))
{
old_rect_vx = rect_vx;
rect_vx = rect_vx + 2;
}
rect_left_x = rect_left_x + rect_vx;
if (rect_left_x <= 0)
{
rect_left_x = width; // 在最右边重新出现
rect_height = rand() % int(height / 4) + height / 4; // 方块高度, 设置为随机的高度
rect_vx = rand() / float(RAND_MAX) * 4 - 7; // [0, 4] - 7 = [-7, -3]
old_rect_vx = rect_vx;
}
// Draw
BeginDrawing();
{
ClearBackground(BLACK);
DrawCircle(ball_x, ball_y, 20, WHITE);
DrawRectangle(rect_left_x, height - rect_height, rect_width, rect_height, WHITE);
}
EndDrawing();
}
CloseWindow();
}
// 加入得分机制,并显示得分
// 在书上代码基础上, 增加得分的时机从“方块到达左边边界”改为:当前方块没有和小球发生碰撞,并且小球刚刚跳过方块时,得分增加
void demo_3_6()
{
float width = 600;
float height = 400;
InitWindow(width, height, "don't touch the square");
SetTargetFPS(60);
float gravity = 0.6;
float radius = 20;
float ball_x = width / 4;
float ball_y = height - radius;
float ball_vy = 0;
float rect_height = 100; // 方块高度
float rect_width = 20; // 方块宽度
float rect_left_x = width * 3 / 4; // 方块左边 x 坐标
float rect_top_y = height - rect_height; // 方块顶部 y 坐标
float rect_vx = -3;
float old_rect_vx = -3; // 之前用于碰撞减速的trick,更新为使用变量记录前一次的速度
int score = 0;
bool first_time_being_left = false;
bool collision = false;
while (!WindowShouldClose())
{
rect_vx = old_rect_vx;
// Update
if (GetKeyPressed() == ' ')
{
ball_vy = -16; // 当按下空格键时, 给小球一个向上的初速度
}
else if (GetKeyPressed() == 'q') // 对应到 ESC 键而不是q键,很奇怪
{
break;
}
ball_vy = ball_vy + gravity; // 根据重力加速度,更新小球y方向速度
ball_y = ball_y + ball_vy; // 根据小球y方向速度更新其y坐标
if (ball_y >= height - radius) // 如果小球落到地面上
{
ball_vy = 0; // y 速度为0
ball_y = height - radius; // 规范其y坐标,避免落到地面下
}
// 如果小球碰到方块
// 由于 raylib 是一开始生成窗口时就指定了 FPS, 这里碰撞的效果不能像 easyx 一样直接调用 Sleep()
// 解决办法是,在更新 rect_left_x 之前判断和减小 rect_vx 的绝对值。
// 并且在每一帧的最初处理部分, 恢复 rect_vx = -3
if ( (rect_left_x <= ball_x + radius)
&& (rect_left_x + rect_width >= ball_x - radius)
&& (height - rect_height <= ball_y + radius))
{
score = 0;
collision = true;
old_rect_vx = rect_vx;
rect_vx = rect_vx + 2;
}
// 如果方块没有和小球碰撞,那么方块刚刚处于小球左边时,增加得分
if (rect_left_x + rect_width < ball_x - radius && first_time_being_left == false && collision == false)
{
first_time_being_left = true;
score++; // 增加得分
}
rect_left_x = rect_left_x + rect_vx;
// 如果方块跑到最左边
if (rect_left_x <= 0)
{
rect_left_x = width; // 在最右边重新出现
first_time_being_left = false;
collision = false;
rect_height = rand() % int(height / 4) + height / 4; // 方块高度, 设置为随机的高度
rect_vx = rand() / float(RAND_MAX) * 4 - 7; // [0, 4] - 7 = [-7, -3]
old_rect_vx = rect_vx;
}
char s[20] = { 0 };
sprintf(s, "score: %d", score);
// Draw
BeginDrawing();
{
ClearBackground(BLACK);
DrawCircle(ball_x, ball_y, 20, WHITE);
DrawRectangle(rect_left_x, height - rect_height, rect_width, rect_height, WHITE);
const int pos_x = 50;
const int pos_y = 30;
const int font_size = 40;
DrawText(s, pos_x, pos_y, font_size, LIGHTGRAY);
}
EndDrawing();
}
CloseWindow();
}
int main()
{
//demo_3_1_3();
//demo_3_2();
//demo_3_3_1();
//demo_3_3_2();
//demo_3_4_2();
//demo_3_5_4();
demo_3_6();
return 0;
}
Greatness is never a given, it must be earned.