296 lines
6.5 KiB
Verilog
296 lines
6.5 KiB
Verilog
// játéklogika
|
|
module game_controller #(
|
|
parameter SCREEN_WIDTH = 1024, // képernyő szélessége
|
|
parameter SCREEN_HEIGHT = 768, // képernyő magassága
|
|
|
|
// labda kezdőkoordinátái
|
|
parameter BALL_START_X = SCREEN_WIDTH / 2,
|
|
parameter BALL_START_Y = SCREEN_HEIGHT / 6,
|
|
//parameter BALL_START_SPEED_VEC = 2'b11,
|
|
|
|
// platformok tulajdonságai
|
|
parameter POD_TOP = SCREEN_HEIGHT - 50,
|
|
parameter POD_WIDTH = SCREEN_WIDTH / 6,
|
|
parameter POD1_START_X = (SCREEN_WIDTH / 2 - POD_WIDTH) / 2,
|
|
parameter POD2_START_X = POD1_START_X + SCREEN_WIDTH / 2,
|
|
|
|
// középső fal tulajdonságai
|
|
parameter WALL_HALF_WIDTH = 4,
|
|
parameter WALL_HEIGHT = SCREEN_HEIGHT / 3,
|
|
|
|
// szimuláció sebessége
|
|
parameter SIMDIV = 2500,
|
|
|
|
// bithosszok
|
|
parameter N_SCR_WIDTH = $clog2(SCREEN_WIDTH),
|
|
parameter N_SCR_HEIGHT = $clog2(SCREEN_HEIGHT),
|
|
parameter N_SIMDIV = $clog2(SIMDIV)
|
|
)(
|
|
input wire clk, // órajel (1MHz)
|
|
input wire rst, // szinkron reset
|
|
|
|
input wire start, // játék indítása
|
|
input wire acknowledge, // továbblépés játék vége után
|
|
|
|
// bal oldali platform koordinátái
|
|
output reg [N_SCR_WIDTH - 1:0] pod1x,
|
|
output reg [N_SCR_WIDTH - 1:0] pod2x,
|
|
|
|
// jobb oldali platform koordinátái
|
|
output reg [N_SCR_WIDTH - 1:0] ballx,
|
|
output reg [N_SCR_HEIGHT - 1:0] bally,
|
|
|
|
// platformok mozgatás-engedélyezése és irányvezérlése
|
|
input wire move_pod1_en,
|
|
input wire move_pod1_dir,
|
|
input wire move_pod2_en,
|
|
input wire move_pod2_dir,
|
|
|
|
// pontszám-kimenetek és pontszámok törlése
|
|
output reg [7:0] score1,
|
|
output reg [7:0] score2,
|
|
input wire clear_score,
|
|
|
|
// hangvezérlése
|
|
output reg hit,
|
|
output reg miss
|
|
);
|
|
|
|
// randobgenerátor (LFSR)
|
|
reg [15:0] rnd;
|
|
always @(posedge clk)
|
|
begin
|
|
if (rst)
|
|
begin
|
|
rnd <= 16'hACE1;
|
|
end
|
|
else
|
|
begin
|
|
rnd <= { rnd[14:0], rnd[15] ^ rnd[13] ^ rnd[12] ^ rnd[10] };
|
|
end
|
|
end
|
|
|
|
// -----------
|
|
|
|
// játékállapotok
|
|
localparam GS_FROZEN = 0; // fagyasztva
|
|
localparam GS_RUNNING = 1; // játék fut
|
|
localparam GS_SCORING = 2; // pontok kiosztása
|
|
localparam GS_GAME_OVER = 3; // játék vége
|
|
|
|
wire restart = (next_game_state == GS_FROZEN) && (game_state == GS_GAME_OVER);
|
|
|
|
// követvező játékállapot
|
|
reg [1:0] next_game_state;
|
|
always @(*)
|
|
begin
|
|
case (game_state)
|
|
default : next_game_state <= start ? GS_RUNNING : GS_FROZEN;
|
|
GS_RUNNING : next_game_state <= (bally > SCREEN_HEIGHT - 5) ? GS_SCORING : GS_RUNNING;
|
|
GS_SCORING : next_game_state <= GS_GAME_OVER;
|
|
GS_GAME_OVER : next_game_state <= acknowledge ? GS_FROZEN : GS_GAME_OVER;
|
|
endcase
|
|
end
|
|
|
|
// játékállapot-regiszter
|
|
reg [1:0] game_state;
|
|
always @(posedge clk)
|
|
begin
|
|
if (rst)
|
|
begin
|
|
game_state <= GS_FROZEN;
|
|
end
|
|
else
|
|
begin
|
|
game_state <= next_game_state;
|
|
end
|
|
end
|
|
|
|
wire game_running = (game_state == GS_RUNNING); // játék fut jelzés
|
|
|
|
// -----------
|
|
|
|
// ladba sebsségszimulációja
|
|
reg speed_boost; // gyorsítás
|
|
reg [2:0] speed_vec; // sebességvektor
|
|
always @(posedge clk)
|
|
begin
|
|
if (rst || restart) // szinkron reset vagy új játék
|
|
begin
|
|
speed_boost <= 1'b0;
|
|
speed_vec <= rnd[15:14];
|
|
hit <= 1'b0;
|
|
end
|
|
else
|
|
begin
|
|
// visszapattanás a függőleges falakról
|
|
if (((ballx == (SCREEN_WIDTH - 1)) && (speed_vec[0] == 1'b1)) || // jobb képernyőszél
|
|
((ballx == 0) && (speed_vec[0] == 1'b0)) || // bal képernyőszél
|
|
((bally > (SCREEN_HEIGHT - WALL_HEIGHT - 1)) && // középső fal
|
|
(((ballx == (SCREEN_WIDTH / 2 - 1)) && (speed_vec[0] == 1'b1)) || ((ballx == (SCREEN_WIDTH / 2)) && (speed_vec[0] == 1'b0)))))
|
|
begin
|
|
speed_vec[0] <= ~speed_vec[0];
|
|
end
|
|
|
|
// visszapattanás a képernyő tetejéről
|
|
if ((bally == 0) && (speed_vec[1] == 1'b0))
|
|
begin
|
|
speed_vec[1] <= ~speed_vec[1];
|
|
end
|
|
|
|
hit <= 1'b0;
|
|
|
|
// visszapattanás a bal platformról
|
|
if ((bally == POD_TOP - 1) && (speed_vec[1] == 1'b1) && (((ballx > pod1x) && (ballx < (pod1x + POD_WIDTH)))))
|
|
begin
|
|
speed_vec[1] <= ~speed_vec[1];
|
|
|
|
speed_boost <= move_pod1_en;
|
|
|
|
hit <= 1'b1;
|
|
end
|
|
|
|
// visszapattanás a jobb platformról
|
|
if ((bally == POD_TOP - 1) && (speed_vec[1] == 1'b1) && ((ballx > pod2x) && (ballx < (pod2x + POD_WIDTH))))
|
|
begin
|
|
speed_vec[1] <= ~speed_vec[1];
|
|
|
|
speed_boost <= move_pod2_en;
|
|
|
|
hit <= 1'b1;
|
|
end
|
|
|
|
end
|
|
end
|
|
|
|
// -----------------
|
|
|
|
// szimuláció frekvenciaosztó számlálója
|
|
reg [N_SIMDIV - 1:0] sim_cntr;
|
|
reg [N_SIMDIV - 1:0] sim_cntr_max;
|
|
always @(posedge clk)
|
|
begin
|
|
if (rst)
|
|
begin
|
|
sim_cntr <= 0;
|
|
sim_cntr_max <= SIMDIV - 1'b1;
|
|
end
|
|
else
|
|
begin
|
|
if (sim_cntr == sim_cntr_max)
|
|
begin
|
|
sim_cntr_max <= speed_boost ? ((SIMDIV / 2) - 1'b1) : (SIMDIV - 1'b1);
|
|
sim_cntr <= 0;
|
|
end
|
|
else
|
|
begin
|
|
sim_cntr <= sim_cntr + 1'b1;
|
|
end
|
|
end
|
|
end
|
|
|
|
wire sim_step = game_running && (sim_cntr == sim_cntr_max); // szimulációs lépés jelzés
|
|
|
|
// labda-pozíciószimuláció
|
|
always @(posedge clk)
|
|
begin
|
|
if (rst || restart)
|
|
begin
|
|
ballx <= BALL_START_X + rnd[8:0] - 8'd255;
|
|
bally <= BALL_START_Y + rnd[13:9] - 5'd16;
|
|
end
|
|
else
|
|
begin
|
|
if (sim_step)
|
|
begin
|
|
ballx <= speed_vec[0] ? (ballx + 1'b1) : (ballx - 1'b1);
|
|
bally <= speed_vec[1] ? (bally + 1'b1) : (bally - 1'b1);
|
|
end
|
|
end
|
|
end
|
|
|
|
// platform mozgatása
|
|
always @(posedge clk)
|
|
begin
|
|
if (rst || restart)
|
|
begin
|
|
pod1x <= POD1_START_X;
|
|
pod2x <= POD2_START_X;
|
|
end
|
|
else if (sim_step)
|
|
begin
|
|
if (move_pod1_en) // bal platform mozgatás-engedélyezése
|
|
begin
|
|
if (move_pod1_dir && (pod1x < ((SCREEN_WIDTH / 2) - POD_WIDTH - WALL_HALF_WIDTH))) // jobbra mozgatás
|
|
begin
|
|
pod1x <= pod1x + 1'b1;
|
|
end
|
|
else if ((!move_pod1_dir) && (pod1x > 0)) // balra mozgatás
|
|
begin
|
|
pod1x <= pod1x - 1'b1;
|
|
end
|
|
end
|
|
|
|
if (move_pod2_en) // jobb platform mozgatás-engedélyezése
|
|
begin
|
|
if (move_pod2_dir && (pod2x < (SCREEN_WIDTH - POD_WIDTH))) // jobbra mozgatás
|
|
begin
|
|
pod2x <= pod2x + 1'b1;
|
|
end
|
|
else if ((!move_pod2_dir) && (pod2x > ((SCREEN_WIDTH / 2) + WALL_HALF_WIDTH))) // balra mozgatás
|
|
begin
|
|
pod2x <= pod2x - 1'b1;
|
|
end
|
|
end
|
|
|
|
end
|
|
end
|
|
|
|
// BCD-számláló funkcionalitás
|
|
function [7:0] bcd_inc;
|
|
input [7:0] a;
|
|
begin
|
|
bcd_inc = (a[3:0] == 4'd9) ? { a[7:4] + 4'd1, 4'd0 } : a + 8'd1;
|
|
end
|
|
endfunction
|
|
|
|
// pontozás
|
|
always @(posedge clk)
|
|
begin
|
|
if (rst || clear_score)
|
|
begin
|
|
score1 <= 8'h00;
|
|
score2 <= 8'h00;
|
|
end
|
|
else if (game_state == GS_SCORING)
|
|
begin
|
|
if (ballx >= (SCREEN_WIDTH / 2))
|
|
begin
|
|
score1 <= bcd_inc(score1);
|
|
end
|
|
else
|
|
begin
|
|
score2 <= bcd_inc(score2);
|
|
end
|
|
end
|
|
end
|
|
|
|
// leeső labda hangvezérlése
|
|
always @(posedge clk)
|
|
begin
|
|
if (rst)
|
|
begin
|
|
miss <= 1'b0;
|
|
end
|
|
else if (game_state == GS_SCORING)
|
|
begin
|
|
miss <= 1'b1;
|
|
end
|
|
else
|
|
begin
|
|
miss <= 1'b0;
|
|
end
|
|
end
|
|
|
|
endmodule
|