Implementing Line of Sight in Qbasic Games
Written by Torahteen
Introduction:
Line of Sight is often overlooked in a lot of good QBasic games. This is surprising to me, because it is both easy to implement, and it adds a good touch of realism. But there are numerous ways to put in line of sight. In this tutorial, I'm going to look at two. The circular and diamond line of sight. By the way, these work best in a tile-based game. You'll have to find some other way if you're doing a FPS, in which case these are unnecisarry. Enough ranting, let's get started.
Diamond Line of Sight
Okay, first of all, I don't know what the heck you call either of these methods. I made up the names, so if you find another name for them, it's probably correct. Anyway, the first thing we're going to implement is a diamond view system. In a diamond view system, the unit can see all of everything in a sort of diamond shape around the unit. There are two different diamonds you can do. One of them, has the points of the diamond pointing up, down, left, and right relative to the screen. The other has the points pointing in those directions relative to the unit. I'll be going over the first one, although I will give a short theory as to how you can do the other one.
Since I like to make my games modular, let's make the code into a function. We'll have the game engine call the function, passing in a map, the x and y values, the distance the unit can see, and a reference to the array we should put the final coordinates in. What I mean by final coordinates is a list of points defining what squares the unit can see. So here is our function declaration (BTW, it is not a true function, but a sub):
DECLARE SUB GetLos(map() AS MapType,x AS INTEGER, y AS INTEGER, sight AS INTEGER, result() AS PointType)
MapType should be defined somewhere in the game. But as an example, here is the MapType we'll use in this game.
TYPE MapType mType AS BYTE Clip AS BYTE END TYPE
mType is the type of tile (Water, Grass, Rock), and is just an example. We'll be using the Clip status to check if a tile can be seen.
The way I will do all this, is with three nested FOR loops. The first loops iterates from the top of the diamond to the bottom. The second loop increments the width of the diamond by two for every line. The third loop goes through each square in the row. Every loop, we will check each square across the line, making sure that its clip value is false. Here is the code.
SUB GetLos(map() AS MapType, x AS INTEGER, y AS INTEGER, sight AS INTEGER, result() AS PointType)) Dim nx, ny As Integer Dim w, d As Integer Dim n As Integer n = 0 w = 1 n = 1 redim preserve unitMove(n) as PointType unitMove(n).x = x unitMove(n).y = y For ny = sight To -(sight) Step -1 For w = 1 To 2 * sight Step 2 For nx = -(w - x) To (w-x) 'Checks go here. sx = nx sy = y + ny if sx > -1 and sx < mapWidth and sy > -1 and sy < mapHeight then n = n + 1 Redim Preserve result(n) As PointType unitMove(n).x = sx unitMove(n).y = sy end if Next nx Next w Next ny End Sub