GML [GM8] Hitscan shotgun code

MegaJim73

Member
I've been tinkering the hitscan code I made in my previous thread for a shotgun in my FPS but it has a couple of quirks that keep it from functioning as intended:
  • When aimed at an enemy, only up to three 'pellets' will hit the enemy and do damage, regardless of how many 'pellets' are fired. Otherwise they make the appropriate number of impacts.
  • The spread is tight but not as 'directed' as intended. Is there a better way to calculate the velocity for the 'pellets'? (global.camcos = cos(direction*pi/180) and global.camsin = sin(direction*pi/180) respectively for reference.)
Code:
{
  // check whether you can shoot
  if (not can_shoot) exit;
  can_shoot = false;
  // show the animation and play the sound
  image_speed = 0.5;
  image_index = 0;
  sound_play(snd_shtgn);
  global.shells-=1;
  var xx, yy, ii;
  xx = global.camx;
  yy = global.camy;
  repeat(6)
  {
  for (i=0; i<256;i+=2)
  {    
    xx += (4+random_range(-1,1))*global.camcos;
    yy -= (4+random_range(-1,1))*global.camsin;
    if (position_meeting(xx,yy,obj_wall_basic))
    {   ///You hit a wall, ricochet.
        t=instance_create(xx,yy,obj_ricochet);
        t.direction=obj_player.direction;
        t.z1=ii.z1*0.75;
    break;
    }
    else
    if (position_meeting(xx,yy,obj_monster_basic))
    {   ///You hit an enemy, deal damage.
      ii = instance_position(xx,yy,obj_monster_basic);
      if (ii == noone) continue;
      with (ii)
      {
      mhealth-=1;
      hurt=1;
      t=instance_create(xx,yy,blood_type);
      t.z1=ii.z1*0.75;
      break;
      }
    }
    else
    if (position_meeting(xx,yy,obj_pillar1))
    {   ///You hit a column, ricochet.
      ii = instance_position(xx,yy,obj_pillar1);
      if (ii == noone) continue;
      with (ii)
      {
      if (indestructible==0)
        {
          mhealth-=1;
          t=instance_create(xx,yy,blood_type);
          t.z1=ii.z1*0.75;
        };
        else
        t=instance_create(xx,yy,blood_type);
        t.z1=ii.z1*0.75;
        break;
      }
    }
    //alert other enemies within radius
    with (obj_monster_basic)
    {
    if ((id != other.id) && collision_circle(global.camx,global.camy,128,id,1,0))
    {
    with (id) alert=1;
    }
    } 
  };
}
}
 

YellowAfterlife

ᴏɴʟɪɴᴇ ᴍᴜʟᴛɪᴘʟᴀʏᴇʀ
Forum Staff
Moderator
The primary issue here is that you are recalculating spread every step. You should rather offset the angle and calculate it once before loop.

Could also use this script for more efficient hitscan, except you'll have to tweak it a bit due to using a vastly outdated version of GM
 

MegaJim73

Member
I've rewritten the code a bit so it uses lengthdir rather than global.camcos or global.camsin instead, and just added the random_range there for the spread. The good news is that hit detection is better, as the pellets spread accordingly and deal the proper damage to enemies. The bad news is that the gun now sucks at hitting multiple enemies at once (it seldom works if the spread is wide enough, but otherwise doesn't, especially when hitting enemies in a row). Is there a better way to improve upon this?
Code:
{
  // check whether you can shoot
  if (not can_shoot) exit;
  can_shoot = false;
  // show the animation and play the sound
  image_speed = 0.3;
  image_index = 0;
  sound_play(snd_shtgn);
  //global.ammo-=1;
  var xx, yy, lx, ly, ii, shots;
  xx = global.camx;
  yy = global.camy;
  shots = 6;
  repeat (shots)
  {
  for (i=0; i<256;i+=2)
  {
    lx = xx+lengthdir_x(i,obj_player.direction+random_range(-4,4));
    ly = yy+lengthdir_y(i,obj_player.direction+random_range(-4,4));
    if (position_meeting(lx,ly,obj_wall_basic))
    {   ///You hit a wall, ricochet.
        t=instance_create(lx,ly,obj_ricochet);
        t.direction=obj_player.direction;
        t.z1=ii.z1*0.75;
    break;
    }
    else
    if (position_meeting(lx,ly,obj_monster_basic))
    {   ///You hit an enemy, deal damage.
      ii = instance_position(lx,ly,obj_monster_basic);
      if (ii == noone) continue;
      with (ii)
      {
      mhealth-=1;
      hurt=1;
      t=instance_create(lx,ly,blood_type);
      t.z1=ii.z1*0.75;
      break;
      }
    }
    else
    if (position_meeting(lx,ly,obj_pillar1))
    {   ///You hit a column, ricochet.
      ii = instance_position(lx,ly,obj_pillar1);
      if (ii == noone) continue;
      with (ii)
      {
      if (indestructible==0)
        {
          mhealth-=1;
          t=instance_create(lx,ly,blood_type);
          t.z1=ii.z1*0.75;
        };
        else
        t=instance_create(lx,ly,blood_type);
        t.z1=ii.z1*0.75;
        break;
      }
    }
    with (obj_monster_basic)
    {
    if ((id != other.id) && collision_circle(global.camx,global.camy,128,id,1,0))
    {
    with (id) alert=1;
    }
    }   
  };
  }
}
 
Top