Cannot get laser to fire in 2D space invaders like game - c#

Recently I've been working on a Space Invaders like game, to help me boost my programming Skills. I've fallen into a few problems. I've been researching for a few days now, in how you would go about making a laser fire, on keyUp.
This is my attempt so far; I can get the laser to fire, but it has stumbled me why the laser doesn't carry on moving up...
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
namespace SpaceInvaders
{
public partial class Form1 : Form
{
public int spriteX = 226;
public int spriteY = 383;
bool bulletFire = false;
int fireTimer = 8;
int laserFired;
public Form1()
{
InitializeComponent();
}
private void exitToolStripMenuItem_Click(object sender, EventArgs e)
{
this.Close();
}
public void laserFire()
{
//on laser fire i wont the bulle to move up while bullet timer is enabled
//moving up slowly with set intervals
while (bulletTimer.Enabled == true)
{
PictureBox laser = new PictureBox();
laser.BackColor = Color.Chartreuse;
laser.Width = 5;
laser.Height = 30;
laserFired = spriteY;
laserFired = laserFired - 10;
this.Controls.Add(laser);
laser.Location = new Point(spriteX, laserFired);
}
}
private void Form1_KeyDown(object sender, KeyEventArgs e)
{
//Fire bullet
if (e.KeyCode == Keys.Up)
{
bulletFire = true;
if (bulletFire == true)
{
laserFire();
bulletTimer.Enabled = true;
}
}
//Controls Right movement
if (spriteX <448)
{
if (e.KeyCode == Keys.Right)
{
spriteX = spriteX + 20;
}
}
//Controls Left Movement
if (spriteX > 0)
{
if (e.KeyCode == Keys.Left)
{
spriteX = spriteX - 20;
}
}
//Points sprite to new location
pctSprite.Location = new Point(spriteX, spriteY);
}
private void bulletTimer_Tick(object sender, EventArgs e)
{
if (fireTimer == 0)
{
bulletTimer.Enabled = false;
}
else { fireTimer = fireTimer - 1; }
}
}
}
Help or advice would be much appreciated thanks.

The problem you have is that on every iteration of the loop, you reset the y position of the bullet by writing laserFired = spriteY;
However, once that is corrected, you will run into another problem: the while loop that moves the laser bullet is only executed in the laserFire method. This means that:
While the laser bullet moves, nothing else can move (because the loop only moves the laser)
Once the laser bullet stops moving, it will never start moving again (because you cannot go back into the loop without calling laserFire() again.
You need to have a single game loop that moves everything in your game, instead of having one loop for every moving object.

Your timer handler simply decrements fireTimer until it's zero. What instigates a re-rendering of the laser? Something needs to invoke laserFire to re-render the laser. Perhaps you meant to call laserFire from bulletTimer_Tick?

Related

Pacman Collecting Coins

I tried two different way to collect coins and both didn't work. I don't know what I'm doing wrong. I'm coding in c#. Is there something I'm missing or is there something I'm supposed to do beforehand?
Here is method number 1:
//collecting coins
foreach(Control x in this.Controls)
{
if (x is PictureBox && x.Tag == "coin")
{
if (((PictureBox)x).Bounds.IntersectsWith(pacman.Bounds))
{
this.Controls.Remove(x); //remove that point
score++; // add to the score
}
}
}
and Here is method number 2:
//collecting coins
foreach(Control x in this.Controls)
{
if (x is PictureBox)
{
if ((string)x.Tag == "coin" && x.Visible == true)
{
if (pacman.Bounds.IntersectsWith(x.Bounds))
{
score += 1;
x.Visible = false;
}
}
}
}
This is work in progress so the code is still missing some parts. Here is a bit of the source code:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace Pac_Man_Game_Clone
{
public partial class Form1 : Form
{
bool goup, godown, goright, goleft, isGameOver;
int score, playerSpeed, redGhostSpeed, yellowGhostSpeed, pinkGhostX, pinkGhostY;
public Form1()
{
InitializeComponent();
restGame();
}
private void Form1_Load(object sender, EventArgs e)
{
}
private void keyisdown(object sender, KeyEventArgs e)
{
if(e.KeyCode == Keys.Up)
{
goup= true;
}
if(e.KeyCode == Keys.Down)
{
godown= true;
}
if(e.KeyCode == Keys.Left)
{
goleft= true;
}
if(e.KeyCode == Keys.Right)
{
goright= true;
}
}
private void keyisup(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Up)
{
goup = false;
}
if (e.KeyCode == Keys.Down)
{
godown = false;
}
if (e.KeyCode == Keys.Left)
{
goleft = false;
}
if (e.KeyCode == Keys.Right)
{
goright = false;
}
}
private void mainGameTimer(object sender, EventArgs e)
{
txtScore.Text = "Score: " + score;
//moving pacman
if(goleft == true)
{
pacman.Left -= playerSpeed;
pacman.Image = Properties.Resources.left;
}
if(goright == true)
{
pacman.Left += playerSpeed;
pacman.Image = Properties.Resources.right;
}
if(godown == true)
{
pacman.Top += playerSpeed;
pacman.Image = Properties.Resources.down;
}
if(goup == true)
{
pacman.Top -= playerSpeed;
pacman.Image = Properties.Resources.Up;
}
//leaving the parameters
//left and right
if (pacman.Left < -10)
{
pacman.Left = 680;
}
if (pacman.Left > 680)
{
pacman.Left = -10;
}
//up and down
if (pacman.Top < -10)
{
pacman.Top = 550;
}
if (pacman.Top > 550)
{
pacman.Top = -10;
}
//collecting coins
foreach(Control x in this.Controls)
{
if (x is PictureBox)
{
if ((string)x.Tag == "coin" && x.Visible == true)
{
if (pacman.Bounds.IntersectsWith(x.Bounds))
{
score += 1;
x.Visible = false;
}
}
}
//runs through wall
if ((string)x.Tag == "wall")
{
if (pacman.Bounds.IntersectsWith(x.Bounds))
{
// run game over
}
}
//bumps to ghost
if ((string)x.Tag == "ghost")
{
if (pacman.Bounds.IntersectsWith(x.Bounds))
{
// run game over
}
}
}
//moving ghosts
redGhost.Left += redGhostSpeed;
if (redGhost.Bounds.IntersectsWith(pictureBox1.Bounds || redGhost.Bounds.IntersectsWith(pictureBox2.Bounds))
{
redGhost += redGhostSpeed;
}
if (score == int.MaxValue)
{
//run game over
}
}
private void restGame()
{
txtScore.Text = "Score: 0";
score= 0;
redGhostSpeed = 5;
yellowGhostSpeed = 5;
pinkGhostX = 5;
pinkGhostY = 5;
playerSpeed = 8;
isGameOver= false;
pacman.Left = 7;
pacman.Top= 35;
redGhost.Left = 219;
redGhost.Top = 56;
yellowGhost.Left = 450;
yellowGhost.Top = 447;
pinkGhost.Left = 521;
pinkGhost.Top = 227;
foreach(Control x in this.Controls)
{
if(x is PictureBox)
{
x.Visible= true;
}
}
gameTimer.Start();
}
private void gameOver(string message)
{
}
}
}
Without having the full source code and the visual tree, I can only try to understand why this isn't working. To me looks like the pacman object isn't defined in the same parent as the coins.
The bounds property is relative to the parent control as coordinate origin.
It works well if each element in the collection of controls are in at the same level of the visual tree, with the same parent. If not, intersect will hardly be true because it is checking against two different coordinate origins, and even if returns true, the position on screen could not match.
As your pacman seems to be referred somewhere else than your collection, maybe your control does not have the same parent and will unlikely have the same origin for your pacman and the coin, and the IF...ELSE will never hit. Please be sure to use the same parent for the pacman and the coins.
Another solution is to draw the game objects on a canvas using the drawing primitives, and create ad hoc objects to store the drawing rectangles. This is the preferred solution as using GDI+ objects to draw game elements doesn't perform well. If you use the canvas instead, all you must do is to update the canvas on each drawing loop with the images of your game objects. This way, you will have no issues with the visual tree of the controls.
Edit: as stated in other comments, if you succeed to hit the intersection condition, in the first version of your code you will also face exception for removing items from the collection while iterating it using foreach. In this case, the solution is to iterate the list first and add the items to a new "removedItemsList" and then iterate this new list to remove the items from the controls collection without iterate it.
It's not so efficient, your second solution with visibility in my opinion is far better. It's not efficient for at least two motives: one because every time you remove a control the visual tree updated for each remaining control. Second, you must allocate a new list, and reiterate it every time you hit a coin. Visibility instead only invalidate the control render rectangle, and on the next draw routing it will be draw invisible.

How to make the button start the game?

I'm currently making my first game, a simple iteration of Pong. I want to have it so that a button can be pressed and this starts the timer, however when I add the button to the game, I find that the game loses the ability to be controlled.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace pong_200
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
bool moveup;//This is a boolean to detect when player's up.
bool movedown;//This is a boolean to detect when player's down.
int speed = 5;//Integer that holds a generic value of 5.
int posx = 5;//Speed of ball horizontally.
int posy = 5;//Speed of ball vertically.
int playerPoints = 0;//Player's score
int cpuPoints = 0;//Computer's score
private void keypressdown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Up)
{
moveup = true;//If the player presses up, the boolean changes to true.
}
if (e.KeyCode == Keys.Down)
{
movedown = true;//If the player presses down, the boolean changes to true.
}
}
private void keypressup(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Up)
{
moveup = false;//If the player lets go of up, the boolean changes to false.
}
if (e.KeyCode == Keys.Down)
{
movedown = false;//If the player lets go of down, the boolean changes to false.
}
}
private void timerTick(object sender, EventArgs e)//This event occurs every 20 m/s.
{
playerScore.Text = "" + playerPoints;//Displays the player's score on the playerScore label.
aiScore.Text = "" + cpuPoints;//Displays the computer's score on the cpuScore label.
ball.Top -= posy;//Sets the top of the ball to Y.
ball.Left -= posx;//Sets the left side of the ball to X.
aiPaddle.Top += speed;//Sets the CPU as the maximum speed integer.
if (playerPoints < 5)//If the score is lower than 5...
{
if (aiPaddle.Top < 0 || aiPaddle.Top > 455)
{
speed = -speed;
} //If the computer has reached the top or bottom of the frame, change the direction back into the frame.
}
else
{
aiPaddle.Top = ball.Top + 30;//Else if the score is more than 5, let the paddle follow the ball for difficulty.
}
if (ball.Left < 0)//If the ball has gone past the player...
{
ball.Left = 434;//Set the ball back to the middle.
posx = -posx;//Change the direction of the ball.
posx -= 2;//Make the ball's speed faster.
cpuPoints++;//Give the CPU one point.
}
if (ball.Left + ball.Width > ClientSize.Width)//If the ball has gone past the computer...
{
ball.Left = 434;//Set the ball back to the middle.
posx = -posx;//Change the ball direction.
posx += 2;//Speed up the ball.
playerPoints++;//Give the player one point.
}
if (ball.Top < 0 || ball.Top + ball.Height > ClientSize.Height)
{
posy = -posy;//If the ball hits either the top or bottom of the frame, reverse the speed of the ball, to keep it in the screen.
}
if (ball.Bounds.IntersectsWith(playerPaddle.Bounds) || ball.Bounds.IntersectsWith(aiPaddle.Bounds))
{
posx = -posx;//Then bounce the ball in the opposite direction.
}
if (moveup == true && playerPaddle.Top > 0)
{
playerPaddle.Top -= 8;//If the boolean is up, and within the upper bounds, move the player towards the top by 8.
}
if (movedown == true && playerPaddle.Top < 455)
{
playerPaddle.Top += 8;//If the boolean is down, and within the lower bounds, move the player towards the bottom by 8.
}
if (playerPoints > 10)
{
pongTimer.Stop();
MessageBox.Show("You Win!");//If the player has more than 10 points, stop the game timer, and show the victory box.
}
if (cpuPoints > 10)
{
pongTimer.Stop();
MessageBox.Show("You Lose!");//If the computer has more than 10 points, stop the game timer and display the loss box.
}
}
private void button1_Click(object sender, EventArgs e)
{
pongTimer = true;
}
}
}
The game itself works when there is no button, but I would like for the game to be started with a button press as I am broadening the horizons. I would appreciate any help or guidance with this!
just a tought:
When working with games, I like to think/work with scenes.
e.g.
Splash Screens --> Menu --> Game --> Pause --> Credits....
Translated to your problem, maybe you could have a form containing your startbutton, and load the next form containing your game on click.

Why does my Picture Box move to the top of the form?

So within my program, I want an object to move left or right depending on what arrow key is held down. I moved the the picture box on the bottom of them form so when any of the two arrow keys are pressed they would move along the bottom. But what's happening is when I press either key, the picture box goes to the top and moves left and right there. I don't know why this is.
Here's the code for the Form1, ignore the code for Form2; that's for experimentation purpose right now:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace Move
{
public partial class Form1 : Form
{
public int lives = 0;
Form2 menu = new Form2();
public Form1()
{
InitializeComponent();
}
private void button1_KeyDown(object sender, KeyEventArgs e)
{
}
private void pictureBox1_Click(object sender, EventArgs e)
{
}
private void Form1_KeyDown(object sender, KeyEventArgs e)
{
int i;
for (i = 0; i < 500; i++)
{
if (e.KeyCode == Keys.Left)
{
pictureBox1.Location = new Point(pictureBox1.Left - 1);
Application.DoEvents();
System.Threading.Thread.Sleep(10);
}
if (e.KeyCode == Keys.Right)
{
pictureBox1.Location = new Point(pictureBox1.Left + 1);
Application.DoEvents();
System.Threading.Thread.Sleep(10);
}
var rect1 = new System.Drawing.Rectangle(pictureBox1.Location, pictureBox1.Size);
var rect2 = new System.Drawing.Rectangle(pictureBox2.Location, pictureBox2.Size);
if (rect1.IntersectsWith(rect2))
{
MessageBox.Show("Game Over!");
System.Threading.Thread.Sleep(1000);
Application.Exit();
}
if (e.KeyCode == Keys.Down)
{
this.Hide();
menu.Show();
}
}
}
}
}
Use
pictureBox1.Location = new Point(pictureBox1.Left - 1, pictureBox1.Top);
and
pictureBox1.Location = new Point(pictureBox1.Left + 1, pictureBox1.Top);
respectively to specify the currently used Y coordinate.
When using the constructor of Point that takes only one value, the system expects this one value to contain both the X and Y coordinates (As higher and lower word of the value) and will use 0 for the Y coordinate because the X values you use are so low that the higher word of the value is 0.

How do you make an object be limited to the boundaries of a Form

I am currently making a Space Invaders type game using C# Windows Forms. When creating the laser cannon which the user controls, I want them to move left and right, shooting lasers. This is my current code for the movement so far:
enter code here
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace Move
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_KeyDown(object sender, KeyEventArgs e)
{
}
private void pictureBox1_Click(object sender, EventArgs e)
{
}
private void Form1_KeyDown(object sender, KeyEventArgs e)
{
int i;
for (i = 0; i < 500; i++)
{
if (e.KeyCode == Keys.Up)
{
pictureBox1.Location = new Point(pictureBox1.Left - 1);
Application.DoEvents();
System.Threading.Thread.Sleep(10);
}
if (e.KeyCode == Keys.Down)
{
pictureBox1.Location = new Point(pictureBox1.Left + 1);
Application.DoEvents();
System.Threading.Thread.Sleep(10);
}
}
}
private void Form1_Load(object sender, EventArgs e)
{
}
}
}
However, I'm having an issue with this; if the image goes too far, it goes out of the boundaries of the form but I want it to do is bounce off and go the other way.
I tried doing this but to no avail, it only moves by a pixel but I think it's a good step(right?...):
if(pictureBox1.Location == new Point(300,300))
{
pictureBox1.Location = new Point(pictureBox1.Left - 1);
}
Like how do I get the correct X,Y coordinates of the whole form so I could tell it to go the other way as well as actually getting it to move?
The smallest X and Y position for a picture box to stay inside the form is 0.
The largest X a picture box can go to is Form.ClientSize.Width - pictureBox.Size.Width
The largest Y a picture box can go is Form.ClientSize.Height - pictureBox.Size.Height.
Check all of these things in an if statement. If either the X or Y of the picture box is outside of the ranges, don't move the picture box, otherwise, do move it.

How do I implement a restart function after game over in my game?

I'm a beginner using Visual Studio to make a C# Windows Form. So I have a brick game (like the classic block game with ball and bricks) where if the player doesn't bounce the ball back, it's basically game over. However when this happens, the timer is just stopped and there's no way to restart. The code I have now just says to create a message box with "You lose" and you have to exit the program to play again. If you reach score 30 then that's a win and to play again you have to exit also.
I've tried googling this and the suggestions I see is if it's all set up already in their cases so implementing it to mine without having to re-do it all in someway is hard. I would like to make a simple implementation (or edit) where there is a play again function. How can I modify existing code to do this? Thank you dearly for any help.
This is the section of code that accounts for game-over if statement.
EDIT= Entire code provided.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Media;
using System.Reflection;
using System.IO;
namespace FinalProjectGame
{
public partial class FrmGame : Form
{
bool goLeft;
bool goRight;
int speed = 10;
int pBallx = 5;
int pBally = 5;
int score = 0;
public FrmGame()
{
InitializeComponent();
}
private void keyisdown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Left && btnGamer.Left > 0)
{
goLeft = true;
}
if (e.KeyCode == Keys.Right && btnGamer.Left + btnGamer.Width < 920)
{
goRight = true;
}
}
private void keyisup(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Left)
{
goLeft = false;
}
if (e.KeyCode == Keys.Right)
{
goRight = false;
}
}
private void TmrMainTimer_Tick(object sender, EventArgs e)
{
pBall.Left += pBallx;
pBall.Top += pBally;
lblScore.Text = "Score: " + score; //keeping score
if (goLeft) { btnGamer.Left -= speed; } //izquierda
if (goRight) { btnGamer.Left += speed; } //derecha
if (btnGamer.Left < 1)
{
goLeft = false; //disables "no-clip"
}
else if (btnGamer.Left + btnGamer.Width > 920)
{
goRight = false;
}
if (pBall.Left + pBall.Width > ClientSize.Width || pBall.Left < 0)
{
pBallx = -pBallx; //left, right wall bounce
}
if (pBall.Top < 0 || pBall.Bounds.IntersectsWith(btnGamer.Bounds))
{
pBally = -pBally; //top, bottom wall bounce
}
foreach (Control x in this.Controls)
//main code brickies subtraction
{
if (x is PictureBox && x.Tag == "blockies")
{
if (pBall.Bounds.IntersectsWith(x.Bounds))
{
this.Controls.Remove(x);
pBally = -pBally;
score++;
} //end of main
//ALT method foreach (Control x in this.Controls)
//{
if (!(x is PictureBox))
continue;
//this is needed if some specific property of the PictureBox is needed.
PictureBox ctl = (PictureBox)x;
if (ctl.Tag.ToString() != "blockies")
continue;
if (!pBall.Bounds.IntersectsWith(ctl.Bounds))
continue;
//this.Controls.Remove(x);
x.Visible = false;
pBally = -pBally;
score++;
//}
}
}//----
//This accounts for user score. Upon completing the game, the user wins. If the user does not capture the ball, it is automatically a game over.
if (score == 30)
{
gameOver();
MessageBox.Show("YES! WINNER!");
}
if (pBall.Top + pBall.Height > ClientSize.Height)
{
gameOver();
MessageBox.Show("SORRY YOU LOSE!");
}
//======
}
private void gameOver()
{
TmrMainTimer.Stop();
}
private void FrmGame_Load(object sender, EventArgs e) //main form load
{
//load the splash screen form that was made with design view
SplashScreen splash = new SplashScreen();
splash.Show();
//using system media to play the audio which is played upon start of the main form
SoundPlayer Sndplayr = new SoundPlayer(Properties.Resources.RoleMusic);
Sndplayr.Play();
}
}
}
If you want to restart that WinForms application, use Application.Restart(). You may close your game form and call restart in your static Main() method afterwards.
private void TmrMainTimer_Tick(object sender, EventArgs e)
{
...
if (pBall.Top + pBall.Height > ClientSize.Height)
{
gameOver();
MessageBox.Show("SORRY YOU LOSE!");
// close the game form
this.Close();
}
}
And in your startup code:
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new FrmGame());
// restart application
Application.Restart();
}
}
Edit:
The example above ist the easiest way to play that game from start. Of course, there are many other options:
As an extension, you can start your game form from a (maybe hidden) program startup form. If you register an event handler on the FrmGame.FormClosed event, you can restart that form again after the previous game was lost.
As many other guys suggested, a StartAgain() method, that resets your logic, is also an option.
Separate drawing logic (View) from game logic (Controller). For a such a simple game it is not necessary and overkill. But it is always a good idea to keep the things simple and clear. See the MVC pattern for your next project...

Categories

Resources