Nuppiz

Vectest

Feb 24th, 2022 (edited)
1,124
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 24.99 KB | None | 0 0
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <dos.h>
  4. #include <math.h>
  5. #include <stdint.h>
  6.  
  7. #define VIDEO_INT           0x10      /* the BIOS video interrupt. */
  8. #define SET_MODE            0x00      /* BIOS func to set the video mode. */
  9. #define VGA_256_COLOR_MODE  0x13      /* use to set 256-color mode. */
  10. #define TEXT_MODE           0x03      /* use to set 80x25 text mode. */
  11.  
  12. #define SCREEN_WIDTH        320       /* width in pixels of mode 0x13 */
  13. #define SCREEN_HEIGHT       200       /* height in pixels of mode 0x13 */
  14. #define NUM_COLORS          256       /* number of colors in mode 0x13 */
  15.  
  16. #define SET_PIXEL(x,y,color)      screen_buf[(y)*SCREEN_WIDTH + (x)] = color
  17.  
  18. #define KB_ARRAY_LENGTH     256
  19. #define KB_QUEUE_LENGTH     256
  20.  
  21. #define KEY_HIT_FLAG        1
  22. #define KEY_PRESSED_FLAG    2
  23. #define KEY_RELEASED_FLAG   0x80 // 128, MSB
  24. #define KEY_SPECIAL_CODE    0xE0 // 224
  25. #define KEY_IS_PRESSED(k)   (g_Keyboard[k] & KEY_PRESSED_FLAG)
  26. #define KEY_WAS_HIT(k)      (g_Keyboard[k] & KEY_HIT_FLAG)
  27. #define KEY_WAS_RELEASED(k) (g_Keyboard[k] & KEY_RELEASED_FLAG)
  28. #define KEY_WAS_TOGGLED(k)  (g_Keyboard[k] & (KEY_HIT_FLAG|KEY_RELEASED_FLAG))
  29. #define KEY_LEFT            75
  30. #define KEY_RIGHT           77
  31. #define KEY_UP              72
  32. #define KEY_DOWN            80
  33. #define KEY_F10             68
  34.  
  35. #define X_AXIS              1
  36. #define Y_AXIS              2
  37.  
  38. #define SQUARE_SIZE         20
  39. #define SCREEN_SIZE         64000
  40. #define SQUARE_ROWS         SCREEN_HEIGHT / SQUARE_SIZE
  41. #define SQUARE_COLUMNS      SCREEN_WIDTH / SQUARE_SIZE
  42. #define degToRad(degree)    ((degree) * M_PI / 180.0)
  43.  
  44. #define RAD_360             (2*M_PI)
  45. #define RAD_180             M_PI
  46. #define RAD_90              (M_PI/2)
  47. #define RAD_45              (M_PI/4)
  48. #define RAD_30              (M_PI/6)
  49. #define RAD_15              (M_PI/12)
  50.  
  51. #define WALL                7
  52. #define COLOUR_RED          40
  53. #define COLOUR_PEACH        64
  54.  
  55. #define player              object_array[0]
  56. #define MAX_SPEED           10.0
  57. #define ACCELERATION_RATE   2.0
  58. #define BRAKE_RATE          0.9
  59. #define SPEED_THRESHOLD     0.2
  60. #define TURN_RATE           5
  61.  
  62. #define CHASE_DISTANCE      75
  63. #define CHASE_DISTANCE_SQ   CHASE_DISTANCE*CHASE_DISTANCE
  64. #define CHASE_TIMEOUT       100
  65.  
  66. #define TILE_WIDTH          8
  67. #define TILE_HEIGHT         8
  68. #define CHARACTER_SIZE      72
  69.  
  70. #define IDLE                0
  71. #define CHASE_TARGET        1
  72.  
  73. uint8_t alphabet [4240];
  74.  
  75. enum Objects
  76. {
  77.     Circle1,
  78.     Circle2,
  79.     Circle3,
  80.     Num_Objects
  81. };
  82.  
  83. typedef struct
  84. {
  85.     float x, y;
  86. } Vec2;
  87.  
  88. typedef struct
  89. {
  90.     int x, y;
  91. } Vec2_int;
  92.  
  93. typedef struct
  94. {
  95.     Vec2 position;
  96.     Vec2_int grid_loc; // location on the grid
  97.     Vec2 direction; // direction
  98.     Vec2 velocity; // velocity
  99.     float magnitude; // magnitude of velocity
  100.     int radius; // circle radius
  101.     uint8_t color;
  102.     uint8_t ai_mode;
  103.     int ai_timer;
  104.     Vec2* ai_target;
  105. } Object;
  106.  
  107. // array which holds all objects (circles in this case)
  108. Object object_array[Num_Objects] = {
  109. //    pos_x  pos_y    grid_x grid_y    direction    velocity    magnitude radius  colour  ai_mode       ai_timer  ai_target
  110.     {{120.0, 40.0,},  {6,     2,},     {1.0, 1.0},  {0.0, 0.0}, 0.0,      8,      14,     IDLE,         0,        IDLE},
  111.     {{40.0,  110.0,}, {1,     5,},     {1.0, 1.0},  {0.0, 0.0}, 0.0,      8,       3,     CHASE_TARGET, 0,        &player.position},
  112.     {{170.0, 40.0,},  {6,     5,},     {3.0, 3.0},  {0.0, 0.0}, 0.0,      8,      12,     IDLE,         0,        IDLE}
  113. };
  114.  
  115. // array which determines the colour of each square on the grid
  116. uint8_t grid_array [] = {7,  7, 7,  7, 7,  7, 7,  7, 7,  7, 7,  7, 7,  7, 7,  7,
  117.                          7, 15, 0, 15, 0, 15, 0, 15, 0, 15, 0, 15, 0, 15, 0,  7,
  118.                          7,  0, 7,  7, 7, 0, 15, 0, 15, 0, 15, 0, 15, 0, 15, 7,
  119.                          7, 15, 7, 15, 0, 15, 0, 15, 0, 15, 0, 15, 0, 15, 0,  7,
  120.                          7,  0, 7, 0, 15, 0, 15, 0, 15, 0, 15, 0, 15, 0, 15, 7,
  121.                          7, 15, 0, 15, 0, 15, 0, 15, 0, 15, 0, 15, 0, 15, 0,  7,
  122.                          7,  0, 15, 0, 15, 0, 15, 0, 15, 0, 15, 0, 15, 0, 15, 7,
  123.                          7, 15, 0, 15, 0, 15, 0, 15, 0, 15, 0, 15, 0, 15, 0,  7,
  124.                          7,  0, 15, 0, 15, 0, 15, 0, 15, 0, 15, 0, 15, 0, 15, 7,
  125.                          7,  7, 7,  7, 7,  7, 7,  7, 7,  7, 7,  7, 7,  7, 7,  7
  126. };
  127.  
  128. Vec2_int pl_grid; // vector to hold the player's grid location
  129.  
  130. struct Input
  131. {
  132.     uint8_t kb_array[KB_ARRAY_LENGTH];
  133.     uint8_t kb_queue[KB_QUEUE_LENGTH];
  134.     uint8_t kb_head;
  135.     uint8_t kb_tail;
  136. };
  137.  
  138. typedef struct Input Input_t;
  139.  
  140. uint8_t *VGA=(uint8_t *)0xA0000000L;        /* this points to video memory. */
  141. uint8_t far screen_buf [64000];
  142.  
  143. Input_t Input = {0};
  144. Input_t* g_Input = &Input;
  145. uint8_t* g_Keyboard = Input.kb_array;
  146.  
  147. static void interrupt (far *old_keyhandler)(void);
  148.  
  149. int running = 1;
  150. float drag = 1.05;
  151. float thrust = 0.3;
  152. int heading = 0; // current direction in degrees
  153. float radians = 0.0; // current direction in radians, as that's what the math functions use
  154.  
  155. void set_mode(uint8_t mode)
  156. {
  157.     union REGS regs;
  158.  
  159.     regs.h.ah = SET_MODE;
  160.     regs.h.al = mode;
  161.     int86(VIDEO_INT, &regs, &regs);
  162. }
  163.  
  164. void load_font()
  165. {
  166.     FILE* file_ptr;
  167.     file_ptr = fopen("FONT.7UP", "rb");
  168.     fread(alphabet, 1, 4240, file_ptr);
  169.     fclose(file_ptr);
  170. }
  171.  
  172. void draw_text(int x, int y, int i, uint8_t color)
  173. {
  174.     uint8_t index_x = 0;
  175.     uint8_t index_y = 0;
  176.     i = i * CHARACTER_SIZE;
  177.  
  178.     for (index_y=0;index_y<TILE_HEIGHT;index_y++)
  179.     {
  180.         for (index_x=0;index_x<TILE_WIDTH;index_x++)
  181.         {
  182.             if (alphabet[i] != 13)
  183.             {
  184.                 SET_PIXEL(x, y, alphabet[i] + color);
  185.                 i++;
  186.                 x++;
  187.             }
  188.             else
  189.             {
  190.                 i++;
  191.                 x++;
  192.             }
  193.         }
  194.         index_x = 0;
  195.         x = x - TILE_WIDTH;
  196.         y++;
  197.     }
  198.     index_y = 0;
  199.     i= 0;
  200. }
  201.  
  202. void render_text(int x, int y, char* string, uint8_t color)
  203. {
  204.     int i = 0;
  205.     char c;
  206.    
  207.     while (string[i] != 0)
  208.     {
  209.         c = string[i];
  210.         draw_text(x, y, c - 32, color);
  211.         x = x + 10;
  212.         i++;
  213.     }
  214. }
  215.  
  216. // keyboard handling stuff until line 229
  217. void interrupt far keyhandler()
  218. {
  219.     uint8_t key_scan = 0;
  220.     static uint8_t key_scan_last = 0;
  221.     static uint8_t key_special = 0;
  222.     static uint8_t key_special_last = 0;
  223.     // obtain scancode
  224.     asm {
  225.         cli // clear interrupt flag; prevent other external interrupts
  226.         in  al, 0x60
  227.         mov key_scan, al
  228.         in  al, 0x61 // get keyboard status
  229.         mov bl, al
  230.         or  al, 0x80 // MSB set
  231.         out 0x61, al // write (ACK)
  232.         mov al, bl   // MSB clear
  233.         out 0x61, al // write
  234.     }
  235.     // remember the last special key code
  236.     if (key_scan_last == KEY_SPECIAL_CODE)
  237.         key_special = key_scan;
  238.     else if (key_scan != KEY_SPECIAL_CODE)
  239.         key_special = 0;
  240.     // place scancode on queue unless it's the same as the previous one
  241.     if (key_scan != key_scan_last && (key_special != key_special_last || key_special_last == 0))
  242.     {
  243.         g_Input->kb_queue[g_Input->kb_tail] = key_scan;
  244.         if (g_Input->kb_tail+1 != g_Input->kb_head)
  245.             g_Input->kb_tail++;
  246.     }
  247.     key_scan_last = key_scan;
  248.     key_special_last = key_special;
  249.     // PIC 8259 reset
  250.     asm {
  251.         mov al, 0x20
  252.         out 0x20, al
  253.         sti // set interrupt flag; allow external interrupts again
  254.     }
  255. }
  256.  
  257. void init_keyboard()
  258. {
  259.     uint8_t far *bios_key_state;
  260.     asm cli
  261.     // save address of current keyhandler interrupt function
  262.     old_keyhandler = _dos_getvect(9);
  263.     // caps lock & num lock off
  264.     bios_key_state = MK_FP(0x040, 0x017);
  265.     *bios_key_state &= (~(32|64));
  266.     old_keyhandler();
  267.     // replace old keyhandler with new keyhandler function
  268.     _dos_setvect(9, keyhandler);
  269.     asm sti
  270. }
  271.  
  272. void deinit_keyboard()
  273. {
  274.     // restore old keyhandler
  275.     asm cli
  276.     _dos_setvect(9, old_keyhandler);
  277.     asm sti
  278.  
  279.     g_Input = NULL;
  280. }
  281.  
  282. void get_keyboard()
  283. {
  284.     int i;
  285.     uint8_t key_scan;
  286.     uint8_t extended = 0;
  287.     uint8_t released = 0;
  288.  
  289.     while (g_Input->kb_head != g_Input->kb_tail)
  290.     {
  291.         key_scan = g_Input->kb_queue[g_Input->kb_head++];
  292.         /* handle special keys, but only if a second scancode follows*/
  293.         if (key_scan == KEY_SPECIAL_CODE)
  294.                 extended = 128;
  295.         /* remember the release flag before clearing it*/
  296.         released = key_scan & KEY_RELEASED_FLAG;
  297.         key_scan &= ~KEY_RELEASED_FLAG;
  298.         if (released)
  299.         {
  300.             g_Input->kb_array[key_scan+extended] &= KEY_HIT_FLAG;
  301.             g_Input->kb_array[key_scan+extended] |= KEY_RELEASED_FLAG;
  302.         }
  303.         else
  304.             g_Input->kb_array[key_scan+extended] |= (KEY_HIT_FLAG|KEY_PRESSED_FLAG);
  305.  
  306.         extended = 0;
  307.     }
  308. }
  309.  
  310. void clear_keys()
  311. {
  312.     int i;
  313.     for (i = 0; i < KB_ARRAY_LENGTH; i++)
  314.         g_Input->kb_array[i] &= KEY_PRESSED_FLAG;
  315. }
  316.  
  317. void control_ingame()
  318. {
  319.     player.direction.x = cos(radians); // calculate directional x-vector
  320.     player.direction.y = sin(radians); // calculate directional y-vector
  321.    
  322.     if (KEY_IS_PRESSED(KEY_UP) && player.magnitude <= MAX_SPEED)
  323.     {
  324.         player.velocity.x += player.direction.x * thrust;
  325.         player.velocity.y += player.direction.y * thrust;
  326.         // calculate the player's current movement speed
  327.         player.magnitude = sqrt((player.velocity.x * player.velocity.x) + (player.velocity.y * player.velocity.y));
  328.     }
  329.     if (KEY_IS_PRESSED(KEY_DOWN))
  330.     {
  331.         // reduce player velocity
  332.         player.velocity.x *= BRAKE_RATE;
  333.         player.velocity.y *= BRAKE_RATE;
  334.             // if player has slowed down to a crawl, stop them entirely
  335.             if (fabs(player.velocity.x) < SPEED_THRESHOLD)
  336.             {
  337.                 player.velocity.x = 0.0;
  338.             }
  339.             if  (fabs(player.velocity.y) < SPEED_THRESHOLD)
  340.             {
  341.                 player.velocity.y = 0.0;
  342.             }
  343.     }
  344.     if (KEY_IS_PRESSED(KEY_LEFT))
  345.     {
  346.         heading -= TURN_RATE;
  347.         if (heading < 0)
  348.             heading = 360;
  349.     }
  350.     if (KEY_IS_PRESSED(KEY_RIGHT))
  351.     {
  352.         heading += TURN_RATE;
  353.         if (heading > 360)
  354.             heading = 0;
  355.     }
  356. }
  357.  
  358. void process_input()
  359. {
  360.     get_keyboard();
  361.  
  362.     control_ingame();
  363.    
  364.     // F10 always exits, wherever you are
  365.     if (KEY_WAS_HIT(KEY_F10))
  366.         running = 0;
  367.  
  368.     clear_keys();
  369. }
  370.  
  371. void draw_circle(Vec2* position, int radius, uint8_t color)
  372. {
  373.     int offset_x;
  374.     int offset_y;
  375.    
  376.     int center_x = position->x;
  377.     int center_y = position->y;
  378.  
  379.     offset_y = 0;
  380.     do
  381.     {
  382.         offset_x = sqrt((float)radius*radius - (float)offset_y*offset_y);
  383.         SET_PIXEL(center_x + offset_x, center_y + offset_y, color); // lower right octant
  384.         SET_PIXEL(center_x - offset_x, center_y + offset_y, color); // lower left octant
  385.         SET_PIXEL(center_x + offset_x, center_y - offset_y, color); // upper right octant
  386.         SET_PIXEL(center_x - offset_x, center_y - offset_y, color); // upper left octant
  387.         SET_PIXEL(center_x + offset_y, center_y + offset_x, color); // bottom right octant
  388.         SET_PIXEL(center_x - offset_y, center_y + offset_x, color); // bottom left octant
  389.         SET_PIXEL(center_x + offset_y, center_y - offset_x, color); // top right octant
  390.         SET_PIXEL(center_x - offset_y, center_y - offset_x, color); // top left octant
  391.  
  392.         offset_y++;
  393.     }
  394.     while (offset_y < offset_x);
  395. }
  396.  
  397. void draw_square(int x, int y, uint8_t colour)
  398. {
  399.     int index_y = 0;
  400.  
  401.     for (index_y=0;index_y<SQUARE_SIZE;index_y++)
  402.     {
  403.         //memsetting the entire row is faster than drawing it pixel by pixel
  404.         memset(screen_buf + (y * SCREEN_WIDTH + x), colour, SQUARE_SIZE);
  405.         y++;
  406.     }
  407. }
  408.  
  409. void draw_dot(Object* obj)
  410. {
  411.     int offset_y = 0;
  412.     int offset_x = 0;
  413.     float dot_radians;
  414.    
  415.     // calculate angle
  416.     dot_radians = atan2(obj->direction.y, obj->direction.x);
  417.    
  418.     // directional dot's offsets from the center of the circle
  419.     offset_y = sin(dot_radians) * obj->radius;
  420.     offset_x = cos(dot_radians) * obj->radius;
  421.     // center of the circle has to be cast into int, otherwise the draw function doesn't work
  422.     SET_PIXEL((int)obj->position.x + offset_x, (int)obj->position.y + offset_y, obj->color + 64);
  423. }
  424.  
  425. void check_grid_loc(Object* obj) // circle's location on the grid
  426. {  
  427.     // calculated by dividing the circle's x/y location by square size
  428.     obj->grid_loc.x = obj->position.x / SQUARE_SIZE;
  429.     obj->grid_loc.y = obj->position.y / SQUARE_SIZE;
  430. }
  431.  
  432. void draw_stuff()
  433. {
  434.     int i = 0; // object array "index"
  435.     int a = 0; // square drawing "index"
  436.     int x;
  437.     int y;
  438.    
  439.     // draw 160 20x20 squares (maximum that can fit on the 320x200 screen)
  440.     while (a < SQUARE_ROWS * SQUARE_COLUMNS)
  441.     {
  442.         for (y = 0; y < SCREEN_HEIGHT; y += SQUARE_SIZE)
  443.         {
  444.             for(x = 0; x < SCREEN_WIDTH; x += SQUARE_SIZE)
  445.             {
  446.                 draw_square(x, y, grid_array[a]);
  447.                 a++;
  448.             }
  449.         }
  450.     }
  451.    
  452.     // change player square to a lovely peach colour
  453.     draw_square(object_array[0].grid_loc.x * SQUARE_SIZE, object_array[0].grid_loc.y * SQUARE_SIZE, COLOUR_PEACH);
  454.    
  455.     while (i < Num_Objects)
  456.     {
  457.         // draw all circles in their current locations
  458.         draw_circle(&object_array[i].position, object_array[i].radius, object_array[i].color);
  459.         draw_dot(&object_array[i]);
  460.         i++;
  461.     }
  462. }
  463.  
  464. int tile_detect(Vec2 pos)
  465. {
  466.     int object_tile; // tile which the object is on (or attempting to be), i.e. array index number from grid_array
  467.     uint8_t tile_colour;
  468.    
  469.     // calculate current grid position
  470.     pos.x /= SQUARE_SIZE;
  471.     pos.y /= SQUARE_SIZE;
  472.    
  473.     // check which grid_array index it corresponds to
  474.     object_tile = (int)pos.y * SQUARE_COLUMNS + (int)pos.x;
  475.    
  476.     tile_colour = grid_array[object_tile]; // check which colour is at that index
  477.    
  478.     return tile_colour; // return said colour
  479. }
  480.  
  481. void edge_detect()
  482. {
  483.     int i = 0;
  484.     while (i < Num_Objects)
  485.     {
  486.         if (object_array[i].position.x - object_array[i].radius <= 0) // left edge
  487.         {
  488.             object_array[i].position.x = 0 + object_array[i].radius;
  489.             object_array[i].velocity.x = 0.0;
  490.         }
  491.        
  492.         if (object_array[i].position.y - object_array[i].radius <= 0) // top edge
  493.         {
  494.             object_array[i].position.y = 0 + object_array[i].radius;
  495.             object_array[i].velocity.y = 0.0;
  496.         }
  497.        
  498.         if (object_array[i].position.x + object_array[i].radius >= (SCREEN_WIDTH - 1)) // right edge
  499.         {
  500.             object_array[i].position.x = (SCREEN_WIDTH - 1) - object_array[i].radius;
  501.             object_array[i].velocity.x = 0.0;
  502.         }
  503.        
  504.         if (object_array[i].position.y + object_array[i].radius >= (SCREEN_HEIGHT - 1)) // bottom edge
  505.         {
  506.             object_array[i].position.y = (SCREEN_HEIGHT - 1) - object_array[i].radius;
  507.             object_array[i].velocity.y = 0.0;
  508.         }
  509.         i++;
  510.     }
  511. }
  512.  
  513. void move_circle(Object* obj, Vec2 movement)
  514. {
  515.     // collision box around the object
  516.     Vec2 test_point_a;
  517.     Vec2 test_point_b;
  518.    
  519.     check_grid_loc(obj);
  520.    
  521.     if (movement.x > 0) // if moving to the right
  522.     {
  523.         obj->position.x += movement.x; // temporarily move the object
  524.         // test_point_a = top right corner
  525.         test_point_a.x = obj->position.x + obj->radius;
  526.         test_point_a.y = obj->position.y - obj->radius;
  527.         // test_point_b = bottom right corner
  528.         test_point_b.x = obj->position.x + obj->radius;
  529.         test_point_b.y = obj->position.y + obj->radius;
  530.        
  531.         // if the movement would result in the object moving inside of a wall...
  532.         if (tile_detect(test_point_a) == WALL || tile_detect(test_point_b) == WALL)
  533.         {
  534.             // ...cancel movement and set velocity to 0
  535.             obj->position.x = (obj->grid_loc.x + 1) * SQUARE_SIZE - obj->radius - 1;
  536.             obj->velocity.x = 0.0;
  537.         }
  538.     }
  539.     else if (movement.x < 0) // if moving to the left
  540.     {
  541.         obj->position.x += movement.x;
  542.         // test_point_a = top left corner
  543.         test_point_a.x = obj->position.x - obj->radius;
  544.         test_point_a.y = obj->position.y - obj->radius;
  545.         // test_point_b = bottom left corner
  546.         test_point_b.x = obj->position.x - obj->radius;
  547.         test_point_b.y = obj->position.y + obj->radius;
  548.        
  549.         if (tile_detect(test_point_a) == WALL || tile_detect(test_point_b) == WALL)
  550.         {
  551.             obj->position.x = obj->grid_loc.x * SQUARE_SIZE + obj->radius;
  552.             obj->velocity.x = 0.0;
  553.         }
  554.     }
  555.  
  556.     if (movement.y < 0) // if moving towards the top
  557.     {
  558.         obj->position.y += movement.y;
  559.         // test_point_a = top right corner
  560.         test_point_a.x = obj->position.x + obj->radius;
  561.         test_point_a.y = obj->position.y - obj->radius;
  562.         // test_point_b = top left corner
  563.         test_point_b.x = obj->position.x - obj->radius;
  564.         test_point_b.y = obj->position.y - obj->radius;
  565.        
  566.         if (tile_detect(test_point_a) == WALL || tile_detect(test_point_b) == WALL)
  567.         {
  568.             obj->position.y = obj->grid_loc.y * SQUARE_SIZE + obj->radius;
  569.             obj->velocity.y = 0.0;
  570.         }
  571.     }
  572.     else if (movement.y > 0) // if moving towards the bottom
  573.     {
  574.         obj->position.y += movement.y;
  575.         // test_point_a = bottom right corner
  576.         test_point_a.x = obj->position.x + obj->radius;
  577.         test_point_a.y = obj->position.y + obj->radius;
  578.         // test_point_b = bottom left corner
  579.         test_point_b.x = obj->position.x - obj->radius;
  580.         test_point_b.y = obj->position.y + obj->radius;
  581.        
  582.         if (tile_detect(test_point_a) == WALL || tile_detect(test_point_b) == WALL)
  583.         {
  584.             obj->position.y = (obj->grid_loc.y + 1) * SQUARE_SIZE - obj->radius - 1;
  585.             obj->velocity.y = 0.0;
  586.         }
  587.     }
  588.     check_grid_loc(obj);
  589. }
  590.  
  591. void calculate_movements()
  592. {
  593.     int i = 0;
  594.    
  595.     // iterate through the object array
  596.     while (i < Num_Objects)
  597.     {
  598.         move_circle(&object_array[i], object_array[i].velocity); // check each circle for wall collisions
  599.         // reduce object velocity with aerial drag
  600.         object_array[i].velocity.y /= drag;
  601.         object_array[i].velocity.x /= drag;
  602.         i++;
  603.     }
  604. }
  605.  
  606. Vec2 getVec2(Vec2 p0, Vec2 p1)
  607. {
  608.     Vec2 v;
  609.     v.x = p1.x - p0.x;
  610.     v.y = p1.y - p0.y;
  611.    
  612.     return v;
  613. }
  614.  
  615. int dotVec2(Vec2 v1, Vec2 v2)
  616. {
  617.     // dot product is the result of two vectors combined into a single number
  618.     float dot_product = (v1.x * v2.x) + (v1.y * v2.y);
  619.    
  620.     /*char dp_str[24];
  621.     sprintf(dp_str, "DP: %f", dot_product);    
  622.     render_text(0, 0, dp_str, 0);*/
  623.    
  624.     return dot_product;
  625. }
  626.  
  627. int getVec2Length(Vec2 v)
  628. {
  629.     float Vec2Length = sqrt((v.x * v.x) + (v.y * v.y));
  630.    
  631.     /*char dm_str[24];
  632.     sprintf(dm_str, "DM: %f", Vec2Length);
  633.     render_text(0, 10, dm_str, 32);*/
  634.    
  635.     return Vec2Length;
  636. }
  637.  
  638. int getVec2Angle(Vec2 v1, Vec2 v2)
  639. {
  640.     /*to calculate the angle between two vectors, we first multiply the directional vector
  641.     magnitudes with each other...
  642.     then divide the dot product with that...
  643.     and take arc cosine from the end result, this will give us the angle*/
  644.    
  645.     float vector_angle = acos(dotVec2(v1, v2) / getVec2Length(v1));
  646.    
  647.     /*char va_str[24];
  648.     sprintf(va_str, "VA: %f", vector_angle);
  649.     render_text(0, 20, va_str, 40);*/
  650.    
  651.     return vector_angle;
  652. }
  653.  
  654. int field_of_vision(Object* object_a, Object* object_b)
  655. {    
  656.     Vec2 distance = getVec2(object_a->position, object_b->position);
  657.    
  658.     float vision_angle = getVec2Angle(distance, object_b->direction);
  659.    
  660.     return vision_angle;
  661. }
  662.  
  663. int testFieldOfView(Vec2 origin, Vec2 direction, Vec2* target)
  664. {
  665.     Vec2 origin_to_target = getVec2(*target, origin);
  666.     float distance = getVec2Length(origin_to_target);
  667.     float angle;
  668.    
  669.     if (distance < CHASE_DISTANCE)
  670.     {
  671.         angle = getVec2Angle(origin_to_target, direction);
  672.  
  673.         if (angle < RAD_45 && angle > -RAD_45)
  674.         {
  675.              return 1;
  676.         }
  677.     }
  678.     return 0;
  679. }
  680.  
  681. Vec2 normalizeVec2(Vec2 v)
  682. {
  683.     Vec2 normalizedVec;
  684.    
  685.     float vec_length = getVec2Length(v);
  686.    
  687.     normalizedVec.x = v.x / vec_length;
  688.     normalizedVec.y = v.y / vec_length;
  689.    
  690.     return normalizedVec;
  691. }
  692.  
  693. void chaseTarget(Object obj)
  694. {
  695.     Vec2 ObjectToTarget = getVec2(obj.position, *obj.ai_target);
  696.     obj.direction = normalizeVec2(ObjectToTarget);
  697.    
  698.     obj.magnitude = getVec2Length(obj.velocity);
  699.    
  700.     if (obj.magnitude <= MAX_SPEED)
  701.     {
  702.         obj.velocity.x += obj.direction.x / ACCELERATION_RATE;
  703.         obj.velocity.y += obj.direction.y / ACCELERATION_RATE;
  704.     }
  705. }
  706.  
  707. void think(Object obj)
  708. {
  709.     if (obj.ai_mode == CHASE_TARGET)
  710.     {
  711.         if (obj.ai_timer > 0)
  712.         {
  713.             chaseTarget(obj);
  714.             obj.ai_timer--;
  715.         }
  716.         else
  717.            obj.ai_mode = IDLE;
  718.     }
  719.     else if (testFieldOfView(obj.position, obj.direction, obj.ai_target) == 1)
  720.     {
  721.         obj.ai_mode = CHASE_TARGET;
  722.         obj.ai_timer = 100;
  723.     }
  724. }
  725.  
  726. void ai_loop()
  727. {
  728.     int i = 0;
  729.    
  730.     while (i < Num_Objects)
  731.     {
  732.         think(object_array[i]);
  733.         i++;
  734.     }
  735. }
  736.  
  737. /*void chase(Object* target, Object* chaser)
  738. {
  739.     float ai_radians;
  740.    
  741.     float distance_x = target->position.x - chaser->position.x; // x-distance between the two objects
  742.     float distance_y = target->position.y - chaser->position.y; // y-distance between the two objects
  743.    
  744.     // calculate angle between the two objects - atan2 allows for both positive and negative angles
  745.     ai_radians = atan2(distance_y, distance_x);
  746.    
  747.     // if object to be chased is close enough and inside field of view, initiate "chase"
  748.     if (testFieldOfView(chaser->position, chaser->direction, target->position) == 1)
  749.     {
  750.         // calculate the directional vector of the "chasing" object
  751.         chaser->direction.x = cos(ai_radians);
  752.         chaser->direction.y = sin(ai_radians);
  753.        
  754.         if (chaser->velocity.x <= MAX_SPEED && chaser->velocity.y <= MAX_SPEED)
  755.         {
  756.             chaser->velocity.x += chaser->direction.x;
  757.             chaser->velocity.y += chaser->direction.y;
  758.         }
  759.     }
  760. }*/
  761.  
  762. void collision_detect(Object* object_a, Object* object_b)
  763. {
  764.     float distance_x;
  765.     float distance_y;
  766.     float distance;
  767.     float collision_depth;
  768.     int tile_colour;
  769.     Vec2 u; // how much each object moves in case of a collision
  770.    
  771.     distance_x = object_a->position.x - object_b->position.x;  // x-distance between the two objects
  772.     distance_y = object_a->position.y - object_b->position.y;  // y-distance between the two objects
  773.    
  774.     // actual distance between the two objects (hypotenuse of the x and y distances)
  775.     distance = sqrt((distance_x * distance_x) + (distance_y * distance_y));
  776.    
  777.     // if distance is less than combined radiuses
  778.     if (distance < (object_a->radius + object_b->radius))
  779.     {
  780.         // calculate how much the objects are "inside" each other
  781.         collision_depth = (object_a->radius + object_b->radius) - distance;
  782.        
  783.         //each object is moved for half of that
  784.         u.x = (distance_x/distance) * (collision_depth/2);
  785.         u.y = (distance_y/distance) * (collision_depth/2);
  786.        
  787.         // first object gets the values as is...
  788.         move_circle(object_a, u);
  789.        
  790.         // ...and for the second object they are flipped
  791.         u.x = -u.x;
  792.         u.y = -u.y;
  793.         move_circle(object_b, u);
  794.     }
  795. }
  796.  
  797. void collision()
  798. {
  799.     int x;
  800.     int i;
  801.    
  802.     // iterate through each object pair to see if they collide
  803.     for (i = 0; i < Num_Objects; i++)
  804.     {
  805.         for (x = i; x < Num_Objects-1; x++)
  806.         {
  807.             collision_detect(&object_array[i], &object_array[x+1]);
  808.         }
  809.     }
  810.    
  811.     // also check that none of the objects are going beyond the screen boundaries
  812.     edge_detect();
  813. }
  814.  
  815. void render()
  816. {    
  817.     // copy off-screen buffer to VGA memory
  818.     memcpy(VGA,screen_buf,SCREEN_SIZE);
  819.  
  820.     // clear off-screen buffer so the screen updates properly
  821.     _fmemset(screen_buf, 0, SCREEN_SIZE);
  822. }
  823.  
  824. void quit()
  825. {  
  826.     deinit_keyboard();
  827.     set_mode(TEXT_MODE);
  828. }
  829.  
  830. void main()
  831. {    
  832.     set_mode(VGA_256_COLOR_MODE);
  833.     init_keyboard();
  834.     load_font();
  835.    
  836.     while (running == 1)
  837.     {
  838.         process_input();
  839.         radians = degToRad(heading);
  840.         //chase(&object_array[0], &object_array[2]);
  841.         //chase(&object_array[2], &object_array[1]);
  842.         ai_loop();
  843.         calculate_movements();
  844.         collision();
  845.         render();
  846.         draw_stuff();
  847.         delay(50);
  848.     }
  849.     quit();
  850. }
Add Comment
Please, Sign In to add comment