PowerUp stuck

Started by
10 comments, last by BeerNutts 7 years, 9 months ago

Ive been trying to figure this power up thing for breakout.

Supposed I have a power up that will lengthen my paddle. The power up class contain a duration variable.

This duration will be updated and decrease overtime. This is just one power up. I am havent thought of any other power ups yet.

Problem I got is I am stuck on figuring out how can you reset the duration of the power up if my paddle get another power up lengthen?

I am using a list for each power Ups


if(PowerUpses.Count > 0)
            {
                timer += (float)gameTime.ElapsedGameTime.TotalSeconds;
                timeConter += (int)timer;
                if (timer >= 1.0F) timer = 0F;
                foreach (var powerUpse in PowerUpses)
                {
                    if (timeConter >= 1)
                    {
                        powerUpse.TTL -= timeConter;
                        timeConter = 0;
                    }
                   
                    if(powerUpse.power == Powers.lengthen)
                    {
                      
                            powerUpse.reset(powerUpse.power);
                            
                        Debug.WriteLine(powerUpse.TTL);
                    }
                }
               
              
            }

           if(powers == Powers.lengthen )
            {
                
                if(originalWidth == width)
                {
                    this.width += 20;
                }
            }

I am really having a hard time with keeping the duration back to the for example value of 10 if the paddle receives another lengthen power up. Even If I put a triger for that, maintaining the duration is kinda really confusing. I dont want the paddle to get more than 1 power up with the same type. I just want to reset it. But since it is already power.lengthen it will keep reseting to 10 because it is being called in the Update()

Advertisement

I'm finding the exact details of your question a little confusing so I apologise if my answer isn't exactly what you want.

It sounds like you just want to reset the duration of your power up if a player picks up the same power again, that should be fairly easy to do. When a player picks up a new power, search through your list and see if they have that power already, if they do then simple reset the TTL to whatever the default value is and then discard the new power they picked up.

One thing I would suggest is you start to use a more object oriented approach to your power ups, I think that will help you solve the problem you have, your code seems to be accessing too much of the power parts directly. A few ideas:

OnUpdate(elapsed time) // Let the power itself decide what to do with the time

OnApplied() // Let the power decide what to do when it is first picked up, this is where you might increase the paddle length

OnRemoved() // This reverses whatever the OnApplied() method did, it should reset the paddle length (this can get complicated if other things mess with the legth too)

Using OnApplied()/OnRemoved(), when you first add the lengthen power up OnApplied() will increase the length of the paddle. Then when you add another one you go though your list and remove any previous power ups of that type (which would call OnRemove() and reset the paddle length) you then add the new power up (calling OnApplied() again) which lengthens the paddle again.

If you want to combine the power up you could do that too. Should the paddle lengthen duration be combined? I.E. if the first power up lasts 10 seconds and you pick up another, should it now last 20 seconds or simply reset to 10s? You just need another method to deal with that.

However you choose to solve this it is probably a good idea to make the power up into a class and access it with methods rather than directly accessing it's values. That will save you a lot of trouble when you decide to add other power ups too.

Interested in Fractals? Check out my App, Fractal Scout, free on the Google Play store.

What about storing the "end time" (which only is changed when you pick up a powerup) instead of storing the "amount of time left" (which has to be updated every frame).

Then, store it in a map.

Something like this: (psuedocode)


PowerUpType { LargerPaddle, SmallerPaddle, FasterPaddleMovement, SlowerBalls}

Map<PowerUpTime, Time> powerUpActivationMap;

void Game::PickUpPowerUp(PowerUpType type, Time powerUpDuration)
{
    powerUpActivationMap[type] = (currentTime() + powerUpDuration);
}

bool Game::PowerUpIsActive(PowerUpType type)
{
    return (powerUpActivationMap[type] > currentTime());
}

int Game::GetBallSpeed()
{
     if(PowerUpIsActive(SlowerBalls))
          return BallSpeed_Slower;
     
     return BallSpeed_Regular;
}

int Game::GetPaddleSize()
{
     bool largerPaddle = PowerUpIsActive(LargerPaddle);
     bool smallerPaddle = PowerUpIsActive(SmallerPaddle));
     
     if(largerPaddle AND smallerPaddle) return PaddleSize_Regular;
     if(largerPaddle)  return PaddleSize_Larger;
     if(smallerPaddle) return PaddleSize_Smaller;

     return PaddleSize_Regular;
}

One thing I would suggest is you start to use a more object oriented approach to your power ups, I think that will help you solve the problem you have, your code seems to be accessing too much of the power parts directly. A few ideas:

Ive been trying to do OOP approach but I maybe doing it wrong. Though Ive been programming for quite a while I havent bother much with OOP. I believe that that will come to me someday. Thought I have been trying pretty hard to make my project use OOP but not because it is the best way for me, but because I believe that It will be simpler and easy to read for me someday when I look back at my previous project. But for now, Im pretty sure I am doing OOP the wrong way.

Another question, just a simple one. Would you rather let the PowerUp class have access to paddle or let the paddle class have access to power up? This is also the kind of question I ask my self when deciding who is the master class(The one controlling)

Edit: I Got it working.


     for (int i = 0; i < PowerUpses.Count; i++)
            {
                // if it collided remove from the list
                if (PowerUpses[i].PowerUpPaddleCollision(paddle))
                {
                    if (paddle.powers.Count > 0)
                    {
                        foreach (var paddlePower in paddle.powers)
                        {
                            if (paddlePower.power == PowerUpses[i].power)
                            {
                               // paddlePower.reset();
                               Debug.WriteLine("paddle power is " + paddlePower.power);
                                paddlePower.OnRemove();
                                paddlePower.OnApplied();
                            }
                            else
                            {
                               
                                paddle.powers.Add(PowerUpses[i]);
                                paddlePower.OnApplied();
                            }
                        }
                    }
                    else
                    {
                        PowerUpses[i].OnApplied();
                        paddle.powers.Add(PowerUpses[i]);
                        
                    }
                  
                    PowerUpses.RemoveAt(i);
                }
                else
                {
                   
                    PowerUpses[i].update(time);
                }

paddle.cs


            for(int i = 0; i < powers.Count; i++)
            {
                if(powers[i].TTL > 0)
                {
                    powers[i].StartTimer(time);
                }
                else
                {
                    powers.RemoveAt(i);
                }
            }

Basically I used 2 list one for the paddle and other for the power up. I havent tested another type of power up yet

What about storing the "end time" (which only is changed when you pick up a powerup) instead of storing the "amount of time left" (which has to be updated every frame).

Then, store it in a map.

I really dont like using maps. But if this is simpler I might have to try this.

I really dont like using maps.


There's many ways to go about it - so I'm not fixated on maps... but if I may inquire, why don't you like maps?
To me, that's like saying one doesn't like arrays or doesn't like functions.
As tools, neither a hammer or drill is 'better', they are just useful in different (and sometimes overlapping) situations.

There's many ways to go about it - so I'm not fixated on maps... but if I may inquire, why don't you like maps?
To me, that's like saying one doesn't like arrays or doesn't like functions.
As tools, neither a hammer or drill is 'better', they are just useful in different (and sometimes overlapping) situations.

What about storing the "end time" (which only is changed when you pick up a powerup) instead of storing the "amount of time left" (which has to be updated every frame).

I think its because its kinda confusing. And I really dont use it much. I am more familiar with list though. And even if i have a chance I opt to list always.

Can you alos elaborate what do you mean by end time and the "amount time left"? quite confuse

I think its because its kinda confusing. And I really dont use it much. I am more familiar with list though. And even if i have a chance I opt to list always.

I was wondering about making a class with fields, one for each type of powerup. Not sure how well that would work though.

Can you alos elaborate what do you mean by end time and the "amount time left"? quite confuse

Current time is "now", and after "delay" time units, your timer runs out.

You run updates many times each second, each update has "frameTime" time units between them, where "delay > frameTime" (by a lot)

At a central place in your program, you have "time = now", ie your global time. You have 5 powerups with timer, p1..p5

Setting a new timer, for p1: "p1 = delay" // Store amount of time left for the timer.

Timeout of eg p2 is tested with "p2 == 0" // Timeout if no time left in the timer.

Also, to make p2 arrive at 0, do you do each update:


time = time + frameTime   // advance global time
p1 = max(0, p1 - frameTime) // decrement p1 by frameTime
p2 = max(0, p2 - frameTime) // decrement p2 by frameTime
p3 = max(0, p3 - frameTime) // decrement p3 by frameTime
p4 = max(0, p4 - frameTime) // decrement p4 by frameTime
p5 = max(0, p5 - frameTime) // decrement p5 by frameTime

The "max" there makes sure the timers never become negative. This system is called "amount of time left" in a timer.

I hope you agree this is what you do.

Another option is to use endtime in timers.

Setting a new timer p1: p1 = time + delay // Store the moment that the timer runs out in the timer.

Testing is then (for p2) "p2 <= time" // My timer ran out before current time?

Setting and testing are just minor shuffles in how you access timers.

The big difference however is in the update:


time = time + frameTime   // advance global time
// and nothing for all timers, since the moment that they run out does not change!

So by storing the endtime (the moment that the timer runs out) in a timer instead of how much time is left, you don't have to update the "amount of left time" each update, for all timers. Obviously, this save a lot of code and cpu time.

There's many ways to go about it - so I'm not fixated on maps... but if I may inquire, why don't you like maps?

I think its because its kinda confusing. And I really dont use it much. I am more familiar with list though. And even if i have a chance I opt to list always.


Certainly. It's a different kind of tool, but useful to know.

As you know, a list holds 'values' at different 'indexes'.


myList[2] = "blue"; //Assigns the value "blue" to the element located at index '2'.

Maps also hold values, but they use 'keys' instead of indices. This means, we can map any value to any key, and a key can be something other than a number.


myMap["color"] = "blue"; //Assigns the value "blue" to the key "color".

Another thing with maps is that because the map doesn't need the keys to be in linear progression (3, 4, 5, etc...), you can do things like this:


myMap[34261] = "blue"; //Assigns the value "blue" to the key 34261, *without* the map having to be over 34,000 elements long.

It's a very useful tool in many circumstances.

Here's some examples:


textureMap[textureID] = LoadTexture(...); //Maps texture IDs to actual textures.

//Stores templates for types of enemies in a map, using the enemy type name ("goblin") as a key.
enemyTemplateMap["goblin"].LoadFromFile("Enemies/goblin_template.cfg"); 

//Looks up the "goblin" template, and uses that template to create a goblin enemy and map it to an enemy ID.
enemyMap[enemyID] = enemyTemplateMap["goblin"].CreateEnemy(); 

Can you alos elaborate what do you mean by end time and the "amount time left"? quite confuse


There's at least two ways to have a timer do something:


//When activated:
{
    powerUp.timeRemaining = 30 seconds;
    ...make paddle larger...
}

//Every frame:
{
    powerUp.timeRemaining -= deltaTime;
    if(powerUp.timeRemaining <= 0)
    {
       ...Our timer is done, so make the paddle normal size again...
    }
}

The above is useful in some situations, but normally I prefer this second method:


//When activated:
{
    //We store the absolute time the powerup ends, not the relative amount of time remaining...
    powerUp.endTime = (currentTime + 30 seconds);
    ...make paddle larger...
}

//Every frame:
{
    //We don't need to substract anything anymore.
    //powerUp.timeUntilDone -= deltaTime;

    //Instead, we just check if we've passed the end time (i.e. we check if the present time is larger than the ending time).
    if(powerUp.endTime < currentTime)
    {
       ...Our timer is done, so make the paddle normal size again...
    }
}

Note: 'deltaTime' is the amount of time between the previous update and this current update. You calculate it like this:


currentFrameTime = gameTime.ElapsedGameTime.TotalSeconds;
deltaTime = (currentFrameTime - previousFrameTime);
previousFrameTime = currentFrameTime;

Edit: I Got it working.


                    if (paddle.powers.Count > 0)
                    {
                        foreach (var paddlePower in paddle.powers)
                        {
                            if (paddlePower.power == PowerUpses[i].power)
                            {
                               // paddlePower.reset();
                               Debug.WriteLine("paddle power is " + paddlePower.power);
                                paddlePower.OnRemove();
                                paddlePower.OnApplied();
                            }
                            else
                            {
                               
                                paddle.powers.Add(PowerUpses[i]);
                                paddlePower.OnApplied();
                            }
                        }
                    }
                    else
                    {
                        PowerUpses[i].OnApplied();
                        paddle.powers.Add(PowerUpses[i]);
                        
                    }
                  

Basically I used 2 list one for the paddle and other for the power up. I havent tested another type of power up yet

This looks wrong if you have multiple power ups. While looping through the paddle's current power ups, you should not have an else if the power up doesn't match inside the loop, otherwise, for every power up that doesn't match, you'll re-add it and call OnApply().

Rather, you should do something like this:


bool isPowerFound = false;
foreach (var paddlePower in paddle.powers) {
  if (paddlePower.power == PowerUpses[i].power) {
    paddlePower.OnRemove();
    paddlePower.OnApplied();
    isPowerFound = true;
    break;
  }
}
// if we didn't find the power up on the paddle, add it now
if (!isPowerFound) {
  PowerUpses[i].OnApplied();
  paddle.powers.Add(PowerUpses[i]);
 }
...

My Gamedev Journal: 2D Game Making, the Easy Way

---(Old Blog, still has good info): 2dGameMaking
-----
"No one ever posts on that message board; it's too crowded." - Yoga Berra (sorta)

This topic is closed to new replies.

Advertisement