Page 2 of 2

Re: How to check if a bullet will hit a target

Posted: Tue Jun 08, 2021 6:27 pm
by tomxp411
togFox wrote: Tue Jun 08, 2021 7:46 am If you want to be super crude about it, just measure the pixels between the bullet and target(s) and if close then slow down the camera. Sometimes it's easy to over-engineer the solution.
This is part what I was thinking.

Slow time when the bullet is just over one diameter away from the target. Then (internally) project a line out from the bullet for one diameter and use the "point distance to line" formula to find the closest approach and see if the bullet enters the hitbox.

(The diameter in question being the largest diameter of the target's hitbox. I usually use a simple circular area to use for preliminary collision testing, then do a more detailed test when the two objects' circular areas overlap.)

https://brilliant.org/wiki/dot-product- ... he%20point.

If the target is moving and might change its path of motion, there's still a small chance it could evade the bullet in some edge conditions, but watching a super near miss is part of the fun.

Re: How to check if a bullet will hit a target

Posted: Tue Jun 08, 2021 9:40 pm
by Gunroar:Cannon()
Thnx for all the extras, super helpful :awesome:
tomxp411 wrote: Tue Jun 08, 2021 6:27 pm
If the target is moving and might change its path of motion, there's still a small chance it could evade the bullet in some edge conditions, but watching a super near miss is part of the fun.
Yeah, I guess that would work too. A near miss :rofl: , and yes the players are moving.

Re: How to check if a bullet will hit a target

Posted: Thu Aug 05, 2021 12:53 pm
by Gunroar:Cannon()
togFox wrote: Tue Jun 08, 2021 7:07 am If you end up writing a function then I wouldn't mind getting a hold of that for my code library of useful functions.
I did it, though you may need to tweak it because it's project specific.

First I tried to use a simple method. I was all like: "Too bad for all these methods and ideas I got, now I'm just gonna use a simple distance check :halloween: muhuhaha".
Yeah that turned out badly. Just...no.
Maybe it would work for someone else, but for me the bullet either...no..just ...no...let me leave it at no.

Any way, then I tried the way knorke said with bump.lua's world's check method. 500 iterations, ...yeah that's bad. But it wasn't over yet! With bump's "check" I made it only 2 iterations(might only even need one), and then increased the speed of the projection. :awesome:

Then I combined it with a distance check to not waste computation time and put it in a function called by the Bullet class every update:

Bits of Bullet class

Code: Select all

function Bullet:checkNearPlayer(dt)
    local near = false
    if (not self.active) then
        return
    end
    for x = 1,#game.players do
        local player = game.players[x]
        if (player~=self.parent and player.life-(self.attack*self.hits)<=0 
             and lume.distance(self.x, self.y, player.x+player.w/2, player.y+player.h/2)<(self.map.slowRange or -1000000) --for fake maps that don't have slowRange, slowRange is actually like...20
             
        and math.random()<self.map.slowChance) then --slowChance is .8
            local sx, sy = self.x, self.y
            for xx = 1, 2 do
                --speed up by ten iterations
                local speedUpBy = 10
                sx, sy = sx+self.vx*dt*speedUpBy*self.angleX,sy+self.vy*speedUpBy*dt*self.angleY
                --checkCollision is just a filter
                local gx, gy, cols, len = self.world:check(self,sx,sy,self.checkCollision)
                sx, sy = gx, gy
                for c = 1,len do
                    if cols[c].other == player then
                        self:slow(player)
                        --makes map's camera follow the bullet for some time
                        self.map:tag(self)
                        return
                    end
                end
                --commented this out but strangely it worked with this code
                --makes the bullet teleport to hit
                --self.world:update(self, sx,sy)
            end
        end
    end
end

function Bullet:slow(player)
       --the player that caused slow down and that is probably about to die :P
        self.map.slowTarget = player
        self.map:slowDown()
        return true
end
Then I had a lot of problems with the camera but just made the camera follow the bullet instead of the player.

Bits of Map class, handles slow motion and dt

Code: Select all


Map.slowRange = 40--okay, 40
Map.slowChance = .8
function Map:slowDown()
    if (self.slowCount and self.slowCount>0) then
        return
    end
    
    if self.host then
        self.host:sendToAll("do", {"slowDown",nil,nil,nil,nil,nil,"map"})
    end
    
    self.slow = true
    self.slowdt = dddt or 1/650
    self.slowCount = ddff or .7
end

function Map:endSlowDown()
    self.slow = false
    self.slowdt = nil
    self.slowCount = 0
end

function Map:moveCamera(x,y,scale,time,skipFunction)
    self.timer:tween(time, self.cameraMan, {
        scale = scale,
        x = x,
        y = y,
    },nil,((not skipFunction and self.cancelMove) or self.cancelMoveLittle) )
    
    self.moving = true
    
    self.cameraMan.oldXPos   = self.cameraMan.x
    self.cameraMan.oldYPos   = self.cameraMan.y
    self.cameraMan.oldScale  = self.cameraMan.scale
    self.cameraMan.oldTime   = time
    self.cameraMan.oldStyle  = self.camera.follow_style
    
    self.camera:setFollowStyle("none")
    
end

function Map:update(dt)
   
    
    local dt = dt or 0
    
    if dt > 0.05 then dt = 0.05 end -- smoothen the movement --I don't like this, it's old code
    
    local truedt = dt
    local fakedt = dt
    local fakePlayerdt = dt
    
    if true then--haha, if true...
        fakedt = self.slowdt or dt
        fakePlayerdt = self.slowdt or dt/1.2
    end
    
    if self.slowCount and self.slowCount>0 then
        self.slowCount = self.slowCount-truedt
        if (self.slowCount<=0) then
            self:endSlowDown()
        end
    end
    ...
    if self.cameraMan then
        self.camera:follow(self.cameraMan.x,self.cameraMan.y)
        self.camera.scale = self.cameraMan.scale or self.camera.scale
    end
    
    self.camera:update(dt)
    
    self.cameraMan = self.cameraMan or {x=self.player.x,y=self.player.y}
    if GF then
  --  self.cameraMan = {x=game.players[1].x,y=game.players[1].y}
    end
    
    if self.player.followX and not self.moving then
        self.cameraMan.x = self.player.x
    end
    if self.player.followY and not self.moving then
        self.cameraMan.y = self.player.y
    end
    
    if (self._tag) then
        self.cameraMan.x = self._tag.x
        self.cameraMan.y = self._tag.y
        
        --tag died and is no longer in world
        if (not self._tag.active) then
            self._tag = nil
        end
    end
end
    
I implemented all this here.