calling if statement and not updating it until it's finished - if-statement

How can I call an if statement (or any other function) without calling it again, until it's finished executing? I have an update function that calls another function (in another class) but because it executes every update, the user doesn't get the time to actually complete the IF statements (the if statements rely on user input) so therefor it returns nothing or only the first part.
Code (where the update is):
public void Update(){
if(Mouse.isButtonDown(0)){
changeTile();
}
while(Keyboard.next()){
if(Keyboard.getEventKey() == Keyboard.KEY_RIGHT && Keyboard.getEventKeyState()){
moveIndex();
}
if(Keyboard.getEventKey() == Keyboard.KEY_LEFT && Keyboard.getEventKeyState()){
moveIndexBack();
}
}
}
changeTile function:
public void changeTile(){
boolean start = true;
if(start){
while(Mouse.next()){
if(Mouse.getEventButton() == 0 && Mouse.getEventButtonState()){
//system uses tileTypes because player textures are tiletypes itself, so in the end we can let them swim by changing tiletypes
int xCoord = (int) Math.floor(Mouse.getX() / 64);
int yCoord = (int) Math.floor((HEIGHT - Mouse.getY() - 1) / 64);
tileType tile1 = map[xCoord][yCoord].getType();
System.out.println("first tile is set to:" + tile1);
start = false;
}
}
}
if(!start){
while(Mouse.next()){
if(Mouse.getEventButton() == 0 && Mouse.getEventButtonState()){
int xCoord2 = (int) Math.floor(Mouse.getX() / 64);
int yCoord2 = (int) Math.floor((HEIGHT - Mouse.getY() - 1) / 64);
tileType tile2 = map[xCoord2][yCoord2].getType();
System.out.println("second tile is set to:" + tile2);
}
}
}

Related

Bukkit countdown message sends message 4 times

I just created a countdown method in Java, but i have a problem when the countdowner broadcasts the messages: 60(and down) seconds until the game starts!
The broadcast gets sent *4. Does anyone know any solution to this?
Here is my code:
Main plugin;
public StartCountdown(Main pl) {
plugin = pl;
}
public static int timeUntilStart;
#Override
public void run() {
for(Player p1 : Bukkit.getOnlinePlayers()){
if(timeUntilStart == 0) {
if(!Game.canStart()) {
plugin.restartCountdown();
ChatUtilities.broadcast(ChatColor.RED + "Not enough players to start. Countdown will");
ChatUtilities.broadcast(ChatColor.RED + "restart.");
p1.playSound(p1.getLocation(), Sound.ENDERDRAGON_WINGS, 5, 1);
return;
}
Game.start();
}
for(Player p : Bukkit.getOnlinePlayers()){
p.setLevel(timeUntilStart);
if(timeUntilStart < 11 || timeUntilStart == 60 || timeUntilStart == 30) {
p.playSound(p.getLocation(), Sound.ORB_PICKUP, 5, 0);
if(timeUntilStart == 1) {
p.playSound(p.getLocation(), Sound.ORB_PICKUP, 5, 1);
}
ChatUtilities.broadcast(String.valueOf(timeUntilStart)
+ " §6Seconds until the game starts!");
}
}
}
timeUntilStart -= 1;
}
}
You are broadcasting for every player that is online. You need to move any code that you don't want to run for every player outside of the for loop.
#Override
public void run() {
if (timeUntilStart == 0) {
if (!Game.canStart()) {
plugin.restartCountdown();
ChatUtilities.broadcast(ChatColor.RED + "Not enough players to start. Countdown will");
ChatUtilities.broadcast(ChatColor.RED + "restart.");
for (Player p : Bukkit.getOnlinePlayers()) p.playSound(p.getLocation(), Sound.ENDERDRAGON_WINGS, 5, 1);
return;
}
Game.start();
}
boolean broadcast;
for (Player p : Bukkit.getOnlinePlayers()) {
p.setLevel(timeUntilStart);
if (timeUntilStart < 11 || timeUntilStart == 60 || timeUntilStart == 30) {
p.playSound(p.getLocation(), Sound.ORB_PICKUP, 5, 0);
if (timeUntilStart == 1) p.playSound(p.getLocation(), Sound.ORB_PICKUP, 5, 1);
broadcast = true;
}
}
if (broadcast) ChatUtilities.broadcast(String.valueOf(timeUntilStart) + " §6Seconds until the game starts!");
timeUntilStart -= 1;
}
as Tanner Little said above
You are broadcasting for every player that is online. You need to move any code that you don't want to run for every player outside of the for loop.
You need to make sure as well that you are cancelling the task. I would recommend using the inbuilt scheduler. You can access the scheduler in this way
private int countDownTimer
private int countDownTime
public void runCountDown() {
countDownTimer = Bukkit.getScheduler.scheduleSyncDelayedTask(plugin, new runnable() {
public void run {
if (countDownTime <= 0) {
//do your bradcasting here
for (Player ingame : Bukkit.getOnlinePlayers()) {
//Do your player specific stuff here
}
Bukkit.getScheduler.cancelTask(countDownTimer);
}
if (countDownTime % 10 == 0) { //You can pick whaterver times u want this is just for an example
//Do periodic broadcasting
}
countDownTime -= 1;
}
}, 0L, 20L); //This means that it would wait 0 ticks to start the countdown and do the task every 20 ticks ie) 1 second.
}
Hopefully this helps you.

Keeps on getting terminate called after throwing an instance of 'std::out_of_range'

bool GameUtil::isValidPath(std::vector<int>& path, Player* player, Game* game) {
///**Get borad*/
std::vector<Square*> board = game->getBoard();
int maxDistanceTravel = 0;
int playerCanTravel = 0;
//first square and last square must be present
if (path[0] == 0 && path[path.size() - 1] == (board.size() - 1)) {
for (int i = 0; i < path.size() - 1; i++) {
/**Max distance of each board from player*/
maxDistanceTravel = compute(board.at(path[i]), player);
playerCanTravel = path[i + 1] - path[i];
if ((playerCanTravel > maxDistanceTravel) && (playerCanTravel <= 0)) {
return false;
}
}
return true;
}
return false;
}
I am a new c++ learner and I am getting the same error over and over again but could not figure out what is wrong with it, it is not obviously an out of range, please help, thanks.
I would first try doing some early checking to make sure you're inputs are valid. Perhaps something like:
bool GameUtil::isValidPath(std::vector<int>& path, Player* player, Game* game) {
assert(!path.empty());
if (path.size() < 2) return false; // or whatever your minimum size is.
As long as you're at it, you should probably scrub the other inputs.
bool GameUtil::isValidPath(std::vector<int>& path, Player* player, Game* game) {
assert(!path.empty());
assert(game);
assert(player);
if (path.size() < 2) return false; // or whatever your minimum size is.
I have a rule of thumb to use references for arguments that should never be null. It looks like in your code that game isn't allowed to be null. So perhaps you could change the function:
bool GameUtil::isValidPath(std::vector<int>& path, Player& player, Game& game) {
assert(!path.empty());
if (path.size() < 2) return false; // or whatever your minimum size is.
And then change where you call. So probably in your code you have something like:
// somewhere buried in your code:
Game * myGame = .../// however you created it.
Game * myPlayer = .../// however you created it.
GameUtil * myGameUtil = .../// however you created it.
...
auto isValid = myGameUtil->isValidPath(path, myPlayer, myGame);
You change it to:
// somewhere buried in your code:
Game * myGame = .../// however you created it.
Game * myPlayer = .../// however you created it.
GameUtil * myGameUtil = .../// however you created it.
...
auto isValid = myGameUtil->isValidPath(path, *myPlayer, *myGame);
Hope that helps.

Pops / clicks when stopping and starting DirectX sound synth in C++ / MFC

I have made a soft synthesizer in Visual Studio 2012 with C++, MFC and DirectX. Despite having added code to rapidly fade out the sound I am experiencing popping / clicking when stopping playback (also when starting).
I copied the DirectX code from this project: http://www.codeproject.com/Articles/7474/Sound-Generator-How-to-create-alien-sounds-using-m
I'm not sure if I'm allowed to cut and paste all the code from the Code Project. Basically I use the Player class from that project as is, the instance of this class is called m_player in my code. The Stop member function in that class calls the Stop function of LPDIRECTSOUNDBUFFER:
void Player::Stop()
{
DWORD status;
if (m_lpDSBuffer == NULL)
return;
HRESULT hres = m_lpDSBuffer->GetStatus(&status);
if (FAILED(hres))
EXCEP(DirectSoundErr::GetErrDesc(hres), "Player::Stop GetStatus");
if ((status & DSBSTATUS_PLAYING) == DSBSTATUS_PLAYING)
{
hres = m_lpDSBuffer->Stop();
if (FAILED(hres))
EXCEP(DirectSoundErr::GetErrDesc(hres), "Player::Stop Stop");
}
}
Here is the notification code (with some supporting code) in my project that fills the sound buffer. Note that the rend function always returns a double between -1 to 1, m_ev_smps = 441, m_n_evs = 3 and m_ev_sz = 882. subInit is called from OnInitDialog:
#define FD_STEP 0.0005
#define SC_NOT_PLYD 0
#define SC_PLYNG 1
#define SC_FD_OUT 2
#define SC_FD_IN 3
#define SC_STPNG 4
#define SC_STPD 5
bool CMainDlg::subInit()
// initialises various variables and the sound player
{
Player *pPlayer;
SOUNDFORMAT format;
std::vector<DWORD> events;
int t, buf_sz;
try
{
pPlayer = new Player();
pPlayer->SetHWnd(m_hWnd);
m_player = pPlayer;
m_player->Init();
format.NbBitsPerSample = 16;
format.NbChannels = 1;
format.SamplingRate = 44100;
m_ev_smps = 441;
m_n_evs = 3;
m_smps = new short[m_ev_smps];
m_smp_scale = (int)pow(2, format.NbBitsPerSample - 1);
m_max_tm = (int)((double)m_ev_smps / (double)(format.SamplingRate * 1000));
m_ev_sz = m_ev_smps * format.NbBitsPerSample/8;
buf_sz = m_ev_sz * m_n_evs;
m_player->CreateSoundBuffer(format, buf_sz, 0);
m_player->SetSoundEventListener(this);
for(t = 0; t < m_n_evs; t++)
events.push_back((int)((t + 1)*m_ev_sz - m_ev_sz * 0.95));
m_player->CreateEventReadNotification(events);
m_status = SC_NOT_PLYD;
}
catch(MATExceptions &e)
{
MessageBox(e.getAllExceptionStr().c_str(), "Error initializing the sound player");
EndDialog(IDCANCEL);
return FALSE;
}
return TRUE;
}
void CMainDlg::Stop()
// stop playing
{
m_player->Stop();
m_status = SC_STPD;
}
void CMainDlg::OnBnClickedStop()
// causes fade out
{
m_status = SC_FD_OUT;
}
void CMainDlg::OnSoundPlayerNotify(int ev_num)
// render some sound samples and check for errors
{
ScopeGuardMutex guard(&m_mutex);
int s, end, begin, elapsed;
if (m_status != SC_STPNG)
{
begin = GetTickCount();
try
{
for(s = 0; s < m_ev_smps; s++)
{
m_smps[s] = (int)(m_synth->rend() * 32768 * m_fade);
if (m_status == SC_FD_IN)
{
m_fade += FD_STEP;
if (m_fade > 1)
{
m_fade = 1;
m_status = SC_PLYNG;
}
}
else if (m_status == SC_FD_OUT)
{
m_fade -= FD_STEP;
if (m_fade < 0)
{
m_fade = 0;
m_status = SC_STPNG;
}
}
}
}
catch(MATExceptions &e)
{
OutputDebugString(e.getAllExceptionStr().c_str());
}
try
{
m_player->Write(((ev_num + 1) % m_n_evs)*m_ev_sz, (unsigned char*)m_smps, m_ev_sz);
}
catch(MATExceptions &e)
{
OutputDebugString(e.getAllExceptionStr().c_str());
}
end = GetTickCount();
elapsed = end - begin;
if(elapsed > m_max_tm)
m_warn_msg.Format(_T("Warning! compute time: %dms"), elapsed);
else
m_warn_msg.Format(_T("compute time: %dms"), elapsed);
}
if (m_status == SC_STPNG)
Stop();
}
It seems like the buffer is not always sounding out when the stop button is clicked. I don't have any specific code for waiting for the sound buffer to finish playing before the DirectX Stop is called. Other than that the sound playback is working just fine, so at least I am initialising the player correctly and notification code is working in that respect.
Try replacing 32768 with 32767. Not by any means sure this is your issue, but it could overflow the positive short int range (assuming your audio is 16-bit) and cause a "pop".
I got rid of the pops / clicks when stopping playback, by filling the buffer with zeros after the fade out. However I still get pops when re-starting playback, despite filling with zeros and then fading back in (it is frustrating).

GIF LZW decompression

I am trying to implement a simple Gif-Reader in c++.
I currently stuck with decompressing the Imagedata.
If an image includes a Clear Code my decompression algorithm fails.
After the Clear Code I rebuild the CodeTable reset the CodeSize to MinimumLzwCodeSize + 1.
Then I read the next code and add it to the indexstream. The problem is that after clearing, the next codes include values greater than the size of the current codetable.
For example the sample file from wikipedia: rotating-earth.gif has a code value of 262 but the GlobalColorTable is only 256. How do I handle this?
I implemented the lzw decompression according to gif spec..
here is the main code part of decompressing:
int prevCode = GetCode(ptr, offset, codeSize);
codeStream.push_back(prevCode);
while (true)
{
auto code = GetCode(ptr, offset, codeSize);
//
//Clear code
//
if (code == IndexClearCode)
{
//reset codesize
codeSize = blockA.LZWMinimumCodeSize + 1;
currentNodeValue = pow(2, codeSize) - 1;
//reset codeTable
codeTable.resize(colorTable.size() + 2);
//read next code
prevCode = GetCode(ptr, offset, codeSize);
codeStream.push_back(prevCode);
continue;
}
else if (code == IndexEndOfInformationCode)
break;
//exists in dictionary
if (codeTable.size() > code)
{
if (prevCode >= codeTable.size())
{
prevCode = code;
continue;
}
for (auto c : codeTable[code])
codeStream.push_back(c);
newEntry = codeTable[prevCode];
newEntry.push_back(codeTable[code][0]);
codeTable.push_back(newEntry);
prevCode = code;
if (codeTable.size() - 1 == currentNodeValue)
{
codeSize++;
currentNodeValue = pow(2, codeSize) - 1;
}
}
else
{
if (prevCode >= codeTable.size())
{
prevCode = code;
continue;
}
newEntry = codeTable[prevCode];
newEntry.push_back(codeTable[prevCode][0]);
for (auto c : newEntry)
codeStream.push_back(c);
codeTable.push_back(newEntry);
prevCode = codeTable.size() - 1;
if (codeTable.size() - 1 == currentNodeValue)
{
codeSize++;
currentNodeValue = pow(2, codeSize) - 1;
}
}
}
Found the solution.
It is called Deferred clear code. So when I check if the codeSize needs to be incremented I also need to check if the codeSize is already max(12), as it is possible to to get codes that are of the maximum Code Size. See spec-gif89a.txt.
if (codeTable.size() - 1 == currentNodeValue && codeSize < 12)
{
codeSize++;
currentNodeValue = (1 << codeSize) - 1;
}

saving contact bodies to be destroyed

In my code I would like to destroy one of two contacted bodies. Within the beginContact the following method in CCPhysicsSprite is called:
-(void)contactMade:(CCPhysicsSprite*)contactedSprite {
int spriteTag1 = self.tag;
int spriteTag2 = contactedSprite.tag;
if (((spriteTag1 == 3) && (spriteTag2 == 4)) || ((spriteTag1 == 4) && (spriteTag2 == 3)) {
CCPhysicsSprite* heroSprite = (CCPhysicsSprite*)[self getChildByTag:4];
b2World* world;
world->DestroyBody(heroSprite.b2Body);
heroSprite.b2Body = NULL;
[heroSprite.parent removeChild:heroSprite];
}
I get a signal SIGABRT pointing to
b2Assert(m_bodyCount > 0);
After searching on this issue. I read that the contact body has to be saved and destroyed after the timestep. How can I do this, given that I have set my contact conditions in the CCPhyscisSprite.
You can add a flag ( like : isDead ... ) to your physical object and in collision event just change that flag value to TRUE .
-(void) CollisionBegin:(b2Fixture*)target With:(b2Fixture*) source
{
if ( target->GetBody()->GetType() == b2_dynamicBody)
{
yourCustomClass *temp = (yourCustomClass *)target->GetBody()->GetUserData();
temp->isDead = true ;
}
}
Then in update function after step get all physical world's object and find that specific object by flag ( Here : isDead ) , and destroy that .
-(void) update: (ccTime) dt
{
int32 velocityIterations = 8;
int32 positionIterations = 3;
world->Step(dt, velocityIterations, positionIterations);
// remove your box2d object here , after step function
for ( b2Body *b = world->GetBodyList(); b; )
{
b2Body *baba = b->GetNext();
if ( b->GetUserData() != NULL && b->GetType() == b2_dynamicBody)
{
yourCustomClass *t = (yourCustomClass *)b->GetUserData();
if ( t->isDead )
{
world->DestroyBody(b); // remove physical body
[self removeChild:t]; // remove node from super layer
}
}
b = baba ;
}
}