· 5 months ago · Apr 19, 2025, 05:45 AM
1==++ Here's the full source for (file 1/1) "RaceCar.cpp"::: ++==
2```RaceCar.cpp
3#include <Windows.h>
4#include <ctime>
5#include <cstdlib>
6#include <math.h>
7#include <stdio.h>
8#include <string>
9#include "resource.h" // Add this with your other includes
10
11// Global Variables
12const int WIDTH = 1366;
13const int HEIGHT = 768;
14const int ROAD_WIDTH = 200;
15const int CAR_WIDTH = 50;
16const int CAR_HEIGHT = 100;
17const int TYRE_SIZE = 10;
18const int FPS = 60;
19const int TIMER = 4;
20const int TURN_RADIUS = 5;
21const double PI = 3.14159265358979323846;
22const double M_PI = 3.14159265358979323846;
23
24int playerX = 100;
25int playerY = HEIGHT - CAR_HEIGHT - 50;
26int playerSpeedX = 0;
27int playerSpeedY = 0;
28int aiX = playerX + CAR_WIDTH + 20;
29int aiY = playerY;
30float aiAngle = -PI / 2; // Add this line
31int aiSpeedX = 0;
32int aiSpeedY = 0;
33int speed = 5;
34int aiSpeed = 5;
35int timer = TIMER;
36int playerTyre1X = playerX + 10;
37int playerTyre1Y = playerY + CAR_HEIGHT - TYRE_SIZE;
38int playerTyre2X = playerX + CAR_WIDTH - TYRE_SIZE - 10;
39int playerTyre2Y = playerY + CAR_HEIGHT - TYRE_SIZE;
40int aiTyre1X = aiX + 10;
41int aiTyre1Y = aiY + CAR_HEIGHT - TYRE_SIZE;
42int aiTyre2X = aiX + CAR_WIDTH - TYRE_SIZE - 10;
43int aiTyre2Y = aiY + CAR_HEIGHT - TYRE_SIZE;
44float playerAngle = -PI / 2; // Initialize to face North by default
45//float playerAngle = 0.0f;
46
47bool gameStarted = false;
48bool gameOver = false;
49bool playerWon = false;
50bool godMode = true;
51//int timer = 30 * 10; // 30 seconds * 10 (timer resolution)
52
53// Window Procedure
54LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
55{
56 switch (message)
57 {
58 case WM_CREATE:
59 SetTimer(hWnd, 1, 1000 / FPS, NULL);
60 break;
61 case WM_TIMER:
62 if (timer > 0)
63 {
64 timer--;
65 InvalidateRect(hWnd, NULL, FALSE);
66 }
67 else if (!gameStarted)
68 {
69 gameStarted = true;
70 srand((unsigned int)time(0));
71 aiSpeed = rand() % 5 + 3;
72
73 // Set initial positions for both cars on the lower left road, facing up
74 playerX = ROAD_WIDTH / 2 - CAR_WIDTH / 2;
75 playerY = HEIGHT - CAR_HEIGHT - 20;
76 //playerAngle = -PI / 2; // -90 degrees, pointing straight up
77 playerAngle = 0; // 0 degrees, pointing straight up (north)
78
79 aiX = ROAD_WIDTH / 2 - CAR_WIDTH / 2;
80 aiY = HEIGHT - CAR_HEIGHT - 100;
81 //aiAngle = -PI / 2; // -90 degrees, pointing north
82 aiAngle = 0; // 0 degrees, pointing north
83 }
84 else if (!gameOver)
85 {
86 // Add God Mode toggle
87 if (GetAsyncKeyState('G') & 1) // Check if G key was just pressed
88 {
89 godMode = !godMode;
90 }
91
92 // Store previous position for collision recovery
93 float prevPlayerX = playerX;
94 float prevPlayerY = playerY;
95 float prevPlayerAngle = playerAngle;
96
97 // Player car controls
98 if (GetAsyncKeyState(VK_LEFT))
99 {
100 if (GetAsyncKeyState(VK_DOWN))
101 playerAngle += 0.05f; // Reverse turning
102 else
103 playerAngle -= 0.05f; // Forward turning
104 }
105 if (GetAsyncKeyState(VK_RIGHT))
106 {
107 if (GetAsyncKeyState(VK_DOWN))
108 playerAngle -= 0.05f; // Reverse turning
109 else
110 playerAngle += 0.05f; // Forward turning
111 }
112
113 // Forward/Backward movement in the direction the car is facing
114 if (GetAsyncKeyState(VK_UP))
115 {
116 // Move forward in the direction of playerAngle
117 playerX += sin(playerAngle) * speed;
118 playerY -= cos(playerAngle) * speed;
119 }
120 if (GetAsyncKeyState(VK_DOWN))
121 {
122 // Move backward in the opposite direction of playerAngle
123 playerX -= sin(playerAngle) * speed;
124 playerY += cos(playerAngle) * speed;
125 }
126
127 // Update player headlights position based on car angle
128 playerTyre1X = playerX + 10;
129 playerTyre1Y = playerY + 5;
130 playerTyre2X = playerX + CAR_WIDTH - TYRE_SIZE - 10;
131 playerTyre2Y = playerY + 5;
132
133 // Road collision detection for player
134 bool onRoad = false;
135 // Vertical road
136 if (playerX >= 0 && playerX <= ROAD_WIDTH - CAR_WIDTH)
137 onRoad = true;
138 // Horizontal road at top (twice as tall)
139 if (playerY >= 0 && playerY <= (ROAD_WIDTH * 2) &&
140 playerX >= 0 && playerX <= WIDTH - CAR_WIDTH)
141 onRoad = true;
142
143 if (!onRoad && !godMode) // Only restrict movement if god mode is off
144 {
145 // Return to previous position if off road
146 playerX = prevPlayerX;
147 playerY = prevPlayerY;
148 playerAngle = prevPlayerAngle;
149 }
150
151 // AI car movement logic
152 if (aiY > ROAD_WIDTH * 2 && aiX < ROAD_WIDTH / 2)
153 {
154 aiSpeedX = 0;
155 aiSpeedY = -aiSpeed;
156 aiAngle = 0; // Facing upward
157 }
158 else if (aiY <= ROAD_WIDTH * 2 && aiX < WIDTH - ROAD_WIDTH)
159 {
160 aiSpeedX = aiSpeed;
161 aiSpeedY = 0;
162 aiAngle = -PI / 2; // Facing right
163 }
164 else if (aiX >= WIDTH - ROAD_WIDTH && aiY <= HEIGHT - ROAD_WIDTH)
165 {
166 aiSpeedX = 0;
167 aiSpeedY = aiSpeed;
168 aiAngle = PI; // Facing downward
169 }
170 else if (aiX > ROAD_WIDTH && aiY >= HEIGHT - ROAD_WIDTH)
171 {
172 aiSpeedX = -aiSpeed;
173 aiSpeedY = 0;
174 aiAngle = PI / 2; // Facing left
175 }
176
177 // AI Car Movement and Headlight Update
178 aiX += aiSpeedX;
179 aiY += aiSpeedY;
180
181 // Calculate the front of the car using its angle
182 float headlightDistance = CAR_HEIGHT / 2 - 10;
183
184 // Calculate headlight positions based on the car's angle
185 float headlightOffsetX = cos(aiAngle) * headlightDistance;
186 float headlightOffsetY = sin(aiAngle) * headlightDistance;
187
188 // Set AI headlights at the front of the car
189 //aiTyre1X = aiX + CAR_WIDTH / 4 + headlightOffsetX;
190 //aiTyre1Y = aiY + headlightOffsetY;
191 //aiTyre2X = aiX - CAR_WIDTH / 4 + headlightOffsetX;
192 //aiTyre2Y = aiY + headlightOffsetY;
193
194 // Collision detection between player and AI cars
195 // Define the corners of the player car
196 int playerCorner1X = playerX;
197 int playerCorner1Y = playerY;
198 int playerCorner2X = playerX + CAR_WIDTH;
199 int playerCorner2Y = playerY;
200 int playerCorner3X = playerX + CAR_WIDTH;
201 int playerCorner3Y = playerY + CAR_HEIGHT;
202 int playerCorner4X = playerX;
203 int playerCorner4Y = playerY + CAR_HEIGHT;
204
205 // Define the corners of the AI car
206 int aiCorner1X = aiX;
207 int aiCorner1Y = aiY;
208 int aiCorner2X = aiX + CAR_WIDTH;
209 int aiCorner2Y = aiY;
210 int aiCorner3X = aiX + CAR_WIDTH;
211 int aiCorner3Y = aiY + CAR_HEIGHT;
212 int aiCorner4X = aiX;
213 int aiCorner4Y = aiY + CAR_HEIGHT;
214
215 // Check if the player car is too close to the opponent car from behind
216 if (!godMode && playerY + CAR_HEIGHT > aiY &&
217 playerY < aiY + CAR_HEIGHT &&
218 playerX + CAR_WIDTH > aiX &&
219 playerX < aiX + CAR_WIDTH)
220 {
221 // Prevent the player car from moving forward
222 if (GetAsyncKeyState(VK_UP))
223 {
224 playerX -= sin(playerAngle) * speed;
225 playerY += cos(playerAngle) * speed;
226 }
227 }
228
229 // Check if any of the player car's corners are inside the AI car
230 if (!godMode && ((playerCorner1X > aiCorner1X && playerCorner1X < aiCorner3X &&
231 playerCorner1Y > aiCorner1Y && playerCorner1Y < aiCorner3Y) ||
232 (playerCorner2X > aiCorner1X && playerCorner2X < aiCorner3X &&
233 playerCorner2Y > aiCorner1Y && playerCorner2Y < aiCorner3Y) ||
234 (playerCorner3X > aiCorner1X && playerCorner3X < aiCorner3X &&
235 playerCorner3Y > aiCorner1Y && playerCorner3Y < aiCorner3Y) ||
236 (playerCorner4X > aiCorner1X && playerCorner4X < aiCorner3X &&
237 playerCorner4Y > aiCorner1Y && playerCorner4Y < aiCorner3Y) ||
238 // Check if any of the AI car's corners are inside the player car
239 (aiCorner1X > playerCorner1X && aiCorner1X < playerCorner3X &&
240 aiCorner1Y > playerCorner1Y && aiCorner1Y < playerCorner3Y) ||
241 (aiCorner2X > playerCorner1X && aiCorner2X < playerCorner3X &&
242 aiCorner2Y > playerCorner1Y && aiCorner2Y < playerCorner3Y) ||
243 (aiCorner3X > playerCorner1X && aiCorner3X < playerCorner3X &&
244 aiCorner3Y > playerCorner1Y && aiCorner3Y < playerCorner3Y) ||
245 (aiCorner4X > playerCorner1X && aiCorner4X < playerCorner3X &&
246 aiCorner4Y > playerCorner1Y && aiCorner4Y < playerCorner3Y)))
247 {
248 // Move the player car back to prevent collision
249 if (GetAsyncKeyState(VK_UP))
250 {
251 playerX -= sin(playerAngle) * speed;
252 playerY += cos(playerAngle) * speed;
253 }
254 if (GetAsyncKeyState(VK_DOWN))
255 {
256 playerX += sin(playerAngle) * speed;
257 playerY -= cos(playerAngle) * speed;
258 }
259
260 // Move the AI car back to prevent collision
261 aiX -= aiSpeedX;
262 aiY -= aiSpeedY;
263 }
264
265 /* Victory conditions commented out
266 if (playerX > WIDTH - ROAD_WIDTH - CAR_WIDTH && playerY < ROAD_WIDTH)
267 {
268 gameOver = true;
269 playerWon = true;
270 }
271 if (aiX > WIDTH - ROAD_WIDTH - CAR_WIDTH && aiY < Road_WIDTH)
272 {
273 gameOver = true;
274 playerWon = false;
275 }
276 */
277
278 InvalidateRect(hWnd, NULL, FALSE);
279 }
280 break;
281 case WM_PAINT:
282 {
283 PAINTSTRUCT ps;
284 HDC hdc = BeginPaint(hWnd, &ps);
285
286 // Create memory DC and bitmap for double buffering
287 HDC memDC = CreateCompatibleDC(hdc);
288 HBITMAP memBitmap = CreateCompatibleBitmap(hdc, WIDTH, HEIGHT);
289 HBITMAP oldBitmap = (HBITMAP)SelectObject(memDC, memBitmap);
290
291 // Clear background
292 HBRUSH lightGreenBrush = CreateSolidBrush(RGB(144, 238, 144)); // Light green color
293 RECT rect = { 0, 0, WIDTH, HEIGHT };
294 FillRect(memDC, &rect, lightGreenBrush);
295 DeleteObject(lightGreenBrush);
296
297 // Draw roads (black rectangles)
298 HBRUSH blackBrush = CreateSolidBrush(RGB(0, 0, 0));
299 // Vertical road
300 RECT verticalRoad = { 0, 0, ROAD_WIDTH, HEIGHT };
301 FillRect(memDC, &verticalRoad, blackBrush);
302 // Horizontal road (twice as tall)
303 RECT horizontalRoad = { 0, 0, WIDTH, ROAD_WIDTH * 2 };
304 FillRect(memDC, &horizontalRoad, blackBrush);
305 DeleteObject(blackBrush);
306
307 // Draw yellow road strips
308 HBRUSH yellowBrush = CreateSolidBrush(RGB(255, 255, 0));
309 SelectObject(memDC, yellowBrush);
310 // Vertical road strips
311 for (int y = 0; y < HEIGHT; y += 80) {
312 Rectangle(memDC, ROAD_WIDTH / 2 - 5, y, ROAD_WIDTH / 2 + 5, y + 40);
313 }
314 // Horizontal road strips
315 for (int x = 0; x < WIDTH; x += 80) {
316 Rectangle(memDC, x, ROAD_WIDTH - 5, x + 40, ROAD_WIDTH + 5);
317 }
318 DeleteObject(yellowBrush);
319
320 // Drawing Player's Car and Headlights
321 HBRUSH redBrush = CreateSolidBrush(RGB(255, 0, 0));
322 SelectObject(memDC, redBrush);
323 int savedDC = SaveDC(memDC);
324 XFORM xform;
325 SetGraphicsMode(memDC, GM_ADVANCED);
326 xform.eM11 = (FLOAT)cos(playerAngle);
327 xform.eM12 = (FLOAT)sin(playerAngle);
328 xform.eM21 = (FLOAT)-sin(playerAngle);
329 xform.eM22 = (FLOAT)cos(playerAngle);
330 xform.eDx = (FLOAT)playerX + CAR_WIDTH / 2;
331 xform.eDy = (FLOAT)playerY + CAR_HEIGHT / 2;
332 SetWorldTransform(memDC, &xform);
333 Rectangle(memDC, -CAR_WIDTH / 2, -CAR_HEIGHT / 2, CAR_WIDTH / 2, CAR_HEIGHT / 2);
334
335 //headlights yellow (player)
336 SelectObject(memDC, CreateSolidBrush(RGB(255, 255, 0)));
337 Rectangle(memDC, -CAR_WIDTH / 2 + 2, -CAR_HEIGHT / 2 + 2, -CAR_WIDTH / 4, -CAR_HEIGHT / 2 + 6);
338 Rectangle(memDC, CAR_WIDTH / 4, -CAR_HEIGHT / 2 + 2, CAR_WIDTH / 2 - 2, -CAR_HEIGHT / 2 + 6);
339
340 HBRUSH headlightBrush = CreateSolidBrush(RGB(255, 255, 255));
341 SelectObject(memDC, headlightBrush);
342 // Consistent headlight offset, relative to the car's dimensions
343 int headlightSize = 10;
344 int playerheadlightOffsetX = 10;
345 int playerheadlightOffsetY = -CAR_HEIGHT / 2 + 15; // Adjusted vertical offset
346 Ellipse(memDC, -CAR_WIDTH / 2 + playerheadlightOffsetX, playerheadlightOffsetY,
347 -CAR_WIDTH / 2 + playerheadlightOffsetX + headlightSize, playerheadlightOffsetY + headlightSize);
348 Ellipse(memDC, CAR_WIDTH / 2 - playerheadlightOffsetX - headlightSize, playerheadlightOffsetY,
349 CAR_WIDTH / 2 - playerheadlightOffsetX, playerheadlightOffsetY + headlightSize);
350 DeleteObject(headlightBrush);
351
352//start
353 int wsY = -CAR_HEIGHT / 2 + int(0.38f * CAR_HEIGHT);
354 int wsH = CAR_HEIGHT / 6;
355 int wsW = int(CAR_WIDTH * 0.7f);
356
357 HBRUSH hWin = CreateSolidBrush(RGB(0, 0, 0));
358 SelectObject(memDC, hWin);
359
360 Rectangle(memDC,
361 -wsW / 2, wsY,
362 wsW / 2, wsY + wsH
363 );
364
365//start sidewindow
366 int stripW = max(2, CAR_WIDTH / 20);
367 int stripH = wsH * 2;
368
369 Rectangle(memDC,
370 -wsW / 2 - stripW,
371 wsY,
372 -wsW / 2,
373 wsY + stripH
374 );
375
376 Rectangle(memDC,
377 wsW / 2,
378 wsY,
379 wsW / 2 + stripW,
380 wsY + stripH
381 );
382//end sidewindow
383
384 int sideW = CAR_WIDTH / 8;
385 Rectangle(memDC,
386 -CAR_WIDTH / 2 + 5, wsY,
387 -CAR_WIDTH / 2 + 5 + sideW, wsY + wsH
388 );
389 Rectangle(memDC,
390 CAR_WIDTH / 2 - 5 - sideW, wsY,
391 CAR_WIDTH / 2 - 5, wsY + wsH
392 );
393
394 DeleteObject(hWin);
395
396 HBRUSH hTy = CreateSolidBrush(RGB(0, 0, 0));
397 SelectObject(memDC, hTy);
398 int t = TYRE_SIZE;
399
400 int fy = -CAR_HEIGHT / 2 + 5;
401 Rectangle(memDC, -CAR_WIDTH / 2, fy, -CAR_WIDTH / 2 + t, fy + t);
402 Rectangle(memDC, CAR_WIDTH / 2 - t, fy, CAR_WIDTH / 2, fy + t);
403
404 int ry = CAR_HEIGHT / 2 - t - 5;
405 Rectangle(memDC, -CAR_WIDTH / 2, ry, -CAR_WIDTH / 2 + t, ry + t);
406 Rectangle(memDC, CAR_WIDTH / 2 - t, ry, CAR_WIDTH / 2, ry + t);
407
408 DeleteObject(hTy);
409
410//ends
411
412
413 RestoreDC(memDC, savedDC);
414 DeleteObject(redBrush);
415
416 // Draw AI car (blue rectangle)
417 // AI Car Rendering
418 // Drawing AI's Car and Headlights
419 // Draw AI car (blue rectangle)
420 // AI Car Rendering
421 // AI Car Rendering
422 //O3's fix working best inconsistent padded positioning tho
423 // Draw AI car (blue rectangle)
424 // ----- Draw AI Car (blue rectangle) with rotated transform -----
425 HBRUSH blueBrush = CreateSolidBrush(RGB(0, 0, 255));
426 SelectObject(memDC, blueBrush);
427 int savedDC2 = SaveDC(memDC); // Save state using a unique variable name
428 SetGraphicsMode(memDC, GM_ADVANCED);
429 XFORM xform2;
430 xform2.eM11 = (FLOAT)cos(aiAngle);
431 xform2.eM12 = (FLOAT)sin(aiAngle);
432
433
434 xform2.eM21 = (FLOAT)-sin(aiAngle);
435 xform2.eM22 = (FLOAT)cos(aiAngle);
436 xform2.eDx = (FLOAT)aiX + CAR_WIDTH / 2;
437 xform2.eDy = (FLOAT)aiY + CAR_HEIGHT / 2;
438 SetWorldTransform(memDC, &xform2);
439 Rectangle(memDC, -CAR_WIDTH / 2, -CAR_HEIGHT / 2, CAR_WIDTH / 2, CAR_HEIGHT / 2);
440 RestoreDC(memDC, savedDC2);
441 DeleteObject(blueBrush);
442
443 // ----- Dynamic AI Headlight Positioning -----
444 //
445 // This solution computes the AI car's nose (front) using its center (cx,cy)
446 // and a front vector derived from aiAngle. Note that the "front distance" is
447 // CAR_HEIGHT/2 when facing up/down (aiAngle == 0 or PI) and CAR_WIDTH/2 when
448 // facing right/left (aiAngle == -PI/2 or PI/2). We then move slightly back from
449 // the extreme nose by frontMargin, and offset perpendicular (by aiheadlightSeparation)
450 // to get the left and right headlight positions.
451 //
452 // Define parameters (adjust as needed):
453 float cx = aiX + CAR_WIDTH / 2.0f;
454 float cy = aiY + CAR_HEIGHT / 2.0f;
455 float frontMargin = 5.0f; // Moves headlights slightly inward from the nose
456 float aiheadlightSeparation = 10.0f; // Lateral offset from the nose for each headlight
457 int aiheadlightSize = 8; // Size of the headlight circle
458
459 // Determine the front distance depending on orientation:
460 float frontDistance;
461 if (aiAngle == 0 || aiAngle == PI)
462 frontDistance = CAR_HEIGHT / 2.0f;
463 else // aiAngle == -PI/2 or PI/2
464 frontDistance = CAR_WIDTH / 2.0f;
465
466 // The default car drawing uses a local coordinate system where the car's nose is at (0, -1)
467 // i.e. at (0, -frontDistance). Thus the front vector (rotated) is:
468 float noseX = cx + (-sin(aiAngle)) * frontDistance;
469 float noseY = cy + (-cos(aiAngle)) * frontDistance;
470
471 // Pull the headlight positions slightly back from the extreme nose using frontMargin:
472 float effectiveX = cx + (-sin(aiAngle)) * (frontDistance - frontMargin);
473 float effectiveY = cy + (-cos(aiAngle)) * (frontDistance - frontMargin);
474
475 // Compute a perpendicular vector to the front. For a front vector f = (-sin(aiAngle), -cos(aiAngle)),
476 // a perpendicular is p = (cos(aiAngle), -sin(aiAngle)). (We use -p for the left headlight.)
477 float px = cos(aiAngle);
478 float py = -sin(aiAngle);
479
480 // Compute left and right headlight positions by offsetting perpendicular to the front:
481 float leftHeadlightX = effectiveX - px * aiheadlightSeparation;
482 float leftHeadlightY = effectiveY - py * aiheadlightSeparation;
483
484 float rightHeadlightX = effectiveX + px * aiheadlightSeparation;
485 float rightHeadlightY = effectiveY + py * aiheadlightSeparation;
486
487 // Draw the AI headlights using the computed world coordinates:
488 HBRUSH aiHeadlightBrush = CreateSolidBrush(RGB(255, 255, 255));
489 SelectObject(memDC, aiHeadlightBrush);
490 Ellipse(memDC, (int)leftHeadlightX, (int)leftHeadlightY,
491 (int)(leftHeadlightX + aiheadlightSize), (int)(leftHeadlightY + aiheadlightSize));
492 Ellipse(memDC, (int)rightHeadlightX, (int)rightHeadlightY,
493 (int)(rightHeadlightX + aiheadlightSize), (int)(rightHeadlightY + aiheadlightSize));
494 DeleteObject(aiHeadlightBrush);
495
496 //voila! It's working perfectly /w the following dynamic code!!!
497 // ----- Draw AI Car (blue rectangle) with rotated transform -----
498 { //revert to..
499 HBRUSH blueBrush = CreateSolidBrush(RGB(0, 0, 255));
500 SelectObject(memDC, blueBrush);
501 int savedDC2 = SaveDC(memDC); // Save current DC state
502 SetGraphicsMode(memDC, GM_ADVANCED);
503 XFORM xform2;
504 xform2.eM11 = (FLOAT)cos(aiAngle);
505 xform2.eM12 = (FLOAT)sin(aiAngle);
506 xform2.eM21 = (FLOAT)-sin(aiAngle);
507 xform2.eM22 = (FLOAT)cos(aiAngle);
508 xform2.eDx = (FLOAT)aiX + CAR_WIDTH / 2;
509 xform2.eDy = (FLOAT)aiY + CAR_HEIGHT / 2;
510 SetWorldTransform(memDC, &xform2);
511 Rectangle(memDC, -CAR_WIDTH / 2, -CAR_HEIGHT / 2, CAR_WIDTH / 2, CAR_HEIGHT / 2);
512
513
514 /*HBRUSH hlBrush = CreateSolidBrush(RGB(255, 255, 255));
515 SelectObject(memDC, hlBrush);
516 int hlSize = 8;
517 int hlOffset = -CAR_HEIGHT / 2 + 5;
518
519 Ellipse(memDC,
520 -CAR_WIDTH / 4 - hlSize / 2, hlOffset,
521 -CAR_WIDTH / 4 + hlSize / 2, hlOffset + hlSize
522 );
523
524 Ellipse(memDC,
525 +CAR_WIDTH / 4 - hlSize / 2, hlOffset,
526 +CAR_WIDTH / 4 + hlSize / 2, hlOffset + hlSize
527 );
528 DeleteObject(hlBrush);*/
529
530 //revert to ..
531
532/* //headlights yellow (AI)
533 SelectObject(memDC, CreateSolidBrush(RGB(255, 255, 0)));
534 Rectangle(memDC, -CAR_WIDTH / 2 + 2, -CAR_HEIGHT / 2 + 2, -CAR_WIDTH / 4, -CAR_HEIGHT / 2 + 6);
535 Rectangle(memDC, CAR_WIDTH / 4, -CAR_HEIGHT / 2 + 2, CAR_WIDTH / 2 - 2, -CAR_HEIGHT / 2 + 6);
536 */
537
538 HBRUSH winB = CreateSolidBrush(RGB(0, 0, 0));
539 SelectObject(memDC, winB);
540
541 int wsY = -CAR_HEIGHT / 2 + int(0.38f * CAR_HEIGHT);
542 int wsH = CAR_HEIGHT / 6;
543 int wsW = int(CAR_WIDTH * 0.7f);
544
545 Rectangle(memDC,
546 -wsW / 2, wsY,
547 wsW / 2, wsY + wsH
548 );
549
550 int stripW = max(2, CAR_WIDTH / 20);
551 int stripH = wsH * 2;
552 Rectangle(memDC,
553 -wsW / 2 - stripW, wsY,
554 -wsW / 2, wsY + stripH
555 );
556 Rectangle(memDC,
557 +wsW / 2, wsY,
558 +wsW / 2 + stripW, wsY + stripH
559 );
560 DeleteObject(winB);
561
562
563 HBRUSH tyB = CreateSolidBrush(RGB(0, 0, 0));
564 SelectObject(memDC, tyB);
565 int t = TYRE_SIZE;
566
567 int fy = -CAR_HEIGHT / 2 + 5;
568 Rectangle(memDC, -CAR_WIDTH / 2, fy, -CAR_WIDTH / 2 + t, fy + t);
569 Rectangle(memDC, +CAR_WIDTH / 2 - t, fy, +CAR_WIDTH / 2, fy + t);
570
571 int ry = +CAR_HEIGHT / 2 - t - 5;
572 Rectangle(memDC, -CAR_WIDTH / 2, ry, -CAR_WIDTH / 2 + t, ry + t);
573 Rectangle(memDC, +CAR_WIDTH / 2 - t, ry, +CAR_WIDTH / 2, ry + t);
574 DeleteObject(tyB);
575
576
577 /*const float frontFrac = 0.38f;
578 int wsY = int(-CAR_HEIGHT / 2 + frontFrac * CAR_HEIGHT);
579 int wsH = CAR_HEIGHT / 6;
580 int wsW = int(CAR_WIDTH * 0.7f);
581 HBRUSH winBrush = CreateSolidBrush(RGB(0, 0, 0));
582 SelectObject(memDC, winBrush);
583
584 Rectangle(memDC,
585 -wsW / 2, wsY,
586 wsW / 2, wsY + wsH
587 );
588
589 int stripW = max(2, CAR_WIDTH / 20);
590 int stripH = wsH * 2;
591
592 Rectangle(memDC,
593 -wsW / 2 - stripW, wsY,
594 -wsW / 2, wsY + stripH
595 );
596
597 Rectangle(memDC,
598 +wsW / 2, wsY,
599 +wsW / 2 + stripW, wsY + stripH
600 );
601 DeleteObject(winBrush);
602
603
604 HBRUSH tyBrush = CreateSolidBrush(RGB(0, 0, 0));
605 SelectObject(memDC, tyBrush);
606 int t = TYRE_SIZE;
607
608 int fy = -CAR_HEIGHT / 2 + 5;
609 Rectangle(memDC, -CAR_WIDTH / 2, fy, -CAR_WIDTH / 2 + t, fy + t);
610 Rectangle(memDC, +CAR_WIDTH / 2 - t, fy, CAR_WIDTH / 2, fy + t);
611
612 int ry = +CAR_HEIGHT / 2 - t - 5;
613 Rectangle(memDC, -CAR_WIDTH / 2, ry, -CAR_WIDTH / 2 + t, ry + t);
614 Rectangle(memDC, +CAR_WIDTH / 2 - t, ry, CAR_WIDTH / 2, ry + t);
615 DeleteObject(tyBrush); */
616
617
618 /*
619 //start
620 int wsY = -CAR_HEIGHT / 2 + int(0.38f * CAR_HEIGHT);
621 int wsH = CAR_HEIGHT / 6;
622 int wsW = int(CAR_WIDTH * 0.7f);
623
624 HBRUSH hWin = CreateSolidBrush(RGB(0, 0, 0));
625 SelectObject(memDC, hWin);
626
627 Rectangle(memDC,
628 -wsW / 2, wsY,
629 wsW / 2, wsY + wsH
630 );
631
632 //start sidewindow
633 int stripW = max(2, CAR_WIDTH / 20);
634 int stripH = wsH * 2;
635
636 Rectangle(memDC,
637 -wsW / 2 - stripW,
638 wsY,
639 -wsW / 2,
640 wsY + stripH
641 );
642
643 Rectangle(memDC,
644 wsW / 2,
645 wsY,
646 wsW / 2 + stripW,
647 wsY + stripH
648 );
649 //end sidewindow
650 */
651 /*
652 int sideW = CAR_WIDTH / 8;
653 Rectangle(memDC,
654 -CAR_WIDTH / 2 + 5, wsY,
655 -CAR_WIDTH / 2 + 5 + sideW, wsY + wsH
656 );
657 Rectangle(memDC,
658 CAR_WIDTH / 2 - 5 - sideW, wsY,
659 CAR_WIDTH / 2 - 5, wsY + wsH
660 );
661*/
662 /*
663 DeleteObject(hWin);
664
665 HBRUSH hTy = CreateSolidBrush(RGB(0, 0, 0));
666 SelectObject(memDC, hTy);
667 int t = TYRE_SIZE;
668
669 int fy = -CAR_HEIGHT / 2 + 5;
670 Rectangle(memDC, -CAR_WIDTH / 2, fy, -CAR_WIDTH / 2 + t, fy + t);
671 Rectangle(memDC, CAR_WIDTH / 2 - t, fy, CAR_WIDTH / 2, fy + t);
672
673 int ry = CAR_HEIGHT / 2 - t - 5;
674 Rectangle(memDC, -CAR_WIDTH / 2, ry, -CAR_WIDTH / 2 + t, ry + t);
675 Rectangle(memDC, CAR_WIDTH / 2 - t, ry, CAR_WIDTH / 2, ry + t);
676
677 DeleteObject(hTy);
678 //ends */
679
680 RestoreDC(memDC, savedDC2);
681 DeleteObject(blueBrush);
682 }
683
684 /*{
685 HBRUSH blueBrush = CreateSolidBrush(RGB(0, 0, 255));
686 SelectObject(memDC, blueBrush);
687
688 int savedDC2 = SaveDC(memDC);
689 SetGraphicsMode(memDC, GM_ADVANCED);
690
691 XFORM xform2;
692 xform2.eM11 = (FLOAT)cos(aiAngle);
693 xform2.eM12 = (FLOAT)sin(aiAngle);
694 xform2.eM21 = (FLOAT)-sin(aiAngle);
695 xform2.eM22 = (FLOAT)cos(aiAngle);
696 xform2.eDx = (FLOAT)aiX + CAR_WIDTH / 2;
697 xform2.eDy = (FLOAT)aiY + CAR_HEIGHT / 2;
698 SetWorldTransform(memDC, &xform2);
699
700 Rectangle(memDC, -CAR_WIDTH / 2, -CAR_HEIGHT / 2, CAR_WIDTH / 2, CAR_HEIGHT / 2);
701
702 {
703 HBRUSH hlBrush = CreateSolidBrush(RGB(255, 255, 255));
704 SelectObject(memDC, hlBrush);
705 int hlSize = 8;
706 int hlOffset = -CAR_HEIGHT / 2 + 5;
707
708 Ellipse(memDC,
709 -CAR_WIDTH / 4 - hlSize / 2, hlOffset,
710 -CAR_WIDTH / 4 + hlSize / 2, hlOffset + hlSize
711 );
712
713 Ellipse(memDC,
714 +CAR_WIDTH / 4 - hlSize / 2, hlOffset,
715 +CAR_WIDTH / 4 + hlSize / 2, hlOffset + hlSize
716 );
717 DeleteObject(hlBrush);
718 }
719
720 {
721 HBRUSH winBrush = CreateSolidBrush(RGB(0, 0, 0));
722 SelectObject(memDC, winBrush);
723
724 int wsY = -CAR_HEIGHT / 2 + int(0.38f * CAR_HEIGHT);
725 int wsH = CAR_HEIGHT / 6;
726 int wsW = int(CAR_WIDTH * 0.7f);
727
728 Rectangle(memDC,
729 -wsW / 2, wsY,
730 wsW / 2, wsY + wsH
731 );
732
733 int stripW = max(2, CAR_WIDTH / 20);
734 int stripH = wsH * 2;
735
736 Rectangle(memDC,
737 -wsW / 2 - stripW, wsY,
738 -wsW / 2, wsY + stripH
739 );
740
741 Rectangle(memDC,
742 +wsW / 2, wsY,
743 +wsW / 2 + stripW, wsY + stripH
744 );
745
746 DeleteObject(winBrush);
747 }
748
749 {
750 HBRUSH tyBrush = CreateSolidBrush(RGB(0, 0, 0));
751 SelectObject(memDC, tyBrush);
752
753 int t = TYRE_SIZE;
754
755 int fy = -CAR_HEIGHT / 2 + 5;
756 Rectangle(memDC, -CAR_WIDTH / 2, fy, -CAR_WIDTH / 2 + t, fy + t);
757 Rectangle(memDC, +CAR_WIDTH / 2 - t, fy, +CAR_WIDTH / 2, fy + t);
758
759 int ry = +CAR_HEIGHT / 2 - t - 5;
760 Rectangle(memDC, -CAR_WIDTH / 2, ry, -CAR_WIDTH / 2 + t, ry + t);
761 Rectangle(memDC, +CAR_WIDTH / 2 - t, ry, +CAR_WIDTH / 2, ry + t);
762
763 DeleteObject(tyBrush);
764 }
765
766 RestoreDC(memDC, savedDC2);
767 DeleteObject(blueBrush);
768 }*/
769
770
771 // ----- Dynamically Compute and Draw AI Headlights -----
772 //
773 // This solution calculates the headlight positions based on the car�s center,
774 // a �front� vector (pointing toward the nose) and a perpendicular vector for lateral offset.
775 // The idea is that the headlights are placed at a fixed distance (headlightDistance)
776 // from the center along the front vector (which is always the nose direction)
777 // and then offset left/right by aiheadlightSeparation.
778 /*{ //revert to..
779 // Car center
780 float cx = aiX + CAR_WIDTH / 2.0f;
781 float cy = aiY + CAR_HEIGHT / 2.0f;
782
783 // Parameters � adjust these to fine-tune the look:
784 // We use CAR_HEIGHT/2 as the full distance from center to nose when facing up.
785 // To mimic the player car�s appearance (headlights slightly inset from the very front),
786 // we subtract 15 pixels.
787 float headlightDistance = CAR_HEIGHT / 2.0f - 15.0f;
788 float aiheadlightSeparation = 10.0f; // Lateral offset from the center of the nose
789 int aiheadlightSize = 8; // Headlight circle size
790
791 // Compute the "front" direction vector.
792 // Since the car�s default (unrotated) orientation has its nose at the top,
793 // the front vector in local coordinates is (0, -1). Rotating that by aiAngle:
794 float frontDirX = -sin(aiAngle);
795 float frontDirY = -cos(aiAngle);
796
797 // Determine the headlight �center� position � a point along the nose,
798 // but moved slightly inward by headlightDistance:
799 float headlightCenterX = cx + frontDirX * headlightDistance;
800 float headlightCenterY = cy + frontDirY * headlightDistance;
801
802 // Compute a perpendicular vector to the front.
803 // A vector perpendicular to (frontDirX, frontDirY) is given by (cos(aiAngle), -sin(aiAngle)).
804 float perpX = cos(aiAngle);
805 float perpY = -sin(aiAngle);
806
807 // Compute left and right headlight positions by offsetting the headlight center along the perpendicular.
808 float leftHeadlightX = headlightCenterX - perpX * aiheadlightSeparation;
809 float leftHeadlightY = headlightCenterY - perpY * aiheadlightSeparation;
810 float rightHeadlightX = headlightCenterX + perpX * aiheadlightSeparation;
811 float rightHeadlightY = headlightCenterY + perpY * aiheadlightSeparation;
812
813 // Draw the AI headlights using the computed world coordinates:
814 HBRUSH aiHeadlightBrush = CreateSolidBrush(RGB(255, 255, 255));
815 SelectObject(memDC, aiHeadlightBrush);
816 Ellipse(memDC, (int)leftHeadlightX, (int)leftHeadlightY,
817 (int)(leftHeadlightX + aiheadlightSize), (int)(leftHeadlightY + aiheadlightSize));
818 Ellipse(memDC, (int)rightHeadlightX, (int)rightHeadlightY,
819 (int)(rightHeadlightX + aiheadlightSize), (int)(rightHeadlightY + aiheadlightSize));
820 DeleteObject(aiHeadlightBrush);
821
822 }*/
823
824
825 {
826 float cx = aiX + CAR_WIDTH / 2.0f;
827 float cy = aiY + CAR_HEIGHT / 2.0f;
828
829 float frontDirX = -sin(aiAngle);
830 float frontDirY = -cos(aiAngle);
831
832 float perpX = cos(aiAngle);
833 float perpY = -sin(aiAngle);
834
835 float headlightDistance = CAR_HEIGHT / 2.0f - 15.0f;
836 float aiheadlightSeparation = 10.0f;
837 int aiheadlightSize = 8;
838
839 float leftHeadlightX = cx + frontDirX * headlightDistance - perpX * aiheadlightSeparation;
840 float leftHeadlightY = cy + frontDirY * headlightDistance - perpY * aiheadlightSeparation;
841 float rightHeadlightX = cx + frontDirX * headlightDistance + perpX * aiheadlightSeparation;
842 float rightHeadlightY = cy + frontDirY * headlightDistance + perpY * aiheadlightSeparation;
843
844 HBRUSH aiHeadlightBrush = CreateSolidBrush(RGB(255, 255, 255));
845 SelectObject(memDC, aiHeadlightBrush);
846 Ellipse(memDC,
847 (int)leftHeadlightX, (int)leftHeadlightY,
848 (int)(leftHeadlightX + aiheadlightSize), (int)(leftHeadlightY + aiheadlightSize)
849 );
850 Ellipse(memDC,
851 (int)rightHeadlightX, (int)rightHeadlightY,
852 (int)(rightHeadlightX + aiheadlightSize), (int)(rightHeadlightY + aiheadlightSize)
853 );
854 DeleteObject(aiHeadlightBrush);
855
856
857 float windowDistance = headlightDistance + 10.0f;
858 float windowX = cx + frontDirX * windowDistance;
859 float windowY = cy + frontDirY * windowDistance;
860 int wsW = int(CAR_WIDTH * 0.7f);
861 int wsH = CAR_HEIGHT / 8;
862
863 HBRUSH winBrush = CreateSolidBrush(RGB(0, 0, 0));
864 SelectObject(memDC, winBrush);
865
866 //misbehaving chunk of rectangle protrusion commented-out
867 /*Rectangle(memDC,
868 int(windowX - wsW / 2), int(windowY - wsH / 2),
869 int(windowX + wsW / 2), int(windowY + wsH / 2)
870 );*/
871
872 float sideOffset = wsW / 2 + 4.0f; // push out from window edge
873 int sideW = 3; // ~3px thick
874 int sideH = wsH; // same height as windscreen
875
876
877 float lwX = windowX - perpX * sideOffset;
878 float lwY = windowY - perpY * sideOffset;
879 Rectangle(memDC,
880 int(lwX - sideW / 2), int(lwY - sideH / 2),
881 int(lwX + sideW / 2), int(lwY + sideH / 2)
882 );
883
884 float rwX = windowX + perpX * sideOffset;
885 float rwY = windowY + perpY * sideOffset;
886 Rectangle(memDC,
887 int(rwX - sideW / 2), int(rwY - sideH / 2),
888 int(rwX + sideW / 2), int(rwY + sideH / 2)
889 );
890 DeleteObject(winBrush);
891 }
892
893
894
895
896
897 //original AI code
898 /* HBRUSH blueBrush = CreateSolidBrush(RGB(0, 0, 255));
899 SelectObject(memDC, blueBrush);
900 savedDC = SaveDC(memDC);
901 SetGraphicsMode(memDC, GM_ADVANCED);
902 XFORM xform2;
903 xform2.eM11 = (FLOAT)cos(aiAngle);
904 xform2.eM12 = (FLOAT)sin(aiAngle);
905 xform2.eM21 = (FLOAT)-sin(aiAngle);
906 xform2.eM22 = (FLOAT)cos(aiAngle);
907 xform2.eDx = (FLOAT)aiX + CAR_WIDTH / 2;
908 xform2.eDy = (FLOAT)aiY + CAR_HEIGHT / 2;
909 SetWorldTransform(memDC, &xform2);
910 Rectangle(memDC, -CAR_WIDTH / 2, -CAR_HEIGHT / 2, CAR_WIDTH / 2, CAR_HEIGHT / 2);
911
912 HBRUSH aiheadlightBrush = CreateSolidBrush(RGB(255, 255, 255));
913 SelectObject(memDC, aiheadlightBrush);
914 int aiheadlightSize = 8;
915
916 // Define AI headlight positions based on calculated offsets
917 Ellipse(memDC, -CAR_WIDTH / 4 - aiheadlightSize / 2, -CAR_HEIGHT / 2 + 5,
918 -CAR_WIDTH / 4 + aiheadlightSize / 2, -CAR_HEIGHT / 2 + 5 + aiheadlightSize);
919 Ellipse(memDC, CAR_WIDTH / 4 - aiheadlightSize / 2, -CAR_HEIGHT / 2 + 5,
920 CAR_WIDTH / 4 + aiheadlightSize / 2, -CAR_HEIGHT / 2 + 5 + aiheadlightSize);
921
922 DeleteObject(aiheadlightBrush);
923 RestoreDC(memDC, savedDC);
924 DeleteObject(blueBrush); */
925
926 // Draw countdown timer if game hasn't started
927 if (!gameStarted)
928 {
929 char timerText[10];
930 sprintf_s(timerText, "%d", timer / 10);
931 SetTextColor(memDC, RGB(255, 0, 0));
932 SetBkMode(memDC, TRANSPARENT);
933 TextOutA(memDC, WIDTH / 2 - 10, HEIGHT / 2 - 10, timerText, strlen(timerText));
934 }
935
936 // Draw God Mode text indicator
937 if (godMode)
938 {
939 SetTextColor(memDC, RGB(255, 0, 0));
940 SetBkMode(memDC, TRANSPARENT);
941 TextOutA(memDC, 10, 10, "God Mode ON", 11);
942 }
943
944 // Copy from memory DC to screen
945 BitBlt(hdc, 0, 0, WIDTH, HEIGHT, memDC, 0, 0, SRCCOPY);
946
947 // Clean up
948 SelectObject(memDC, oldBitmap);
949 DeleteObject(memBitmap);
950 DeleteDC(memDC);
951
952 EndPaint(hWnd, &ps);
953 break;
954 }
955 case WM_DESTROY:
956 KillTimer(hWnd, 1);
957 PostQuitMessage(0);
958 break;
959 case WM_KEYDOWN:
960 if (wParam == VK_F1)
961 {
962 MessageBoxW(hWnd, L"2D Racing Game 3.0 Programmed in C++ Win32 API (491 lines of code) by Entisoft Software (c) Evans Thorpemorton", L"About", MB_OK | MB_ICONINFORMATION); // orig 395 lines
963 }
964 //break;
965 if (wParam == VK_ESCAPE)
966 {
967 PostQuitMessage(0);
968 }
969 break;
970 default:
971 return DefWindowProc(hWnd, message, wParam, lParam);
972 }
973 return 0;
974}
975
976int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
977{
978 // Register window class
979 WNDCLASSEX wc = { 0 };
980 wc.cbSize = sizeof(WNDCLASSEX);
981 wc.style = CS_HREDRAW | CS_VREDRAW;
982 wc.lpfnWndProc = WndProc;
983 wc.cbClsExtra = 0;
984 wc.cbWndExtra = 0;
985 wc.hInstance = hInstance;
986 wc.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_ICON1)); // Modified line
987 //wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
988 wc.hCursor = LoadCursor(NULL, IDC_ARROW);
989 wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
990 wc.lpszMenuName = NULL;
991 wc.lpszClassName = L"RacingGame";
992 wc.hIconSm = (HICON)LoadImage(hInstance, // Modified line
993 MAKEINTRESOURCE(IDI_ICON1), // Modified line
994 IMAGE_ICON, // Modified line
995 16, // Modified line
996 16, // Modified line
997 LR_DEFAULTCOLOR); // Modified line
998 //wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
999 RegisterClassEx(&wc);
1000
1001 // Calculate the position to center the window
1002 int screenWidth = GetSystemMetrics(SM_CXSCREEN);
1003 int screenHeight = GetSystemMetrics(SM_CYSCREEN);
1004 int windowX = (screenWidth - WIDTH) / 2;
1005 int windowY = (screenHeight - HEIGHT) / 2;
1006
1007 // Create window
1008 HWND hWnd = CreateWindowEx(0, L"RacingGame", L"Racing Game (ArrowKeys=Move G=GodMode)", WS_OVERLAPPEDWINDOW, windowX, windowY, WIDTH, HEIGHT, NULL, NULL, hInstance, NULL);
1009
1010 // Show window
1011 //ShowWindow(hWnd, nCmdShow);
1012 ShowWindow(hWnd, SW_SHOWMAXIMIZED);
1013
1014 // Main loop
1015 MSG msg = { 0 };
1016 while (GetMessage(&msg, NULL, 0, 0))
1017 {
1018 TranslateMessage(&msg);
1019 DispatchMessage(&msg);
1020 }
1021
1022 return 0;
1023}
1024```