So, I'm having trouble with my Breakout again. The score and lives keep going. I've tried to change it to score += or score = score+= 1, but nothing. Also, my sound keeps playing besides the times where the paddle and puck collide. I've tried putting Instance. Stop but it just keeps it from playing. I've done my research for the past two days and still haven't been able to figure out it out. Should I just make a different sound class like in Repeating sound from one Instance ? Just asking if y'all could point me in the right direction. I know the problem lies in the segment I've included. This is in my main game.cs:
protected override void Update(GameTime gameTime)
{
// Allows the game to exit
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
this.Exit();
paddle.Update();
puck.Update();
foreach (Brick brick in bricks)
{
brick.CheckCollision(puck);
{ score = score += 1 ; }
}
if (puck.OffBottom())
{
lives+= 1;
if (lives == 0)
StartGame();
};
puck.PaddleCollision(paddle.GetBounds());
crashSoundInstance.Play();
// This bottom statement I tried adding to see if it worked, but nothing...
// if (puck.PaddleCollision(paddle.GetBounds(false)))
// { crashSoundInstance.Pause(); }
base.Update(gameTime);
}
Related
I've been working on a Breakout-style project recently and wanted to make it so that once a user enters the 'cheat mode', they'll be able to move the ball in their desired direction.
Here's what my code looks like: https://gist.github.com/anonymous/7589f4f141888c3c32c7
I've included the return; in my ball class due to the fact that if I don't, the program will not recognise the changes in the X and Y. So basically, my problem is, I want the program to ignore the existing x and y speeds and use the ones provided by the user if the cheat mode is enabled. (Meaning if the user enters the cheat mode, the program should stop the ball where it last was, in terms of x and y coordinates, and let the user move it)
Example of what I mean:
Player enters cheat mode -> Presses Up.
- Ball keeps moving up until it hits the top of the form and then should bounce back in the opposite direction to which it hit the wall.
How do I implement this into my program? I used the 'if statement' for the boolean cheat mode and the return function to exit the moveBall procedure (which ignores the xSpeed and ySpeed but ultimately stops the ball from moving on it's own completely, so the player has to keep clicking Up to move the ball up, otherwise it stays in place.
EDIT:
Okay, I've fixed the issue where the ball wouldn't move, I just added a few more variables for the X and Y change of the ball.
Here's what my code looks like now:
public void moveBall()
{
if (Form1.cheatModeClicked == true)
{
ballRec.X += cheatX;
ballRec.Y -= cheatY;
}
else
{
ballRec.X += xSpeed;
ballRec.Y -= ySpeed;
}
}
However, the ball collision still doesn't want to work, and I don't know why?
It sounds like you need to add a method to the ball class to allow the ball's speed to be set externally. Then you can call that method when keys are pressed, depending on the cheat mode state. The cheat mode state should be stored outside the ball class anyway. The ball itself should only know about ball things and not what a non-ball concept such as cheat mode is.
Here is some pseudo code, I might have missed a few things in the description but hopefully it helps
class Form
{
bool _inCheatMode = false;
Ball ball;
void EnterCheatMode()
{
_inCheatMode = true;
ball.SetSpeed(0, 0); //stop the ball
}
void ExitCheatMode()
{
_inCheatMode = false;
}
void KeyDown(Keys key)
{
if (_inCheatMode)
{
if (key == Keys.Up)
ball.SetSpeed(0, -1);
}
}
}
class Ball
{
public void SetSpeed(x, y)
{
}
}
In my pong game I'm making I have two paddles and a ball. I'm trying to make so when the ball collides with the paddle, an effect/animation is shown. I have a spritehseet and a working animation. I use this to detect when the animation plays (please notice that I havent fixed the position of the effect yet, so it plays on 400, 300 just to see if it works)
public bool BallHitEffect()
{
if (gPaddle.gpRect.Intersects(ball.ballRect))
{
return true;
}
else { return false; }
And in my Draw:
protected override void Draw(GameTime gameTime)
{
spriteBatch.Begin();
if (BallHitEffect())
{
animatedSprite.Draw(spriteBatch, new Vector2(400, 250));
}
}
Now it appears when it collide, but only for a short millisecond, because when the ball leaves the paddle, it disappears. I'm aware that it's coded to only appear when it is colliding with the paddle, but in what way could I possibly make it only disappear only when it's animation ends?
You can easily used elapsed time and some makeshift timers to do this. I assume your spritesheet is a series of frames, and that you already have rendering set up.
You will need some variables to start out:
double frameTimePlayed; //Amount of time (out of animationTime) that the animation has been playing for
bool IsPlaying; //Self-Explanitory
int frameCount; //Frames in your sprite, I'm sure you already handle this in your animation logic, but I just threw it in here
int animationTime = 1000; //For 1 second of animation.
In your update method you need to
Check if the ball is intersecting, and set IsPlaying to true
If the animation IsPlaying, increment the frameTimePlayed by the elapsed time
If the frameTimePlayed is equal to or greater than the animationTime, stop the animation by setting IsPlaying to false
In your draw method you need to
Draw the animation, if IsPlaying
Here is some example code:
protected override void Update(GameTime gameTime)
{
//If it is not already playing and there is collision, start playing
if (!IsPlaying && BallHitEffect)
IsPlaying = true;
//Increment the frameTimePlayed by the time (in milliseconds) since the last frame
if (IsPlaying)
frameTimePlayed += gameTime.ElapsedGameTime.TotalMilliseconds;
//If playing and we have not exceeded the time limit
if (IsPlaying && frameTimePlayed < animationTime)
{
// TODO: Add update logic here, such as animation.Update()
// And increment your frames (Using division to figure out how many frames per second)
}
//If exceeded time, reset variables and stop playing
else if (IsPlaying && frameTimePlayed >= animationTime)
{
frameTimePlayed = 0;
IsPlaying = false;
// TODO: Possibly custom animation.Stop(), depending on your animation class
}
}
And for drawing, pretty easy, just check is IsPlaying and draw if that is the case.
I made sure to comment the code good, so hopefully this will help you understand and work better.
You could also use a double and use TotalSeconds instead of milliseconds if needed, and calculate elapsed time with float elapsed = (float)gameTime.ElapsedGameTime.TotalSeconds;
I'm having trouble with touch/multitouch input.
I want to draw a small rectangle, 100x100 in dimensions, wherever the user presses (mission accomplished) but I also want them to move as the user moves his fingers (that's not happening atm).
I'm also getting weird behaviour besides the not-moving part, let's say I touch first with my thumb, then with my middle finger. Two cubes appear bellow each finger, but if I remove the finger I place first (thumb in this scenario) the cube under the finger I placed second (middle finger) will disappear and the one where my thumb was will still be there. I guess this issue will solve itself once I get this to update correctly whenever there is movement.
This are the Draw and Update snippets. Any help appreciated:
protected override void Update(GameTime gameTime)
{
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
this.Exit();
TouchCollection touchLocations = TouchPanel.GetState();
i = 0;
foreach (TouchLocation touchLocation in touchLocations)
{
if (touchLocation.State == TouchLocationState.Pressed)
{
pos[i] = touchLocation.Position;
}
i++;
}
base.Update(gameTime);
}
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);
spriteBatch.Begin();
for (j = 0; j < i; j++)
{
spriteBatch.Draw(whiteRectangle, new Rectangle(((int)pos[j].X - 50), ((int)pos[j].Y - 50), 100, 100), Color.Chocolate);
}
spriteBatch.End();
base.Draw(gameTime);
}
I would recommend using a Dictionary assuming you want to associate touch locations to their position. The key should be the TouchLocation.Id
TouchLocation.Id will remain the same for a given interaction. There is no guarantee that the order of TouchLocations will be the same from one frame to another, so you have to use their ID and not the order they appear in the collection.
I'm a bit late on this, but well here is what was wrong and how I solve it...
foreach (TouchLocation touchLocation in touchLocations)
{
if (touchLocation.State == TouchLocationState.Pressed)
{
pos[i] = touchLocation.Position;
}
i++;
}
I guess I was sleepy when I wrote this part of the code (nothing good happens after 2 AM... not even good code) I don't know why I was checking if the location state was pressed... that's why it didn't move when I move... first frame it is indeed pressed but once you start moving it it's .Moved ... all in all, removed that if and it works like a charm...
foreach (TouchLocation touchLocation in touchLocations)
{
pos[i] = touchLocation.Position;
i++;
}
All in all now it behaves as intended.
Cheers!
I'm developing a 2D game with XNA game studio 4.0 and I need to make my "Hero" sprite shoot a shot sprite, which is a rectangle.
When I press left control to shoot, the shot is starting from my player. So far, it's ok, but the problem is that it never stops - its position never goes to theVoid.
Here is my code for shooting:
protected override void Update(GameTime gameTime)
{
if (Keyboard.GetState().IsKeyDown(Keys.LeftControl) && isShotted == false)
{
isShotted = true;
shotPosition = playerPosition;
}
if (isShotted == true && (shotPosition.X <= shotPosition.X+150) )
{
shotPosition.X += shotSpeed.X * (float)gameTime.ElapsedGameTime.TotalSeconds;
}
else
{
isShotted = false;
shotPosition = theVoid;
}
}
Some clarification:
playerPosition is my "Hero" sprite position.
theVoid is Vector2 (700,700), when I set shotPosition = theVoid the shot dissapears.
The shot never disapears because you are updating shotPosition.x every update. You are checking:
if (isShotted == true && (shotPosition.X <= shotPosition.X+150) )
And then inside that if you increment shotPosition.X:
shotPosition.X += shotSpeed.X * (float)gameTime.ElapsedGameTime.TotalSeconds;
One option to fix this would be to check shotPosition.X against the player position - per #jonhopkins comment. If the player can move near the same speed as the shot though, they could just follow it and then the shot would never disappear, this may or may not be what you want.
Your other option is to store the position of where the shot was fired, and compare something like:
if (isShotted == true && (shotPosition.initialX+150 >= shotPosition.currentX) )
Make sure you think about this in terms of how your players and objects move around the coordinate system though. If your player is always stationary in regards to the x-axis that could simplify things compared to if they can run around the screen..
Here is the gameplay. There is three condition.
The player step on a Switch-Tile and it became false.
1) When the Enemy step on it (trapped) AND the player step on it too, the Enemy will be destroyed.
2) But when the Enemy step on it AND the player DIDN'T step on it too, the Enemy will be escaped.
3) If the Switch-Tile condition is true then nothing happened. The effect is activated when the Switch tile is false (player step on the Switch-Tile).
Because there are a lot of Enemy and a lot of Switch-Tile, I have to use foreach loop.
The problem is after the Enemy is ESCAPED (case 2) and step on another Switch-Tile again, nothing happened to the enemy!
I didn't know what's wrong. The effect should be the same, but the Enemy pass the Switch tile like nothing happened (They should be trapped)
Can someone tell me what's wrong?
Here is the code :
public static void switchUpdate(GameTime gameTime)
{
foreach (SwitchTile switch in switchTiles)
{
foreach (Enemy enemy in EnemyManager.Enemies)
{
if (switch.Active == false)
{
if (!enemy.Destroyed)
{
if (switch.IsCircleColliding(enemy.EnemyBase.WorldCenter,
enemy.EnemyBase.CollisionRadius))
{
enemy.EnemySpeed = 10; //reducing Enemy Speed if it enemy is step on the Tile (for about two seconds)
enemy.Trapped = true;
float elapsed = (float)gameTime.ElapsedGameTime.Milliseconds;
moveCounter += elapsed;
if (moveCounter> minMoveTime)
{
//After two seconds, if the player didn't step on Switch-Tile.
//The Enemy escaped and its speed back to normal
enemy.EnemySpeed = 60f;
enemy.Trapped = false;
}
}
}
}
else if (switch.Active == true && enemy.Trapped == true
&& switch.IsCircleColliding(enemy.EnemyBase.WorldCenter,
enemy.EnemyBase.CollisionRadius)
)
{
//When the Player step on Switch-Tile and
//there is an enemy too on this tile which was trapped = Destroy Enemy
enemy.Destroyed = true;
}
}
}
}
else if (switch.Active == true && enemy.Trapped == true
&& switch.IsCircleColliding(enemy.EnemyBase.WorldCenter,
enemy.EnemyBase.CollisionRadius)
)
{
//When the Player step on Switch-Tile and
//there is an enemy too on this tile which was trapped = Destroy Enemy
enemy.Destroyed = true;
}
This code will never be true since you set whether the enemy is trapped or not only if the switch is not active. Once you set it to true you should really break out the loop and then test again to see whether you should destroy the enemy or not.
Rethink the logic you want to do, and ensure that at each stage you can gain access to the correct information for the enemy etc.
P.S You do NOT need to use a foreach loop. You could easily use a for loop and iterate over the container or if you were really sadistic you could simple hardcode for every enemy yourself. Foreach loops are simply one way to solve this kind of issue, just because they can be used, doesnt mean you need to use them ;)