• Hey Guest! Ever feel like entering a Game Jam, but the time limit is always too much pressure? We get it... You lead a hectic life and dedicating 3 whole days to make a game just doesn't work for you! So, why not enter the GMC SLOW JAM? Take your time! Kick back and make your game over 4 months! Interested? Then just click here!

Legacy GM collisions on fast projectiles... about to give up

Niels

Member
Hi everyone,

I have a questions about how to implent a (easy enough for me to understand) code for for shooting enemies.

my game is in a 2d platform perspective and my player character has a machine gun that fires bullets (obviously ;) ).

problem is that fast flying objects actually "teleport" from step to step making a collision event or place_meeting useless because the bullet will register the collision on when the enemy is at the "step-point" for the bullet.

First solution I came up was using a line for collision when shooting where the nearest enemy gets his "hp" substracted and a bloodspatter object gets drawn on that enemy.

But reading the gamemaker help files about collision_lines, I found out that collision_lines don't garantee that the instance_id that returns is the object colliding nearest to the start of the line :(

Then I found the following script on gmlscripts:
http://www.gmlscripts.com/script/collision_line_first

but I honestly have a hard time wrapping my head around it as GML beginner :(

how do I use the instance ID that returns?
Do I put in the obj_enemy step event:
"if instance_id = inst
{hp -=1
}
?

or is there a easier code to use for the hitscan line I try to make?

thx in advance
 
A

Aura

Guest
Pretty simple.

Code:
var inst = collision_line_first(x, y, x + lengthdir_x(speed, direction), y + lenthdir_y(speed, direction), object, false, false);
if (inst != noone) {
   /*inst.solid = true;
   move_contact_solid(direction, -1);
   inst.solid = false;*/
   while (!place_meeting(x, y, inst)) {
      x += lengthdir_x(1, direction);
      y += lengthdir_y(1, direction);
   }
   //COLLISION CODE HERE
}
You may use the commented part instead of the while statement, but it's not guaranteed to always work. You can remove the while statement as well if you don't want "precise" collisions, it would speed up things.
 

Niels

Member
Thx for the reply, but won't flagging moving enemy objects as solid cause all kinds of problems? (At least the help file advices us to not use movable objects as solid)
 
A

Aura

Guest
That is why I commented out that part. You can remove it and use the while statement.

But it's very unlikely to cause issues with the instances that are not already solid because they would become solid for a very short period of time to let move_contact_solid() work and then become normal. But you can simply use the while statement. In fact, the while statement is optional as well and exists only for precision.
 

Niels

Member
I was wondering if it's possible to use a bullet that travels 16px per step from right to left and use:
Code:
If  yprevious = obj_enemy.y (and some code here that adds sprite size) && x < obj_enemy.x  && xprevious > obj_enemy.x {
Instance_create(obj_enemy.x+8,y,obj _impact)
If something like this will work:)
A well will try the code you posted first, looks way more professional haha.

Thx for three answers
 

TheouAegis

Member
In bullet's step event
Code:
for(var i=0; i<abs(hspd); i++)
with instance_place(x + i * sign(hspd), y, obj_enemy_parent)
{
    hp -= 1;
    with other instance_destroy();
    exit;
}
Would do 1 damage to the first enemy encountered and then stop checking after that. The bullet would then be destroyed. If you want the bullet to be drawn on that final step (which in my opinion it shouldn't), then you'd wan to set a flag instead of destroying the bullet, then in the Draw End Event, check if that flag is set and destroy the instance then.
 

Niels

Member
In bullet's step event
Code:
for(var i=0; i<abs(hspd); i++)
with instance_place(x + i * sign(hspd), y, obj_enemy_parent)
{
    hp -= 1;
    with other instance_destroy();
    exit;
}
Would do 1 damage to the first enemy encountered and then stop checking after that. The bullet would then be destroyed. If you want the bullet to be drawn on that final step (which in my opinion it shouldn't), then you'd wan to set a flag instead of destroying the bullet, then in the Draw End Event, check if that flag is set and destroy the instance then.
But wont this have the same collision problems where it teleports past a enemy?
 

TheouAegis

Member
Ummm... Maaaaybeeee.....

Code:
for(var s, i=0; i<abs(hspd); i++)
{
    s = i * hspd;
    with obj_enemy_parent
    if place_meeting(x + hspd + s, y, other.id)
    {
        hp -= 1;
        with other instance_destroy();
        exit;
    }
}
Girlfriend has a friend over, so it's hard to concentrate on code right now, but I think this would work. But I just now had an idea for another way.

Code:
var xx = x, yy = y, hh = sprite_height, dir, max, targ = -4, ex;
dir = hspd > 0;
max = room_width * dir;
with obj_enemy_parent
{
    ex = x + hspd;
    if abs(y + vspd - yy) < sprite_height + hh >> 1;
    if dir
    {
        if ex < max && ex >= xx
        {
            max = ex;
            targ = id;
        }
    }
    else
    {
        if x + hspd > max && ex <= xx
        {
            max = ex;
            targ = id;
        }
    }
}
if targ
if max - x< hspd
{
targ.hp -= 1;
instance_destroy();
}[/code]

So in theory if I wrote it right, find the enemy who will move closest to the bullet's current position without going past, then check if the distance from the enemy's predicted position and the bullet's is within the bullet's speed.
 
Top