.. _program_listing_file_src_animation_lightninganimation.cpp: Program Listing for File lightninganimation.cpp =============================================== |exhale_lsh| :ref:`Return to documentation for file ` (``src/animation/lightninganimation.cpp``) .. |exhale_lsh| unicode:: U+021B0 .. UPWARDS ARROW WITH TIP LEFTWARDS .. code-block:: cpp #include "../utility.h" #include "lightninganimation.h" namespace PixelMaestro { LightningAnimation::LightningAnimation(Section& section) : Animation(section) { type_ = AnimationType::Lightning; map(); } void LightningAnimation::map() { // Clear the grid for (uint16_t x = 0; x < section_.get_dimensions().x; x++) { for (uint16_t y = 0; y < section_.get_dimensions().y; y++) { set_map_color_index(x, y, 255); } } /* * Assume horizontal movement. Choose a random point on the y-axis starting at 0, then move from left to right. * "102" is the maximum length of the grid that a single fork can cover (102 equates to 40%). */ Point start = {0, 0}; for (uint8_t bolt = 0; bolt < num_bolts_; bolt++) { if (orientation_ == Orientation::Vertical || orientation_ == Orientation::VerticalFlipped) { start.set((uint16_t)Utility::rand(section_.get_dimensions().x), 0); draw_bolt_vertical(bolt, &start, drift_, fork_chance_, 102); } else { start.set(0, (uint16_t)Utility::rand(section_.get_dimensions().y)); draw_bolt_horizontal(bolt, &start, drift_, fork_chance_, 102); } } } void LightningAnimation::update() { map(); update_cycle(0, palette_->get_num_colors()); } void LightningAnimation::draw_bolt_horizontal(uint8_t bolt_num, Point* start, int8_t drift, uint8_t fork_chance, uint8_t max_fork_length) { Point cursor = {start->x, start->y}; /* * Calculate the maximum length of the bolt. * For the main bolt, we set the length equal to the length of the grid. * For forks, we cap the distance at a percentage of the grid length (calculated using max_fork_length). */ uint16_t length; if (cursor.x == 0) { length = section_.get_dimensions().x; } else { if ((cursor.x + (section_.get_dimensions().x * (max_fork_length / (float)100))) > section_.get_dimensions().x) { length = section_.get_dimensions().x - cursor.x; } else { length = cursor.x + (section_.get_dimensions().x * (max_fork_length / (float)100)); } } /* * For each step along the grid, generate a random number and compare it to the drift threshold. * This determines the direction that the bolt moves in. */ for (uint16_t x = cursor.x; x < length; x++) { int8_t drift_roll = Utility::rand(UINT8_MAX) - INT8_MAX; if (drift_roll > drift) { if (cursor.y + 1 < section_.get_dimensions().y) { cursor.y += 1; } } else { if (cursor.y - 1 >= 0) { cursor.y -= 1; } } cursor.x++; set_map_color_index(x, cursor.y, cycle_index_ + bolt_num); // Check to see if we should fork the bolt. if (x < (uint16_t)section_.get_dimensions().x) { uint8_t fork_roll = Utility::rand(UINT8_MAX); if (fork_roll < fork_chance) { /* * If we forked... * 1) Change the drift so that it sends the bolt away from the parent. We do this by increasing the drift threshold to 85% in the opposite direciton, making it extremely likely that the bolt will move that way. * 2) Reduce the chance of another fork by 50%. * 3) Reduce the length of the next fork by a random amount. We don't want forks longer than their parents. */ if (drift_roll < drift) { draw_bolt_horizontal(bolt_num, &cursor, 90, fork_chance / 2, Utility::rand(max_fork_length)); } else { // Invert threshold draw_bolt_horizontal(bolt_num, &cursor, -90, fork_chance / 2, Utility::rand(max_fork_length)); } } } } } void LightningAnimation::draw_bolt_vertical(uint8_t bolt_num, Point* start, int8_t drift, uint8_t fork_chance, uint8_t max_fork_length) { Point cursor = {start->x, start->y}; uint32_t length; if (cursor.y == 0) { length = section_.get_dimensions().y; } else { if (cursor.y + ((section_.get_dimensions().y * (max_fork_length / (float)100))) > section_.get_dimensions().y) { length = section_.get_dimensions().y - cursor.y; } else { length = cursor.y + (section_.get_dimensions().y * (max_fork_length / (float)100)); } } for (uint16_t y = cursor.y; y < length; y++) { int8_t drift_roll = Utility::rand(UINT8_MAX) - INT8_MAX; if (drift_roll < drift) { // Intentionally inverted from draw_bolt_horizontal. if (cursor.x + 1 < section_.get_dimensions().x) { cursor.x += 1; } } else { if (cursor.x - 1 >= 0) { cursor.x -= 1; } } cursor.y++; set_map_color_index(cursor.x, y, cycle_index_ + bolt_num); if (y < (uint16_t)section_.get_dimensions().y) { uint8_t fork_roll = Utility::rand(UINT8_MAX); if (fork_roll < fork_chance) { if (drift_roll > drift) { draw_bolt_vertical(bolt_num, &cursor, 90, fork_chance / 2, Utility::rand(max_fork_length)); } else { draw_bolt_vertical(bolt_num, &cursor, -90, fork_chance / 2, Utility::rand(max_fork_length)); } } } } } uint8_t LightningAnimation::get_bolt_count() const { return num_bolts_; } uint8_t LightningAnimation::get_fork_chance() const { return fork_chance_; } int8_t LightningAnimation::get_drift() const { return drift_; } void LightningAnimation::set_bolt_count(uint8_t bolt_count) { this->num_bolts_ = bolt_count; } void LightningAnimation::set_fork_chance(uint8_t fork_chance) { this->fork_chance_ = fork_chance; } void LightningAnimation::set_drift(int8_t drift) { this->drift_ = drift; } }