Advertisement
Guest User

obstacle avoidance

a guest
Jan 28th, 2018
75
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 14.92 KB | None | 0 0
  1. // todo: reduce the amount of raycast checks
  2.  
  3. // returns true if it needs to overrite normal movement to avoid obstacle
  4. function AiPlayer::handleObstacle(%this)
  5. {
  6.     %scale = getWord(%this.getScale(), 2);
  7.    
  8.     if(vectorLen(getWords(%this.getVelocity(), 0, 1)) < 1 * %scale)
  9.         %this.stuckCount += $SceneryRP::TickTime / 66;
  10.     else
  11.         %this.stuckCount = 0;
  12.    
  13.     // figuring out of the bot is stuck or not
  14.     if(%this.stuckCount > 15)
  15.         %this.isStuck = true;
  16.     else
  17.         %this.isStuck = false;
  18.    
  19.     // checks to see if there's a player in our way
  20.     if(!%this.isSideStepping)
  21.         %this.playerSideStep();
  22.     else
  23.         %this.stopSideStep();
  24.    
  25.     %start = vectorAdd(%this.getHackPosition(), "0.2");
  26.     %raycast = containerRaycast(%start, vectorAdd(%start, vectorScale(%this.getForwardVector(), 1 * %scale)), $TypeMasks::fxBrickObjectType | $TypeMasks::PlayerObjectType, %this);
  27.    
  28.     if(isObject(%col = getWord(%raycast, 0)) && %col != %this.getMountedObject(0))
  29.     {
  30.         // seeing if we can jump over the obstacle
  31.         // if top of the box is a certain distance away from the root of the bot then we can jump over it
  32.         if(%col.getType() & $TypeMasks::fxBrickObjectType && %this.stuckCount > 5)
  33.         {
  34.             %topBrick = %col.getTopBrick();
  35.             %worldBox = %topBrick.getWorldBox();
  36.             %height = getWord(%worldBox, 5);
  37.             %zPosition = getWord(%this.getPosition(), 2);
  38.            
  39.             // if we can jump over a wall then jump over the wall
  40.             if(%height - %zPosition < 3.5 * %scale && %height - %zPosition > 0)
  41.             {
  42.                 %this.jump();
  43.                 return false;
  44.             }
  45.         }
  46.         else if(%this.isStuck)
  47.             %this.jump();
  48.        
  49.         // shoving players
  50.         if(%col.getClassName() $= "Player" && %this.isStuck)
  51.         {
  52.             %this.shovePlayer(%col);
  53.             return false;
  54.         }
  55.         else if(%this.stuckCount > 30) // no clue what this check is for
  56.         {
  57.             %this.shovePlayer(%col);
  58.             return false;
  59.         }
  60.     }
  61.     // if we're stuck then just jump in desperation
  62.     else if(%this.stuckCount > 25)
  63.         %this.jump();
  64.    
  65.     return %this.avoidWall() || %this.isSideStepping;
  66. }
  67.  
  68. function AiPlayer::avoidWall(%this)
  69. {
  70.     %scale = getWord(%this.getScale(), 2);
  71.    
  72.     %endPosition = %this.moveGoal;
  73.    
  74.     // trying to see if there's an object in front of the bot
  75.    
  76.     if(vectorLen(%this.getVelocity()) < 1 * %scale)
  77.         %distance = 0.1;
  78.     else
  79.         %distance = 1.5;
  80.    
  81.     %col = %this.boxSearch(vectorAdd(%this.getHackPosition(), vectorScale(%this.getForwardVector(), %distance)));
  82.     %ceilingCheck = containerRaycast(%this.getPosition(), vectorAdd(%this.getPosition(), "0 0 15"), $TypeMasks::fxBrickObjectType, false);
  83.    
  84.     // if there's a ceiling then abandon the wall avoidance
  85.     if(isObject(%door = %this.areDoorsNear()) || isObject(getWord(%ceilingCheck, 0)) || getWord(%this.getScale(), 2) < 0.5)
  86.     {
  87.         // if there's a door in our way then open it
  88.         if(isObject(%door))
  89.             %this.openDoorInPath();
  90.        
  91.         return %this.interiorAvoidance();
  92.     }
  93.     // if we're doing interior obstacle avoidance but aren't in an interior anymore then restore normal movement
  94.     else if(%this.avoidingInterior)
  95.     {
  96.         %this.avoidingInterior = false;
  97.         %this.setMoveX(0);
  98.         %this.setMoveY(1);
  99.     }
  100.    
  101.     // getting normal of the wall so we can walk along it
  102.     if(isObject(%col))
  103.         %normal = %this.getNormal(%col);
  104.    
  105.     // if its a wall then walk along it
  106.     if(isObject(%col) && mAbs(getWord(vectorToEuler(%normal), 0)) < 5 && %normal != 0)
  107.     {
  108.         // getting the direction we should walk along
  109.         %botRightVector = vectorCross(%this.getForwardVector(), "0 0 1");
  110.         %normalRightVector = vectorCross(%normal, "0 0 1");
  111.         %relativePosition = vectorSub(%this.getPosition(), %endPosition);
  112.        
  113.         if(%this.isPositionToRight $= "")
  114.         {
  115.             %isPositionToRight = %this.isPositionToRight2(%endPosition);
  116.             %this.isPositionToRight = %isPositionToRight;
  117.         }
  118.        
  119.         // if the position is to the right and the normal is to the left, flip the normal
  120.         if(%this.isPositionToRight && vectorDot(%botRightVector, %normalRightVector) > 0)
  121.         {
  122.             %normalRightVector = vectorScale(%normalRightVector, -1);
  123.             %this.obstacleSide = 1; // means the wall is on the right hand side of the bot
  124.         }
  125.         // if the position is to the left and the normal is to the right, flip the normal
  126.         else if(!%this.isPositionToRight && vectorDot(%botRightVector, %normalRightVector) < 0)
  127.         {
  128.             %normalRightVector = vectorScale(%normalRightVector, -1);
  129.             %this.obstacleSide = 0; // means the wall is on the left hand side of the bot
  130.         }
  131.         else
  132.             %this.obstacleSide = 1; // means the wall is on the right hand side of the bot
  133.        
  134.         // if there's shit to the left and we are going left then switch direction
  135.         if(%this.isWallToSide(0, true) && %this.obstacleSide == 1)
  136.         {
  137.             %normalRightVector = vectorScale(%normalRightVector, -1);
  138.             %this.obstacleSide = 0;
  139.         }
  140.         // if there's shit to the right and we're going to the right then switch direction
  141.         else if(%this.isWallToSide(1, true) && %this.obstacleSide == 0)
  142.         {
  143.             %normalRightVector = vectorScale(%normalRightVector, -1);
  144.             %this.obstacleSide = 1;
  145.         }
  146.        
  147.         // used to set the direction the bot should be going in to avoid the obstacle
  148.         %this.obstacleDirection = %normalRightVector;
  149.         %aimPosition = vectorAdd(%this.getEyePoint(), vectorScale(%this.obstacleDirection, 500));
  150.         %this.setAimLocation(%aimPosition);
  151.         %this.clearMoveGoal();
  152.        
  153.         return true;
  154.     }
  155.     // if we're following a wall but we can now walk towards the movegoal
  156.     else if(%this.obstacleDirection !$= "" && ((%beeline = %this.canBeeLine(%endPosition)) || !%this.areWallsAround()))
  157.     {
  158.         %this.obstacleDirection = "";
  159.         %this.isPositionToRight = "";
  160.         %this.obstacleSide = -1;
  161.         return false;
  162.     }
  163.     // following a wall if we can't beeline. below is for handling walking along wall corners
  164.     else if(%this.obstacleDirection !$= "" && !%beeline)
  165.     {
  166.         // checking to see if we can walk around a wall's corner
  167.         if(!isObject(%this.isWallToSide()) && getSimTime() - %this.lastFlip > 500)
  168.         {
  169.             if(%this.obstacleSide)
  170.             {
  171.                 %position = vectorAdd(%this.getEyePoint(), vectorScale(vectorCross(%this.obstacleDirection, "0 0 1"), 500));
  172.                 %this.obstacleSide = 1;
  173.                 %this.obstacleDirection = vectorCross(%this.obstacleDirection, "0 0 1");
  174.             }
  175.             else
  176.             {
  177.                 %position = vectorAdd(%this.getEyePoint(), vectorScale(vectorCross(%this.obstacleDirection, "0 0 1"), -500));
  178.                 %this.obstacleSide = 0;
  179.                 %this.obstacleDirection = vectorScale(vectorCross(%this.obstacleDirection, "0 0 1"), -1);
  180.             }
  181.            
  182.             %this.lastFlip = getSimTime();
  183.             %this.setAimLocation(vectorAdd(%position, vectorScale("0 0 2.1", %scale)));
  184.             %this.clearMoveGoal();
  185.         }
  186.        
  187.         return true;
  188.     }
  189.     // we aren't following a wall to begin with and we found nothing to walk along
  190.     else
  191.     {
  192.         %this.obstacleDirection = "";
  193.         %this.isPositionToRight = "";
  194.         %this.obstacleSide = -1;
  195.         return false;
  196.     }
  197. }
  198.  
  199. // much simpler obstacle algorithm for inside spaces, just set x move to 1 or -1 depending on if movegoal is to right/left
  200. function AiPlayer::interiorAvoidance(%this)
  201. {
  202.     %scale = getWord(%this.getScale(), 2);
  203.    
  204.     if(vectorLen(%this.getVelocity()) < 0.5 * %scale)
  205.     {
  206.         %position = vectorAdd(%this.getPosition(), "0 0 0.1");
  207.         %rightVector = vectorCross(%this.getForwardVector(), "0 0 1");
  208.        
  209.         for(%i = 0; %i < 3; %i++)
  210.         {
  211.             %start = vectorAdd(%position, vectorScale(%rightVector, 0.9 * (%i - 1) * %scale));
  212.             %endPosition = vectorAdd(%start, vectorScale(%this.getForwardVector(), 2));
  213.            
  214.             if(isObject(%col = getWord(containerRaycast(%start, %endPosition, $TypeMasks::fxBrickObjectType, false), 0)))
  215.                 %foundObject = true;
  216.         }
  217.        
  218.         if(%foundObject)
  219.         {
  220.             %this.avoidingInterior = true;
  221.            
  222.             if(%this.isPositionToRight2(%this.moveGoal))
  223.             {
  224.                 %this.setMoveX(1);
  225.                 %this.setMoveY(0);
  226.                 return true;
  227.             }
  228.             else
  229.             {
  230.                 %this.setMoveX(-1);
  231.                 %this.setMoveY(0);
  232.                 return true;
  233.             }
  234.         }
  235.         else
  236.         {
  237.             %this.avoidingInterior = false;
  238.             %this.setMoveX(0);
  239.             %this.setMoveY(1);
  240.             return false;
  241.         }
  242.     }
  243.     else if(%this.avoidingInterior)
  244.     {
  245.         %this.avoidingInterior = false;
  246.         %this.setMoveX(0);
  247.         %this.setMoveY(1);
  248.         return false;
  249.     }
  250.    
  251.     return false;
  252. }
  253.  
  254. function AiPlayer::playerSideStep(%this)
  255. {
  256.     %scale = getWord(%this.getScale(), 2);
  257.    
  258.     if(vectorLen(%this.getVelocity()) < 0.5 * %scale)
  259.     {
  260.         %col = %this.isObjectInWay($TypeMasks::PlayerObjectType | $TypeMasks::StaticShapeObjectType, %this);
  261.        
  262.         if(isObject(%col) && !%this.isSideStepping && %col != %this.getMountedObject(0) && %col.getDatablock() != nameToId(MedievalStandardBot))
  263.         {
  264.             %this.isSideStepping = true;
  265.             %this.setMoveX(getRandom(0, 1) ? -1 : 1);
  266.            
  267.             %this.schedule(1500, stopSideStep);
  268.         }
  269.     }
  270. }
  271.  
  272. function AiPlayer::stopSideStep(%this)
  273. {
  274.     %this.isSideStepping = false;
  275.     %this.setMoveX(0);
  276. }
  277.  
  278. function AiPlayer::shovePlayer(%this, %col)
  279. {
  280.     if(getSimTime() - %col.lastShove < 1000)
  281.         return;
  282.    
  283.     %scale = getWord(%this.getScale(), 2);
  284.    
  285.     %this.playThread(0, activate2);
  286.     %col.addVelocity(vectorAdd(vectorScale(%this.getForwardVector(), 7), vectorScale("0 0 5", %scale)));
  287.     %col.lastShove = getSimTime();
  288. }
  289.  
  290. function AiPlayer::isWallToSide(%this, %customSide, %raycast)
  291. {
  292.     %rightVector = vectorCross(%this.getForwardVector(), "0 0 1");
  293.    
  294.     if(%customSide $= "")
  295.         %customSide = %this.obstacleSide;
  296.    
  297.     if(%customSide)
  298.         %position = vectorAdd(%this.getEyePoint(), vectorScale(%rightVector, 2));
  299.     else
  300.         %position = vectorAdd(%this.getEyePoint(), vectorScale(%rightVector, -2));
  301.    
  302.     if(%raycast)
  303.     {
  304.         %raycast = containerRaycast(%this.getEyePoint(), %position, $TypeMasks::fxBrickObjectType, false);
  305.         return isObject(getWord(%raycast, 0));
  306.     }
  307.     else if(isObject(%col = %this.boxSearch(%position)))
  308.         return %col;
  309.     else
  310.         return 0;
  311. }
  312.  
  313. function AiPlayer::areWallsAround(%this)
  314. {
  315.     %rightVector = vectorCross(%this.getForwardVector(), "0 0 1");
  316.    
  317.     %scale = getWord(%this.getScale(), 2);
  318.    
  319.     %col |= %this.boxSearch(vectorAdd(%this.getEyePoint(), vectorScale(%this.getForwardVector(), 2 * %scale)));
  320.     %col |= %this.boxSearch(vectorAdd(%this.getEyePoint(), vectorScale(%this.getForwardVector(), -2 * %scale)));
  321.     %col |= %this.boxSearch(vectorAdd(%this.getEyePoint(), vectorScale(%rightVector, 2 * %scale)));
  322.     %col |= %this.boxSearch(vectorAdd(%this.getEyePoint(), vectorScale(%rightVector, -2 * %scale)));
  323.    
  324.     return %col;
  325. }
  326.  
  327. // much better way of calculating angle than whatever shitty ass function i was using before. i don't use it in the pathfinding shit but i'm keeping it anyway because its so fucking good
  328. // its a month later context: i had some old get angle from position code i wrote a few years ago where it did trig instead of linear algebra and linear algebra is more fashionable than trig which is why this method is good
  329. function Player::getAngleFromPosition(%this, %position)
  330. {
  331.     %forwardVector = vectorNormalize(getWords(%this.getForwardVector(), 0, 1));
  332.     %vectorToPosition = vectorNormalize(getWords(vectorSub(%position, %this.getPosition()), 0, 1));
  333.     %dot = vectorDot(%forwardVector, %vectorToPosition);
  334.     %theta = mACos(%dot);
  335.     return %theta * 180 / $PI;
  336. }
  337.  
  338. // see is point on one side of the plane or not code from the eggine
  339. function Player::isPositionToRight(%this, %position)
  340. {
  341.     return (vectorDot(vectorCross(%this.getForwardVector(), "0 0 1"), vectorSub(%this.getPosition(), %position)) < 0);
  342. }
  343.  
  344. // we need to snap the vector to the nearest axis because ???
  345. // this is another situation where i didn't comment this shit when i wrote it and its a month later
  346. function Player::isPositionToRight2(%this, %position)
  347. {
  348.     return (vectorDot(vectorCross(snapVectorToNearestAxis(%this.getForwardVector()), "0 0 1"), vectorSub(%this.getPosition(), %position)) < 0);
  349. }
  350.  
  351. // ignores z axis
  352. function snapVectorToNearestAxis(%vector)
  353. {
  354.     %x = getWord(%vector, 0);
  355.     %y = getWord(%vector, 1);
  356.    
  357.     if(mAbs(%x) < mAbs(%y))
  358.     {
  359.         if(%y < 0)
  360.             return "0 -1 0";
  361.         else if(%y > 0)
  362.             return "0 1 0";
  363.     }
  364.     else
  365.     {
  366.         if(%x < 0)
  367.             return "-1 0 0";
  368.         else
  369.             return "1 0 0";
  370.     }
  371. }
  372.  
  373. // its not a box search anymore because boxes aren't too good for what i need them for. why you might ask well i don't have a clue i wrote this code a month ago and didn't comment it
  374. function AiPlayer::boxSearch(%this, %position)
  375. {
  376.     // does box search at given position. box search because a box more accurately represents the player collision box
  377.     // return ContainerFindFirst($TypeMasks::fxBrickObjectType, %position, 0.5, 0.5, 0.5);
  378.    
  379.     %scale = getWord(%this.getScale(), 2);
  380.    
  381.     initContainerRadiusSearch(%position, 0.5 * %scale, $TypeMasks::fxBrickObjectType);
  382.     while(%col = containerSearchNext())
  383.     {
  384.         if(strPos(%col.getDatablock().getName(), "Door") == -1 && %col.isColliding())
  385.             return %col;
  386.     }
  387.    
  388.     return 0;
  389. }
  390.  
  391. function AiPlayer::areDoorsNear(%this)
  392. {
  393.     initContainerRadiusSearch(%this.getPosition(), 2, $TypeMasks::fxBrickObjectType);
  394.     while(%col = containerSearchNext())
  395.     {
  396.         if(strPos(%col.getDatablock().getName(), "Door") != -1)
  397.             return %col;
  398.     }
  399. }
  400.  
  401. // if it finds a door then open it
  402. function AiPlayer::openDoorInPath(%this)
  403. {
  404.     %raycast = containerRaycast(%this.getEyePoint(), %this.moveGoal, $TypeMasks::fxBrickObjectType, false);
  405.     %col = getWord(%raycast, 0);
  406.    
  407.     if(isObject(%col) && strPos(%col.getDatablock().getName(), "Door") != -1 && strPos(%col.getDatablock().getName(), "Open") == -1)
  408.     {
  409.         %this.player = %this;
  410.         serverCmdActivateStuff(%this);
  411.         %this.player = 0;
  412.     }
  413. }
  414.  
  415. // gets normal from a colision brick
  416. function AiPlayer::getNormal(%this, %col)
  417. {
  418.     %raycast = containerRaycast(%this.getHackPosition(), vectorAdd(%col.getPosition(), "0 0 -0.01"), $TypeMasks::fxBrickObjectType, false);
  419.    
  420.     if(isObject(getWord(%raycast, 0)))
  421.         return getWords(%raycast, 4, 6);
  422. }
  423.  
  424. function AiPlayer::canBeeLine(%this, %endPosition)
  425. {
  426.     %scale = getWord(%this.getScale(), 2);
  427.    
  428.     // checks to see if it can walk straight to the position or not. used in ::avoidWall, used to disengage walking along the wall
  429.     %rightVector = vectorCross(%this.getForwardVector(), "0 0 1");
  430.    
  431.     // doing 3 raycasts, two from the sides of the bot, one from the center. we do 3 so it doesn't get caught on corners its trying to walk around (actually, to see if you only have to do 2)
  432.     for(%i = 0; %i < 3; %i++)
  433.     {
  434.         %start = vectorAdd(%this.getEyePoint(), vectorScale(%rightVector, 0.9 * (%i - 1) * %scale));
  435.        
  436.         if(isObject(getWord(containerRaycast(%start, %endPosition, $TypeMasks::fxBrickObjectType, false), 0)))
  437.             return false;
  438.     }
  439.    
  440.     return true;
  441. }
  442.  
  443. function AiPlayer::isObjectInWay(%this, %mask, %ignore)
  444. {
  445.     %scale = getWord(%this.getScale(), 2);
  446.    
  447.     // checks to see if it can walk straight to the position or not. used in ::avoidWall, used to disengage walking along the wall
  448.     %rightVector = vectorCross(%this.getForwardVector(), "0 0 1");
  449.    
  450.     // doing 3 raycasts, two from the sides of the bot, one from the center
  451.     for(%i = 0; %i < 3; %i++)
  452.     {
  453.         %start = vectorAdd(%this.getEyePoint(), vectorScale(%rightVector, 1.1 * (%i - 1) * %scale));
  454.         %end = vectorAdd(%start, vectorScale(%this.getForwardVector(), 1 * %scale));
  455.        
  456.         if(isObject(%col = getWord(containerRaycast(%start, %end, %mask, %ignore), 0)))
  457.             return %col;
  458.     }
  459.    
  460.     return false;
  461. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement