Here is what it looks like:
video
I removed a few objects to make sure it would still fire if the ray hit only the user_tank, but for some reason when I un-comment those two lines it doesn’t…?
Here is what it looks like:
video
I removed a few objects to make sure it would still fire if the ray hit only the user_tank, but for some reason when I un-comment those two lines it doesn’t…?
So I was able to incorporate horacebury’s code, but I’m getting a weird response when my user_tank collides with my enemy tank’s invisible sensor (radar).
Here is a short vid of what is happening: video
* For some reason the video quality on dropbox is terrible, but if you download the video it should be HD.
Here is my code for the enemy tank, fyi all the objects without local preceding them have a forward declaration:
[lua]
local enemyT02 = loader:spriteWithUniqueName(“Eturret2”)
enemyT02.class = “EnemyTank02”
------------Adding a Radar for Etank02
--------
ET02radar = display.newCircle(enemyT02.x,enemyT02.y, 10)
ET02radar.isVisible = false
physics.addBody(ET02radar,“static”,{radius=400,isSensor=true})
– detect a target entering the object’s area and fire at it
function ET02radar:collision(e)
if (e.phase == “began” and e.other.class == “Player”) then
print(“began”)
timer.performWithDelay(1, function()
fire( ET02radar, e.other )
end, 1)
end
return true
end
ET02radar:addEventListener(“collision”, ET02radar)
– fires bullet
function fire( tower, user_tank )
– solution: “firing solution” - the collision point between the tower’s bullet and the target
– success: true if the tower can successfully fire on the target, false if the target will escape
local solution, success = intercept( tower, user_tank, bulletSpeed )
–
local math_deg = math.deg – localize ‘math.deg’ for better performance
local math_atan2 = math.atan2 – localize ‘math.atan2’ for better performance
– Calculates the angle between specified points A & B
local function angleBetween( enemyB02X, enemyB02Y, user_tankX, user_tankY )
local angle = ( math_deg( math_atan2( user_tankY-enemyB02Y, user_tankX-enemyB02X ) )+180) --; return angle
if ( angle < 0 ) then angle = angle + 360 end ; return angle % 360
end
local ang = angleBetween( enemyB02.x, enemyB02.y, user_tank.x, user_tank.y )
enemyT02.rotation = ang
–
– only fire if the firing solution is successful
if (success) then
– calculate vx and vy
local angle = angleOf( tower, solution )
local pt = rotateTo( {x=bulletSpeed, y=0}, angle)
local pt2 = mathapi.rotateAboutPoint( {x=enemyT02.x,y=enemyT02.y -65}, enemyT02, enemyT02.rotation - 90 )
– create bullet
Enemybullet = loader:createSpriteFromSHDocument(“Weapon5ex”, “GameFX”, “LevelAssets.pshs”);
Enemybullet.x, Enemybullet.y, Enemybullet.solution = pt2.x, pt2.y, solution
--bullet.x = pt2.x; bullet.y = pt2.y;
physics.addBody(Enemybullet,{friction = 0, bounce = 1.0, density = 1.5, radius=10, isSensor = true})
Enemybullet:scale(.65,.65)
Enemybullet.class = “bullet”
Enemybullet.isBulet = true
Enemybullet.rotation = enemyT02.rotation + 90
– fire bullet
--bullet:applyForce( pt2.x - enemyT02.x, pt2.y - enemyT02.y, enemyT02.x, enemyT02.y )
Enemybullet:setLinearVelocity(pt.x, pt.y)
end
end
[/lua]
Also, I want the bullets to react the physical environment, but in doing so causes my enemy tank fire bullets towards the player even if there is an obstacle between them.
In adition to what I have already, should I add my original method of firing an invisible bullet and if it collides only with the user then tell it to fire a real bullet Or would that be the wrong to go about things?
Hi @Saerothir,
What is the weird response you’re getting? I didn’t see it in the video. Is it an error message?
On another note, when you turned on “hybrid view” in the video, I almost gasped… how many physics bodies/shapes are making up that one scene? It appears you’ve used a third-party tool to trace the objects? The outlying debris and walls look to be made of dozens or even hundreds of overlapping shapes. I’m sure that tool did its tracing very “accurately”, but you should probably build these physics bodies yourself. The lower pile of rocks, for example, could probably be constructed of 4 shapes instead of what appears to be 104. While it wouldn’t be as perfectly accurate, it would be close enough that the user wouldn’t notice it (it’s not like you need a tiny marble to roll across a detailed, jagged piece of terrain). Anyway, food for thought… this kind of over-use of the physics engine could drag your app performance way down on slower devices.
Brent
Oh, now I see your other request at the bottom, below the code. horacebury’s code doesn’t yet factor in obstacles that are sitting in the potential path of the projectile. Fortunately, you can add this yourself, using raycasting.
All you need to do, when the bullet direction is calculated by the predictive aiming code, is to cast a ray from the source (enemy tank) out to an extended distance along the predicted path (it can be some point off the screen; just multiply out the vector length). Then, detect if there’s an obstacle between the source and the player, and void (skip) the bullet firing if true.
See the demo project below about how to implement raycasting. With this, there is definitely not any need for “invisible bullets” or anything like that.
http://www.coronalabs.com/blog/2013/05/07/physics-raycasting-and-reflection/
Brent
haha! I figured you’d make a comment about that. ;) Yeah, I don’t know why they show up like that. I only use one physics outline - I trace around the object using SpriteHelper, example: photo
I’m an extreme perfectionist and I didn’t think meticulously tracing around the object would yield more than one physics shape. If you’ll notice in the right-side panel, there is some greyed-out text that says ‘UntitledFixture’, that represents my physics outline. If I wanted I could make many more, but like you said that would most likely cause performance issues.
I’ll email the dev and ask if this is normal.
Really?! Yay! I was ecstatic when they announced raycasting (as I can see it being a hugely efficient solution to many gaming scenarios ) but I thought it was only available to ‘PRO’ users. lol this is very welcome news. :D
I’ll get to work on it right away!
Oh yes, this meticulous tracing will result in a ton of physics shapes. For a few reasons:
No physics shape can have more than 8 sides (except a circle, which clearly has more than 8 “sides” as seen in the hybrid view; but that’s a special case).
No physics shape can have concave angles… so, when you try to trace a complex shape, it will need to accommodate all of those concave angles by making additional shapes. Sometimes it can’t be avoided, but certainly you should simplify your traced objects to under 10 shapes if possible (ideally more like 5 or 6).
As for raycasting, you’re right, it’s currently only for Pro users. However, the next public release is coming quite soon, and when it’s released you’ll have access to raycasting as a Starter.
Brent
lol okay, that makes sense. I’ll work on reducing them. B)
Would changing their shape from concave to convex make a difference?
Alright. So at the moment I can work with it, but until the next pubRelease I can’t actually build with it?
BTW - lol the “weird response” that I was referring to was the enemy-tank firing many bullets towards the user rather than just one, like in horacebury’s included physics example.
To my knowledge, I haven’t changed any of the original firing settings from horacebury’s code… could it be related to my physics outline? Like the rocks, in that it is showing multiple physics shapes and each one colliding with the radar is causing multiple bullets to be fired?
Once I get the bullet’s collision working properly, I’ll be adding a cap to the number of bullets that can be present in the display at any given time.
For example: say the brown tanks can fire five bullets; once all five have been fired, the Etank would not be able to fire again until at least one is removed, making the overall count 4. Same with the user.
Thoughts?
Btw - I’d just like to say, if there are some documents or articles that will help me learn and figure out how to implement an idea/concept we discuss, please let me know.
I in no way want to be perceived as someone who is looking to everyone else for all the answers and solutions to a problem I might encounter during the development process - as that is not even remotely my attitude.
When I run your demo project in the simulator and I click within the display, I get an error -
"Line: 34
Attempt to call field ‘rayCast’ (a nil value)"
Hi @Saerothir,
For the raycasting API (and the demo project), you’ll have to wait until the next public build, but as I mentioned, that’s coming very soon.
As for a ton of bullets being fired at once, I think I know what’s happening. When I watch the video, it appears that your tank is also composed of many shapes. If that’s true, you’re actually generating a collision on every instance of a shape colliding with the firing radius. So, you’ll get a collision report when the tank’s “right tread” collides, when it’s “left tread” collides, when it’s “body front” collides, when it’s “read exhaust pipe” collides, and any other instance where ANY of it’s individual body shapes collides.
The solution to this is generally to create a “counter” property on the tank like “collisionCount” and increase/decrease that count on each collision “began”/“ended” event respectively. So, when any shape that makes up the tank body collides with the firing radius (began phase), you add 1 to the count, and when a shape exits the firing radius (ended phase), you subtract 1. Then, you only queue firing of a bullet if the count is 1… but not greater than 1. This means that when the tank first crosses the firing radius line, a bullet will be fired, but no other bullets will be fired until the tank fully exits the field and then re-enters it.
Of course, ideally, you’ll want to set up a system where the enemy continues to fire on some kind of repeating timer while the tank remains in the field… but that’s a whole different topic and will require a modified approach.
Brent
Oh okay. I’ll be anxiously and impatiently waiting! :lol:
Well actually, my user_tank is only comprised of one outline. With SH you can create multiple physics-bodies on one object, identified by a custom tag e.g. the greyed-out-text I pointed out before, for example I could outline the front and back wheel of a bicycle and give them custom tags/identifiers if I wanted to program unique collisions for each portion of the same object.
In my case, I just have one physics-shape which is an outline of the entire tank… and SH seems to like to chop it up into multiple physics-shapes <_<
Yes, and that is precisely what I’m going to do.
I would probably have something random, like as long as the user_tank is within the radar shoot x number of bullets, randomizing each shot from between say 1 and 2 second delays.
would it make sense to wrap all of the code inside the entire enemy fire function in an if else statement?
[lua]
function Fire()
local EtankBullets = 0
if EtankBullets < 5 then
EtankBullets = EtankBullets +1
—
—
– FireBullet code –
—
—
else if EtankBullets == 5 then
— stop function
end
end
[/lua]
Hi Saer,
If SH insists on chopping up your tank trace into many shapes, you’ll need to make it into one shape manually (not using SH), or else implement the counting system I talked about.
For the repetitive firing, I suppose one method would be to start a repeating timer while the tank is inside the range, and cancel the timer when the tank exits the range. This wouldn’t give your a random increment time between bullets however. For that you’d need to run a timer (just once), fire the bullet, start a new timer of a different random duration, fire a bullet, and keep repeating that process.
Brent
Yeah, I was able to re-trace the user_tank and get it down to just one shape. Obviously the turret is independent from the tank-body so I had to trace that also, and now I have only two bullets being fired when the tank collides with the radial sensor.
I’ll either add a collision counter or some type of collision filter to fix it.
Okay, that sounds like a good idea. I’ll work on that while I wait for the pubRelease. B)
btw, I was able to re-trace many of my objects and here is the result: photo
Definitely better than it was.
Hi @Saerothir,
What is the current progress on this? I sort of lost track of what was going wrong. By the video, the raycasting seems to be working, but there must be some subtle thing I’m not noticing…
Brent
The main issue is getting the enemy tank to fire only when the ray collides with the user_tank.
As shown in the video, when the user_tank collides with the radar the enemy then casts a ray towards the user and when it hits the user_tank the enemy fires a bullet - all fine and good - however, the issue is when I un-comment the lines shown (in the vid) it still casts the ray but it no longer triggers the fire function, even when the user_tank is the only object the ray collides with.
Hi @Saerothir,
Are your enemy tanks physics objects too? If the raycast is originating from their center, it’s quite possible that it considers the enemy tank a “hit”, and a closer hit than the Player tank. I’d suggest you carefully check over your logic handling of the raycast, and perhaps experiment with other raycast filters in addition to “closest”.
As another side note, I would suggest that while the Player tank remains in the radar sensor, you run a continual timer of the increment on how fast the enemy can fire. On each execution of it, I’d cast a new ray toward the Player and check if the bullet is clear to fire (no obstacle in the path).
Hey Brent,
here is a video response
Just to clarify - At the beginning when I talk about how I thought the first hit was referring to the user tank, obviously since there was a wall between the user_tank and the enemy tank, that wall would be considered the closest first hit (assuming the enemy tank was not colliding with the ray).
Sorry for the rambling in the beginning of the vid; I hope in the end I was clear enough.
Hi Saer,
The new public release just went live.
http://www.coronalabs.com/blog/2013/06/04/new-public-release/
This will allow you to use raycasting, which I know you’re eager to test out.
Have fun!
Brent
Hi Saer,
This might be a really simple fix. I can’t tell in the video (the code text is blurry even if I expand the video), but what is the conditional line you’re using to detect “if the hit is Player”? Most signs indicate that the conditional logic is written incorrectly, not the raycasting logic.
Most likely, you will not be able to use the raycast filter “closest”. Because there are walls and the radar sensor, you’ll need to gather all hits, sorted from closest (to the enemy) to farthest. Then, you’ll need to loop through those and ask “is there a wall object before the Player? If yes, then void the firing.”.
So, let me know about the first question. I think it’s a simple logic error.
Brent
Hey Brent,
Yeah I started working on it right when I found out.
Thanks again for all your help, I really appreciate it.
I had fun messing around with your demo project.
Implementing rayCasting wasn’t too difficult.
So far I’ve got a ray being cast at the user_tank when it collides with the radar, and when the user_tank leaves the radar or the enemy casting the ray is destroyed, the ray is removed - really easy stuff - the only thing I’m having trouble with is figuring out how to tell the ray to stay on the user_tank as long as it is within the radar bounds.
(Then I would have a timer, like you suggested, for shooting behavior while the user_tank is in ‘range’ )
I have the code from rayCast API docs that prints information in the terminal etc… and I’m hoping I implemented this correctly.
At the beginning of my fire function I have all the code that deals with making the ray:
[lua]
function fire( tower, user_tank )
E1Dray = physics.rayCast( enemyB02.x, enemyB02.y, user_tank.x, user_tank.y, “closest” )
local hitFirst = E1Dray[1]
local hitX, hitY = hitFirst.position.x, hitFirst.position.y
DRline = display.newLine( enemyB02.x, enemyB02.y, user_tank.x, user_tank.y )
DRline.width = 10
DRline:setColor( 255,50,40,100 )
DRline.blendMode = “add”
level1group:insert( DRline )
if E1Dray then
– There’s at least one hit.
print( "Hit count: " … tostring( #E1Dray ) )
– Output all the results.
for i,v in ipairs(E1Dray) do
print( "Hit: ", i, object_name, " Position: ", v.position.x, v.position.y, " Surface normal: ", v.normal.x, v.normal.y )
end
print( "The first object hit is: ", E1Dray[1].object, " at position: ", E1Dray[1].position.x, E1Dray[1].position.y, "
where the surface normal is: ", E1Dray[1].normal.x, E1Dray[1].normal.y )
else
– There’s no hit.
[/lua]
Also, would it make sense to have some type of Runtime listener that would constantly be checking if there are obstacles in the way and if not then check if the user_tank is within the radar bounds and if that is true then execute the enemy fire function?