Advertisement
alien_fx_fiend

2D Car Racing (Finally AI Headlights Dynamically Positioning Fixed!!) *FINAL VER 3*

Mar 18th, 2025
138
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 26.56 KB | Source Code | 0 0
  1. ==++ Here's the full code 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
  12. const int WIDTH = 1366;
  13. const int HEIGHT = 768;
  14. const int ROAD_WIDTH = 200;
  15. const int CAR_WIDTH = 50;
  16. const int CAR_HEIGHT = 100;
  17. const int TYRE_SIZE = 10;
  18. const int FPS = 60;
  19. const int TIMER = 4;
  20. const int TURN_RADIUS = 5;
  21. const double PI = 3.14159265358979323846;
  22. const double M_PI = 3.14159265358979323846;
  23.  
  24. int playerX = 100;
  25. int playerY = HEIGHT - CAR_HEIGHT - 50;
  26. int playerSpeedX = 0;
  27. int playerSpeedY = 0;
  28. int aiX = playerX + CAR_WIDTH + 20;
  29. int aiY = playerY;
  30. float aiAngle = -PI / 2;  // Add this line
  31. int aiSpeedX = 0;
  32. int aiSpeedY = 0;
  33. int speed = 5;
  34. int aiSpeed = 5;
  35. int timer = TIMER;
  36. int playerTyre1X = playerX + 10;
  37. int playerTyre1Y = playerY + CAR_HEIGHT - TYRE_SIZE;
  38. int playerTyre2X = playerX + CAR_WIDTH - TYRE_SIZE - 10;
  39. int playerTyre2Y = playerY + CAR_HEIGHT - TYRE_SIZE;
  40. int aiTyre1X = aiX + 10;
  41. int aiTyre1Y = aiY + CAR_HEIGHT - TYRE_SIZE;
  42. int aiTyre2X = aiX + CAR_WIDTH - TYRE_SIZE - 10;
  43. int aiTyre2Y = aiY + CAR_HEIGHT - TYRE_SIZE;
  44. float playerAngle = -PI / 2;  // Initialize to face North by default
  45. //float playerAngle = 0.0f;
  46.  
  47. bool gameStarted = false;
  48. bool gameOver = false;
  49. bool playerWon = false;
  50. bool godMode = true;
  51. //int timer = 30 * 10; // 30 seconds * 10 (timer resolution)
  52.  
  53. // Window Procedure
  54. LRESULT 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.         HBRUSH headlightBrush = CreateSolidBrush(RGB(255, 255, 255));
  336.         SelectObject(memDC, headlightBrush);
  337.         // Consistent headlight offset, relative to the car's dimensions
  338.         int headlightSize = 10;
  339.         int playerheadlightOffsetX = 10;
  340.         int playerheadlightOffsetY = -CAR_HEIGHT / 2 + 15;  // Adjusted vertical offset
  341.         Ellipse(memDC, -CAR_WIDTH / 2 + playerheadlightOffsetX, playerheadlightOffsetY,
  342.             -CAR_WIDTH / 2 + playerheadlightOffsetX + headlightSize, playerheadlightOffsetY + headlightSize);
  343.         Ellipse(memDC, CAR_WIDTH / 2 - playerheadlightOffsetX - headlightSize, playerheadlightOffsetY,
  344.             CAR_WIDTH / 2 - playerheadlightOffsetX, playerheadlightOffsetY + headlightSize);
  345.         DeleteObject(headlightBrush);
  346.         RestoreDC(memDC, savedDC);
  347.         DeleteObject(redBrush);
  348.  
  349.         // Draw AI car (blue rectangle)
  350.         // AI Car Rendering
  351.         // Drawing AI's Car and Headlights
  352.                     // Draw AI car (blue rectangle)
  353.         // AI Car Rendering
  354.         // AI Car Rendering
  355.         //O3's fix working best inconsistent padded positioning tho
  356.             // Draw AI car (blue rectangle)
  357.         /* // ----- Draw AI Car (blue rectangle) with rotated transform -----
  358.         HBRUSH blueBrush = CreateSolidBrush(RGB(0, 0, 255));
  359.         SelectObject(memDC, blueBrush);
  360.         int savedDC2 = SaveDC(memDC);  // Save state using a unique variable name
  361.         SetGraphicsMode(memDC, GM_ADVANCED);
  362.         XFORM xform2;
  363.         xform2.eM11 = (FLOAT)cos(aiAngle);
  364.         xform2.eM12 = (FLOAT)sin(aiAngle);
  365.         xform2.eM21 = (FLOAT)-sin(aiAngle);
  366.         xform2.eM22 = (FLOAT)cos(aiAngle);
  367.         xform2.eDx = (FLOAT)aiX + CAR_WIDTH / 2;
  368.         xform2.eDy = (FLOAT)aiY + CAR_HEIGHT / 2;
  369.         SetWorldTransform(memDC, &xform2);
  370.         Rectangle(memDC, -CAR_WIDTH / 2, -CAR_HEIGHT / 2, CAR_WIDTH / 2, CAR_HEIGHT / 2);
  371.         RestoreDC(memDC, savedDC2);
  372.         DeleteObject(blueBrush);
  373.  
  374.         // ----- Dynamic AI Headlight Positioning -----
  375.         //
  376.         // This solution computes the AI car's nose (front) using its center (cx,cy)
  377.         // and a front vector derived from aiAngle. Note that the "front distance" is
  378.         // CAR_HEIGHT/2 when facing up/down (aiAngle == 0 or PI) and CAR_WIDTH/2 when
  379.         // facing right/left (aiAngle == -PI/2 or PI/2). We then move slightly back from
  380.         // the extreme nose by frontMargin, and offset perpendicular (by aiheadlightSeparation)
  381.         // to get the left and right headlight positions.
  382.         //
  383.         // Define parameters (adjust as needed):
  384.         float cx = aiX + CAR_WIDTH / 2.0f;
  385.         float cy = aiY + CAR_HEIGHT / 2.0f;
  386.         float frontMargin = 5.0f;            // Moves headlights slightly inward from the nose
  387.         float aiheadlightSeparation = 10.0f;   // Lateral offset from the nose for each headlight
  388.         int aiheadlightSize = 8;             // Size of the headlight circle
  389.  
  390.         // Determine the front distance depending on orientation:
  391.         float frontDistance;
  392.         if (aiAngle == 0 || aiAngle == PI)
  393.             frontDistance = CAR_HEIGHT / 2.0f;
  394.         else // aiAngle == -PI/2 or PI/2
  395.             frontDistance = CAR_WIDTH / 2.0f;
  396.  
  397.         // The default car drawing uses a local coordinate system where the car's nose is at (0, -1)
  398.         // i.e. at (0, -frontDistance). Thus the front vector (rotated) is:
  399.         float noseX = cx + (-sin(aiAngle)) * frontDistance;
  400.         float noseY = cy + (-cos(aiAngle)) * frontDistance;
  401.  
  402.         // Pull the headlight positions slightly back from the extreme nose using frontMargin:
  403.         float effectiveX = cx + (-sin(aiAngle)) * (frontDistance - frontMargin);
  404.         float effectiveY = cy + (-cos(aiAngle)) * (frontDistance - frontMargin);
  405.  
  406.         // Compute a perpendicular vector to the front. For a front vector f = (-sin(aiAngle), -cos(aiAngle)),
  407.         // a perpendicular is p = (cos(aiAngle), -sin(aiAngle)). (We use -p for the left headlight.)
  408.         float px = cos(aiAngle);
  409.         float py = -sin(aiAngle);
  410.  
  411.         // Compute left and right headlight positions by offsetting perpendicular to the front:
  412.         float leftHeadlightX = effectiveX - px * aiheadlightSeparation;
  413.         float leftHeadlightY = effectiveY - py * aiheadlightSeparation;
  414.  
  415.         float rightHeadlightX = effectiveX + px * aiheadlightSeparation;
  416.         float rightHeadlightY = effectiveY + py * aiheadlightSeparation;
  417.  
  418.         // Draw the AI headlights using the computed world coordinates:
  419.         HBRUSH aiHeadlightBrush = CreateSolidBrush(RGB(255, 255, 255));
  420.         SelectObject(memDC, aiHeadlightBrush);
  421.         Ellipse(memDC, (int)leftHeadlightX, (int)leftHeadlightY,
  422.             (int)(leftHeadlightX + aiheadlightSize), (int)(leftHeadlightY + aiheadlightSize));
  423.         Ellipse(memDC, (int)rightHeadlightX, (int)rightHeadlightY,
  424.             (int)(rightHeadlightX + aiheadlightSize), (int)(rightHeadlightY + aiheadlightSize));
  425.         DeleteObject(aiHeadlightBrush); */
  426.  
  427.         //voila! It's working perfectly /w the following dynamic code!!!
  428.         // ----- Draw AI Car (blue rectangle) with rotated transform -----
  429.         {
  430.             HBRUSH blueBrush = CreateSolidBrush(RGB(0, 0, 255));
  431.             SelectObject(memDC, blueBrush);
  432.             int savedDC2 = SaveDC(memDC);  // Save current DC state
  433.             SetGraphicsMode(memDC, GM_ADVANCED);
  434.             XFORM xform2;
  435.             xform2.eM11 = (FLOAT)cos(aiAngle);
  436.             xform2.eM12 = (FLOAT)sin(aiAngle);
  437.             xform2.eM21 = (FLOAT)-sin(aiAngle);
  438.             xform2.eM22 = (FLOAT)cos(aiAngle);
  439.             xform2.eDx = (FLOAT)aiX + CAR_WIDTH / 2;
  440.             xform2.eDy = (FLOAT)aiY + CAR_HEIGHT / 2;
  441.             SetWorldTransform(memDC, &xform2);
  442.             Rectangle(memDC, -CAR_WIDTH / 2, -CAR_HEIGHT / 2, CAR_WIDTH / 2, CAR_HEIGHT / 2);
  443.             RestoreDC(memDC, savedDC2);
  444.             DeleteObject(blueBrush);
  445.         }
  446.  
  447.         // ----- Dynamically Compute and Draw AI Headlights -----
  448.         //
  449.         // This solution calculates the headlight positions based on the car�s center,
  450.         // a �front� vector (pointing toward the nose) and a perpendicular vector for lateral offset.
  451.         // The idea is that the headlights are placed at a fixed distance (headlightDistance)
  452.         // from the center along the front vector (which is always the nose direction)
  453.         // and then offset left/right by aiheadlightSeparation.
  454.         {
  455.             // Car center
  456.             float cx = aiX + CAR_WIDTH / 2.0f;
  457.             float cy = aiY + CAR_HEIGHT / 2.0f;
  458.  
  459.             // Parameters � adjust these to fine-tune the look:
  460.             // We use CAR_HEIGHT/2 as the full distance from center to nose when facing up.
  461.             // To mimic the player car�s appearance (headlights slightly inset from the very front),
  462.             // we subtract 15 pixels.
  463.             float headlightDistance = CAR_HEIGHT / 2.0f - 15.0f;
  464.             float aiheadlightSeparation = 10.0f;  // Lateral offset from the center of the nose
  465.             int aiheadlightSize = 8;              // Headlight circle size
  466.  
  467.             // Compute the "front" direction vector.
  468.             // Since the car�s default (unrotated) orientation has its nose at the top,
  469.             // the front vector in local coordinates is (0, -1). Rotating that by aiAngle:
  470.             float frontDirX = -sin(aiAngle);
  471.             float frontDirY = -cos(aiAngle);
  472.  
  473.             // Determine the headlight �center� position � a point along the nose,
  474.             // but moved slightly inward by headlightDistance:
  475.             float headlightCenterX = cx + frontDirX * headlightDistance;
  476.             float headlightCenterY = cy + frontDirY * headlightDistance;
  477.  
  478.             // Compute a perpendicular vector to the front.
  479.             // A vector perpendicular to (frontDirX, frontDirY) is given by (cos(aiAngle), -sin(aiAngle)).
  480.             float perpX = cos(aiAngle);
  481.             float perpY = -sin(aiAngle);
  482.  
  483.             // Compute left and right headlight positions by offsetting the headlight center along the perpendicular.
  484.             float leftHeadlightX = headlightCenterX - perpX * aiheadlightSeparation;
  485.             float leftHeadlightY = headlightCenterY - perpY * aiheadlightSeparation;
  486.             float rightHeadlightX = headlightCenterX + perpX * aiheadlightSeparation;
  487.             float rightHeadlightY = headlightCenterY + perpY * aiheadlightSeparation;
  488.  
  489.             // Draw the AI headlights using the computed world coordinates:
  490.             HBRUSH aiHeadlightBrush = CreateSolidBrush(RGB(255, 255, 255));
  491.             SelectObject(memDC, aiHeadlightBrush);
  492.             Ellipse(memDC, (int)leftHeadlightX, (int)leftHeadlightY,
  493.                 (int)(leftHeadlightX + aiheadlightSize), (int)(leftHeadlightY + aiheadlightSize));
  494.             Ellipse(memDC, (int)rightHeadlightX, (int)rightHeadlightY,
  495.                 (int)(rightHeadlightX + aiheadlightSize), (int)(rightHeadlightY + aiheadlightSize));
  496.             DeleteObject(aiHeadlightBrush);
  497.         }
  498.  
  499.  
  500.  
  501.  
  502.  
  503.         //original AI code
  504.         /* HBRUSH blueBrush = CreateSolidBrush(RGB(0, 0, 255));
  505.         SelectObject(memDC, blueBrush);
  506.         savedDC = SaveDC(memDC);
  507.         SetGraphicsMode(memDC, GM_ADVANCED);
  508.         XFORM xform2;
  509.         xform2.eM11 = (FLOAT)cos(aiAngle);
  510.         xform2.eM12 = (FLOAT)sin(aiAngle);
  511.         xform2.eM21 = (FLOAT)-sin(aiAngle);
  512.         xform2.eM22 = (FLOAT)cos(aiAngle);
  513.         xform2.eDx = (FLOAT)aiX + CAR_WIDTH / 2;
  514.         xform2.eDy = (FLOAT)aiY + CAR_HEIGHT / 2;
  515.         SetWorldTransform(memDC, &xform2);
  516.         Rectangle(memDC, -CAR_WIDTH / 2, -CAR_HEIGHT / 2, CAR_WIDTH / 2, CAR_HEIGHT / 2);
  517.  
  518.         HBRUSH aiheadlightBrush = CreateSolidBrush(RGB(255, 255, 255));
  519.         SelectObject(memDC, aiheadlightBrush);
  520.         int aiheadlightSize = 8;
  521.  
  522.         // Define AI headlight positions based on calculated offsets
  523.         Ellipse(memDC, -CAR_WIDTH / 4 - aiheadlightSize / 2, -CAR_HEIGHT / 2 + 5,
  524.             -CAR_WIDTH / 4 + aiheadlightSize / 2, -CAR_HEIGHT / 2 + 5 + aiheadlightSize);
  525.         Ellipse(memDC, CAR_WIDTH / 4 - aiheadlightSize / 2, -CAR_HEIGHT / 2 + 5,
  526.             CAR_WIDTH / 4 + aiheadlightSize / 2, -CAR_HEIGHT / 2 + 5 + aiheadlightSize);
  527.  
  528.         DeleteObject(aiheadlightBrush);
  529.         RestoreDC(memDC, savedDC);
  530.         DeleteObject(blueBrush); */
  531.  
  532.         // Draw countdown timer if game hasn't started
  533.         if (!gameStarted)
  534.         {
  535.             char timerText[10];
  536.             sprintf_s(timerText, "%d", timer / 10);
  537.             SetTextColor(memDC, RGB(255, 0, 0));
  538.             SetBkMode(memDC, TRANSPARENT);
  539.             TextOutA(memDC, WIDTH / 2 - 10, HEIGHT / 2 - 10, timerText, strlen(timerText));
  540.         }
  541.  
  542.         // Draw God Mode text indicator
  543.         if (godMode)
  544.         {
  545.             SetTextColor(memDC, RGB(255, 0, 0));
  546.             SetBkMode(memDC, TRANSPARENT);
  547.             TextOutA(memDC, 10, 10, "God Mode ON", 10);
  548.         }
  549.  
  550.         // Copy from memory DC to screen
  551.         BitBlt(hdc, 0, 0, WIDTH, HEIGHT, memDC, 0, 0, SRCCOPY);
  552.  
  553.         // Clean up
  554.         SelectObject(memDC, oldBitmap);
  555.         DeleteObject(memBitmap);
  556.         DeleteDC(memDC);
  557.  
  558.         EndPaint(hWnd, &ps);
  559.         break;
  560.     }
  561.     case WM_DESTROY:
  562.         KillTimer(hWnd, 1);
  563.         PostQuitMessage(0);
  564.         break;
  565.     case WM_KEYDOWN:
  566.         if (wParam == VK_F1)
  567.         {
  568.             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
  569.         }
  570.         //break;
  571.         if (wParam == VK_ESCAPE)
  572.         {
  573.             PostQuitMessage(0);
  574.         }
  575.         break;
  576.     default:
  577.         return DefWindowProc(hWnd, message, wParam, lParam);
  578.     }
  579.     return 0;
  580. }
  581.  
  582. int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
  583. {
  584.     // Register window class
  585.     WNDCLASSEX wc = { 0 };
  586.     wc.cbSize = sizeof(WNDCLASSEX);
  587.     wc.style = CS_HREDRAW | CS_VREDRAW;
  588.     wc.lpfnWndProc = WndProc;
  589.     wc.cbClsExtra = 0;
  590.     wc.cbWndExtra = 0;
  591.     wc.hInstance = hInstance;
  592.     wc.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_ICON1));        // Modified line
  593.     //wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
  594.     wc.hCursor = LoadCursor(NULL, IDC_ARROW);
  595.     wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
  596.     wc.lpszMenuName = NULL;
  597.     wc.lpszClassName = L"RacingGame";
  598.     wc.hIconSm = (HICON)LoadImage(hInstance,                           // Modified line
  599.         MAKEINTRESOURCE(IDI_ICON1),           // Modified line
  600.         IMAGE_ICON,                           // Modified line
  601.         16,                                   // Modified line
  602.         16,                                   // Modified line
  603.         LR_DEFAULTCOLOR);                     // Modified line
  604.     //wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
  605.     RegisterClassEx(&wc);
  606.  
  607.     // Calculate the position to center the window
  608.     int screenWidth = GetSystemMetrics(SM_CXSCREEN);
  609.     int screenHeight = GetSystemMetrics(SM_CYSCREEN);
  610.     int windowX = (screenWidth - WIDTH) / 2;
  611.     int windowY = (screenHeight - HEIGHT) / 2;
  612.  
  613.     // Create window
  614.     HWND hWnd = CreateWindowEx(0, L"RacingGame", L"Racing Game (ArrowKeys=Move G=GodMode)", WS_OVERLAPPEDWINDOW, windowX, windowY, WIDTH, HEIGHT, NULL, NULL, hInstance, NULL);
  615.  
  616.     // Show window
  617.     //ShowWindow(hWnd, nCmdShow);
  618.     ShowWindow(hWnd, SW_SHOWMAXIMIZED);
  619.  
  620.     // Main loop
  621.     MSG msg = { 0 };
  622.     while (GetMessage(&msg, NULL, 0, 0))
  623.     {
  624.         TranslateMessage(&msg);
  625.         DispatchMessage(&msg);
  626.     }
  627.  
  628.     return 0;
  629. }
  630. ```
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement