2016-04-21 16:30:53

Hi,

I am working on a little game in my free time, mainly to learn about game mechanics and programming for them. I would really be helped by someone I can IM about this and bounce ideas off of now and again when I get stuck. I for example am having some issues with the soundPool class at the moment and I think this is a problem someone who has more experience with it could solve in 10 seconds, allowing me to continue on.
Is there anyone who can give me a hand with this on something like Skype or an other IM service from time to time?

Thanks,
Zersiax

2016-04-21 18:44:20

Hi there,
For a while the sound pool confused me too, but I will try to explain how it works.
Imagine you have your little game. Now, imagine every single sound that needs to play is a sound object.
Sound gun, step, amb, enemyloop, enemytaunt;
Etc.
If your game was tiny, this would totally work.
However, once things start to get more dynamic (I.E.), you need a lot of sounds to play all at once, the sound pool will be a lot more useful for panning things in the background for you.
What's probably got you confused are so called sound slots. Imagine your phone with all its applications on its home screen.
You only want to use the calculator app, so you move your focus around until you find it, then activate it.
In the same way, when you want the sound pool to keep track of one particular sound, you can give it a sound slot to keep track of.
int gun, step, amb, enemyloop, enemytaunt;
Now when you want to assign one of these to a sound slot, you would do:
gun=pool.play_stationary("insert_path_to_sound_here/insert_sound_name_here.wav", false, false);
Possibly confusing? I'll do my best to try and clear that confusion up.
What that basically says is, assign the sound slot, gun, to a sound of your choosing, in between the quotation marks.
After the quotation marks comes. False, false);
This specifies. Non looping (I.E.), only plays once. Never set a one shot sound looping sound to true, or else some interesting things could happen.
The second false specifies non persistent, I.E., when this sound finishes playing, its slot is freed ready to be used again.
Think of it like downloading an update file to your phone, but once the update gets installed, the package file gets deleted.
Rough I know, but its really the best I could possibly think of.
For panning, the methods you will need are play_1d or play_2d, update_listener_1d, or update_listener_2d.
This all depends on if your game is true 1d or 2d, I.E., in a sidescroller with true jumps or a game with all 4 directions of movement, or 1d, a sidescroller.
Keep in mind the listener, that's you. The listener is your point of view. The sound x is where the sound should come from.
You should never really need to use the play_extended methods unless you have really specific requirements.
I hope this helps, write in if you need more help.

2016-04-24 21:23:36

Hi,

So ...what's going on is this. My code is below, it is a modified version of the windows_attack script. I am trying to make it into a pong game, but I'm having a few problems, namely:
- The ball comes towards the player, but the volume doesn't really increase. Ithink there's something wrong with my volume calculations or I am suing soundPool wrong.
- I am trying to , instead of having balls spawn space-invader style, have a hit ball be either hit back or let  through based on a random number. Not sure if I should trick it into just still spawning balls but make it a random event and use a 'hit back'  sound, or actually make the same ball object go up and down. What would be the best strategy here?

Here's my code:

#include "sound_positioning.bgt"
#include "dynamic_menu.bgt"


// Constants
const int board_size = 21;
const int initial_position = 10;
const int initial_lives = 11;
const int initial_spawn_interval = 3500;
const int initial_enemy_speed = 20;

// Game state
enemy@[] board(board_size);
int player_position;
int player_lives;
int score;
int enemy_speed;
int spawn_interval;

// Pre-loaded sounds
sound start;
sound hit;
sound miss;
sound end;
sound music;
void init() {
// Set up variables with their initial values
player_lives = initial_lives;
player_position = initial_position;
score = 0;
enemy_speed = initial_enemy_speed;
spawn_interval = initial_spawn_interval;

// Preload some sounds
start.stream("start.wav");
end.stream("end.wav");
hit.load("hit.wav");
miss.load("miss.wav");
}

void main() {
init();
start.play();
show_game_window("Windows Attack");

while(start.playing) {
// Make it interruptable like the pros do
if(key_pressed(KEY_RETURN)) {
start.stop(); // This line will go down in history
}
wait(5);
}
start.close();
music.load("marble.ogg");
music.volume=-10;

dynamic_menu menu;
menu.add_item("menu_start_game.wav", "start");
menu.add_item("menu_exit.wav", "exit");
menu.allow_escape = true;
menu.wrap = true;
music.play_looped();
int choice;
do {
choice = menu.run("menustart.wav", false);
if(choice == 1) {
PlayRound();
}
} while(choice!=0 and choice!=2);

}

void PlayRound() {

timer spawner; // This controls the spawning of pingpong balls

// Main loop begins here
while(true) {
// Player death
if(player_lives <= 0 or key_pressed(KEY_ESCAPE)) {
for(int i=0; i<board_size; i++) {
@board[i] = null;
}
end.play_wait();
alert("No pingPong ball anymore my friend", "Your score was: " + score);
exit();
}

// Allow player to move
if(key_pressed(KEY_LEFT) and player_position>0) {
player_position--;
}

if(key_pressed(KEY_RIGHT) and player_position < (board_size-1)) {
player_position++;
}

// Allow player to use bat
if(key_pressed(KEY_SPACE)) {
if(@board[player_position] !is null) {
hit.stop();
hit.play();
score += board[player_position].landed ? 5 : 10;
enemy_speed += 1; // will take this out later, and change the speed in the form of difficulty levels
@board[player_position] = null;
}
else {
miss.stop();
miss.play();
}
}

// Spawn pingpong balls  at the specified interval
if(spawner.elapsed >= spawn_interval) {
spawner.restart();
// Determine its horizontal position
int enemy_position;
enemy_position = random(0, board_size-1);
if(@board[enemy_position] is null) {
enemy e(enemy_position);
@board[enemy_position] = @e;
}
}

// Allow all pingpong balls to move
for(int i=0; i<board_size; i++) {
if(@board[i] !is null) {
board[i].act();
}
}

wait(5);
}
}
class enemy {
int horizontal_position;
int height; // in this case means the ball's vertical axis from the opposite player to the human player
bool landed;
int speed;
sound noise;
timer mover;
enemy(int pos) {
// alert("Message", "Enemy created at" + pos + ".");
horizontal_position = pos;
height = 100;
speed = enemy_speed;
landed = false;
noise.load("ping.wav");
noise.volume = -100;
position_sound_2d(@noise, player_position, 0, horizontal_position, height, 1, 10, 1); // this is supposed to increase in volume when it comes closer, but that doesn't seem to work
noise.play_looped();
}

void act() {
if(landed) { // scored
if(!noise.playing) {
@board[horizontal_position] = null;
}
else {
position_sound_1d(@noise, player_position, horizontal_position, 1, 1);
}
return;
}
height = 100 - mover.elapsed*speed/500;
if(height<=0) {
landed = true;
noise.stop();
noise.load("land.wav");
noise.volume = 0;
position_sound_1d(@noise, player_position, horizontal_position, 1, 1);
noise.play();
player_lives--;
return;
}
position_sound_1d(@noise, player_position, horizontal_position, 1, 1);
noise.volume = 0 + height;
}
}

2016-04-27 01:50:25

@zersiax,
After looking through the code, I sent you a forum email containing what I think will fix the issue.
Hope this helps you.

2016-04-28 16:01:41 (edited by Zersiax 2016-04-28 16:02:45)

Hi,

I cleaned up the code some, and added how I think the logic should flow. I am running into a few issues still, though. Namely:
- even though position2d is now being used in the act() method, the volume still doesn't handle properly
- I am trying to modify an object's variable, but am being told the object is not declared. This is true, the object is declared later. Can BGT only run sequentially?

If anyone would be available to debug these issues with me that would be great smile
The code currently looks like this:

#include "sound_positioning.bgt"
#include "dynamic_menu.bgt"


// Constants
const int board_size = 21;
const int initial_position = 10;
const int initialScore1 = 0;
const int initialScore2 = 0;

const int initial_spawn_interval = 3500;
const int initial_ball_speed = 20;

// Game state
ball@[] board(board_size);
int player_position;
int score1;
int score2;
int ball_speed;
int spawn_interval;

// Pre-loaded sounds
sound start;
sound hit;
sound miss;
sound end;
sound music;
void init() {
// Set up variables with their initial values
score1 = initialScore1;
player_position = initial_position;
score2 = 0;
ball_speed = initial_ball_speed;
spawn_interval = initial_spawn_interval;

// Preload some sounds
start.stream("start.wav");
end.stream("end.wav");
hit.load("hit.wav");
miss.load("miss.wav");
}

void main() {
init();
start.play();
show_game_window("Windows Attack");

while(start.playing) {

// Make it interruptable like the pros do
if(key_pressed(KEY_RETURN)) {
start.stop(); // This line will go down in history
}
wait(5);
}
start.close();
music.load("marble.ogg");
music.volume=-10;

dynamic_menu menu;
menu.add_item("menu_start_game.wav", "start");
menu.add_item("menu_exit.wav", "exit");
menu.allow_escape = true;
menu.wrap = true;
music.play_looped();
int choice;
do {
choice = menu.run("menustart.wav", false);
if(choice == 1) {
PlayRound();
}
} while(choice!=0 and choice!=2);

}

void PlayRound() {
music.stop();
timer spawner; // This controls the spawning of enemies

// Main loop begins here
while(true) {
// Player death
if(score1 >= 11 or score2 >= 11 or key_pressed(KEY_ESCAPE)) {
for(int i=0; i<board_size; i++) {
@board[i] = null;
}
end.play_wait();
alert("Final Score", "Your score was: " + score1 + " points for you and" + score2 + " for the opponent");
exit();
}

// Allow player to move
if(key_pressed(KEY_LEFT) and player_position>0) {
player_position--;
}

if(key_pressed(KEY_RIGHT) and player_position < (board_size-1)) {
player_position++;
}

// Allow player to fire
if(key_pressed(KEY_SPACE)) {
if(@board[player_position] !is null) {
hit.stop();
hit.play();
for(int i = 0; i < 100; i+10) {
b.vertical = i; // this isn't currently working
if(vertical > 100) { // if the other side of the table has been reached
int ai = random(1,10);
if(ai <= 5) {
score1++;
board[ball_position] = null;
// play score sound
}
else {
board[ball_position] = null; // maybe play blocked sound. Ball should disappear since a new one will be spawned anyway
}


}
}


}
else {
miss.stop();
miss.play();
}
}

// Spawn enemies at the specified interval
if(spawner.elapsed >= spawn_interval) {
spawner.restart();
// play 'returned'  sound
// Determine its horizontal position
int ball_position;
ball_position = random(0, board_size-1);
if(@board[ball_position] is null) {
ball  b(ball_position);
@board[ball_position] = @b;
}
}

// Allow all enemies to act
for(int i=0; i<board_size; i++) {
if(@board[i] !is null) {
board[i].act();
}
}

wait(5);
}
}
class ball {
int horizontal_position;
int vertical;

int speed;
sound noise;
timer mover;
ball(int pos) {

horizontal_position = pos;
vertical = 100;
speed = ball_speed;

noise.load("ping.wav");
noise.volume = -100;
position_sound_2d(@noise, player_position, 0, horizontal_position, vertical, 1, 10, 1);
noise.play_looped();
}

void act() {

if(!noise.playing) {
@board[horizontal_position] = null;
}
else {
position_sound_2d(@noise, player_position, 0, horizontal_position, vertical, 1, 10, 1);
}

vertical = 100 - 10;
if(vertical<=0) {
score2++;
noise.stop();
noise.load("land.wav");
noise.volume = 0;
position_sound_1d(@noise, player_position, horizontal_position, 1, 1);
noise.play();

return;
}
position_sound_1d(@noise, player_position, horizontal_position, 1, 1);
noise.volume = 0 + vertical;
}
}

Thanks,

2016-04-28 18:55:59

Hi,
you declare your ball object inside an if statement. That will make it live only within that particular if statement. So, the main issue is not that BGT would only be able to run sequentially or linearly, or that you would be forced to declare variables in a specific order, but it's that if you declare a variable inside a function, loop, conditional or whatever, the variable is local only for that particular scope. It's usually better to create class instances globally for this reason, and that's why your board array is global.

The other issue is that from a quick glance at your current code, I couldn't see anything in the ball class declaration that would actually create the connection between a new instance of the class and your board array. The class and the array are actually two different things. You might consider creating another global function for spawning balls that would first create the ball instance and then insert_last it into the array. It might be slightly different than how the Windows Attack tutorial does it, I can't remember the exact details, but it's the way I usually do it.

Hope this helps,
Lukas

I won't be using this account any more or participating in the forum activity through other childish means like creating an alternate account. I've asked for the account to be removed but I'm not sure if that's actually technically possible here. Just writing this for people to know that I won't be replying, posting new topics or checking private messages until the account is potentially removed.

2016-04-28 19:01:11

This is what I keep running into . I try to follow the tutorials in the helpfile but keep running into things that are apparently not best practices at all, where I get confused. For example, position2d takes a source_y argument which in my code is the vertical variable, but I have no idea if I can even do that o if it has to be an array index. The function reference shows this is not necessary but I seem tofind more and more that people do things ocmpletley different from the helpfiles.