Raycasting and other helper stuff



  • Hey, can this engine raycast without FlxTilemap?
    I didn't find any information about this.



  • @Username posted in simple raycast?:

    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!


Log in to reply
 

Looks like your connection to HaxeFlixel was lost, please wait while we try to reconnect.