2014-07-28 13:21:37 (edited by nyanchan 2014-07-28 13:26:52)

Hi.
So, I'm thinking about this whenever I try to test creating FPS, and I can't find the answer. Please give me some ideas.
Definitions:
1. For thinking about this problem, we use BGT because it's popular among audio gamers and programmers.
2.Objects are defined as a class, and it has all required information, such as x and y coordinates in the class's proparties.
3.We use first person shooter stile for moving, which means player can rotate 360 degrees like Swamp or RTR. The moving system uses aprone's posted algorithm.
4. The game field are defined as a two-dimensional array, containing information of walls as map tips.
5. In the game field array, 0 means nothing, and 1 means a wall.
6. Objects have some sound buffers, and each object must have a looping sound that indicates its position.
7. If the wall separates some objects from player, they must be muted, or the sound volumes must be cut.

How are swamp and RTR does the mute? Or do you have a good idea to achieve this?

I don't speak as good as I write, and I don't listen as good as I speak.

2014-07-28 18:12:46

Hi,
Aprone has an algorithm for fps moving? tongue
As for muting things in bgt, you could try something like this.
sound_pool sounds;
sounds.max_distance=20;

Underworld Tech.
Accessibility from us, to you.
Visit us

2014-07-28 18:19:50

Hi Yukio.  I've sent you an email through the forum regarding this.
Let me know if you don't receive it.

~ Ian Reed
Visit BlindGamers.com to rate blind accessible games and see how others have rated them.
Try my free JGT addon, the easy way to play Japanese games in English.
Or try the free games I've created.

2014-07-28 19:48:54

Hi Yukio,

The code I sent you in my email uses more math and is much more accurate, but I thought I'd also share a much easier to understand but less accurate solution.
I actually used something like this when I was initially doing first person stuff but later changed to the more math heavy version when I needed more accuracy for my radar.

I'm just writing this up from memory so hopefully I get it right.
It uses C# syntax.
The Walls variable is a 2 dimensional array of booleans.
For every sound in your world you see if it's farther from the player than a certain mute distance, if so then just mute it and don't check for walls.
For the nearby sounds you run everyone through this IsBehindWall function to see if it should be muted or not.
bool IsBehindWall(Vector2 source, Vector2 target)
{
    float scanDistance = (target - source).Length;
    var slope = target - source;
    slope.Normalize();
    int scanStep = .2; // the steps along the line that we are checking for walls.  Lower numbers give slightly more accuracy but not as much as a more math driven solution.
    var slopeStep = scanStep * slope;
    var pos = source;
    for (int i=0; i <= scanDistance; i += scanStep)
    {
        // we move the pos variable along the line between source and target.
        pos += slopeStep;
        int x = (int)Math.Floor(pos.X);
        int y = (int)Math.Florr(pos.Y);
        if (Walls[x, y])
            return true; // we found a wall along the line between source and target.
    } // end for loop
    // if we got this far then we took .2 steps along the whole line between source and target and never hit a wall.
    return false;
}

The above example expects you have a Vector class that can be multiplied by a float, provide it's length, and other common vector operations.
The operations aren't hard to do, but it makes the code shorter to write them this way.
If you need examples of the vector operations let me know.

Ian Reed

~ Ian Reed
Visit BlindGamers.com to rate blind accessible games and see how others have rated them.
Try my free JGT addon, the easy way to play Japanese games in English.
Or try the free games I've created.

2014-07-29 00:51:47 (edited by nyanchan 2014-07-29 00:53:04)

Thanks Ian, I've replied.
Kyle, it is much more complicated than just muting sounds far from listener. But thank you for answering.

If Ghorthalon or Aprone see this topic, please let me know how you coded the algorithm. I'm very interested in it.

I don't speak as good as I write, and I don't listen as good as I speak.

2014-07-29 02:24:29

I once asked Aprone if he had anything better than iterating along the line segment between the listener and the object. I believe his answer was something like "If you come up with such a thing, I'd like to hear about it!" I don't think my Skype history from that far back is still around, but I could check. wink

I remember trying this once, but I don't remember which project.
I keep expecting it to lag, but it somehow has no noticeable effect on speed. Maybe it would if there were too many sounds in the distance?

看過來!
"If you want utopia but reality gives you Lovecraft, you don't give up, you carve your utopia out of the corpses of dead gods."
MaxAngor wrote:
    George... Don't do that.

2014-07-30 04:05:33

Hello there. Here is the post I saved that Aprone posted a while back with his suggestions. It also contains a technique for movement code for an FPS.

Previously I wrote a thread to help people who were trying to learn the basic concepts of programming.  It was aimed at the absolute beginner.  For this next thread I will be changing my focus to the somewhat more advanced programmers, and I write this here so that people who benefited from the last thread won't misunderstand and think that this is the next step in their programming journey.  smile
In this post I want to cover some free 2D movement and sound panning methods like those used in Swamp.  I'm asked about this every so often and I would usually just respond with "It's complicated".  Recently I decided to run Ghorthalon through the process to be helpful, but also to see if it would be as hard to explain as I feared it might be.  As it turns out, the process went pretty smoothly and it seemed like a good idea to write up the steps here for the benefit of everyone.
This will cover 1 way that this could be done and it is intended to give you the concepts behind panning sound to mimic objects all around you.  I will try to keep the code generic so that it can be used in any language which supports the ability to pan sounds and adjust their volume.  Because this is intended for programmers with a bit more experience, it is very possible that some people will not understand how to follow along.  If that happens there isn't much I can do to help you, it will just mean that you still need more work understanding things like arrays, loops, and so forth.
First we will cover free movement in a smooth landscape which is not locked to a grid.  We will assume that your player's X and Y coordinates are stored in the variables mya and myb.  The variable theta will hold the angle, in degrees, that your person is facing.  I thought the use of radians might be a bit over some people's heads, so to keep things comfortable this code will do everything in degrees.  Theta value of 0 represents East, 90 is South, 180 is West, and 270 is North.  Of course a value such as 30 would be aiming the player a little bit South but mostly East.  We will start with these 2 lines of code.
tempa = mya + (0.1 * Cos((theta * 3.14) / 180))
tempb = myb + (0.1 * Sin((theta * 3.14) / 180))
The 0.1 is the distance the player will travel, and this code is not meant to jump you directly to some destination but is rather meant to be placed in your main game loop so that it is repeated multiple times as you inch your way along the map.  At the end of those 2 lines of code, the variables tempa and tempb will be holding the new X and Y coordinates that your player should be at after moving the 0.1 distance and facing the angle theta.
You might be wondering why the new coordinates are being stored in tempa and tempb, instead of being put back into mya and myb.  It's true that your player won't actually be moving until you say mya = tempa and myb = tempb, but I used those temporary variables to help you with colision detection.  Before you actually move your player, this is a good time to make sure your player won't be running inside of a wall or other obstacle.  Just check using tempa and tempb, and if the area is actually clear, then you can update mya and myb to be the values stored in tempa and tempb.
Within your game loop you could continue to add or subtract from theta as the left or right arrow keys are held down.  Moving forward with the up arrow would repeatedly run your movement code, and moving backward can be accomplished by just using -0.1 instead of 0.1 as the distance part.
Moving smoothly around a map is only a small part of the battle.  The more difficult task is to have sounds pan and adjust volume to match.  I am going to generalize all sounds that you might be using, even though in your game every decorative sound, enemy, or gun shot will all be their own sources of sound.  Arrays are a very important part of this, so I recommend keeping your sound sources grouped so that you can easily loop through them.
As you move around or as sound sources move around you, the first step is to loop through all of the sounds and ignore any that are out of range.  The range will be some maximum distance you decide, which marks the distance that any sound will be impossible to hear.  For this example I will use the number 75.  To ignore sounds that are too far away, you must first calculate the distance between you and each sound.
d = Int(Sqr(((mya - sounda) ^ 2) + ((myb - soundb)) ^ 2))
I am using mya and myb again to be the X and Y coordinates of your person.  Sounda and Soundb are the coordinates for the sound we are checking.  When this line of code is finished, the distance between you and the sound will be stored in the variable D.  Now that we know the distance we can only proceede to the next steps if D is less than 75.  Remember that 75 is our maximum distance we want players to be able to hear.
Now that we are dealing with a sound that is within range, we need to find out the absolute angle between you and the sound.  Not everyone is going to understand the difference between absolute angles and relative angles so I will see if I can explain it.  When dealing with absolute angles, this looks at the entire game world and compairs your coordinates to the sound's coordinates.  When dealing with relative angles, the world is viewed from your player's perspective so your player's coordinates won't come in to play.  I hate to possibly confuse people right here, but it will make far more sense later if I explain this here.
So now on to calculating that global angle!  It is a total of 6 lines.
temp1 = sounda - mya
temp2 = myb - soundb
If temp1 = 0 And temp2 = 0 Then absolutetheta = -1
If temp2 > 0 Then absolutetheta = Atn(temp1 / temp2)
If temp2 <= 0 Then absolutetheta = Atn(temp1 / temp2) + 3.14
absolutetheta = (absolutetheta * (180 / 3.14))
Once again I am using a few temporary variables just to make things a little easier to separate.  When we are finished, the variable absolutetheta holds the absolute angle between the player and the sound.  Now we need to use this absolute angle to find out the relative angle, and thankfully this is as easy as just subtracting the angle the player is facing from the absolute angle.
relativetheta = absolutetheta - theta
To put things into perspective I will try to explain a little bit about what this relative angle means.  If relativetheta was equal to zero, then the sound is exactly in front of us.  If relativetheta equals 45 then the sound is 45 degrees to our right, putting it halfway between being in front of us and being exactly to our right.  180 would be behind us and 270 would be directly off to our left.  Clearly we are getting closer to our goal, but we still have more to do.
We need to figure out our horizontal panning so we will use a line of code that is similar to one we used before.
temph =  Cos(relativetheta * 3.14 / 180)
This will return a value between -1 and +1 but we need it to actually match the maximum panning values of the language you are using.  For this example we will assume that your language uses -10000 for panning all the way to the left, and +10000 for panning all the way to the right.  So to get our -1 to +1 to match the -10000 to +10000, we can just multiply temph by 10000.
temph = temph * 10000
Later on if you find that your sounds are going the exact opposite to how they should be, just make this -10000 instead.  Basically putting the negative sign flips the left and right.
Use your language's sound commands to set the panning to be temph.
We aren't done yet though!  Volume still needs to be figured out.  For that we will use another line of code which will break down the vertical component. 
tempv =  Sin(relativetheta * 3.14 / 180)
The variable tempv now holds a value between -1 and +1.  When tempv is less than zero it means that the sound is somewhere in front of you.  A value greater than 1 means it is coming from behind you.  This lets you use some kind of muffling feature or volume reduction if you want to help players know that it is behind them, but of course your language needs to support those features to use them.
To adjust our volume we will use the distance between us and the sound.  The good news is that we already had the distance calculated and stored in the variable D from earlier.  We will also be using the number 75 which was the maximum distance we can hear sounds from.  Check your language and find out what value represents a sound being completely muted.  For this example we will assume that a value of 0 will play the sound at full volume, and a value of -5000 is complete silence.  Use the value for mute in the equation.
tempvolume = (d*-5000)/75
Now just use your language to set this sound's volume to be equal to tempvolume.  And you're done!  Horray!
I'm not really sure how to end this little tutorial, so I guess I'll end it by asking people to help each other out with this.  If you understand what is going on and are able to make it work, consider lending a hand to help others who are still trying to figure it out.  I've heard that many programming techniques get treated as secrets among developers.  While I can understand the desire to hold on to knowledge that gives you an advantage with your games, but at the same time it works to hold back the developer community in general.  I'd like to see everyone advancing their understanding of these types of concepts so that future games will be better as a result!  smile

Go to Heaven for the climate, Hell for the company. - Mark Twain

2014-08-23 18:42:07

Hi,
Yukio, I'm not posting specific code, just a quick way to achieve this:
Scan around the player on your map and check for walls and objects that could be close. To make it simple, use a specific distance, e.g. 10 units in every cardinal direction. If you are scanning, say, north and you encounter a wall, have a temporary cut value stored. Then, as you go further north, reduce the volume of the objects you encounter.
Use a small value, in case you have many wall tiles. This can simulate wall thickness as well.
If you want to make it better, have a hearing_distance property on every object. Then, use this scan on the whole map and if the hearing distance is greater than the distance between the player and the object, reduce the object's volume.
This is normally handled by audio libraries and the effect we can achieve won't be as realistic, but it will work. In most cases a volume cut would not be enough, you'd also need a highcut filter, but this is of course a lot more complicated.

Rob

----------
Robjoy, AKA Erion
Visit my site for all the things I do and to contact me.
You can also stop by for a slice of Pi

2014-08-23 21:57:51

If you don't have a lowpass, it's not worth it.  Nothing distinguishes a quieter sound on the other side of a wall from the same in the same room and naturally quiet or something far away but also in the same room.
You can "fake" the lowpass.  This is simple, but will double the size of your game.  The idea is to just create mysound.wav and mysound_lowpassed.wav.  You can do batch converting with any number of different things.  ffmpeg and audacity come to mind, but I believe Goldwave also does.
It happens that, mathematically, placing these sounds in the exact same spot in 3D space will add them together appropriately.  At least by the algorithms that are usually used.  If you have access to a gain multiplier on each, you can then represent every entity as a sum of two sounds: the regular and the lowpassed.  As you turn the regular quieter and the lowpassed sound louder, it will sound as though you are progressively applying a filter to it.  The trick is to make sure that the gains always sum to 1, so that later stages in your 3d panner will still work as expected.
The actual algorithm discussed here is the only way, at least unless you're using a structure for your game that is more complicated than an array.  Various other options exist, but I really do not want to try to explain them, and they make writing the map editor much, much more challenging.  It is worth noting that this is another case wherein you can offload to a physics library, which usually has raycasting built in.

My Blog
Twitter: @ajhicks1992

2014-08-24 04:38:24

I've achieved that by scanning walls between listener and the objects. Currently, it's working fine without slowing down the game performance.

I don't speak as good as I write, and I don't listen as good as I speak.