To learn and of course for fun I'm building a snake imitation, the only difference should be that instead of an endless chain, a lot of enemies or objects appear on the map and the game should be made more and more difficult.
The code snippet is supposed to show how I create my controls, but I have the problem that only the last created control is actually captured by my "IntersectsWith", all those created before that, as well as the very first one, are then no longer any opponents for me and my player just goes through them.
What is the best way to do this so that all created objects can be found under one definition so that I don't have to write hundreds of IntersectsWith If statements.
I would like to learn how to dynamically create controls and also dynamically have direct access to them, in which my player can interact with them through collision.
I really thought I could solve this with a random character generator and different control names can solve this, but alas - that's not the reality ^^
Random rnd = new Random();
PictureBox Enemy = new PictureBox();
private async void timer1_Tick(object sender, EventArgs e)
{
if (Person.Bounds.IntersectsWith(Food.Bounds))
{
int ascii_index2 = rnd.Next(97, 123);
char char1 = Convert.ToChar(ascii_index2);
char char2 = Convert.ToChar(ascii_index2);
string myletter = Convert.ToString(char1) + Convert.ToString(char2);
Enemy = new PictureBox
{
Location = new Point(rnd.Next(20, playground.Right - 20), rnd.Next(20, playground.Bottom - 20)),
Name = "Enemy" + myletter,
Size = new Size(24,24),
BackColor = Color.Red,
};
this.Controls.Add(Enemy);
Enemy.BringToFront();
Food.Location = new Point(rnd.Next(20, playground.Right - 20), rnd.Next(20, playground.Bottom - 20));
score++;
lbScore.Text = "Score: " + score.ToString();
}
if(Person.Bounds.IntersectsWith(Enemy.Bounds))
{
timer1.Stop();
}
if (Person.Left <= playground.Left && !changed)
{
Person.Location = new Point(playground.Right, Person.Location.Y);
changed = true;
}
else
if (Person.Right >= playground.Right && !changed)
{
Person.Location = new Point(playground.Left, Person.Location.Y);
changed = true;
}
else
if (Person.Top <= playground.Top && !changed)
{
Person.Location = new Point(Person.Location.X, playground.Bottom);
changed = true;
}
else
if (Person.Bottom >= playground.Bottom && !changed)
{
Person.Location = new Point(Person.Location.X, playground.Top);
changed = true;
}
Here a picture from what i have : Player = BlackDot, Food = GreenDot, Enemy = RedDot
It moves auto in the direction you clicked and you can move faster if you hold the Key.
Move Keys: W,A,S,D
You need to create a list and store all the created enemies in there.
First you need to create a List:
List<PictureBox> enemyList = new List<PictureBox>();
and after you've created a new Enemy add it to your List
Enemy = new PictureBox{};
enemieList.add(Enemy);
Because then you can check for every PictureBox in this List and whether it Intersects with your Player or not.
foreach(PictureBox p in enemyList)
{
if(Person.Bounds.IntersectsWith(p.Bounds))
{
timer1.Stop();
}
}
That would be my fast solution to your problem.
Assuming that Person is your player, instead of having an enemy field of type PictureBox, have an enemies field of type List<PictureBox>. You then add each new enemy PictureBox to that list and then you can do this:
if (enemies.Any(enemy => person.Bounds.IntersectsWith(enemy.Bounds))
Related
I want to develop an experimental program in unity. In the program, I use scripts to create a series of objects and assign values to them. I use Tobii's SDK to develop an eye movement experimental program. In order to get the line of sight feedback of these objects (actually a ray collision detection principle), I created a script and added this script for each object. But when I run, I find that only the last of the series of objects I create will give correct feedback, and the other objects will not give feedback。
My feedback script is as follow:
void Update () {
if (_gazeAwareComponent.HasGazeFocus) {
img.color = _outColor;
newText = textName.text;
MainInteraction.isEnter = true;
} else {
img.color = initinalColor;
newText = null;
MainInteraction.isEnter = false;
}
}
I use a static variable to control the state of feedback.
And in my main script, my fuction is:
void createTargetAndText (int number) {
int[] a = GetRandomSequence(10, currentTrailTime);
for (int i = 0; i < number; i++) {
GameObject image = new GameObject();
image.transform.localScale = Vector3.one;
image.name = a[i].ToString();
image.AddComponent<Image>();
image.AddComponent<SphereCollider>();
image.GetComponent<SphereCollider>().radius = targetSize / 2;
image.AddComponent<Feedback>();
image.GetComponent<Image>().sprite = sourceImage;
image.transform.SetParent(currentGameObject.transform.GetChild(3).transform);
image.layer = LayerMask.NameToLayer("UI");
GameObject textGame = new GameObject();
textGame.name = a[i].ToString();
textGame.AddComponent<Text>();
textGame.GetComponent<Text>().font = textFont;
textGame.GetComponent<Text>().text = textGame.name;
textGame.GetComponent<Text>().fontSize = 48;
textGame.GetComponent<Text>().alignment = TextAnchor.MiddleCenter;
textGame.GetComponent<Text>().color = Color.black;
textGame.transform.SetParent(image.transform);
textGame.layer = LayerMask.NameToLayer("UI");
}
}
The only problem is MainInteration.isEnter doesn't work, when I try to change the color to debug, it works.
if (_gazeAwareComponent.HasGazeFocus) {
img.color = _outColor;
newText = textName.text;
MainInteraction.isEnter = true;
if (this.name == "2") {
MainInteraction.isEnter = true;
img.color = Color.cyan;
}
}
I guess the problem may come from:
the static variables in Unity.
Can someone help me answer it? Thank you
I am trying to add several pictures (using PictureBox) of music notes to a Music Staff Form.
In a certain Mouse Event (MouseUp), a Music Note is created, and a music note should appear on the screen. However, only when the first note is created does the image appear on the screen. For every other note created after the first one, the image does not show up.
In the below method, the Music Note is created:
private void Key_MouseUp(object sender, MouseEventArgs e)
{
foreach (MusKey mk in panel1.Controls)
{
if (sender == mk) //true for the specific key pressed on the Music Keyboard
{
if (e.Button == MouseButtons.Left)
{
timer1.Enabled = false;
sp.Stop();
string bNoteShape = null;
// ticks -> milliseconds
if (count >= 16)
{
bNoteShape = "SemiBreve";
duration = 1024;
}
else if (count >= 8 && count <= 15)
{
bNoteShape = "DotMinim";
duration = 768;
}
else if (count >= 4 && count <= 7)
{
bNoteShape = "Crotchet";
duration = 384;
}
else if (count >= 2 && count <= 3)
{
bNoteShape = "Quaver";
duration = 128;
}
else
{
bNoteShape = "Semi-Quaver";
duration = 90; //63 is too short
}
MusicNote mn = new MusicNote(mk.getMusicNote(), duration, bNoteShape, mk.getNote());
Notes.Add(mn);
mn.picturebox1.Location = new Point(xLoc1, yLoc1);
panel2.Controls.Add(mn.picturebox1); //adding MusicNote component to MusicStaff (panel2) collection
}
}
}
}
When the Note is created, it is sent to the MusicNote constructor:
public MusicNote(int iNotepitch, int iDuration, String iBnoteShape, String iNote)
{
notepitch = iNotepitch;
noteduration = iDuration;
noteshape = iBnoteShape;
note = iNote;
picturebox1.ImageLocation = NoteImage_path + noteshape + ".bmp";
picturebox1.BackColor = Color.Transparent;
picturebox1.Location = new Point(xLoc, yLoc);
xLoc = xLoc + 15;
}
I have tried initializing the location (and incrementing xLoc) both through the constructor, and also in the form itself in method Key_MouseUp, but neither seems to make a difference.
The logic seems to be correct, as the picture of the first music note always loads, but I cannot understand why every other note after the first does not show up on my screen.
Any help will be appreciated, thanks!
Edit: perhaps maybe there is another alternative to PictureBox that I could use to store the music notes?
well it looks like your not initializing a new "picturebox1"
picturebox1 = new PictureBox(); //Add this
picturebox1.ImageLocation = NoteImage_path + noteshape + ".bmp";
edit:
Ok in general we need a few things to add a control to a form.
the new Control (look like you have that) 2
Adding it to the parent control (looks like you have that)
panel2.Controls.Add(mn.picturebox1); //adding MusicNote component to MusicStaff (panel2) collection
redraw the control --
this can happen automatically when you resize the form or you can call refresh(on the panel) after the new control is added to the panel.
panel2.Controls.Add(mn.picturebox1);
panel2.Refresh();
I am currently creating a 2d platformer in monogame.
I created a block that, when hit by the player, starts dissapearing. When it dissapears, i draw a rectangle around it. Every Tile of the same type (BrittleTile) also starts dissapearing, untill the entire connected mob of BrittleTiles has dissapeared.
The problem is that for every BrittleTile that is destroyed, my game runs noticably slower, until it becomes a slideshow after 10 or so BrittleTiles destroyed. I have no idea as to what may cause this, i've been trying to ease the Update method of the class but nothing seems to help.
Any idea as to what may cause this?
class BrittleTile: Tile, IIncludeSound
{
public Rectangle DestroyedCheckRectangle;
private BrittleTile brittle;
private bool _isPlayed;
private bool _hasBroken;
private SoundEffect _sfxBreak;
private SoundEffectInstance _sfxiBreak;
private TimeSpan _breakTimer = new TimeSpan();
public Rectangle BrokenViewRectangle { get; set; }
private bool _isBreaking = false;
public BrittleTile(Texture2D texture, Rectangle baseViewRectangle, Rectangle brokenViewRectangle):base(texture, baseViewRectangle, true )
{
this.BrokenViewRectangle = brokenViewRectangle;
this.ViewRectangle = baseViewRectangle;
}
public void Update(GameTime gameTime, Hero hero, Entity[,] grid)
{
if (!this._hasBroken)
{
if (!this._isBreaking && !this._hasBroken && this.hasCollision)
_checkCollision(hero, grid);
if (this._isBreaking)
{
if (!this._isPlayed)
_sfxiBreak.Play();
this._isPlayed = true;
this._breakTimer += gameTime.ElapsedGameTime;
if (this._breakTimer.TotalMilliseconds < 250)
this.GhostMode(gameTime);
else
{
this._isBreaking = false;
this.hasCollision = false;
this._breakTimer -= this._breakTimer;
}
}
else
{
if (!this.hasCollision && this.DestroyedCheckRectangle.Width == 0)
{
this.DestroyedCheckRectangle.X = this.DestinationRectangle.X - 10;
this.DestroyedCheckRectangle.Y = this.DestinationRectangle.Y - 10;
this.DestroyedCheckRectangle.Height = this.DestinationRectangle.Height + 20;
this.DestroyedCheckRectangle.Width = this.DestinationRectangle.Width + 20;
this._hasBroken = true;
}
}
}
}
public override void Draw(SpriteBatch spriteBatch)
{
spriteBatch.Draw(this.Texture, this.DestinationRectangle, this.BrokenViewRectangle, Color.White);
if (this.hasCollision)
spriteBatch.Draw(this.Texture, this.DestinationRectangle, this.ViewRectangle, Color.White * this.GhostDraw * 0.9f);
spriteBatch.Draw(this.Texture, DestroyedCheckRectangle, new Rectangle(1, 1, 1, 1), Color.Yellow);
Console.WriteLine(this.DestroyedCheckRectangle.X + ", " + this.DestroyedCheckRectangle.Y + ", " + this.DestroyedCheckRectangle.Width + ", " + this.DestroyedCheckRectangle.Height);
}
private void _checkCollision(Hero hero, Entity[,] grid)
{
if (this.DestinationRectangle.Intersects(hero.AttackHitBox))
{
this._isBreaking = true;
}
foreach (Shuriken star in hero.Stars)
{
if (this.DestinationRectangle.Intersects(star.DestinationRectangle))
this._isBreaking = true;
}
foreach (Entity entityObject in grid)
{
if (hasCollision && entityObject.GetType() == typeof(BrittleTile)){
brittle = entityObject.DeepCopy() as BrittleTile;
if (this.DestinationRectangle.Intersects(brittle.DestroyedCheckRectangle))
this._isBreaking = true;
}
}
}
override public void LoadSounds(ContentManager content)
{
this._sfxBreak = content.Load<SoundEffect>("SFX/brittleBreak");
_sfxiBreak = _sfxBreak.CreateInstance();
_sfxiBreak.Volume = 0.2f;
}
}
First, this line:
if (!this._isBreaking && !this._hasBroken && this.hasCollision)
the !this._hasBroken is superfluous.
My first warning sign is this line:
brittle = entityObject.DeepCopy() as BrittleTile;
I assume DeepCopy() makes a new version of the object, and copies all it's properties, right? Seeing the code of that might help pin it down, but on that assumption...
For every Tile, you're cycling through every object in you're grid and you're completely duplicating that object as a BrittleTile, why?
My first change would be to modify that foreach to have this within it:
var brittle = entityObject as BrittleTile
if (brittle != null && hasCollision){
if (this.DestinationRectangle.Intersects(brittle.DestroyedCheckRectangle))
this._isBreaking = true;
}
}
Not sure this is the primary cause of the slowdown, but it is definitely an issue. If you're cloning an object and then immediately throwing an object away, you're almost certainly doing something wrong. If you're cloning an object and you're not editing the properties of that copy at all (and using those edits), you're definitely doing something wrong. I'd be wary before using a method like that unless you're really sure that's what you want.
I am extremely new to programming, and I have started off with C#. I am now trying to make my first game, I decided on snake. So far I have been trying to research this question, but all of the answers I see are ones that pertain to people who are using a different method of moving their snake around.
My program uses two doubles (left and top) in order to store where the snake is on the Canvas. My program also uses two doubles for the "food" in the game, called randomFoodSpawnLeft and randomFoodSpawnTop.
My question is this. How does one detect collision between two rectangular objects with just a left and top value? I am rather confused.
snakeWindow is the Window, snakeHead is the rectangle that represents a snake, left is the left value of the snake, top is the top value of the snake.
void timer_Tick(object sender, EventArgs e)
{
double left = Canvas.GetLeft(snakeHead);
double top = Canvas.GetTop(snakeHead);
if (keyUp)
{
top -= 3;
}
else if (keyDown)
{
top += 3;
}
else if (keyLeft)
{
left -= 3;
}
else if (keyRight)
{
left += 3;
}
// These statements see if you have hit the border of the window, default is 1024x765
if (left < 0)
{
left = 0;
gameOver = true;
}
if (top < 0)
{
top = 0;
gameOver = true;
}
if (left > snakeWindow.Width)
{
left = 0;
gameOver = true;
}
if (top > snakeWindow.Height)
{
top = 0;
gameOver = true;
}
// Statements that detect hit collision between the snakeHead and food
//
if (foodEaten == true)
{
spawnFood();
textBlockCurrentScore.Text += 1;
}
// If gameOver were to be true, then the game would have to end. In order to accomplish this I display to the user that the game is over
// and the snakeHead is disabled, and should restart.
if (gameOver == true)
{
keyRight = false;
keyLeft = false;
keyUp = false;
keyDown = false;
top = 0;
left = 0;
textBlockGameOver.Text = "GAME OVER!";
snakeCanvas.Background = Brushes.Blue;
}
Canvas.SetLeft(snakeHead, left);
Canvas.SetTop(snakeHead, top);
}
You can use System.Windows.Rect.IntersectsWith. Try it like this:
Rect rect1 = new Rect(left1, top1, widht1, height1);
Rect rect2 = new Rect(left2, top2, widht2, height2);
bool intersects = rect1.IntersectsWith(rect2);
Of course you will have to check the snake's head against all it's parts.
Just bought a dartboard and thought to create a little scoring application, so far i have set up the player names and individual buttons to start the game. three games - 301, 501 and 1001, these are the targets scores to get to zero by throwing three darts each in turn by two players.
I have included many buttons for the score of each dart from 20 down to 1, each for single, double, triple, bull, outer bull and a no score button. Once the games starts the first three button presses should be attributed to player one then the following three buttons pressed to allocate the corresponding score to player 2. The games ends with the winning player achieving the target score (or whittles it down to zero).
I could have a player selection button to do this but was after some tips on a way of coding the alternate pattern of scoring to be automatic.
Any help greatly appreciated. Thank you
namespace dbstats
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
btnPlay.Visible = false;
btnReset.Visible = false;
btnUndo.Visible = false;
gbDartBoard.Visible = false;
gbScoreBoard.Visible = false;
lbP1Select.Visible = false;;
lbP2Select.Visible = false;
cmbP1.Visible = false;
cmbP2.Visible = false;
string[] lines = File.ReadAllLines(#"playerStats.csv");
foreach (var line in lines)
{
string[] names = line.Split(',');
if (names[0] != "NAME")
{
cmbP1.Items.Add(names[0]);
cmbP2.Items.Add(names[0]);
}
}
}
private void tsm301_Click(object sender, EventArgs e)
{
lbP1Select.Visible = true;
cmbP1.Visible = true;
lbP2Select.Visible = true;
cmbP2.Visible = true;
btnPlay.Visible = true;
tbPlayer1.Text = "301";
tbPlayer2.Text = "301";
gamesToolStripMenuItem.Visible = false;
manageToolStripMenuItem.Visible = false;
}
private void btnPlay_Click(object sender, EventArgs e)
{
if (cmbP1.SelectedItem == cmbP2.SelectedItem || cmbP1.SelectedItem == null || cmbP2.SelectedItem == null)
{
MessageBox.Show("Make Sure:" + "\n\n"
+ "The Players are NOT the same." + "\n"
+ "&" + "\n"
+ "At least one selection is NOT left blank", "Choose Again!");
}
else
{
lbP1Select.Visible = false;
cmbP1.Visible = false;
lbP2Select.Visible = false;
cmbP2.Visible = false;
btnPlay.Visible = false;
lbPlayer1.Text = cmbP1.SelectedItem.ToString();
lbPlayer2.Text = cmbP2.SelectedItem.ToString();
btnReset.Visible = true;
btnUndo.Visible = true;
gbDartBoard.Visible = true;
gbScoreBoard.Visible = true;
lbPlayer1.Visible = true; ;
lbPlayer2.Visible = true;
}
}
}
Keep a turnsEntered member variable to whatever class is managing turns/scoring.
// Call after every time a new score is entered. Start at 0.
turnsEntered++;
if (turnsEntered % 3 == 0)
{
SwitchPlayer(); // However you keep track of current player - switch here
}
After the 3rd score is entered it will switch players...after 3 more it will switch again, etc...
You can later check turnsEntered to determine when the game is over. Set it back to zero when you reinitialize for a new game.