Page 1 of 3 123 LastLast
Results 1 to 10 of 25

Thread: Collision detection in 3D for obstacles, sword fighting...

  1. #1

    Collision detection in 3D for obstacles, sword fighting...

    Hello,

    I need a collision detection for mainly 2 purposes:
    - when the player is walking he should not walk 'through' obstacles
    - when the player beats I want to know which monster(s) are hit

    It is for a 3D kind of medieval RPG Action Game developed with DanJetX.

    All my meshes are stored in a Engine based on a TList.

    I have a very basic collision detection working a a circle's radius, taken and altered from a sample from Dan:

    function TForm1.boundcollide(spriteself: TDJXEngineItem): boolean;
    var i: integer;
    colSpr: TDJXEngineItem;
    ColPt: TD3DXVector2;
    tmpVec: TD3DXVector2;
    ndist: Double;
    begin
    //Collision with other sprites
    //do not be alarmed by the complexity of the
    //calculations, they are really simple
    //once you take a closer look
    result:=false;
    for i:=0 to Engine.Count-1 do begin
    ndist:=distance_dbl(spriteself.x,spriteself.z,0,En gine.Sprites[i].X,Engine.Sprites[i].Z,0);
    if (Engine.Sprites[i]<>spriteself) and (ndist<Innomsprite(spriteself).nRadius+Innomsprite (Engine.Sprites[i]).nRadius+1)
    then begin
    colSpr:=Engine.Sprites[i];
    //Player schl?§gt
    if (spriteself.name='spieler') and (meshplayer(spriteself).status=schlag1) then begin
    if (colspr.name='innom') and (meshinnom(colspr).status<>schmerz) then begin
    meshinnom(colspr).nanimpos:=0;
    meshinnom(colspr).status:=schmerz;
    meshinnom(colspr).hit(meshplayer(spriteself).nhitp ower);
    end;
    end;
    //Innom schl?§gt
    if (spriteself.name='innom') and (meshinnom(spriteself).status<>schlag1) and (meshinnom(spriteself).status<>schmerz) then begin
    if (colspr.name='bauer') then begin
    meshinnom(spriteself).nanimpos:=0;
    meshinnom(spriteself).status:=schlag1;
    meshbauer(colspr).hit(meshinnom(spriteself).nhitpo wer);
    end;
    if (colspr.name='spieler') then begin
    meshinnom(spriteself).nanimpos:=0;
    meshinnom(spriteself).status:=schlag1;
    meshplayer(colspr).hit(meshinnom(spriteself).nhitp ower);
    end;
    end;
    if (Engine.Sprites[i]<>spriteself) and (ndist<Innomsprite(spriteself).nRadius+Innomsprite (Engine.Sprites[i]).nRadius)
    then begin
    result:=true;
    colSpr:=Engine.Sprites[i];
    ColPt:=D3DXVector2((spriteself.X+colSpr.X)/2,(spriteself.z+colSpr.z)/2);
    tmpVec:=D3DXVector2(spriteself.X - colSpr.X,spriteself.z - colSpr.z);
    D3DXVec2Normalize(tmpVec, tmpVec);
    if innomsprite(spriteself).bolmovable then begin
    if innomsprite(ColSpr).bolmovable then begin
    spriteself.x:=ColPt.x + tmpVec.x * innomsprite(spriteself).nRadius;
    spriteself.z:=ColPt.y + tmpVec.y * innomsprite(spriteself).nRadius;
    end
    else begin
    spriteself.x := ColSpr.x + tmpVec.x * innomsprite(ColSpr).nRadius + tmpVec.x * innomsprite(spriteself).nRadius;
    spriteself.z := ColSpr.z + tmpVec.y * innomsprite(ColSpr).nRadius + tmpVec.y * innomsprite(spriteself).nRadius;
    end;
    end;
    end;
    { if innomsprite(ColSpr).bolmovable then begin
    if innomsprite(spriteself).bolmovable then begin
    ColSpr.x := ColPt.x - tmpVec.x * innomsprite(ColSpr).nRadius;
    ColSpr.z := ColPt.y - tmpVec.y * innomsprite(ColSpr).nRadius;
    end
    else begin
    ColSpr.x := spriteself.x - tmpVec.x * innomsprite(spriteself).nRadius - tmpVec.x * innomsprite(ColSpr).nRadius;
    ColSpr.z := spriteself.z - tmpVec.y * innomsprite(spriteself).nRadius - tmpVec.y * innomsprite(ColSpr).nRadius;
    end;
    end; }
    exit;
    end;
    end;
    end;
    One problem is it only works with circles, so this is bad when it comes to fences and walls etc. So I need another case for rectangle collisions?

    The other problem is, 'spieler' means player, 'innom' is the monster, 'bauer' is a villagers and each of them has a nrotatey variable beween -pi and pi which direction the person faces.
    Now when many monsters surround the player, one gets hits but not the one in the right direction, it may also be one standing behind the player...

    I am not experienced with that, can somebody help me out, how do you guys do this?

    Thanks,
    Firle

  2. #2

    Collision detection in 3D for obstacles, sword fighting...

    Now when many monsters surround the player, one gets hits but not the one in the right direction, it may also be one standing behind the player...
    Store the direction the player is facing as a vector. It can be made from facing angle

    Code:
    vDir &#58;= vector&#40;cos&#40;angle,0,sin&#40;angle&#41;&#41;;
    To find out if player faces the monster first calculate vector v between player and monster positions. Then calculate the dot product of v and players direction. If it is greater than zero than monster is in front of a player otherwise monster is behind.

    This method gives you information if the monster is behind or in front of the player. The monster can be in front of the player but outside players
    viewing field (too far ont he right or left). To check this further tests are needed. An example

    Code:
    I am assuming that player has 90 degree field of view.
         \  front   /
           \      /
             \  /
      left ---P --- right
             /  \
           /      \
         / back     \
    
    v &#58;= Monster.Pos - Player.Pos;
    d &#58;= dotProduct&#40;Player.Dir,v&#41;;
    if d > 0 then begin //the monster over the vertical line on the picture
     d &#58;= ArcCos&#40;d&#41;;
     if &#40;d < pi/4&#41; or &#40;d > 3*pi/4&#41; then //player is in the front area
    As for collisons with obstacles you need bounding rectangles. You can do collision in two passes. First with static objects based on rectangles and second with monsters based on circles.

    Hope you find it usefull.

  3. #3

    Collision detection in 3D for obstacles, sword fighting...

    Hello grudzio,

    thanks a lot for this very useful info and explanations!

    I'll try that, looks very good to me, just what I need I guess.

    Thanks a lot!

    Firlefanz

  4. #4

    Collision detection in 3D for obstacles, sword fighting...

    One question about this explanation:

    vdir is : TD3DXVector3 right?

    v and d are single or double, right?

    What is Monster.Pos and Player.Pos?

    I have x,y,z Position variable for each of them.

    Is it also a TD3DXVector3 with X,Y,Z?

    Thanks,
    firle

  5. #5

    Collision detection in 3D for obstacles, sword fighting...

    Yes it is.

    The Dotproduct of 2 Vectors (in your case TD3DXVector3) gives a float value.

    The ArcCos of this value gives the angle (in radians), in which the 2 points are positioned to each other.

    DotProduct =


    function DotProduct(const a, b: TPoint3): Real;
    begin
    Result:= (a.x * b.x) + (a.y * b.y) + (a.z * b.z);
    end;
    <a href="http://www.greatgamesexperiment.com/game/Valgard/?utm_source=gge&amp;utm_medium=badge_game"><img border="0" alt="GGE" title="GGE" src="http://static.greatgamesexperiment.com/badge/game/valgard/gge400x56.png"></a>

  6. #6

    Collision detection in 3D for obstacles, sword fighting...

    Player.Pos and Monster.Pos are 3D vectors (TD3DXVector3) and describe world position of player and monster. They are composed of x,y,z variables you use currently.

    Player.Dir is also TD3DXVector3 describing orientation of the player (or monster). It can be made from nrotatey variable you have

    Player.Dir := MakeTD3DXVector3( cos(nrotatey), 0, sin(nrotatey));

    If you store nrotatey in angles dont forget to change it to radians before you pass it to sin and cos functions.

    vDir is also a TD3DXVector3 but in my example it is replaced by Player.Dir.

    v is also a TD3DXVector3. So in the line
    v := Monster.Pos - Player.Pos;
    "-" means vector subtraction.

    d is a scalar value (single or double).

    I am sorry for the confusion. I hope it is more clear now.

    I just noticed that it is already anwsered. I am so sloooow typer .

  7. #7

    Collision detection in 3D for obstacles, sword fighting...

    Just one more thing. Like Huehnerschaender already said, the dotProduct(v1,v2) returns an cosine of an angle between vectors v1 and v2. So it can be used to determine if player is facing monster. This can be usefull if you want the attacks to give more damage if made from side or behind.

  8. #8

    Collision detection in 3D for obstacles, sword fighting...

    Looks very good. Thank you both for those explantions, I will try that later and be back with more questions or let you know if it worked.

    Firle

  9. #9

    Collision detection in 3D for obstacles, sword fighting...

    Hello,

    yesterday I build a new routine for fighting collisions.
    But something is wrong with it, when I am in the radius of the monster, in some position I hit it never, in another position I hit it always no matter how I rotate.

    I guess I did something wrong here.

    Code:
    function TForm1.fightcollide&#40;spriteself&#58; TDJXEngineItem&#41;&#58; boolean;
    var i&#58; integer;
        colSpr&#58; TDJXEngineItem;
        ColPt&#58; TD3DXVector2;
        tmpVec&#58; TD3DXVector2;
        ndist,nrot&#58;  Double;
        vdir,v&#58; TD3DXVector3;
        d&#58; single;
    begin
      result&#58;=false;
      nrot&#58;=degtorad&#40;spriteself.nrotatey&#41;;
      vDir &#58;= D3DXVector3&#40;cos&#40;nrot&#41;,0,sin&#40;nrot&#41;&#41;;
      for i&#58;=0 to Engine.Count-1 do begin
        ndist&#58;=distance_dbl&#40;spriteself.x,spriteself.z,0,Engine.Sprites&#91;i&#93;.X,Engine.Sprites&#91;i&#93;.Z,0&#41;;
        if &#40;Engine.Sprites&#91;i&#93;<>spriteself&#41;
        and &#40;ndist<Innomsprite&#40;spriteself&#41;.nRadius*2+Innomsprite&#40;Engine.Sprites&#91;i&#93;&#41;.nRadius*2&#41;
        then begin
          colSpr&#58;=Engine.Sprites&#91;i&#93;;
          //Player hits Monster
          if &#40;spriteself.name='spieler'&#41; and &#40;meshplayer&#40;spriteself&#41;.status=schlag1&#41; then begin
            if &#40;colspr.name='innom'&#41; and &#40;meshinnom&#40;colspr&#41;.status<>schmerz&#41; then begin
          	  D3DXVec3Subtract&#40;v,D3DXVector3&#40;colspr.X,colspr.Y,colspr.Z&#41;,D3DXVector3&#40;spriteself.X,spriteself.Y,spriteself.Z&#41;&#41;;
              d&#58;= &#40;v.x * vdir.x&#41; + &#40;v.z * vdir.z&#41;;
              d &#58;= ArcCos&#40;d&#41;;
              //if &#40;d <pi> 3*pi/4&#41; then begin //player is in the front area
              if &#40;d <pi> 2*pi/3&#41; then begin //player is in the front area
                meshinnom&#40;colspr&#41;.nanimpos&#58;=0;
                meshinnom&#40;colspr&#41;.status&#58;=schmerz;
                meshinnom&#40;colspr&#41;.hit&#40;meshplayer&#40;spriteself&#41;.nhitpower&#41;;
              end;
            end;
          end;
        end;
      end;
    end;
    Player is here spriteself, the monster is here the Engine item ColSpr.
    I just changed the angle a bit for testing purposes but still the same, it depends on the position not on the rotation right now.

    My rotation is a bit strange. When turning around I decrease it, I start at 0, at around -7 I am rotatet one time etc, at -14 two times.

    When I render with -nrotatey-pi/2 for Y Rotation it is alright.
    So much to my nrotateY.

    Firle

  10. #10

    Collision detection in 3D for obstacles, sword fighting...

    Hey, the code format does strange things, the line is

    ...I cannot post it even with quote etc it always get changed

    :evil:
    Very angry! Cannot post the code!

    When posting it it gets changed eached time, even with quote!

    Code:
    if &#40;d <pi> 2*pi/3&#41; then begin //player is in the front area
    Firle

Page 1 of 3 123 LastLast

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
  •