92. Let’s play pool (3)
In this post, I want to figure out a way of taking pool shots. It’s not easy to set angles and power accurately with just your fingers. Maybe the accelerometer can help.
Aiming the shot
A big part of aiming a pool shot is walking round the table and standing behind the white ball, and aiming it carefully at whatever you want to hit. I thought about rotating the whole table around the centre of the white ball, so that we are always shooting from the bottom towards the top, but this would mean a large part of the table would rotate off the screen, unless the table was small.
Instead, it seems sensible that, as in real life, the table stays where it is, and we walk around it until we find the right angle. We can do this with the iPad accelerometer, which can detect changes in the tilt and rotation of the iPad. I had no idea how to use it, but figured it out from the Gravity demo project built into Codea (the one with the arrow icon).
So what I want to do is this. I want to show an aiming line from the centre of the white ball out to the edge of the screen, showing where the shot will go. As you rotate and tilt the iPad, you can make the line point in any direction. Then, touching the screen will make the shot (at this stage, you don’t get to decide how hard to hit, baby steps first).
--set aiming angle based on accelerometer aim.x,aim.y=aim.x*.9+Gravity.x*.1,aim.y*.9+.1*Gravity.y local b=balls[0].body --this just makes the next line easier to read --draw a line line(b.x, b.y, b.x-aim.x * 300000, b.y-aim.y * 300000)
Gravity.x and Gravity.y give us the direction the iPad is pointing in (although they point the wrong way, towards us instead of away from us). There is a problem, that it can be too sensitive and jump around a lot, so I created a vec2 called aim, which uses a weighted average of recent Gravity positions. It uses 90% of its current value, plus 10% of the latest Gravity figure. This makes the result much smoother.
Then I draw a line from the centre of the white ball, away from us (aim.x and aim.y are negative because otherwise the line would come towards us). I’ve been lazy in just drawing a very long line, I should really calculate it properly so it ends at the edge of the screen.
Finally, touching the screen applies a force to the white ball.
function touched(touch) if touch.state==ENDED then local b=balls[0].body b:applyForce(-10000*vec2(aim.x,aim.y)) end end
I also had a go at fitting the right dimensions of the table (width = double the height) to the screen. It somehow looks too wide, but those are the rules.
I’m not sure at this stage whether a user could hold the iPad’s aim steady, and set the strength of the stroke at the same time, by pressing on some kind of scale. Maybe one has to be set before the other. I also haven’t thought yet about whether to include left and right spin, by hitting the white ball off centre. That would mean a third setting we have to juggle when making a shot.
The code so far is here.
Woah that’s really awesome. I like the way the lines become thick if it’s not steady. Well done!! I think you should fix the orientation of the screen justin case someone forgets to lock screen orientation.
Yep, orientation is an issue.
I think the next post is even better.