Results 1 to 9 of 9

Thread: Object Oriented programin (step one of many)

Hybrid View

Previous Post Previous Post   Next Post Next Post
  1. #1
    Hi,

    I've been trying to alter the above code, to move the Shape smoothly, instead of this grid jump mode , well I'm having a hell of a time ... since shape has TOP and LEFT value and I'm calculating using that...everything Is fine if I go down, an right...
    but the moment I go up or left.... it has problems :
    11111
    1X001
    10111

    1 is wall, 0 is nothing, X is the object, my problem is if I move UP or LEFT ... it calculates down to 1,1 the moment the TOP,LEFT first pixel line enters 1,1... is there a way to make this stop... only have 1,1 if I'm fully inside ... (sorry for the terrible explanation)

    Code:
    unit MainFrm;
    // idea is
    // I check available directions...
    // then I set a direction
    // when I would hit a wall...I check again available directions...
    // then I set a direction...
    // could be good
    interface
    uses
      Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
      Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.ExtCtrls, Vcl.StdCtrls;
    type
      TMain = class(TForm)
        Panel1: TPanel;
        Panel2: TPanel;
        Button1: TButton;
        Button2: TButton;
        Timer1: TTimer;
        Edit1: TEdit;
        Edit2: TEdit;
        Edit3: TEdit;
        procedure DrawMap();
        procedure DrawMonster();
        procedure Button1Click(Sender: TObject);
        procedure Button2Click(Sender: TObject);
        procedure Timer1Timer(Sender: TObject);
      private
        { Private declarations }
      public
        { Public declarations }
      end;
      TDirection = ( dUp, dDown , dLeft, dRight );
      TMonster = class
        strict private
          FName : string;
          FPositionX,FPositionY : integer;
          FVelocityX,FVelocityY : integer;
          FSetDir : TDirection;
          Direction : array of TDirection;
        published
          property Name : string
            read FName write FName;
          property PositionX : integer
            read FPositionX write FPositionX;
          property PositionY : integer
            read FPositionY write FPositionY;
          property SetDir : TDirection
            read FSetDir write FSetDir;
          property VelocityX : integer
            read FVelocityX write FVelocityX;
          property VelocityY : integer
            read FVelocityY write FVelocityY;
          constructor Create( Name : string ; PositionX,PositionY : integer ; SetDir : TDirection );
          procedure GetPossibleDirections();
          procedure OnMove;
      end;
    
    
    
      TMapLine = array [0..19] of Integer;
      TMap = array [0..14] of TMapLine;
    const
      Map: Array [0..14,0..19] of Integer = ((1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1),
                                             (1,0,0,0,0,0,1,0,0,0,0,1,1,0,0,0,0,0,0,1),
                                             (1,0,1,1,1,0,1,1,1,0,0,1,1,0,0,0,0,1,0,1),
                                             (1,0,1,0,1,0,1,0,0,0,0,0,0,0,0,0,0,1,0,1),
                                             (1,0,1,0,1,0,1,0,0,0,0,1,1,1,1,1,1,1,0,1),
                                             (1,0,1,0,0,0,1,0,0,0,0,1,0,0,0,0,0,0,0,1),
                                             (1,0,1,0,1,0,1,0,0,0,1,1,1,1,1,1,1,1,1,1),
                                             (1,0,1,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0,1),
                                             (1,0,1,0,0,0,1,0,0,0,0,0,0,1,1,0,0,0,0,1),
                                             (1,0,1,0,1,0,1,1,1,0,1,0,0,0,1,0,0,0,0,1),
                                             (1,0,1,0,1,0,1,1,1,0,1,1,0,0,1,0,1,0,0,1),
                                             (1,0,1,0,1,0,1,1,1,0,0,1,0,0,1,0,0,0,0,1),
                                             (1,0,1,1,1,0,1,1,1,0,0,0,0,0,1,0,0,0,0,1),
                                             (1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,1),
                                             (1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1));
    
    var
      Main: TMain;
      Monster : array of TMonster;
      // hacky way later fix
      AI : array of TShape;
    
    
    implementation
    {$R *.dfm}
    constructor TMonster.Create(Name: string ; PositionX,PositionY : integer; SetDir : TDirection);
    begin
      FName := Name;
      FPositionX := PositionX;
      FPositionY := PositionY;
      FSetDir := SetDir;
      FVelocityX := 0;
      FVelocityY := 0;
    end;
    procedure TMonster.GetPossibleDirections;
    begin
      // debug
      Main.Edit1.Text:='';
      // empty directions
      SetLength(Direction,0);
      // no wall found up, way is free
      if Map[PositionY-1,PositionX] <> 1 then
        begin
          SetLength(Direction,length(Direction)+1);
          Direction[High(Direction)]:=dUp;
          Main.Edit1.Text:=Main.Edit1.Text+' UP ';
        end;
      // no wall found down, way is free
      if Map[PositionY+1,PositionX] <> 1 then
        begin
          SetLength(Direction,length(Direction)+1);
          Direction[High(Direction)]:=dDown;
          Main.Edit1.Text:=Main.Edit1.Text+' DOWN ';
        end;
      // no wall found left , way is free
      if Map[PositionY,PositionX-1] <> 1 then
        begin
          SetLength(Direction,length(Direction)+1);
          Direction[High(Direction)]:=dLeft;
          Main.Edit1.Text:=Main.Edit1.Text+' LEFT ';
        end;
      // no wall found right , way is free
      if Map[PositionY,PositionX+1] <> 1 then
        begin
          SetLength(Direction,length(Direction)+1);
          Direction[High(Direction)]:=dRight;
          Main.Edit1.Text:=Main.Edit1.Text+' RIGHT ';
        end;
    end;
    procedure TMonster.OnMove;
    begin
      VelocityY := 0;
      VelocityX := 0;
      if SetDir = dUp then
        begin
          if Map[PositionY-1,PositionX] = 1 then
            begin
              GetPossibleDirections();
              SetDir := Direction[random(length(Direction))];
            end;
        end;
      if SetDir = dDown then
        begin
          if Map[PositionY+1,PositionX] = 1 then
            begin
              GetPossibleDirections();
              SetDir := Direction[random(length(Direction))];
            end;
        end;
      if SetDir = dRight then
        begin
          if Map[PositionY,PositionX+1] = 1 then
            begin
              GetPossibleDirections();
              SetDir := Direction[random(length(Direction))];
            end;
        end;
      if SetDir = dLeft then
        begin
          if Map[PositionY,PositionX-1] = 1 then
            begin
              GetPossibleDirections();
              SetDir := Direction[random(length(Direction))];
            end;
        end;
    
    if SetDir = dUp then
        VelocityY:=-2;
      if SetDir = dDown then
        VelocityY:=+2;
      if SetDir = dRight then
        VelocityX:=+2;
      if SetDir = dLeft then
        VelocityX:=-2;
    
    end;
    procedure TMain.Button1Click(Sender: TObject);
    var i : integer;
    begin
      DrawMap();
      // we do 2 monsters for now
      SetLength(Monster,1);
      SetLength(AI,1);
      Monster[0] := TMonster.Create('Robert',1,1,dDown);
    //  Monster[1] := TMonster.Create('Devid',3,1,dDown);
    //  Monster[2] := TMonster.Create('Antal',18,4,dLeft);
      for i := 0 to length(Monster)-1 do
        begin
          AI[i] := TShape.Create(self);
          AI[i].Parent:=Panel2;
          AI[i].Top:=Monster[i].PositionY*(Panel2.Height div 15);
          AI[i].Left:=Monster[i].PositionX*(Panel2.Width div 20);
          AI[i].Height:=Panel2.Height div 15;
          AI[i].Width:=Panel2.Width div 20;
          AI[i].Brush.Color:=clGreen;
          AI[i].Pen.Color:=clGreen;
          AI[i].Visible:=true;
        end;
    end;
    procedure TMain.Button2Click(Sender: TObject);
    var i : integer;
    begin
      Timer1.Enabled:=true;
      {for i := 0 to length(Monster)-1 do
        begin
          Monster[i].OnMove;
        end;
      DrawMonster(); }
    end;
    procedure TMain.DrawMonster;
    var i : integer;
    begin
      // re-draw monster at new position
      for i := 0 to length(Monster)-1 do
        begin
    //      AI[i].Top:=Monster[i].StartY*(Panel2.Height div 15);
    //      AI[i].Left:=Monster[i].StartX*(Panel2.Width div 20);
          AI[i].Top:=AI[i].Top+Monster[i].VelocityY;
          AI[i].Left:=AI[i].Left+Monster[i].VelocityX;
          Monster[i].PositionY:=AI[i].Top div (Panel2.Height div 15);
          Edit2.Text:=inttostr(Monster[i].PositionY);
          Monster[i].PositionX:=AI[i].Left div (panel2.Width div 20);
          Edit3.Text:=inttostr(Monster[i].PositionX);
        end;
    end;
    procedure TMain.Timer1Timer(Sender: TObject);
    var i : integer;
    begin
      for i := 0 to length(Monster)-1 do
        begin
          Monster[i].OnMove;
        end;
      DrawMonster();
    end;
    procedure TMain.DrawMap;
    var x,y: integer;
        Wall : TShape;
    begin
        for y := 0 to 14 do
          for x := 0 to 19 do
              begin
                if Map[y,x] = 1 then
                  begin
                    Wall := TShape.Create(self);
                    Wall.Parent:=Panel2;
                    Wall.Top:=y*(Panel2.Height div 15);
                    Wall.Left:=x*(Panel2.Width div 20);
                    Wall.Height:=Panel2.Height div 15;
                    Wall.Width:=Panel2.Width div 20;
                    Wall.Brush.Color:=clRed;
                    Wall.Pen.Color:=clRed;
                    Wall.Visible:=true;
                  end;
              end;
    end;
    end.
    I've altered so there is only one moving monster.

    Please help

    Greetings
    Robert

  2. #2
    PGDCE Developer Carver413's Avatar
    Join Date
    Jun 2010
    Location
    Spokane,WA,Usa
    Posts
    206
    it is generally better to use a case statement for TDirection to prevent more then one block of code from executing in a single pass.
    also you should build a table of directions in a counter clock list either 4 or 8 directions. now there is no up or down only left or right foward or back.
    use an index var to set the direction add to location to move forward, subtract to move back. change index var to turn left or right.
    now you can move the monster in the same direction until it hits a wall then chose to go left or right.
    this is a link for a hex map there is some good stuff in there that could help you in your own design
    http://www.redblobgames.com/grids/hexagons/

  3. #3
    Hi,

    thank you for trying, but that confuses me only, and it is not the question I've asked...
    the Monster is moving inside the "labyrinth" automatically...


    my problem is the grid based collision is only working correctly if I move from grid to grid... if I move smoothly it does not
    example :

    wall is (pixels)
    0,0 - 31,31 (wall)
    32,32 - 63,63 (air)

    according to my logic the top,left corner of the monster square enters 63,63 , then it is divided down to array position of 1,1
    logic checks 1,1 top tile free or not ? -1 = wall! ( is correct... )
    movement stops at 63,63 because we hit wall...

    what I would like to solve is it should result in 1,1 if I get all the way down to 32,32 .... if it would div by 32 here now
    check for wall... and turn in another possible direction I would have "perfect" collision....


    Greetings
    Robert

    ps.: when I get back to work... I'll think about this a bit more, problem is there are many tutorials online, but most of em not work, or are
    way to complicated to grasp... I for starters don't need a fully fledged platform game sample which is beyond my comprehension for now

  4. #4
    Hello,

    After reading a few tile based collision detection tutorials with smooth scrolling enabled...I realized , that I need to check collisions based on direction I'm traveling in ( this might not work if I go both X,Y at same time, but for now I don't really care, one step at a time and not get overwhelmed)

    So right now I kinda hacked my own code... which is ugly
    Code:
    procedure TMain.DrawMonster;
    var i : integer;
    begin
      // re-draw monster at new position
      for i := 0 to length(Monster)-1 do
        begin
    //      AI[i].Top:=Monster[i].StartY*(Panel2.Height div 15);
    //      AI[i].Left:=Monster[i].StartX*(Panel2.Width div 20);
          AI[i].Top:=AI[i].Top+Monster[i].VelocityY;
          AI[i].Left:=AI[i].Left+Monster[i].VelocityX;
          if (Monster[i].SetDir = dDown) or (Monster[i].SetDir = DRight) then
            begin
              Monster[i].PositionY:=AI[i].Top div (Panel2.Height div 15);
              Edit2.Text:=inttostr(Monster[i].PositionY);
              Monster[i].PositionX:=AI[i].Left div (panel2.Width div 20);
              Edit3.Text:=inttostr(Monster[i].PositionX);
            end;
    
          if (Monster[i].SetDir = dUp) or (Monster[i].SetDir = DLeft) then
            begin
              Monster[i].PositionY:=(AI[i].Top+(AI[i].Height-1)) div (Panel2.Height div 15);
              Edit2.Text:=inttostr(Monster[i].PositionY);
              Monster[i].PositionX:=(AI[i].Left+(AI[i].Width-1)) div (panel2.Width div 20);
              Edit3.Text:=inttostr(Monster[i].PositionX);
            end;
    
    
        end;
    My mistake up till now, and with all my previous attempts as well was this
    when I calculated bottom and right side I simply did LEFT+WIDTH or TOP+WIDTH...which
    in the case of a 32x32 tile
    which has top,left 1,1
    resulted in a bottom,right 33,33 I know it seems so stupid now, but somehow I did not see it...

    that Is why now I add to left and top , height-1 and width-1...so I
    get 1,1 and 32,32...

    I tried it and it works...on the far right corner of the level there is no perfect touch on my monitor 1920x1080, but that is probably because (or 99% sure) my tile sizes are not n2...

    so I guess I did It...this will work nicely at 640x480 with 32x32 tiles...

    I'll modify my class in the upcoming days..to handle this calculation inside it...and not like this

    Greetings
    Robert

  5. #5
    Hi!
    I would suggest that you start unsig node based approach whend dealing with movment or pathfinding. Nodes are placed in the center of your map cells. Each node contains information about to which other node you can travel from it and movment cost for such movment.
    You also handle your units position based on ther center position instead of their TopLeft corner.
    So when you are moving your units from one point to another you are simply moving their center position from one map node to another.

    Advantages:
    - since you store posible movment in node connections you no longer need to always go and check all nearby tiles to figure out if you can move there or not
    - becouse you store each posible movment (node connections) for each node you can easily implement one way movment (moving from node A to node B is posible, but moving from node B to anode A is not posible)
    - you can have node connection between any two nodes. This alows you to implement things like portals with ease.
    - each node connection also stores the movment cost/movment speed so you can easily implement the ability to move faster when going downhill vercus goung uphill.
    - most popular pathfinding algorithms bases on node systems so you are already one step closer in implementing any of them.
    - by storing aditional value to each node you can easily determine whether a multitile sized unit can move to that tile or not (http://aigamedev.com/open/tutorial/c...d-pathfinding/)

    Disadvantages:
    - you need to generate and store node graph which could take some time and increases memory consumption
    - if using dynamic map loading (chunk based maps) you need to also dynamically update this node graph upon loading and unloading of each chunk.

    If you want I can make you a quick and dirty example of this but you will have to wait athleast till tomorow as I need to go to bed now in order to wake up early enough to go to work tomorow.

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •