module FPGA_FINAL( input CLK, reset, start, output reg [0:27] led, output reg [2:0] life, input left, right, input throw, input show_two_row, output testLED, output reg a,b,c,d,e,f,g, output reg [0:3] COM, input highSpeed ); reg [7:0]blockFirst = 8'b11111111; reg [7:0]blockSecond = 8'b00000000; reg [0:7]barrier = 8'b00000011; reg [2:0]plat_position; // 板子位置 reg [2:0]ball_position; // 球 位置 reg [2:0]ball_y_position; // 球 y 座標 reg [3:0]count_digit = 4'b000; //個位數分數 reg [3:0]count_ten = 4'b0000; //十位數分數 reg upPosition; integer horizonPosition; reg handsOn; // bool,紀錄球現在丟出去了沒 reg gameOverFlag; reg gameFinishFlag; reg showBonus; // bool 顯示額外球 reg [2:0] Bonus_x; // 額外球的位子x reg [2:0] Bonus_y; // 額外球的位子x reg ball_is_on_the_gronud; // 檢查球是否沒被盤子接住 initial begin // 歸零,重製 8x8 LED led[0:23] = 23'b11111111111111111111; led[27] = 1; led[24:26] = 3'b000; life = 3'b111; plat_position = 3'b010; // 預設在 x=2 的位置 ball_position = 3'b011; // 預設在 x=3 的位置 ball_y_position = 3'b010; // 預設在 y=1 的位置 handsOn = 1; // 預設為 為丟出狀態 count_digit = 4'b0; // 分數預設0 count_ten = 4'b0; upPosition = 1; // 預設為 向上 horizonPosition = 0; // 預設為 正中間方向 gameOverFlag = 0; gameFinishFlag = 0; showBonus = 0; ball_is_on_the_gronud = 0; end // 開始所有除頻器 divfreq F(CLK, divclk); buttondivfreq BT(CLK, highSpeed, buttonclk); integer ballTime; integer doubleTime; // 判斷 所有操作 always @(posedge buttonclk) begin if(start) begin if(reset) begin if(gameOverFlag || gameFinishFlag) begin blockFirst = 8'b11111111; if(show_two_row) blockSecond = 8'b11111111; else blockSecond = 8'b00000000; life = 3'b111; gameOverFlag = 0; gameFinishFlag = 0; end plat_position <= 3'b010; // 預設在 x=2 的位置 ball_position <= 3'b011; // 預設在 x=3 的位置 ball_y_position <= 3'b010; // 預設在 y=1 的位置 handsOn = 1; // 預設為 為丟出狀態 upPosition = 1; // 預設為 向上 horizonPosition = 0; // 預設為 正中間方向 showBonus = 0; ball_is_on_the_gronud = 0; end // 判斷 向左 if(left) if(plat_position>0) begin plat_position <= plat_position-1; if(handsOn==1)ball_position <= ball_position-1; end // 判斷 向右 if(right) if(plat_position<5) begin plat_position <= plat_position+1; if(handsOn==1)ball_position <= ball_position+1; end // 判斷 丟出球 if(throw) if(handsOn) begin handsOn = 0; end // 下方操作球的運 行 // 除頻用 if(ballTime<2) ballTime <= ballTime+1; else //開始判斷球的行進 begin ballTime <= 0; if(handsOn==0) // 如果是丟出去的狀態才移動 begin // 先判斷垂直方向 if(upPosition) if(ball_y_position<7) // 還沒到頂端 ball_y_position <= ball_y_position+1; else begin ball_y_position <= ball_y_position-1; // 到頂端就開始往下 upPosition = 0; end else if(ball_y_position>1) ball_y_position <= ball_y_position-1; // 判斷水平方向 if(horizonPosition==1) if(ball_position<7) ball_position <= ball_position+1; // 範圍內右移 else begin horizonPosition = -1; // 超過範圍就轉向左邊 ball_position <= ball_position-1; end else if(horizonPosition==-1) if(ball_position>0) ball_position <= ball_position-1; // 範圍內左移 else begin horizonPosition = 1; // 超過範圍就轉向右邊 ball_position <= ball_position+1; end // 判斷特殊狀況(碰到板子) if(ball_y_position==1) if(ball_position==plat_position) begin if(horizonPosition==0) horizonPosition = -1; else ball_y_position <= ball_y_position+1; upPosition = 1; end else if(ball_position==plat_position+1) begin upPosition = 1; ball_y_position <= ball_y_position+1; end else if(ball_position==plat_position+2) begin if(horizonPosition==0) horizonPosition = 1; else ball_y_position <= ball_y_position+1; upPosition = 1; end else if(ball_position==plat_position-1 && horizonPosition==1) begin horizonPosition = -1; ball_position <= ball_position-1; ball_y_position <= ball_y_position+1; upPosition = 1; end else if(ball_position==plat_position+3 && horizonPosition==-1) begin horizonPosition = 1; ball_position <= ball_position+1; ball_y_position <= ball_y_position+1; upPosition = 1; end else begin horizonPosition = 0; ball_y_position <= ball_y_position-1; showBonus = 0; ball_is_on_the_gronud = 1; life = life*2; // 扣除生命值 if(life==3'b000) gameOverFlag = 1; end // // 判斷特殊狀態 , 撞到障礙物 if(ball_y_position==4) if(barrier[ball_position]==1) begin if(upPosition) upPosition = 0; else begin horizonPosition = -horizonPosition; upPosition = 1; end if(ball_position==0) horizonPosition = 1; if(ball_position==7) horizonPosition = -1; ball_position <= ball_position + horizonPosition; if(upPosition) ball_y_position <= ball_y_position +1; else ball_y_position <= ball_y_position -1; end // // 判斷特殊狀態 , 撞到第一排磚塊 if(ball_y_position==6) if(blockSecond[ball_position]==1) begin count_digit <= count_digit + 1'b1; if(count_digit == 4'b1001) begin count_digit <= 4'b0; count_ten = count_ten + 1'b1; end blockSecond[ball_position] = 0; if(upPosition) upPosition = 0; else begin horizonPosition = -horizonPosition; upPosition = 1; end if(ball_position==0) horizonPosition = 1; if(ball_position==7) horizonPosition = -1; ball_position <= ball_position + horizonPosition; if(upPosition) ball_y_position <= ball_y_position +1; else ball_y_position <= ball_y_position -1; //判斷是否結束 if(blockSecond == 8'b00000000 && blockFirst == 8'b000000000) gameFinishFlag = 1; end // // 判斷特殊狀態 , 撞到第二排磚塊 if(ball_y_position==7) if(blockFirst[ball_position]==1) begin count_digit <= count_digit + 1'b1; if(count_digit == 4'b1001) begin count_digit <= 4'b0; count_ten = count_ten + 1'b1; end blockFirst[ball_position] = 0; upPosition = 0; if(ball_position==0) horizonPosition = 1; if(ball_position==7) horizonPosition = -1; ball_position <= ball_position + horizonPosition; ball_y_position <= ball_y_position -1; //判斷是否結束 if(blockSecond == 8'b00000000 && blockFirst == 8'b00000000) gameFinishFlag = 1; end // 障礙物右移 if(ball_is_on_the_gronud == 0) begin barrier = barrier<<1; if(barrier == 8'b0) barrier = 8'b00000011; end end end // Bonus ball 除頻 , 每五秒從左邊射一發 if(doubleTime<50 && showBonus == 0 && handsOn == 0 && ball_is_on_the_gronud == 0) begin doubleTime <= doubleTime+1; Bonus_x = plat_position ; Bonus_y = 1; end else begin if(handsOn == 0) begin doubleTime <= 0; showBonus = 1; if(Bonus_y == 7) begin showBonus = 0; end if(Bonus_y < 7) begin Bonus_y = Bonus_y + 1; end // Bonus ball 撞到第一排磚塊 if((Bonus_y == 6 && blockSecond[Bonus_x] == 1)) begin count_digit <= count_digit + 1'b1; if(count_digit == 4'b1001) begin count_digit <= 4'b0; count_ten = count_ten + 1'b1; end blockSecond[Bonus_x] = 0; showBonus = 0; end // Bonus ball 撞到第二排磚塊 if((Bonus_y == 7 && blockFirst[Bonus_x] == 1)) begin count_digit <= count_digit + 1'b1; if(count_digit == 4'b1001) begin count_digit <= 4'b0; count_ten = count_ten + 1'b1; end blockFirst[Bonus_x] = 0; showBonus = 0; end end // Bonus ball end end end // 顯示用 always @(posedge divclk) begin reg [0:2]row; reg count_digit_enable; // 跑 0~7 行 if(row>=7) row <= 3'b000; else row <= row + 1'b1; // 設定這次要畫第 n 行 led[24:26] = row; // 如果 gameOverFlag ==1就畫圖 if(gameOverFlag) begin led[0:23] = 24'b111111111111111111111111; if(row==0 || row==7) led[0:7] = 8'b01111110; else if(row==1 || row==6) led[0:7] = 8'b10111101; else if(row==2 || row==5) led[0:7] = 8'b11011011; else if(row==3 || row==4) led[0:7] = 8'b11100111; else led[0:7] = 8'b11111111; end // 顯示結束畫面 else if(gameFinishFlag) begin led[0:23] = 24'b111111111111111111111111; if(row==0 || row==7) led[8:15] = 8'b11100111; else if(row==1 || row==6) led[8:15] = 8'b11011011; else if(row==2 || row==5) led[8:15] = 8'b10111101; else if(row==3 || row==4) led[8:15] = 8'b01111110; else led[8:15] = 8'b11111111; end else begin // 開始畫板子 ( R ) if(row==plat_position || row==plat_position+1 || row==plat_position+2) led[0:7] = 8'b11111110; else led[0:7] = 8'b11111111; // 開始畫球 ( G ) if(handsOn) if(row==plat_position+1) // 放在正中間 led[8:15] = 8'b11111101; else led[8:15] = 8'b11111111; else if(row==ball_position) begin reg [7:0] map; case(ball_y_position) 3'b000: map = 8'b11111110 ; 3'b001: map = 8'b11111101 ; 3'b010: map = 8'b11111011 ; 3'b011: map = 8'b11110111 ; 3'b100: map = 8'b11101111 ; 3'b101: map = 8'b11011111 ; 3'b110: map = 8'b10111111 ; 3'b111: map = 8'b01111111 ; endcase led[8:15] = map; end else led[8:15] = 8'b11111111; //開始畫磚塊 led[16:23] = {~blockFirst[row], ~blockSecond[row], 6'b111111}; // 畫 Bonus ball if(showBonus == 1) if(row==Bonus_x) begin case(Bonus_y) 3'b000: begin led[7] = 0 ; led[23] = 0; end 3'b001: begin led[6] = 0 ; led[22] = 0; end 3'b010: begin led[5] = 0 ; led[21] = 0; end 3'b011: begin led[4] = 0 ; led[20] = 0; end 3'b100: begin led[3] = 0 ; led[19] = 0; end 3'b101: begin led[2] = 0 ; led[18] = 0; end 3'b110: begin led[1] = 0 ; led[17] = 0; end 3'b111: begin led[0] = 0 ; led[16] = 0; end endcase end // 畫障礙物 if(barrier[row] == 1) begin led[3] = 0; led[11] = 0; end // 顯示分數 if(count_digit_enable == 0) begin count_digit_enable = 1; COM = 4'b1110; end else begin count_digit_enable = 0; COM = 4'b1101; end end // 顯示個位 if(count_digit_enable == 1) begin case(count_digit) 4'b0000:{a,b,c,d,e,f,g}=7'b0000001; 4'b0001:{a,b,c,d,e,f,g}=7'b1001111; 4'b0010:{a,b,c,d,e,f,g}=7'b0010010; 4'b0011:{a,b,c,d,e,f,g}=7'b0000110; 4'b0100:{a,b,c,d,e,f,g}=7'b1001100; 4'b0101:{a,b,c,d,e,f,g}=7'b0100100; 4'b0110:{a,b,c,d,e,f,g}=7'b0100000; 4'b0111:{a,b,c,d,e,f,g}=7'b0001111; 4'b1000:{a,b,c,d,e,f,g}=7'b0000000; 4'b1001:{a,b,c,d,e,f,g}=7'b0000100; endcase end // 顯示十位 else begin case(count_ten) 4'b0000:{a,b,c,d,e,f,g}=7'b0000001; 4'b0001:{a,b,c,d,e,f,g}=7'b1001111; 4'b0010:{a,b,c,d,e,f,g}=7'b0010010; 4'b0011:{a,b,c,d,e,f,g}=7'b0000110; 4'b0100:{a,b,c,d,e,f,g}=7'b1001100; 4'b0101:{a,b,c,d,e,f,g}=7'b0100100; 4'b0110:{a,b,c,d,e,f,g}=7'b0100000; 4'b0111:{a,b,c,d,e,f,g}=7'b0001111; 4'b1000:{a,b,c,d,e,f,g}=7'b0000000; 4'b1001:{a,b,c,d,e,f,g}=7'b0000100; endcase end end endmodule // 顯示用的除頻器 module divfreq(input CLK, output reg CLK_div); reg[24:0] Count; always @(posedge CLK) begin if(Count>25000) begin Count <= 25'b0; CLK_div <= ~CLK_div; end else Count <= Count + 1'b1; end endmodule // 按鈕用的除頻器 module buttondivfreq(input CLK, highSpeed, output reg CLK_div); reg[24:0] Count; always @(posedge CLK) begin if(highSpeed == 0) begin if(Count>2500000) // 20 Hz begin Count <= 25'b0; CLK_div <= ~CLK_div; end else Count <= Count + 1'b1; end else begin if(Count>1000000) // 50 Hz begin Count <= 25'b0; CLK_div <= ~CLK_div; end else Count <= Count + 1'b1; end end endmodule