diff --git a/pong2.cpp b/pong2.cpp index ae47c10..3091283 100644 --- a/pong2.cpp +++ b/pong2.cpp @@ -12,7 +12,7 @@ constexpr uint16_t SPRITE_POSITION_REGISTERS = VIDEO_REGISTERS; constexpr uint16_t SPRITE_COLLISIONS = VIDEO_REGISTERS + 30; constexpr uint16_t SPRITE_MULTICOLOR = VIDEO_REGISTERS + 28; constexpr uint16_t VIDEO_MEMORY = 1024; -constexpr auto starting_bank = 192; +constexpr uint8_t SPRITE_STARTING_BANK = 192; namespace { @@ -22,268 +22,164 @@ volatile uint8_t &memory(const uint16_t loc) return *reinterpret_cast(loc); } -struct Color +constexpr bool test_bit(const uint8_t data, const uint8_t bit) { - enum class Name : uint8_t { - Black = 0, - White = 1, - Red = 2, - Cyan = 3, - Purple = 4, - Green = 5, - Blue = 6, - Yellow = 7, - Orange = 8, - Brown = 9, - LightRed = 10, - DarkGrey = 11, - Grey = 12, - LightGreen = 13, - LightBlue = 14, - LightGrey = 15 - }; - - constexpr Color(const Name t_name, const uint8_t t_r, const uint8_t t_g, const uint8_t t_b) - : name(t_name), r(t_r), g(t_g), b(t_b) - { - } - - Name name; - uint8_t r; - uint8_t g; - uint8_t b; + return (data & (1 << bit)) != 0; }; - -template -constexpr auto square(T t) + +void set_bit(const uint16_t loc, const uint8_t bitnum, bool val) { - return t*t; -} - -constexpr auto distance(const Color &lhs, const uint8_t t_r, const uint8_t t_g, const uint8_t t_b) -{ - // http://stackoverflow.com/questions/4754506/color-similarity-distance-in-rgba-color-space - return square(lhs.r - t_r) + square(lhs.g - t_g) + square(lhs.b - t_b); -} - -template -constexpr auto distance_table(T colors, const uint8_t t_r, const uint8_t t_g, const uint8_t t_b) -{ - std::array distances{}; - auto pos = std::begin(distances); - - - for (const auto &color : colors) { - *pos = distance(color, t_r, t_g, t_b); - ++pos; + if (val) { + memory(loc) |= (1 << bitnum); + } else { + memory(loc) &= (0xFF ^ (1 << bitnum)); } - - return distances; -} - -template - constexpr Color nearest_color(T colors, - const uint8_t t_r, const uint8_t t_g, const uint8_t t_b) -{ - const auto ds = distance_table(colors, t_r, t_g, t_b); - const auto distance = std::min_element(std::begin(ds), std::end(ds)) - std::begin(ds); - return colors[distance]; - - /* - return *std::min_element(std::begin(colors), std::end(colors), - [&](const auto &lhs, const auto &rhs) - { - return distance(lhs, t_r, t_g, t_b) < distance(rhs, t_r, t_g, t_b); - }); - */ -} - -void clear_bit(const uint16_t loc, const uint8_t bitnum) -{ - memory(loc) &= (0xFF ^ (1 << bitnum)); -} - -void set_bit(const uint16_t loc, const uint8_t bitnum) -{ - memory(loc) |= (1 << bitnum); } void write_multi_color_pixel(uint16_t) { } +void write_pixel(uint16_t) +{ +} + + template void write_multi_color_pixel(uint16_t loc, D1 d1, D2 d2, D3 d3, D4 d4, D ... d) { memory(loc) = (d1 << 6) | (d2 << 4) | (d3 << 2) | d4; write_multi_color_pixel(loc + 1, d...); } - -constexpr bool test_bit(const uint8_t data, const uint8_t bit) -{ - return (data & (1 << bit)) != 0; -}; - - +template + void write_pixel(uint16_t loc, D1 d1, D2 d2, D3 d3, D4 d4, D5 d5, D6 d6, D7 d7, D8 d8, D ... d) +{ + memory(loc) = (d1 << 7) | (d2 << 6) | (d3 << 5) | (d4 << 4) | (d5 << 3) | (d6 << 2) | (d7 << 1) | d8; + write_pixel(loc + 1, d...); +} + + template void make_sprite(uint8_t memory_loc, D ... d) { - write_multi_color_pixel((starting_bank + memory_loc) * 64, d...); + if constexpr (sizeof...(d) == 12 * 21) { + write_multi_color_pixel((SPRITE_STARTING_BANK + memory_loc) * 64, d...); + } else { + write_pixel((SPRITE_STARTING_BANK + memory_loc) * 64, d...); + } } - - + void enable_sprite(const uint8_t sprite_number, const uint8_t memory_loc, const bool multicolor, const bool double_width, const bool double_height) { - set_bit(SPRITE_ENABLE_BITS, sprite_number); - memory(SPRITE_DATA_POINTERS + sprite_number) = starting_bank + memory_loc; - if (double_width) { - set_bit(SPRITE_EXPAND_HORIZONTAL, sprite_number); - } else { - clear_bit(SPRITE_EXPAND_HORIZONTAL, sprite_number); - } - - if (double_height) { - set_bit(SPRITE_EXPAND_VERTICAL, sprite_number); - } else { - clear_bit(SPRITE_EXPAND_VERTICAL, sprite_number); - } - - if (multicolor) { - set_bit(SPRITE_MULTICOLOR, sprite_number); - } else { - clear_bit(SPRITE_MULTICOLOR, sprite_number); - } - + set_bit(SPRITE_ENABLE_BITS, sprite_number, true); + memory(SPRITE_DATA_POINTERS + sprite_number) = SPRITE_STARTING_BANK + memory_loc; + set_bit(SPRITE_EXPAND_HORIZONTAL, sprite_number, double_width); + set_bit(SPRITE_EXPAND_VERTICAL, sprite_number, double_height); + set_bit(SPRITE_MULTICOLOR, sprite_number, multicolor); } -void display_int(uint8_t x, uint8_t y, uint8_t val) +void display(uint8_t x, uint8_t y, uint8_t val) { memory(VIDEO_MEMORY + y * 40 + x) = val; } - - + +auto joystick(const uint8_t port) { + struct State{ + State(const uint8_t portdata) + : up(!test_bit(portdata,0)), + down(!test_bit(portdata,1)), + left(!test_bit(portdata,2)), + right(!test_bit(portdata,3)), + fire(!test_bit(portdata,4)) + { + } + + bool up; + bool down; + bool left; + bool right; + bool fire; + }; + + if (port == 2) { + return State(memory(56320)); + } else { + return State(memory(56321)); + } +}; + + +volatile uint8_t &sprite_x(const uint8_t sprite_num) +{ + return memory(SPRITE_POSITION_REGISTERS + sprite_num * 2); +}; + +volatile uint8_t &sprite_y(const uint8_t sprite_num) +{ + return memory(SPRITE_POSITION_REGISTERS + sprite_num * 2 + 1); +}; + } - - int main() { - constexpr std::array colors {Color{Color::Name::Black, 0,0,0}, - Color{Color::Name::White, 255,255,255}, - Color{Color::Name::Red, 104, 55, 43}, - Color{Color::Name::Cyan, 112, 164, 178}, - Color{Color::Name::Purple, 111, 61, 134}, - Color{Color::Name::Green, 88, 141, 67}, - Color{Color::Name::Blue, 53, 40, 121}, - Color{Color::Name::Yellow, 184, 199, 111}, - Color{Color::Name::Orange, 111, 79, 37}, - Color{Color::Name::Brown, 67, 57, 0}, - Color{Color::Name::LightRed, 154, 103, 89}, - Color{Color::Name::DarkGrey, 68, 68, 68}, - Color{Color::Name::Grey, 108, 108, 108}, - Color{Color::Name::LightGreen, 154, 210, 132}, - Color{Color::Name::LightBlue, 108, 94, 181}, - Color{Color::Name::LightGrey, 149, 149, 149}}; - - //constexpr auto nearest_black = nearest_color(colors, 0, 0, 0); - //constexpr auto nearest_red = nearest_color(colors, 255, 255, 0); - - make_sprite(0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,2,2,2,2,0,0,0,0, - 0,0,0,2,2,2,2,2,2,0,0,0, - 0,0,2,2,2,1,1,2,2,2,0,0, - 0,0,2,2,1,1,1,1,2,2,0,0, - 0,0,2,2,1,1,1,1,2,2,0,0, - 0,0,2,2,1,1,1,1,2,2,0,0, - 0,0,2,2,1,1,1,1,2,2,0,0, - 0,0,2,2,1,1,1,1,2,2,0,0, - 0,0,2,2,1,1,1,1,2,2,0,0, - 0,0,2,2,1,1,1,1,2,2,0,0, - 0,0,2,2,2,1,1,2,2,2,0,0, - 0,0,0,2,2,2,2,2,2,0,0,0, - 0,0,0,0,2,2,2,2,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0 + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0, + 0,0,0,0,0,0,1,1,0,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0, + 0,0,0,0,0,1,1,0,0,0,1,1,1,1,1,1,1,1,1,0,0,0,0,0, + 0,0,0,0,0,1,1,1,0,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0, + 0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0, + 0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0, + 0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0, + 0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0, + 0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0, + 0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0, + 0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0, + 0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0, + 0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0, + 0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ); - - enable_sprite(0, 0, true, false, false); + + enable_sprite(0, 0, false, false, false); make_sprite(1, - 0,0,0,0,1,1,1,1,0,0,0,0, - 0,0,0,0,1,1,1,1,0,0,0,0, - 0,0,0,0,1,1,1,1,0,0,0,0, - 0,0,0,0,1,1,1,1,0,0,0,0, - 0,0,0,0,2,2,2,2,0,0,0,0, - 0,0,0,0,2,2,2,2,0,0,0,0, - 0,0,0,0,2,1,1,2,0,0,0,0, - 0,0,0,0,1,1,1,1,0,0,0,0, - 0,0,0,0,1,1,1,1,0,0,0,0, - 0,0,0,0,1,1,1,1,0,0,0,0, - 0,0,0,0,1,1,1,1,0,0,0,0, - 0,0,0,0,1,1,1,1,0,0,0,0, - 0,0,0,0,1,1,1,1,0,0,0,0, - 0,0,0,0,1,1,1,1,0,0,0,0, - 0,0,0,0,2,1,1,2,0,0,0,0, - 0,0,0,0,2,2,2,2,0,0,0,0, - 0,0,0,0,2,2,2,2,0,0,0,0, - 0,0,0,0,1,1,1,1,0,0,0,0, - 0,0,0,0,1,1,1,1,0,0,0,0, - 0,0,0,0,1,1,1,1,0,0,0,0, - 0,0,0,0,1,1,1,1,0,0,0,0 + 0,0,0,0,0,2,2,0,0,0,0,0, + 0,0,0,0,0,2,2,0,0,0,0,0, + 0,0,0,0,0,2,2,0,0,0,0,0, + 0,0,0,0,0,2,2,0,0,0,0,0, + 0,0,0,0,0,2,2,0,0,0,0,0, + 0,0,0,0,0,2,2,0,0,0,0,0, + 0,0,0,0,0,2,2,0,0,0,0,0, + 0,0,0,0,0,2,2,0,0,0,0,0, + 0,0,0,0,0,2,2,0,0,0,0,0, + 0,0,0,0,0,2,2,0,0,0,0,0, + 0,0,0,0,0,2,2,0,0,0,0,0, + 0,0,0,0,0,2,2,0,0,0,0,0, + 0,0,0,0,0,2,2,0,0,0,0,0, + 0,0,0,0,0,2,2,0,0,0,0,0, + 0,0,0,0,0,2,2,0,0,0,0,0, + 0,0,0,0,0,2,2,0,0,0,0,0, + 0,0,0,0,0,3,3,0,0,0,0,0, + 0,0,0,0,0,1,1,0,0,0,0,0, + 0,0,0,0,0,3,3,0,0,0,0,0, + 0,0,0,0,0,1,1,0,0,0,0,0, + 0,0,0,0,0,3,3,0,0,0,0,0 ); - + enable_sprite(1, 1, true, false, true); enable_sprite(2, 1, true, false, true); - const auto joy = [](const uint8_t d){ - struct State{ - State(const uint8_t portdata) - : up(!test_bit(portdata,0)), - down(!test_bit(portdata,1)), - left(!test_bit(portdata,2)), - right(!test_bit(portdata,3)), - fire(!test_bit(portdata,4)) - { - } - bool up; - bool down; - bool left; - bool right; - bool fire; - }; - return State(d); - }; - - const auto joy_port2 = [joy](){ - return joy(memory(56320)); - }; - - const auto joy_port1 = [joy](){ - return joy(memory(56321)); - }; - - - const auto sprite_x = [](const uint8_t sprite_num) -> decltype(auto) - { - return (memory(SPRITE_POSITION_REGISTERS + sprite_num * 2)); - }; - - const auto sprite_y = [](const uint8_t sprite_num) -> decltype(auto) - { - return (memory(SPRITE_POSITION_REGISTERS + sprite_num * 2 + 1)); - }; - const auto sprite_collisions = []() { const auto collisions = memory(SPRITE_COLLISIONS); memory(SPRITE_COLLISIONS) = 0; @@ -302,10 +198,7 @@ int main() test_bit(collisions, 4),test_bit(collisions, 5),test_bit(collisions, 6),test_bit(collisions, 7)}; }; - std::pair ball_vec{1,1}; - uint8_t player1 = '0'; - uint8_t player2 = '0'; const auto reset_ball = [&]{ sprite_x(0) = 255/2; @@ -314,67 +207,79 @@ int main() reset_ball(); - sprite_x(1) = 20; - sprite_y(1) = 50; + sprite_x(1) = 15; + sprite_y(1) = 255/2; sprite_x(2) = 255; - sprite_y(2) = 150; + sprite_y(2) = 255/2; - uint8_t num_volleys = 0; + memory(53280) = 12; + memory(53281) = 0; + + + struct Player + { + void update_position() + { + if (const auto joy = joystick(player_num); + joy.up) + { + sprite_y(player_num) += 3; + } else if (joy.down) { + sprite_y(player_num) -= 3; + } + }; + + void scored() { + ++score; + } + + const uint8_t player_num; + uint8_t score = '0'; + }; + + Player p1{1}; + Player p2{2}; + + const auto raster_off_screen = [](){ + return memory(53266) == 250 && !test_bit(memory(53265),7); + }; while (true) { - - if (memory(53266) == 245 - && !test_bit(memory(53265),7)) { - + if (raster_off_screen()) + { if (const auto collisions = sprite_collisions(); collisions.sprite0 && (collisions.sprite1 || collisions.sprite2)) { std::get<0>(ball_vec) *= -1; //invert ball x velocity - // "bounce" vall out of collision area + // "bounce" ball out of collision area sprite_x(0) += std::get<0>(ball_vec); - ++num_volleys; } -// if (num_volleys == 10) { -// std::get<0>(ball_vec) += 1; -// } - - const auto ball_x = sprite_x(0) += std::get<0>(ball_vec); - const auto ball_y = sprite_y(0) += std::get<1>(ball_vec); - // Update paddle positions - if (const auto joy = joy_port1(); joy.up) - { - sprite_y(1) += 3; - } else if (joy.down) { - sprite_y(1) -= 3; - } - - if (const auto joy = joy_port2(); joy.up) - { - sprite_y(2) += 3; - } else if (joy.down) { - sprite_y(2) -= 3; - } + p1.update_position(); + p2.update_position(); // ball hit the top or bottom wall - if (ball_y == 45 || ball_y == 235) { + if (const auto ball_y = sprite_y(0) += std::get<1>(ball_vec); + ball_y == 45 || ball_y == 235) + { std::get<1>(ball_vec) *= -1; } - if (ball_x == 1) { + if (const auto ball_x = sprite_x(0) += std::get<0>(ball_vec); + ball_x == 1) { // ball hit left wall, player 2 scored - ++player2; + p2.scored(); reset_ball(); } else if (ball_x == 255) { // ball hit right wall, player 1 scored - ++player1; + p1.scored(); reset_ball(); } - display_int(10, 12, player1); - display_int(30, 12, player2); + display(10, 12, p1.score); + display(30, 12, p2.score); } } }