Drive a tank around the screen lazarus / 39-Graphics ---------------------------------------------------------------------- TBMan · 2025-03-24 17:22 I've been playing around with rotating points and rectangles. I wanted to try rotating a bitmap and I succeeded this morning. I even managed to get the background to redraw. Here's the code. I don't know what I will do with this, but maybe combining with some sort of acceleration factor would be interesting. Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i program rotatetank3;{ version 3  Rotates a 32x32 tile with 0 as the transparent color  Press Q or q or esc to quit.  Keypad controls rotation and movement + = clockwise rotation - = counterclockwise rotation       7 8 9      4 5 6      1 2 3 The tank will rotate to direction prior to movement if not already in that orientation  There isn't any screen range checking done. PTCgraph clips by default}  uses  ptccrt,  ptcgraph,  Math; const  MaxCol = 31; type  MapIconType = array[0..maxcol, 0..maxcol] of byte; const     desert01: MapIconType = ((2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,    2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2),    (2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2),    (2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2),    (2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 26, 2, 2, 2, 2, 26, 2, 2, 2, 2, 2, 2, 22, 2, 22, 2, 2, 2, 2, 2),    (2, 2, 2, 2, 2, 2, 2, 29, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2),    (2, 2, 2, 2, 2, 26, 29, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 22, 2, 2, 2, 2),    (2, 2, 2, 2, 2, 112, 23, 23, 23, 2, 2, 2, 2, 2, 2, 2, 2, 29, 2, 26, 29, 29, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2),    (2, 2, 2, 2, 26, 29, 26, 2, 2, 2, 2, 2, 2, 2, 2, 29, 29, 29, 24, 2, 2, 29, 29, 112, 29, 2, 2, 2, 2, 2, 2, 2),    (2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 24, 26, 24, 24, 24, 2, 2, 26, 24, 24, 2, 2, 2, 2, 2, 2, 2),    (2, 2, 2, 2, 23, 26, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 24, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2),    (2, 2, 2, 2, 23, 2, 2, 2, 2, 2, 22, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2),    (2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2),    (2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2),    (2, 2, 2, 2, 2, 2, 2, 22, 2, 2, 2, 2, 26, 2, 2, 2, 2, 2, 2, 2, 2, 2, 29, 29, 29, 2, 2, 2, 2, 2, 2, 2),    (2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 26, 111, 2, 2, 112, 29, 2, 2, 2, 2, 2),    (2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 26, 2, 2, 2, 2, 111, 29, 2, 2, 22, 22, 29, 2, 2, 2, 2, 2),    (2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 22, 2, 2, 19, 2, 2, 2, 2, 22, 29, 112, 29, 2, 2, 2),    (2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 26, 22, 22, 22, 2, 2, 2),    (2, 2, 2, 2, 2, 2, 2, 2, 2, 23, 23, 2, 2, 29, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2),    (2, 2, 2, 2, 2, 2, 2, 23, 2, 2, 2, 2, 2, 29, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 26),    (2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 19, 19, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2),    (2, 2, 2, 2, 2, 2, 26, 2, 2, 2, 2, 2, 2, 19, 26, 22, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2),    (2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 22, 2, 2, 2, 2, 2, 2, 2, 2, 2),    (2, 2, 2, 26, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2),    (2, 2, 2, 2, 2, 2, 2, 2, 2, 29, 22, 26, 22, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 22, 2, 2, 26, 2, 2),    (2, 2, 2, 2, 29, 29, 2, 2, 2, 112, 19, 26, 29, 22, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2),    (2, 2, 29, 112, 22, 19, 19, 2, 29, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2),    (2, 2, 19, 2, 2, 2, 2, 2, 2, 2, 2, 111, 2, 2, 2, 2, 2, 2, 2, 2, 2, 22, 2, 112, 29, 112, 29, 2, 2, 2, 2, 2),    (2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 113, 29, 2, 2, 2, 2, 29, 2, 2, 2, 2),    (2, 2, 2, 2, 22, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 22, 22, 2, 29, 2, 2, 2),    (2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 22, 2, 2, 2, 2, 2, 29, 22, 22, 2, 2, 22, 2, 112, 2, 2, 2),  (2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2));     TheTank: MapIconType = ((0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0),    (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0),    (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 41, 41, 0, 0, 0,    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0),    (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 26, 26, 0, 0, 0,    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0),    (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 26, 26, 0, 0, 0,    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0),    (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 26, 26, 0, 0, 0,    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0),    (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 26, 26, 0, 0, 0,    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0),    (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 20, 20, 20, 26, 26, 20, 20,    20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0),    (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 20, 190, 190, 190, 26, 26, 190,    190, 190, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0),    (0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 190, 190, 190, 190, 190, 26, 26,    190, 190, 190, 190, 190, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0),    (0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 190, 190, 190, 190, 190, 26, 26,    190, 190, 190, 190, 190, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0),    (0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 190, 190, 190, 190, 190, 26, 26,    190, 190, 190, 190, 190, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0),    (0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 190, 190, 190, 190, 21, 26, 26,    21, 190, 190, 190, 190, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0),    (0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 190, 190, 190, 21, 23, 23, 23,    23, 21, 190, 190, 190, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0),    (0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 190, 190, 21, 23, 23, 23, 23, 23,    23, 21, 190, 190, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0),    (0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 190, 190, 21, 23, 1, 1, 1, 1, 23,    21, 190, 190, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0),    (0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 190, 190, 21, 23, 1, 1, 1, 1, 23,    21, 190, 190, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0),  (0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 190, 190, 21, 23, 1, 1, 1, 1, 23,    21, 190, 190, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0),    (0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 190, 190, 21, 23, 1, 1, 1, 1, 23,    21, 190, 190, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0),    (0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 190, 190, 21, 23, 23, 23, 23, 23,    23, 21, 190, 190, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0),    (0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 190, 190, 190, 21, 21, 21, 21,    21, 21, 190, 190, 190, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0),    (0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 190, 190, 190, 190, 190, 190, 190,    190, 190, 190, 190, 190, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0),    (0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 190, 190, 190, 190, 190, 190, 190,    190, 190, 190, 190, 190, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0),    (0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 190, 190, 190, 190, 190, 190, 190,    190, 190, 190, 190, 190, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0),    (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 20, 20, 20, 20, 20, 20, 20,    20, 20, 20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0),    (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 20, 20, 20, 20, 20, 20, 20,    20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0),    (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 20, 20, 20, 20, 20, 20, 20,    20, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0),    (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0),    (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0),    (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0),    (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0),    (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0));   type   TSinglePoint = record    x, y: single;  end;   linedata = record    P: Tsinglepoint;    color: byte;  end;   matrixType = array[0..maxcol, 0..maxcol] of linedata; var  I: integer;  ch: char;  lastdegree: integer;   cx, cy: integer;     // center x and center y  b: MatrixType;  gmode, gdriver: smallint;    procedure SetUpTank(x, y: integer);  var    rr, cc: integer;  begin    // setup initial tank coord matrix    for rr := 0 to maxcol do    begin      for cc := 0 to maxcol do      begin        b[rr, cc].color := TheTank[rr, cc];      b[rr, cc].p.x := x + cc;        b[rr, cc].p.y := y + rr;      end;    end;     cx := X + 16;   // x + 1/2 matrix width    cy := y + 16;   // y + 1/2 matrix depth   end;   procedure drawcell(xx, yy: integer);  var    startx, rr, cc: integer;  begin    startx := xx;    for rr := 0 to maxcol do    begin      xx := startX;      for cc := 0 to maxcol do      begin        putpixel(xx, yy, desert01[rr, cc]);        Inc(xx);      end;      Inc(yy);    end;  end;    procedure rotatepoint(var P: Tsinglepoint; degrees, centerx, centerY: float);  var    newx, newy, angle: float;    cx, cy, y, x: single;  begin    angle := degTorad(degrees);    cx := centerx;    cy := centery;    x := p.x;    y := p.y;    x := x - cx;    Y := y - cy;    newx := (x * cos(angle)) - (y * sin(angle));    newy := (x * sin(angle)) + (y * cos(angle));    newx := newx + cx;    newy := newy + cy;    p.x := newx;    p.y := newy;  end;   procedure moveobject(var M: MatrixType; Xc, Yc: integer);  var    r, c: integer;  begin    for r := 0 to maxcol do      for c := 0 to maxcol do      begin        M[r, c].p.x := M[r, c].p.x + Xc;        M[r, c].p.Y := M[r, c].p.Y + Yc;      end;  end;   procedure rotateobject(var M: Matrixtype; Degrees, CenterX, CenterY: integer);  var     r, c: integer;    Row, Column: integer;  begin    for r := 0 to maxcol do      for c := 0 to maxcol do      begin        rotatepoint(M[r, c].p, degrees, centerx, centery);        Column := round(M[r, c].p.x) mod (maxcol + 1);  // map x,y to background tile pixel        Row := round(m[r, c].p.y) mod (maxcol + 1);         // redraw background        putpixel(round(m[r, c].p.x), round(m[r, c].p.y), desert01[Row, Column]);         //overlay tank on screen        if m[r, c].color <> 0 then          putpixel(round(M[r, c].p.x), round(m[r, c].p.y), m[r, c].color);      end;  end;    procedure showobject(M: MatrixType);  var    r, c: integer;  begin    for r := 0 to maxcol do      for c := 0 to maxcol do        if m[r, c].color <> 0 then          putpixel(round(M[r, c].p.x), round(m[r, c].p.y), m[r, c].color);  end;    procedure DrawBackground;  var    ScreenX, ScreenY: integer;    r, c: integer;  begin    screenY := 0;    for r := 0 to 5 do    begin      screenx := 0;      for c := 0 to 8 do      begin        drawcell(screenx, screeny);        Inc(screenx, maxcol + 1);      end;      Inc(screeny, maxcol + 1);    end;  end;  begin   gdriver := vesa;  // this is for my system - check documentation for use of initgraph   Gmode := installusermode(320, 200, 256, 1, 8000, 6000);  WindowTitle := 'Tank Rotation';  initgraph(gdriver, gmode, '');   SetupTank(160, 128);   DrawBackground;    lastdegree := 0;  ShowObject(b);   repeat    i := 0;    ch := readkey;      case ch of      '-': i := -1;      // counter clockwise      '+': i := 1;       // clockwise      '3': begin        if lastdegree <> 135 then        begin          if lastdegree > 135 then i := -1;          if lastdegree < 135 then i := 1;          if lastdegree > 315 then   // 316 to 360          begin          i := 1;            repeat              rotateobject(b, i, cx, cy);              LastDegree := lastDegree + i;              delay(10);            until lastdegree = 360;            lastdegree := 0;          end;          repeat            rotateobject(b, i, cx, cy);            LastDegree := lastDegree + i;            delay(10);        until lastdegree = 135;        end;        Inc(cx);        Inc(cy);        i := 0;        moveobject(b, 1, 1);      end;      '1': begin        if lastdegree <> 225 then        begin          if lastdegree = 0 then lastdegree := 360;          if lastdegree > 225 then i := -1          else            i := 1;          if lastdegree <= 45 then          begin            i := -1;            repeat            rotateobject(b, i, cx, cy);              LastDegree := lastDegree + i;              delay(10);            until lastdegree = 0;            i := -1;            lastdegree := 360;          end;        repeat            rotateobject(b, i, cx, cy);            LastDegree := lastDegree + i;            delay(10);          until lastdegree = 225;        end        else           i := 0;        Dec(cx);        Inc(cy);        moveobject(b, -1, 1);      end;      '9': begin        if lastdegree <> 45 then        begin          if lastdegree < 45 then i := 1;          if (lastdegree > 45) and (lastdegree <= 225) then            i := -1;          if lastdegree > 225 then          begin            i := 1;            repeat            rotateobject(b, i, cx, cy);              LastDegree := lastDegree + i;              delay(10);            until lastdegree = 360;          lastdegree := 0;            // i := 1;          end;           repeat            rotateobject(b, i, cx, cy);            LastDegree := lastDegree + i;            delay(10);          until lastdegree = 45;          ;        end;        Inc(cx);        Dec(cy);        I := 0;      moveobject(b, 1, -1);      end;       '7': begin        if lastdegree = 0 then lastdegree := 360;        if lastdegree <= 90 then lastdegree := 360 + lastdegree;        if lastdegree <> 315 then      begin          if (lastdegree > 315) then            i := -1        else            i := 1;          repeat            rotateobject(b, i, cx, cy);            LastDegree := lastDegree + i;            delay(10);          until (lastdegree = 315);        end;        i := 0;        Dec(cx);        Dec(cy);        moveobject(b, -1, -1);      end;      '8': begin        // rotate to face position        if (lastdegree <> 0) and (lastdegree <> 360) then        begin          if lastdegree > 180 then i := 1          else            i := -1;        repeat            rotateobject(b, i, cx, cy);            LastDegree := lastDegree + i;            delay(10);          until (lastdegree = 0) or (lastdegree = 360);        end;        Dec(cy);      moveobject(b, 0, -1);        i := 0;      end;      '2': begin      if (lastdegree <> 180) then        begin          if lastdegree > 180 then i := -1          else            i := 1;          repeat          rotateobject(b, i, cx, cy);            LastDegree := lastDegree + i;            delay(10);          until (lastdegree = 180);        end;        Inc(cy);        moveobject(b, 0, 1);        i := 0;      end;      '4': begin        if lastdegree <> 270 then        begin        if lastdegree < 180 then lastdegree := 360 + lastdegree;        if lastdegree > 270 then i := -1          else            i := 1;         repeat            rotateobject(b, i, cx, cy);            LastDegree := lastDegree + i;            delay(10);          until (lastdegree = 270);        end;        Dec(cx);        moveobject(b, -1, 0);        i := 0;      end;      '6': begin        if lastdegree <> 90 then        begin          if lastdegree > 90 then i := -1        else            i := 1;          repeat            rotateobject(b, i, cx, cy);            LastDegree := lastDegree + i;            delay(10);          until (lastdegree = 90);        end;        i := 0;        Inc(cx);        moveobject(b, 1, 0);      end;    end;    lastdegree := lastdegree + i;    if LastDegree < 1 then lastdegree := 360;    if lastdegree >= 360 then lastdegree := 0;     RotateObject(b, i, cx, cy);     while keypressed do readkey;  // eat up extra keypresses    until (ch = 'q') or (ch = 'Q') or (ch = chr(27));   closegraph;end. ---------------------------------------------------------------------- Boleeman · 2025-03-25 05:22 Not a Tank but: Came across a car simulator here: https://github.com/GuvaCode/mini_pro jects/tree/main/miniprojects/Parken Demo shows how to implement a chain of "vehicles" that are controlled by a single force. Also attached are 3 misc opensource Tank Game Sources in Delphi (from github) Perhaps might be able to get some ideas from these.