Two part question regarding RayCasting

An easy way to figure out which x is the problem is to put a print statement just before that line that prints out all of the x’s.  Like this: print(dst.x, src.x).  You’ll immediately see which one is nil.  Then consider where the src object being passed to this function came from.  Go there, insert more print statements, etc.  This is a ‘manual’ debugging approach that I find extremely useful (as opposed to using an IDE with breakpoints and variable inspection, which can also be useful).

It’s hard to say exactly why you’re error is occurring though, since it’s a lot of code for me to inspect detail.

Glad the suggestion on tables was helpful.  I haven’t used LevelHelper, but I have to imagine that there’s a way to use it that doesn’t require you to set up separate variables and functions for each element.

  • Andrew

Thanks for all your help and advice, Andrew.

Ah yes, I forgot I was able to print things like that. :slight_smile:

After doing what you suggested, I was somewhat able to figure out why it couldn’t locate the ‘src.x’… though in the end the answer was incredibly simple. All I had to do was isolate my RayCast function, and that solved it!
Actually upon further inspection, I wasn’t isolating the entire function, just the ‘if’ statement that checks what object/s the ray has hit. :smiley:

if ( EDray[1].object.class and EDray[1].object.class == "PlayerTank" or EDray[1].object.class == "Uturret" or EDray[1].object.class == "bullet") then

[lua]
– Casts a ray towards the user_tank to determine whether or not the enemy should fire.
function ETfire( self, user_tank )
    
    EDray = physics.rayCast( self.x, self.y, user_tank.x, user_tank.y, “unsorted” )
        
    local hitFirst = EDray[1]
    local hitX, hitY = hitFirst.position.x, hitFirst.position.y
    
    if EDray then
        – There’s at least one hit.
        print( "Hit count: " … tostring( #EDray ) )

        – Output all the results.
         for i,v in ipairs(EDray)  do
            print( "Hit: ", i, v.object.class, " Position: ", v.position.x, v.position.y, " Surface normal: ", v.normal.x, v.normal.y )
    end
        print( "The first object hit is: ",
        EDray[1].object.class, " at position: ", EDray[1].position.x, EDray[1].position.y, " where the surface normal is: ", EDray[1].normal.x, EDray[1].normal.y )

        else
        – There’s no hit.
    end
    
    if ( EDray[1].object.class and EDray[1].object.class == “PlayerTank” or EDray[1].object.class == “Uturret” or EDray[1].object.class == “bullet”) then
        
        print(“PlayerTank in range! Fire!”)
        timer.performWithDelay( 10, ShootEnemyBullet)
end

–[[
I  closed/ended the ‘if’ statement right after the statement’s conditional logic,
rather than putting the ‘end’ at the very end - after all the code/functions
that deal with creating the bullet, calculating angle the right angle to shoot the bullet,
collision-detection for the bullet etc… etc…

I’m not completely sure why ending the ray’s ‘if’ statement  solved it, I have an idea,
but regardless I’m happy it works.
–]]
[/lua]

Now all that’s left is figuring out a way to add the ray to some sort of collision filter… or at least figure out how to specify an object I don’t want to interact with the ray - in my case the radars.
As seen in the video, when the user_tank is in the area where both radars overlap, the rays register a collision when they hit the rim of the other tank’s radar.

-Saer

*I was able to solve the issue :slight_smile:

Well unfortunately my reaction was premature. :\
It only works under certain circumstances - video

:sigh: lol well, I’ll figure it out.
I also noticed that a possible cause of my troubles could be that I have both radars assigning a value to the ‘EnemyFiringTimer
(I have a foward declaration at the top of my code - local EnemyFiringTimer )

e.g. as seen in my original post when a tank’s radar it hit ( in the example above it’s the second tank’s radar) the EnemyFiringTimer is assigned a value -
[lua] EnemyFiringTimer = timer.performWithDelay(500, function() ETfire( enemyT02, event.other ) end, -1)
– enemyT02 is defined so it knows where to fire the bullet from 'n such.
[/lua]

but when I shoot a tank, this is called in addition to the code that removes the tank:
[lua] if EnemyFiringTimer then timer.cancel(EnemyFiringTimer) end [/lua]
Which obviously cancels both out.

So yeahhh… haha I’m at a loss for words. I’ll just keep experimenting and eventually get it. :slight_smile:

  • I edited the code in the dropbox file -

I can’t quite get it to work… It just registers two hits, both the middle box.

-Saer
 

Hi there,
first to say I didn’t read all the prev posts, so this is more a genereal advice for raycasting and class like interaction of objects (tank turret and tank body)

First thing I don’t understand is why you cast a ray with the property “unsorted” and than take the first result out of the hit table. I mean that’s completly random, you could cast the ray with “any” and it would give you nearly same results.

In my actual project my maincharacter has a flashlight and I want the light to get shorter if it hits a wall, but not if it hits an enemy. So I cast a “sorted” ray and loop through the results from nearest to farest. If one of them is a wall I break the loop and return the hit object and the actual cordinates of the hit. To identify if hit an enemy or a wall all objects got an so called objectType. A string that tells what kind of object the ray hit. With that it’s possible to “mask” the results, as you could ignore specific objectTypes.

As Andrew mentioned before it would be nice to create something like a tank object, a table that contains all parts of a tank. The different parts could refer to there parent table, so it’s possible to link from one part to all of the others. That should solve the problem, that you don’t know which part of the tank has been hit and how to get the others.

local tank ={} tank.turret = display.newImage("tank\_turret.png") tank.turret.parent\_obj = tank tank.body = display.newImage("tank\_body.png") tank.body.parent\_obj = tank

One important thing is that this is a circular reference which can cause memory leaks if not handles correctly. Before destroying a part of the tank you have to nil out all the it.

display.remove(tank.turret) tank.turret.parent\_obj = nil tank.turret = nil

Maybe my suggestions help you, if not it’s ok too.

Greetings Torben

Thanks for weighing in, Torben.

I didn’t really think about that… As you say, it yields the same result, but according to the documentation using ‘Any’ is faster so I guess I might as well change it. actually, as stated in the docs,
unsorted : Return all results, in no particular order.
Any : Return one result, not necessarily the closest one. – “returns *one result” this would not work because the one result I’m checking for is the first hit.

Yeah, for my project I only need raycasting for my enemy tanks - as a form of environmental awareness sensing whether or not an object is in the enemy’s “firing path”, if you will.
As far as “masking” the results go, how would I do that?
As seen above, I use this:

    EDray = physics.rayCast( self.x, self.y, user\_tank.x, user\_tank.y, "any" )              local hitFirst = EDray[1]     local hitX, hitY = hitFirst.position.x, hitFirst.position.y          if EDray then         -- There's at least one hit.         print( "Hit count: " .. tostring( #EDray ) )         -- Output all the results.          for i,v in ipairs(EDray)  do             print( "Hit: ", i, v.object.class, " Position: ", v.position.x, v.position.y, " Surface normal: ", v.normal.x, v.normal.y )     end         print( "The first object hit is: ",         EDray[1].object.class, " at position: ", EDray[1].position.x, EDray[1].position.y, " where the surface normal is: ", EDray[1].normal.x, EDray[1].normal.y )         else         -- There's no hit.     end     if ( EDray[1].object.class == "PlayerTank" or EDray[1].object.class == "Uturret" or EDray[1].object.class == "bullet") then                  print("PlayerTank in range! Fire!")         timer.performWithDelay( 40, ShootEnemyBullet )  

Every object that is hit, I get its information printed in the terminal.
So here’s an example of a condition where I need the ray to ignore certain objects -
I have metal-barriers/obstacles that the tank can’t drive over, but it can still shoot over.
Now when I place an object inside LevelHelper, I can assign it a custom tag and using the following code I can access every object that shares the defined tag:
 

-- Every object that has the tag 'WALLS' is rotated 90º -- local walls = loader:spritesWithTag(LevelHelper\_TAG.WALLS) for i = 1, #walls do  local curSpr = walls[i];     curSpr.rotation = 90     print( curSpr.rotation ) end

It grabs every object that has the tag ‘WALLS’ assigned to it and rotates each one 90º.
(If I were to show you in the simulator, every wall would appear to have been rotated 90º)

Now my question would be, how could I tell the ray to ignore ‘curSpr’?

Yes, your suggestion was helpful. I’m always open to opinions. :slight_smile:

Edit: Sorry if the code came out weird, it wasn’t rendering quite right in the preview window. :mellow:

Edit: As far as tables/creating objects etc…
Since my objects are already created and positioned via LevelHelper, wouldn’t it be possible to simply use code similar to what I just showed, for adding them to a table?
Another example of how I use ‘tags’, is for my IGmines (in -ground) which can only be destroyed if a tank runs over one:
 

lol sorry for the long post. :wink:

I will post some rearanged code from my project, to show how ignoring some objects work. Don’t be to confused by the information about raycasting in the docs. It states that “sorted” rays have the slowest performance, but it’s not a big deal in most cases. I shoot like 10 “sorted” rays in an enter frame loop and there’s nearly no hit on performance.

Here is a little shoot function I use, that only returns the first valid hit and ignores the others.
The problem with raycasting is that the rays interact mit every physic shape, even if you set isBodyActive=false for it.

local function shoot\_ray(start\_x, start\_y, end\_x, end\_y) local hits = physics.rayCast( start\_x, start\_y, end\_x, end\_y, "sorted" ) local ray\_hit={} if hits then for i=1, #hits do local hit = hits[i] local object = hit.object if object.object\_type == "tank" or object.object\_type == "wall" then ray\_hit.x, ray\_hit.y = hit.position.x, hit.position.y ray\_hit.object = object break end end end return ray\_hit end

Shoots a ray from one point to another and returns the first valid hit. If there is no hit it returns an empty table.

lol I don’t know why I’m having trouble with this (maybe because it’s after 5:00 A.M. ) :wink:

I threw together a simple little ‘demo project’ to try your method, but I can’t get the ray to ignore the middle box:

link

  • I edited the code in the dropbox file -

I can’t quite get it to work… It just registers two hits, both the middle box.

-Saer