跳动的爱心 程序

 

609c72c017d44ab886f310a1400d813b.png

 654aa9bc1d78421492e470114587c8a3.png

 

 #include <stdlib.h>

#include <stdio.h>

#include <math.h>

#include <time.h>

#include <SDL2/SDL.h>

#define HEART_POINTS_NUM 2000

#define EDGE_POINTS_NUM 6000

#define CENTER_POINTS_NUM 8000

#define FRAMES_NUM 20

#define FRAMES_SIZE 20466 // HEART_POINTS_NUM + EDGE_POINTS_NUM + CENTER_POINTS_NUM + halo_num 的最大可能值(见 create_heart 函数)

SDL_Point frames[FRAMES_NUM][FRAMES_SIZE];

const int speed[4] = { 8, 16, 32, 64 };

int current_speed_index = 0; // [0, speed array's size]

int current_render_frame = 0; // [0, FRAMES_NUM]

int pause = 0; // 是否暂停

//屏幕宽度

const int WINDOW_WIDTH = 1080;

//屏幕高度

const int WINDOW_HEIGHT = 1920;

const int ORIGIN_X = WINDOW_WIDTH / 2;

const int ORIGIN_Y = WINDOW_HEIGHT / 2;

const int IMAGE_ENLARGE = 20;

// Utils

double random_double(double min, double max) {

    double range = (max - min);

    double div = RAND_MAX / range;

    return min + (rand() / div);

}

int random_int(int min, int max) {

    return min + rand() / (RAND_MAX / (max - min + 1) + 1);

}

// x = 16sin^3(t)

// y = 13cos(t) - 5cos(2t) - 2cos(3t) - cos(4t)

// t: [0, 2pi]

SDL_Point heart_point(double t, double shrink_ratio) {

    double x = 16 * pow(sin(t), 3);

    double y = -(13 * cos(t) - 5 * cos(2 * t) - 2 * cos(3 * t) - cos(4 * t));

    // enlarge

    x *= shrink_ratio;

    y *= shrink_ratio;

    // shift

    x += ORIGIN_X;

    y += ORIGIN_Y;

    SDL_Point p = { x, y };

    return p;

}

SDL_Point scatter_inside(int x, int y, double beta) {

    double ratio_x = -beta * log(random_double(0.0, 1.0));

    double ratio_y = -beta * log(random_double(0.0, 1.0));

    double dx = ratio_x * (x - ORIGIN_X);

    double dy = ratio_y * (y - ORIGIN_Y);

    SDL_Point p = { x - dx, y - dy };

    return p;

}

SDL_Point shrink(int x, int y, double ratio) {

    double force = -1.0 / (pow(pow(x - ORIGIN_X, 2) + pow(y - ORIGIN_Y, 2), 0.6));

    int dx = ratio * force * (x - ORIGIN_X);

    int dy = ratio * force * (y - ORIGIN_Y);

    SDL_Point p = { x - dx, y - dy };

    return p;

}

double curve(double p) {

    return 2.0 * (2.0 * sin(4.0 * p)) / (2.0 * M_PI);

}

SDL_Point calc_position(int x, int y, double ratio) {

    double force = 1.0 / (pow(pow(x - ORIGIN_X, 2) + pow(y - ORIGIN_Y, 2), 0.520));

    double dx = ratio * force * (x - ORIGIN_X) + random_int(-1, 1);

    double dy = ratio * force * (y - ORIGIN_Y) + random_int(-1, 1);

    SDL_Point p = { x - dx, y - dy };

    return p;

}

void create_heart() {

    // 基础爱心

    SDL_Point heart_points[HEART_POINTS_NUM];

    for (int i = 0; i < HEART_POINTS_NUM; ++i) {

        double t = random_double(0.0, 2 * M_PI);

        heart_points[i] = heart_point(t, IMAGE_ENLARGE);

    }

    // 基础爱心上每个点向内扩散3个点

    SDL_Point edge_points[EDGE_POINTS_NUM];

    int index = 0;

    for (int i = 0; i < HEART_POINTS_NUM; ++i) {

        for (int j = 0; j < 3; ++j) {

            edge_points[index] = scatter_inside(heart_points[i].x, heart_points[i].y, 0.05);

            index++;

        }

    }

    // 向更中心位置添加4000个点,随机选取基础爱心上的点进行扩散

    SDL_Point center_points[CENTER_POINTS_NUM];

    for (int j = 0; j < CENTER_POINTS_NUM; ++j) {

        SDL_Point random_heart_point = heart_points[random_int(0, HEART_POINTS_NUM)];

        center_points[j] = scatter_inside(random_heart_point.x, random_heart_point.y, 0.17);

    }

    // 生成所有帧

    for (int i = 0; i < FRAMES_NUM; ++i) {

        int index2 = 0;

        // 外侧光晕

        int halo_num = 3000 + (int)(4000 * pow(curve(i * 1.0 / 10.0 * M_PI), 2)); // 3000-4466

        int halo_radius = 4 + 6 * (1 + curve(i / 10 * M_PI));

        for (int j = 0; j < halo_num; ++j) {

            double t = random_double(0.0, 2 * M_PI);

            SDL_Point tmp_p = heart_point(t, IMAGE_ENLARGE-2);

            tmp_p = shrink(tmp_p.x, tmp_p.y, halo_radius);

            SDL_Point p = {

                tmp_p.x + random_int(-14, 14),

                tmp_p.y + random_int(-14, 14)

            };

            frames[i][index2] = p;

            index2++;

        }

        double ratio = 10.0 * curve(i / 10.0 * M_PI); // 圆滑的周期的缩放比例

        // 根据缩放比例映射基础爱心、内沿和中心所有的点

        for (int j = 0; j < HEART_POINTS_NUM; ++j) {

            frames[i][index2] = calc_position(heart_points[j].x, heart_points[j].y, ratio);

            index2++;

        }

        for (int j = 0; j < EDGE_POINTS_NUM; ++j) {

            frames[i][index2] = calc_position(edge_points[j].x, edge_points[j].y, ratio);

            index2++;

        }

        for (int j = 0; j < CENTER_POINTS_NUM; ++j) {

            frames[i][index2] = calc_position(center_points[j].x, center_points[j].y, ratio);

            index2++;

        }

    }

}

Uint32 lastupdate = 0;

void update() {

    Uint32 current = SDL_GetTicks();

    const Uint32 per_frame_in_ms = 1000 / speed[current_speed_index];

    if (current - lastupdate >= per_frame_in_ms) {

        lastupdate = current;

        // Core update logic

        current_render_frame++;

        if (current_render_frame >= FRAMES_NUM) {

            current_render_frame = 0;

        }

    }

}

void draw(SDL_Renderer* renderer) {

    SDL_SetRenderDrawColor(renderer, 252, 139, 171, 255);

    SDL_RenderDrawPoints(renderer, frames[current_render_frame], FRAMES_SIZE);

}

int main(int argv, char** args) {

    srand(time(NULL));

    // Initial SDL

    if (SDL_Init(SDL_INIT_VIDEO) != 0) {

        printf("SDL_Init HAS FAILED. ERROR: %s\n", SDL_GetError());

        return 1;

    }

    // Initial window

    SDL_Window* window = SDL_CreateWindow(

                             "DRAW HEART",

                             SDL_WINDOWPOS_UNDEFINED,

                             SDL_WINDOWPOS_UNDEFINED,

                             WINDOW_WIDTH,

                             WINDOW_HEIGHT,

                             0

                         );

    if (!window) {

        printf("SDL_CreateWindow HAS FAILED. ERROR: %s\n", SDL_GetError());

        return 1;

    }

    // Initial renderer

    SDL_Renderer* renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);

    if (!renderer) {

        printf("SDL_CreateRenderer HAS FAILED. ERROR: %s\n", SDL_GetError());

        return 1;

    }

    // Initial

    create_heart();

    // Main loop

    int running = 1;

    while (running) {

        // Handle events

        SDL_Event e;

        while (SDL_PollEvent(&e)) {

            if (e.type == SDL_QUIT) {

                running = 0;

            } else if (e.type == SDL_KEYUP) {

                switch (e.key.keysym.sym) {

                case SDLK_TAB:

                    current_speed_index++;

                    if (current_speed_index >= 4) {

                        current_speed_index = 0;

                    }

                    break;

                default:

                    break;

                }

            } else if (e.type == SDL_KEYDOWN) {

                switch (e.key.keysym.sym) {

                case SDLK_SPACE:

                    pause = !pause;

                    break;

                default:

                    break;

                }

            }

        }

        // Update

        if (!pause) {

            update();

        }

        // Start draw

        // Erase the last frame in dark

        SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);

        SDL_RenderClear(renderer);

        // Draw stuff

        draw(renderer);

        // Draw current frame to screen

        SDL_RenderPresent(renderer);

    }

    // Clean up

    SDL_DestroyWindow(window);

    SDL_DestroyRenderer(renderer);

    SDL_Quit();

    return 0;

}

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值