From 9b204a4af02a562324273a0a0f792d3842a7603f Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Thu, 8 Sep 2016 19:16:52 -0600 Subject: [PATCH] Pong rework-working --- examples/pong.cpp | 457 ++++++++++++++++++++++++++-------------------- 1 file changed, 254 insertions(+), 203 deletions(-) diff --git a/examples/pong.cpp b/examples/pong.cpp index 41d97e3..0a35972 100644 --- a/examples/pong.cpp +++ b/examples/pong.cpp @@ -4,29 +4,23 @@ #include #include -constexpr uint16_t JOYSTICK_PORT_A = 56320; // joystick #2 -constexpr uint16_t JOYSTICK_PORT_B = 56321; // joystick #1 -constexpr uint16_t SPRITE_DATA_POINTERS = 2040; -constexpr uint16_t VIDEO_REGISTERS = 53248; -constexpr uint16_t SPRITE_ENABLE_BITS = VIDEO_REGISTERS + 21; -constexpr uint16_t SPRITE_EXPAND_HORIZONTAL = VIDEO_REGISTERS + 29; -constexpr uint16_t SPRITE_EXPAND_VERTICAL = VIDEO_REGISTERS + 23; -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 SPRITE_PRIORITY = VIDEO_REGISTERS + 27; -constexpr uint16_t VIDEO_MEMORY = 1024; -constexpr uint8_t SPRITE_STARTING_BANK = 192; -constexpr uint16_t BORDER_COLOR = 53280; -constexpr uint16_t BACKGROUND_COLOR = 53281; -constexpr uint16_t SPRITE_0_COLOR = VIDEO_REGISTERS + 39; -constexpr uint16_t SPRITE_1_COLOR = SPRITE_0_COLOR + 1; -constexpr uint16_t SPRITE_2_COLOR = SPRITE_1_COLOR + 1; - - namespace { + volatile uint8_t &memory(const uint16_t loc) + { + return *reinterpret_cast(loc); + } + template + auto square(T t) { + return t * t; + } + + constexpr bool test_bit(const uint8_t data, const uint8_t bit) + { + return (data & (1 << bit)) != 0; + }; + struct Color { uint8_t num; @@ -35,15 +29,63 @@ namespace { uint8_t b; }; - volatile uint8_t &memory(const uint16_t loc) + struct JoyStick { - return *reinterpret_cast(loc); + static constexpr uint16_t JOYSTICK_PORT_A = 56320; // joystick #2 + static constexpr uint16_t JOYSTICK_PORT_B = 56321; // joystick #1 + + struct PortData + { + uint8_t data; + }; + + JoyStick(const PortData d) + : up(!test_bit(d.data, 0)), + down(!test_bit(d.data, 1)), + left(!test_bit(d.data, 2)), + right(!test_bit(d.data, 3)), + fire(!test_bit(d.data, 4)) + { + } + + JoyStick(const uint8_t port_num) + : JoyStick(PortData{port_num==2?memory(JOYSTICK_PORT_A):memory(JOYSTICK_PORT_B)}) + { + } + + auto direction_vector() const + { + return std::make_pair(left?-1:(right?1:0), up?-1:(down?1:0)); + } + + bool up,down,left,right,fire; + }; + + /// New Code + + template + auto operator+(std::pair lhs, const std::pair &rhs) + { + lhs.first += rhs.first; + lhs.second += rhs.second; + return lhs; } - constexpr bool test_bit(const uint8_t data, const uint8_t bit) + template + decltype(auto) operator+=(std::pair &lhs, const std::pair &rhs) { - return (data & (1 << bit)) != 0; - }; + lhs.first += rhs.first; + lhs.second += rhs.second; + return (lhs); + } + + template + decltype(auto) operator*=(std::pair &lhs, const std::pair &rhs) + { + lhs.first *= rhs.first; + lhs.second *= rhs.second; + return (lhs); + } void set_bit(const uint16_t loc, const uint8_t bitnum, bool val) { @@ -53,142 +95,20 @@ namespace { memory(loc) &= (0xFF ^ (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...); - } - - 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) - { - 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 low_priority, - const bool double_width, const bool double_height) - { - memory(SPRITE_DATA_POINTERS + sprite_number) = SPRITE_STARTING_BANK + memory_loc; - set_bit(SPRITE_ENABLE_BITS, sprite_number, true); - 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); - set_bit(SPRITE_PRIORITY, sprite_number, low_priority); - } - - 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; - - auto direction_vector() const - { - return std::make_pair(left?-1:(right?1:0), up?-1:(down?1:0)); - } - }; - - if (port == 2) { - return State(memory(JOYSTICK_PORT_A)); - } else { - return State(memory(JOYSTICK_PORT_B)); - } - }; - - - 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); - }; - - template - auto square(T t) { - return t * t; - } - - template - auto color_distance(const Color &lhs, const Color &rhs) - { - return (square(lhs.r - r) + square(lhs.g - g) + square(lhs.b - b)) - < (square(rhs.r - r) + square(rhs.g - g) + square(rhs.b - b)); - } - - - template - auto nearest_color(const Colors &colors) - { - return *std::min_element(std::begin(colors), std::end(colors), color_distance); - } - - - auto sprite_collisions() { - const auto collisions = memory(SPRITE_COLLISIONS); - return std::make_tuple( - test_bit(collisions, 0),test_bit(collisions, 1),test_bit(collisions, 2), - test_bit(collisions, 3),test_bit(collisions, 4),test_bit(collisions, 5), - test_bit(collisions, 6),test_bit(collisions, 7)); - }; - struct Player { - Player(const uint8_t num, const uint8_t startx, const uint8_t starty) + Player(const uint8_t num, std::pair sprite_pos, + const std::pair &start_pos) : player_num(num), - x(sprite_x(player_num)), - y(sprite_y(player_num)) + pos(sprite_pos) { - x = startx; - y = starty; + pos = start_pos; } void update_position() { - y += joystick(player_num).direction_vector().second * 3; + pos.second += JoyStick(player_num).direction_vector().second * 3; }; void scored() { @@ -196,17 +116,170 @@ namespace { } const uint8_t player_num; - volatile uint8_t &x; - volatile uint8_t &y; + std::pair pos; uint8_t score = '0'; }; + + + + struct VIC_II + { + static constexpr uint16_t SPRITE_DATA_POINTERS = 2040; + static constexpr uint16_t VIDEO_REGISTERS = 53248; + static constexpr uint16_t VIDEO_MEMORY = 1024; + static constexpr uint8_t SPRITE_STARTING_BANK = 192; + static constexpr uint16_t BORDER_COLOR = 53280; + static constexpr uint16_t BACKGROUND_COLOR = 53281; + static constexpr uint16_t SPRITE_POSITION_REGISTERS = VIDEO_REGISTERS; + static constexpr uint16_t SPRITE_ENABLE_BITS = VIDEO_REGISTERS + 21; + static constexpr uint16_t SPRITE_EXPAND_VERTICAL = VIDEO_REGISTERS + 23; + static constexpr uint16_t SPRITE_PRIORITY = VIDEO_REGISTERS + 27; + static constexpr uint16_t SPRITE_MULTICOLOR = VIDEO_REGISTERS + 28; + static constexpr uint16_t SPRITE_EXPAND_HORIZONTAL = VIDEO_REGISTERS + 29; + static constexpr uint16_t SPRITE_COLLISIONS = VIDEO_REGISTERS + 30; + static constexpr uint16_t SPRITE_0_COLOR = VIDEO_REGISTERS + 39; + static constexpr uint16_t SPRITE_1_COLOR = SPRITE_0_COLOR + 1; + static constexpr uint16_t SPRITE_2_COLOR = SPRITE_1_COLOR + 1; + static constexpr uint16_t SCREEN_RASTER_LINE = 53266; + + + volatile uint8_t& border() { + return memory(BORDER_COLOR); + } + + volatile uint8_t& background() { + return memory(BACKGROUND_COLOR); + } + + volatile uint8_t& display(uint8_t x, uint8_t y) + { + return memory(VIDEO_MEMORY + y * 40 + x); + } + + template + static auto color_comparison(const Color &lhs, const Color &rhs) + { + // distance between colors: + // sqrt( (r1 - r2)^2 + (g1 - g2)^2 + (b1 - b2)^2 ) + return (square(lhs.r - r) + square(lhs.g - g) + square(lhs.b - b)) + < (square(rhs.r - r) + square(rhs.g - g) + square(rhs.b - b)); + } + + template + static auto nearest_color(const Colors &colors) + { + return *std::min_element(std::begin(colors), std::end(colors), color_comparison); + } + + auto frame(Player &p1, Player &p2) + { + struct Frame + { + Frame(VIC_II &t_vic, Player &p1, Player &p2) + : player1(p1), player2(p2), vic(t_vic) + { + while (memory(SCREEN_RASTER_LINE) != 250) {} + } + + ~Frame() { + vic.display(10, 12) = player1.score; + vic.display(20, 12) = player2.score; + } + + Player &player1; + Player &player2; + VIC_II &vic; + }; + + return Frame(*this, p1, p2); + } + + void write_multi_color_pixel(uint16_t) + { + // 0th case + } + + void write_pixel(uint16_t) + { + // 0th case + } + + template + void write_multi_color_pixel(uint16_t loc, uint8_t d1, uint8_t d2, uint8_t d3, uint8_t d4, D ... d) + { + memory(loc) = (d1 << 6) | (d2 << 4) | (d3 << 2) | d4; + write_multi_color_pixel(loc + 1, d...); + } + + template + void write_pixel(uint16_t loc, bool d1, bool d2, bool d3, bool d4, bool d5, bool d6, bool d7, bool 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) + { + 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...); + } + } + + /// New Code + void enable_sprite(const uint8_t sprite_number, const uint8_t memory_loc, + const bool multicolor, const bool low_priority, + const bool double_width, const bool double_height) + { + memory(SPRITE_DATA_POINTERS + sprite_number) = SPRITE_STARTING_BANK + memory_loc; + set_bit(SPRITE_ENABLE_BITS, sprite_number, true); + 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); + set_bit(SPRITE_PRIORITY, sprite_number, low_priority); + } + + + auto sprite_collisions() { + const auto collisions = memory(SPRITE_COLLISIONS); + + return std::make_tuple( + test_bit(collisions, 0),test_bit(collisions, 1),test_bit(collisions, 2), + test_bit(collisions, 3),test_bit(collisions, 4),test_bit(collisions, 5), + test_bit(collisions, 6),test_bit(collisions, 7)); + } + volatile uint8_t &sprite_1_color() + { + return memory(SPRITE_1_COLOR); + } + + volatile uint8_t &sprite_2_color() + { + return memory(SPRITE_2_COLOR); + } + + std::pair sprite_pos(const uint8_t sprite_num) + { + return { + memory(SPRITE_POSITION_REGISTERS + sprite_num * 2), + memory(SPRITE_POSITION_REGISTERS + sprite_num * 2 + 1) + }; + } + + + }; + } + + + int main() { - - constexpr std::array colors {{ + const std::array colors = {{ Color{0, 0x00, 0x00, 0x00}, Color{1, 0xFF, 0xFF, 0xFF}, Color{2, 0x88, 0x39, 0x32}, @@ -225,8 +298,10 @@ int main() Color{15, 0x9F, 0x9F, 0x9F} }}; - - make_sprite(0, + VIC_II vic; + + + vic.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,0,0,0,0,0,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0, @@ -250,12 +325,7 @@ int main() 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, false, true, false, false); - - - make_sprite(1, + vic.make_sprite(1, 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, @@ -279,79 +349,60 @@ int main() 0,0,0,0,0,3,3,0,0,0,0,0 ); + vic.enable_sprite(0, 0, false, true, false, false); + vic.enable_sprite(1, 1, true, false, false, true); + vic.enable_sprite(2, 1, true, false, false, true); - - enable_sprite(1, 1, true, false, false, true); - enable_sprite(2, 1, true, false, false, true); + vic.border() = vic.nearest_color<128,128,128>(colors).num; // 50% grey + vic.background() = vic.nearest_color<0,0,0>(colors).num; // black + vic.sprite_1_color() = vic.nearest_color<255,0,0>(colors).num; // red + vic.sprite_2_color() = vic.nearest_color<0,255,0>(colors).num; // green std::pair ball_velocity{1,1}; - const auto reset_ball = [&]{ - sprite_x(0) = 255/2; - sprite_y(0) = 255/2; + const auto reset_ball = [&vic]{ + // resets position but keeps velocity + vic.sprite_pos(0) = std::make_pair(255/2, 255/2); }; reset_ball(); - memory(BORDER_COLOR) = nearest_color<128,128,128>(colors).num; - memory(BACKGROUND_COLOR) = nearest_color<0,0,0>(colors).num; - memory(SPRITE_1_COLOR) = nearest_color<255,0,0>(colors).num; - memory(SPRITE_2_COLOR) = nearest_color<0,255,0>(colors).num; - - - - Player p1(1, 15, 255/2); - Player p2(2, 255, 255/2); - - struct Frame - { - Frame(Player &p1, Player &p2) - : player1(p1), player2(p2) - { - while (!(memory(53266) == 250 && !test_bit(memory(53265),7))) {} - } - - ~Frame() { - display(10, 12, player1.score); - display(20, 12, player2.score); - } - - Player &player1; - Player &player2; - }; + Player p1(1, vic.sprite_pos(1), {15, 255/2}); + Player p2(2, vic.sprite_pos(2), {255, 255/2}); + // Game Loop while (true) { - Frame rt(p1, p2); + auto frame = vic.frame(p1, p2); - if (const auto [s0, s1, s2, s3, s4, s5, s6, s7] = sprite_collisions(); + if (const auto [s0, s1, s2, s3, s4, s5, s6, s7] = vic.sprite_collisions(); s0 && (s1 || s2)) { auto &x_velocity = std::get<0>(ball_velocity); x_velocity *= -1; //invert ball x velocity // "bounce" ball out of collision area - sprite_x(0) += x_velocity; + vic.sprite_pos(0).first += x_velocity; } // Update paddle positions p1.update_position(); p2.update_position(); - // ball hit the top or bottom wall - if (const auto ball_y = sprite_y(0) += std::get<1>(ball_velocity); + if (const auto ball_y = vic.sprite_pos(0).second += std::get<1>(ball_velocity); ball_y == 45 || ball_y == 235) { - std::get<1>(ball_velocity) *= -1; + std::get<1>(ball_velocity) *= -1; // invert ball y velocity } const auto score = [reset_ball](auto &player){ + // called when a player scores player.scored(); reset_ball(); }; - if (const auto ball_x = sprite_x(0) += std::get<0>(ball_velocity); + if (const auto ball_x = vic.sprite_pos(0).first += std::get<0>(ball_velocity); ball_x == 1) { // ball hit left wall, player 2 scored score(p2);