simple raycast?



  • I want to raycast, such that ray will travel in a certain vector up until a certain distance, and return first sprite it intersect? how can I do?



  • This post is deleted!


  • This post is deleted!


  • This post is deleted!

  • administrators

    Hey! Sorry 'bout that. We've had a couple reports of this and disabled Akismet for the time being. Can you see if it works now?



  • I was kind of board and needed a small distraction and might eventually need this code myself so i have come-up with this. Its based on some old line drawing code that i had laying around. I reconfigured it for HaxeFlixel. To my best of knowing HaxeFlixel does not have this, only: Nape Ray. Which needs to be configured for HaxeFlixel anyways.

    // source Pew.hx
    package;
    
    import flixel.FlxObject;
    
    class Pew {
        // Returns first object of a, if point(x, y) will hit the hitbox.
        public static function isHit(x:Float, y:Float, a:Array<FlxObject>):FlxObject {
            if (a != null && a.length > 0) {
                for (o in a) {
                    if (x >= o.x&&x <= o.x+o.width&&y >= o.y&&y <=o.y+o.height) {
                        return o;
                    }
                  }
              }
              return null;
          }
    
          // shoot from point (sx, sy) to (ex, ex) if will return the first hit a.
          public static function shoot(sx:Float, sy:Float, ex:Float, ey:Float, a:Array<FlxObject>=null):FlxObject {
              var dx:Float    = ex - sx;
              var dy:Float    = ey - sy;
              if (a == null || a.length == 0) {
                  return null;
              }
              if (dx >= 0) {
                  if (_p(dx) > _p(dy)) {
                      return _shootHor(sx, sy, ex, ey, a, false);
                  } else {
                      return _shootVer(sx, sy, ex, ey, a, false);
                 }
              } else {
                  if (_p(dx) > _p(dy)) {
                      return _shootHor(ex, ey, sx, sy, a, true);
                  } else {
                      return _shootVer(ex, ey, sx, sy, a, true);
                  }
              }
              return null;
          }
    
          // return positive value;
          private static function _p(v:Float) {
              if (v < 0) { return 0 - v; } return v;
          }
    
          // Make a vertical line and return first hit object
          private static function _shootVer(sx:Float, sy:Float, ex:Float, ey:Float, a:Array<FlxObject>, reverse:Bool=false):FlxObject {
              var r:FlxObject;
              var dx=Math.abs(sx - ex),dy=Math.abs(sy - ey);
              var p=(2*dy-dx),x=sx,y=sy,e=ex,inc=1;
              if (sy > ey) { x=ex; y=ey; e = sy; }
              if (sx > ex) { inc=1; }
              if (reverse){ inc=-1; }
              while (y <= e) {
                  if ((r=isHit(x, y++, a))!=null) { return r; }
                  if (p <= 0) {
                      p+=2*dx;
                  } else {
                      x+=inc;p+=(2*(dx-dy));
                  }
              }
              return null;
          }
    
          // Make a horizontal line and return first hit object
          private static function _shootHor(sx:Float, sy:Float, ex:Float, ey:Float, a:Array<FlxObject>, reverse:Bool=false):FlxObject {
              var r:FlxObject;
              var dx=Math.abs(sx - ex),dy=Math.abs(sy - ey);
              var p=(2*dy-dx),x=sx,y=sy,e=ex,inc=1;
              if (sx > ex) { x=ex; y=ey; e=sx; }
              if (sy > ey) { inc=-1; }
              if (reverse) { inc=1; }
              while (x <= e) {
                  if ((r=isHit(x++, y, a))!=null) { return r; }
                  if (p <= 0) {
                      p+=2*dy;
                  } else {
                      y+=inc;p+=(2*(dy-dx));
                  }
              }
              return null;
          } 
      }
    

    Usage: Pew.shoot(begin_x, begin_y, end_x, _end_y, list_of_potentials); it should return the first hit from the list or null; You can also test one pixel with isHit() yourself. You can either cast your sprites or any FlxObject child's before adding them in an array, or do a simple search and replace on it :D

    Issues: This is based on some old code that i have mostly edited by search&replace. In my personal test it works! The only problem I seen is it might overshoot with one pixel. If it bugs on you then check the variables from _shoot*. Maybe look at inc first.!

    Optimization: You can probably want to do a quadrant check first before shooting, and/or an inbouds check on the list items before shooting. Or adept the code that it will always doe this by itself.

    Limitations: It can be heavy duty depending on the data, so use with care. isHit() will check on the hitbox, not on the pixels. It will only return the first hit object. You must reconfigure it if you want all hit objects in a list. It can only shoot in a strait line - but bullets usually do that! - . Also it comes with no warranty and I'm not really supporting it :D

    For me this is useful, i hope it is for you as wel!

    Good Night!



  • @nospoone It works now! Thnx.



  • @nictaylr You also just might want to combine _shoot* to one function. Its probably 2 now because on the original code i was debugging it a wile and probably got really tired of the axis. On the other hand it might save you some comparison/arithmetic if you don't!



  • Also, while reading the code you can probably substitute:

    (2*dy-dx)
    

    for a varible instead of just keep calculating it.!


Log in to reply