Skip to content

220. World of Warships #3

August 3, 2015

There is a time when you have to stop adding lots of cool stuff, and tidy up, and include game rules. Also, you always find that you built something the wrong way, and have to tear it down and rewrite it. None of that is much fun.

That’s what I have mainly been doing, but I do also have some fun new stuff to share with you, such as auto-aiming and different camera views. This video shows the result, and I’ll explain it all below

The video shows me exchanging fire with another ship, both of us using automatic aiming.

The guns can only rotate within certain limits, (otherwise they might shoot part of their own ship) – I set a maximum rotation of 140 degrees left or right, and maximum elevation (up) of 85 degrees. You’ll see that in the video, I have to turn the ship quite a lot, until the back guns can aim at the target.

I’ve also imposed a 10 second reloading time (plus a small random time) on all the guns, and included little colour indicators at the bottom right of the screen, which are green if the gun can fire, and yellow if they are reloading.

So when I touch the screen to fire, the program calculates the (left/right/up) angles to the target, and shoots all the guns which are fully reloaded and which can rotate enough to aim at the target.

Exactly the same happens for the target ship, except I have programmed it to automatically fire at me every 11 seconds.

Automatic aiming

To aim at the target, I need two angles

  • y axis – the left/right angle to the target
  • z axis – the upward angle of the gun turrets

We can use simple trigonometry to calculate the y axis angle, like this

local d=(target-self.pos) --direction vector to target
local a=math.deg(math.atan2(-d.z,d.x))-self.angle

If you draw a simple picture, you should be able to figure this out. Note

  • we use -d.z because under OpenGL, we face forward into -z, and
  • we subtract the rotation angle of the ship at the end

Once I have this angle, I can calculate the rotation angle for each gun. For the guns at the front, this is just the angle without any adjustment, but the guns at the back need 180 degrees added because they are facing the back of the ship. Then I test whether the guns are able to turn this far.

The z axis angle requires one of those fancy trajectory formulae, which I found in Wikipedia. It seems to work quite well, although it seems to overshoot a little. I add a bit of randomness, so the aim varies a bit.

I note that because all the guns use the same y axis rotation, the shells from the front guns land further forward than the back guns. Ideally, the angle should be slightly different for the front and back guns, so they all land on the same spot. I may fix this in future.

 Camera views

Different camera views make a huge difference to a game, so I’ve included quite a few, which are listed along the bottom of the screen. Touching one of them changes the view, as shown in the video.

  • Behind1 – directly behind the ship
  • Behind2 – behind and to the left of the ship
  • Bridge – view from the bridge of the ship
  • Top – top down view from a long way up
  • Scan – continuously rotating view, good for checking for enemies all around
  • Target – locks the view onto the current target
  • Zoom – zooms in and out

Here is my function that sets up the camera

function SetCamera()
    if zooming then 
        zoom=zoom+1
        if zoom>#viewZoom then zoom=1 end
        zooming=false
    end
    if camView=="Behind1" or camView=="Behind2" or camView=="Bridge" then
        camPos=S.pos+RotateVector(viewPos[camView],S.angle,0)
        camLook=camPos+RotateVector(vec3(40,0,0),S.angle,0)
        viewAngle=0
    elseif camView=="Top" then
        camPos=S.pos+viewPos[camView]
        camLook=S.pos+RotateVector(vec3(1,0,0),S.angle,0)
        viewAngle=0 
    elseif camView=="Scan" then
        camPos=S.pos+RotateVector(vec3(-40,10,0),viewAngle,0)
        camLook=S.pos
        viewAngle=viewAngle+0.25        
    elseif camView=="Target" then
        camLook=E[target].pos
        camPos=S.pos+(S.pos-E[target].pos):normalize()*30+vec3(0,10,0)
        viewAngle=0
    end
    camera(camPos.x,camPos.y,camPos.z,camLook.x,camLook.y,camLook.z) 
end

Zooming

First, we test if are zooming. I should explain that you zoom by simply providing a number in the perspective() function, so zooming is as simple as writing perspective(20). The normal default is 45 (the number of degrees covered by the width of the screen), and if you reduce this, you zoom in. I’ve set 4 zoom levels – 45,20,5,2, and touching “Zoom” rotates through these options.

If we zoom, we don’t change our view, we simply zoom in or out.

Ship-based positions

The two “behind” and the bridge options are very simple. I provide a vector which is the position of the camera relative to the ship, and for the bridge it is vec3(12,6,0), which I calculated by trial and error. So I rotate this vector by the angle of the ship, add it to the ship’s position, and that is my camera position.

I don’t want to look directly at the ship, but ahead, so for the “look” part of the camera setting, I add a vector vec3(40,0,0), again rotated by the angle of the ship. The reason this vector only has a number for x, is that the starting angle of the ship is left to right along the x axis (remember the initial picture), pointing towards +x. So the vector vec3(40,0,0) is 40 pixels in front of the ship, before any rotation.

The “Top” option is very similar. The camera position doesn’t need to be rotated left or right, because it is directly above.

Scanning

The “Scan” option is interesting, because we want the camera to swing around the ship, looking over the the top of it to scan the horizon for enemy ships. The camera position is simply the ship position plus a vector rotated by an angle, which increases slightly each frame. Note the camera looks directly at the ship because we don’t need to look ahead, since we are rotating continuously.

Targeting

The “Target” option is also interesting. It’s easy enough to set the camera to look at the target, but I want the camera to be positioned behind our ship, looking over the top of it, looking at the target – this is so I can see the guns firing, and any damage cause by the enemy. So my calculation goes like this

  1. start with our ship position
  2. calculate the direction from the enemy ship to us
  3. normalize it to give it a length of 1
  4. multiply by 30, which takes the camera 30 pixels past our ship, and then
  5. add 10 to the y value so we can see over the top of our ship

So if you draw a line from the target to our ship and kept going for 30 pixels, that’s where the camera would be.

And you can be sure that this code didn’t just write itself. It took me quite a while, and I had quite a few puzzling moments before finally getting it to work. I don’t think I have any natural talent for geometry.

Next is a really difficult challenge – deciding when shells hit the target, what damage they cause, and how to show the damage. I have absolutely no idea how to do it, right now.

 

Advertisement

From → 3D, Games, Graphics, Shaders

Leave a Comment

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: