-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathbullet.vhd
More file actions
248 lines (203 loc) · 6.96 KB
/
bullet.vhd
File metadata and controls
248 lines (203 loc) · 6.96 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
USE ieee.numeric_std.ALL;
USE work.declarations.ALL;
ENTITY bullet IS
PORT (
clk, rstn : in std_logic;
mode : IN STD_LOGIC_VECTOR(MODE_STATE_WIDTH-1 DOWNTO 0);
x_pos_start, y_pos_start : in integer;
x_pos_out, y_pos_out : out integer;
direction : in integer range 0 to 7;
want_active : in std_logic;
is_active : out std_logic;
xscan, yscan : IN INTEGER;
flag : OUT STD_LOGIC
);
END bullet;
ARCHITECTURE behavior OF bullet IS
--------------- Define variables -----------------
CONSTANT bullet_size : INTEGER := 10; -- Diameter of square bullet
-- Variable for modulo clocks
SIGNAL cnt : INTEGER := 0;
-- Variables required for drawing square
SIGNAL x_left, y_up : INTEGER := 200;
SIGNAL x_right, y_down : INTEGER := 200;
-- Variables for movement
SIGNAL y_movement : INTEGER := 0;
SIGNAL x_movement : INTEGER := 0;
-- Extra variables for position. Needed to check for collision before updating.
signal x_pos_next, y_pos_next : integer := 200;
signal x_pos_temp, y_pos_temp : integer := 200;
-- Corner coordinates for collision checking
signal top_left_x, top_left_y : integer;
signal top_right_x, top_right_y : integer;
signal bottom_left_x, bottom_left_y : integer;
signal bottom_right_x, bottom_right_y : integer;
signal is_top_left_wall, is_top_right_wall, is_bottom_left_wall, is_bottom_right_wall : std_logic;
signal x_pos : integer := 400;
signal y_pos : integer := 200;
signal active_now : std_logic := '0';
signal want_delete : std_logic := '0';
-- Clock dividers for different speeds
SIGNAL slow_clk_div, fast_clk_div : INTEGER range 0 to 140000 := 0; -- Combined range for efficiency
BEGIN
------------------- Variable updates ---------------
is_active <= active_now;
-- Calculate sides for drawing
x_pos_out <= x_pos;
y_pos_out <= y_pos;
x_left <= x_pos;
x_right <= x_pos + bullet_size;
y_up <= y_pos;
y_down <= y_pos + bullet_size;
-- Calculate corner positions
top_left_x <= x_pos_next;
top_left_y <= y_pos_next;
top_right_x <= x_pos_next + bullet_size;
top_right_y <= y_pos_next;
bottom_left_x <= x_pos_next;
bottom_left_y <= y_pos_next + bullet_size;
bottom_right_x <= x_pos_next + bullet_size;
bottom_right_y <= y_pos_next + bullet_size;
---------------------- Port maps ----------------------
-- Add four game fields to check wall collision of each bullet corner
game_field_top_left : field port map(
clk => clk, rstn => rstn,
xscan => top_left_x, yscan => top_left_y,
mode => mode,
flag => is_top_left_wall
);
game_field_top_right : field port map(
clk => clk, rstn => rstn,
xscan => top_right_x, yscan => top_right_y,
mode => mode,
flag => is_top_right_wall
);
game_field_bottom_left : field port map(
clk => clk, rstn => rstn,
xscan => bottom_left_x, yscan => bottom_left_y,
mode => mode,
flag => is_bottom_left_wall
);
game_field_bottom_right : field port map(
clk => clk, rstn => rstn,
xscan => bottom_right_x, yscan => bottom_right_y,
mode => mode,
flag => is_bottom_right_wall
);
------------------ Processes -----------------------
-- Process for generating slower clocks
clock_dividers : PROCESS (clk, rstn)
BEGIN
IF rstn = '0' THEN
fast_clk_div <= 0;
slow_clk_div <= 0;
ELSIF rising_edge(clk) THEN
IF fast_clk_div < 100000 THEN
fast_clk_div <= fast_clk_div + 1;
ELSE
fast_clk_div <= 0;
END IF;
IF slow_clk_div < 140000 THEN
slow_clk_div <= slow_clk_div + 1;
ELSE
slow_clk_div <= 0;
END IF;
END IF;
END PROCESS;
become_active : process (clk, rstn)
begin
if rstn = '0' then
active_now <= '0';
elsif rising_edge(clk) then
if (want_active = '1') then
active_now <= '1';
elsif (want_delete = '1') then
active_now <= '0';
end if;
end if;
end process;
-- Draw bullet
draw : PROCESS (clk, rstn)
BEGIN
IF (rstn = '0' or mode = MAIN_MENU or mode = GAME_OVER_SCREEN or active_now = '0') THEN
flag <= '0';
ELSIF rising_edge(clk) THEN
if (mode = ONE_CPU_GAME OR mode = TWO_CPU_GAME) THEN
-- draw bullet square
if (xscan >= x_left AND xscan <= x_right AND yscan >= y_up AND yscan <= y_down) then
flag <= '1';
else
flag <= '0';
end if;
else
flag <= '0';
end if;
END IF;
END PROCESS;
-- Calculate next position
movement_calculation : PROCESS (clk, rstn)
BEGIN
IF (rstn = '0' or mode = MAIN_MENU or mode = GAME_OVER_SCREEN or active_now = '0') THEN
-- Initial position
x_pos_next <= x_pos;
y_pos_next <= y_pos;
ELSIF rising_edge(clk) THEN
-- Check directionection to see how much the bullet can move in X and Y
-- direction 0 is up, direction 1 is NE, direction 2 is E, etc.
-- Y
IF ((direction = 7) or (direction = 0) or (direction = 1)) THEN
y_movement <= -1;
ELSIF (direction = 3 or direction = 4 or direction = 5) THEN
y_movement <= 1;
ELSE
y_movement <= 0;
END IF;
-- X
IF ((direction = 5) or (direction = 6) or (direction = 7)) THEN
x_movement <= -1;
ELSIF (direction = 1 or direction = 2 or (direction = 3)) THEN
x_movement <= 1;
ELSE
x_movement <= 0;
END IF;
-- Movement
-- Fast movement for vertical/horizontal
IF (fast_clk_div = 0) THEN
IF (direction = 0 or direction = 2 or direction = 4 or direction = 6) THEN
y_pos_next <= y_pos + y_movement;
x_pos_next <= x_pos + x_movement;
END IF;
-- Slow movement for diagonals
ELSIF (slow_clk_div = 0) THEN
IF (direction = 1 or direction = 3 or direction = 5 or direction = 7) THEN
y_pos_next <= y_pos + y_movement;
x_pos_next <= x_pos + x_movement;
END IF;
end if;
END IF;
END PROCESS;
-- Collision check before movement update.
position_update : PROCESS (clk, rstn)
BEGIN
IF (rstn = '0' or mode = MAIN_MENU or mode = GAME_OVER_SCREEN or active_now = '0') THEN
x_pos <= x_pos_start;
y_pos <= y_pos_start;
x_pos_temp <= x_pos;
y_pos_temp <= y_pos;
ELSIF rising_edge(clk) THEN
-- Update temp vars first
x_pos_temp <= x_pos_next;
y_pos_temp <= y_pos_next;
-- Check collision using temp vars
IF (is_top_left_wall = '0') AND (is_top_right_wall = '0') AND (is_bottom_left_wall = '0') AND (is_bottom_right_wall = '0') THEN
x_pos <= x_pos_temp;
y_pos <= y_pos_temp;
want_delete <= '0';
ELSE
want_delete <= '1';
END IF;
END IF;
END PROCESS;
END behavior;