Poängsystem för "pilbågsspel"
Hej!
Har en uppgift i programmering 1 och vet inte riktigt hur jag ska göra för att lösa den sista delen av uppgiften.
Uppgiften går ut på att skapa ett "skjutspel" med en måltavla samt ett sikte. Därefter ska det gå att skjuta på måltavlan och räkna poäng beroende på var skottet/pilen träffar måltavlan. Så ju närmare mitten man träffar måltavlan, desto fler poäng får man och tvärtom.
Vet inte riktigt hur jag ska ta mig tillväga mer än att det kommer vara ett par if-satser och att jag kommer behöva använda avståndsformeln (centrum på måltavlan och avståndet/radien till skottpunkten).
T.ex. när avståndet till skottets centrumkoordinater är mindre eller lika med 5 så ska det ge 10 poäng, när radien är mellan 5 och 10 så ska det ge 8 poäng o.s.v. Dock osäker om det sättet kommer funka när måltavlan även ska röra sig fram och tillbaka i X-led.
Bifogar all min kod här nedan (alla klasser och "form-koden" så det är rätt mycket). Får ursäkta den röriga strukturen som uppstått när jag testat och experimenterat runt.
Tacksam för all form av hjälp!
Form1.cs
public partial class Form1 : Form
{
Måltavla mål;
Sikte sikte;
Skott[] skott;
//Deklarera antal skott och ge det värdet 0
int antalSkott = 0;
//Deklarera kontrollvärde (så vissa metoder inte körs innan andra metoder) och ge det värdet false
bool kontrollvärde = false;
bool kontrollvärde2 = false;
bool rörelseÅtHöger = true;
int höjd;
int bredd;
public Form1()
{
InitializeComponent();
//Bocka i checkboxar
chkMus.Checked = true;
chkMediumMåltavla.Checked = true;
chkMediumSkott.Checked = true;
chkPrickskytte.Checked = true;
//Sätt startvärde
tbxAntalSkott.Text = "10";
//Avaktivera knappar
btnSkjut.Enabled = false;
btnUpp.Visible = false;
btnNer.Visible = false;
btnHöger.Visible = false;
btnVänster.Visible = false;
btnSkjut.Visible = false;
btnAvbryt.Enabled = false;
btnSpelaIgen.Enabled = false;
//Skapa ett sikt-objekt med namnet sikte och ge det positionen 0, 0 och storleken 20
sikte = new Sikte(200, 200, 20);
int antalSkott;
bool antalSkottCheck = int.TryParse(tbxAntalSkott.Text, out antalSkott);
if (!antalSkottCheck)
{
//Felmeddelande
MessageBox.Show("Vänligen fyll i ett giltigt värde för antal skott (heltal)", "Meddelande",
MessageBoxButtons.OK, MessageBoxIcon.Information);
return;
}
//Skapa ett skott-objekt med namnet skott och låt antalet skott bestämmas av textboxen
skott = new Skott[int.Parse(tbxAntalSkott.Text)];
//Aktivera dubbelbuffering för mjukare animationer
this.DoubleBuffered = true;
}
private void Form1_Load(object sender, EventArgs e)
{
//Sätt höjd och bredd till skärmstorleksvärden
höjd = Screen.PrimaryScreen.Bounds.Height;
bredd = Screen.PrimaryScreen.Bounds.Width;
//Sätt storleken på form1 till skärmstorleken
this.Size = new Size(bredd, höjd);
//Placera måltavlan i mitten av skärmen
mål = new Måltavla(ClientSize.Width / 2, ClientSize.Height / 2, 100);
//Uppdatera kontrollen med det senaste resultatet.
tabPageSpel.Paint += tabPageSpel_Paint;
//Sätt kontrollvärde till true
kontrollvärde2 = true;
//Fyll tabcontrol i form1
this.tabControl1.Dock = DockStyle.Fill;
//Maximera fönstret
this.WindowState = FormWindowState.Maximized;
}
private void tabPageSpel_Paint(object sender, PaintEventArgs e)
{
//Måla upp måltavlan
mål.Rita(e.Graphics);
//Måla upp siktet
sikte.Rita(e.Graphics);
//Måla upp skotten
for (int i = 0; i < antalSkott; i++)
{
if (skott[i] != null) skott[i].Rita(e.Graphics);
}
}
private void chkMus_CheckedChanged(object sender, EventArgs e)
{
//Om checkbox för muskontroll är ikryssad så ska checkbox för knappkontroll vara okryssad och vice versa
if (chkMus.Checked == true)
{
chkKnapp.Checked = false;
}
else
{
chkKnapp.Checked = true;
}
//Om checkboxen för knappkontroll är ikryssad så ska knappar visas och vice versa
if (chkKnapp.Checked == true)
{
btnUpp.Visible = true;
btnNer.Visible = true;
btnHöger.Visible = true;
btnVänster.Visible = true;
btnSkjut.Visible = true;
}
else if (chkMus.Checked == true)
{
btnUpp.Visible = false;
btnNer.Visible = false;
btnHöger.Visible = false;
btnVänster.Visible = false;
btnSkjut.Visible = false;
}
}
private void chkKnapp_CheckedChanged(object sender, EventArgs e)
{
//Om checkbox för knappkontroll är ikryssad så ska checkbox för muskontroll vara okryssad och vice versa
if (chkKnapp.Checked == true)
{
chkMus.Checked = false;
}
else
{
chkMus.Checked = true;
}
//Om checkboxen för knappkontroll är ikryssad så ska knappar visas och vice versa
if (chkKnapp.Checked == true)
{
btnUpp.Visible = true;
btnNer.Visible = true;
btnHöger.Visible = true;
btnVänster.Visible = true;
btnSkjut.Visible = true;
}
else if (chkMus.Checked == true)
{
btnUpp.Visible = false;
btnNer.Visible = false;
btnHöger.Visible = false;
btnVänster.Visible = false;
btnSkjut.Visible = false;
}
}
private void chkSmallMåltavla_CheckedChanged(object sender, EventArgs e)
{
//Om en checkbox är ikryssad så ska de övriga vara okryssade
if (chkSmallMåltavla.Checked == true)
{
chkMediumMåltavla.Checked = false;
chkLargeMåltavla.Checked = false;
}
else
{
chkLargeMåltavla.Checked = false;
chkMediumMåltavla.Checked = true;
}
//Radien på måltavlan sätts utifrån vilken checkbox som är ikryssad
if (chkSmallMåltavla.Checked == true)
{
mål.Radie = 50;
tabPageSpel.Invalidate();
}
else if (chkMediumMåltavla.Checked == true && kontrollvärde2 == true)
{
mål.Radie = 100;
tabPageSpel.Invalidate();
}
else if (chkLargeMåltavla.Checked == true)
{
mål.Radie = 150;
tabPageSpel.Invalidate();
}
}
private void chkMediumMåltavla_CheckedChanged(object sender, EventArgs e)
{
//Om en checkbox är ikryssad så ska de övriga vara okryssade
if (chkMediumMåltavla.Checked == true)
{
chkLargeMåltavla.Checked = false;
chkSmallMåltavla.Checked = false;
}
else
{
chkSmallMåltavla.Checked = false;
chkLargeMåltavla.Checked = true;
}
//Radien på måltavlan sätts utifrån vilken checkbox som är ikryssad
if (chkSmallMåltavla.Checked == true)
{
mål.Radie = 50;
tabPageSpel.Invalidate();
}
else if (chkMediumMåltavla.Checked == true && kontrollvärde2 == true)
{
mål.Radie = 100;
tabPageSpel.Invalidate();
}
else if (chkLargeMåltavla.Checked == true)
{
mål.Radie = 150;
tabPageSpel.Invalidate();
}
}
private void chkLargeMåltavla_CheckedChanged(object sender, EventArgs e)
{
//Om en checkbox är ikryssad så ska de övriga vara okryssade
if (chkLargeMåltavla.Checked == true)
{
chkSmallMåltavla.Checked = false;
chkMediumMåltavla.Checked = false;
}
else
{
chkMediumMåltavla.Checked = false;
chkSmallMåltavla.Checked = true;
}
//Radien på måltavlan sätts utifrån vilken checkbox som är ikryssad
if (chkSmallMåltavla.Checked == true)
{
mål.Radie = 50;
tabPageSpel.Invalidate();
}
else if (chkMediumMåltavla.Checked == true && kontrollvärde2 == true)
{
mål.Radie = 100;
tabPageSpel.Invalidate();
}
else if (chkLargeMåltavla.Checked == true)
{
mål.Radie = 150;
tabPageSpel.Invalidate();
}
}
private void chkSmallSkott_CheckedChanged(object sender, EventArgs e)
{
//Om en checkbox är ikryssad så ska de övriga vara okryssade
if (chkSmallSkott.Checked == true)
{
chkMediumSkott.Checked = false;
chkLargeSkott.Checked = false;
}
else
{
chkLargeSkott.Checked = false;
chkMediumSkott.Checked = true;
}
}
private void chkMediumSkott_CheckedChanged(object sender, EventArgs e)
{
//Om en checkbox är ikryssad så ska de övriga vara okryssade
if (chkMediumSkott.Checked == true)
{
chkLargeSkott.Checked = false;
chkSmallSkott.Checked = false;
}
else
{
chkSmallSkott.Checked = false;
chkLargeSkott.Checked = true;
}
}
private void chkLargeSkott_CheckedChanged(object sender, EventArgs e)
{
//Om en checkbox är ikryssad så ska de övriga vara okryssade
if (chkLargeSkott.Checked == true)
{
chkSmallSkott.Checked = false;
chkMediumSkott.Checked = false;
}
else
{
chkMediumSkott.Checked = false;
chkSmallSkott.Checked = true;
}
}
private void chkPrickskytte_CheckedChanged(object sender, EventArgs e)
{
//Om en checkbox är ikryssad så ska de övriga vara okryssade
if (chkPrickskytte.Checked == true)
{
chkRörlig.Checked = false;
}
else
{
chkRörlig.Checked = true;
}
}
private void chkRörlig_CheckedChanged(object sender, EventArgs e)
{
//Om en checkbox är ikryssad så ska de övriga vara okryssade
if (chkRörlig.Checked == true)
{
chkPrickskytte.Checked = false;
}
else
{
chkPrickskytte.Checked = true;
}
}
private void btnSpela_Click(object sender, EventArgs e)
{
int antalSkott2;
bool antalSkottCheck2 = int.TryParse(tbxAntalSkott.Text, out antalSkott2);
if (!antalSkottCheck2)
{
//Felmeddelande
MessageBox.Show("Vänligen fyll i ett giltigt värde för antal skott (heltal)", "Meddelande",
MessageBoxButtons.OK, MessageBoxIcon.Information);
return;
}
//Sätt kontrollvärde till true
kontrollvärde = true;
//Om checkboxen för knappkontroll är ikryssad så ska knapp för att skjuta aktiveras
if (chkKnapp.Checked == true)
{
btnSkjut.Enabled = true;
}
//Om checkboxen för att måltavlan ska röra sig är ikryssad så ska en timer starta
if (chkRörlig.Checked == true)
{
timer1.Start();
}
//Avaktivera knapp
btnSpela.Enabled = false;
//Aktivera knapp
btnAvbryt.Enabled = true;
}
private void btnUpp_Click(object sender, EventArgs e)
{
//Flytta siktet upp
if (chkKnapp.Checked == true)
{
sikte.Flytta(0, -5);
tabPageSpel.Invalidate();
}
}
private void btnVänster_Click(object sender, EventArgs e)
{
//Flytta siktet åt vänster
if (chkKnapp.Checked == true)
{
sikte.Flytta(-5, 0);
tabPageSpel.Invalidate();
}
}
private void btnNer_Click(object sender, EventArgs e)
{
//Flytta siktet neråt
if (chkKnapp.Checked == true)
{
sikte.Flytta(0, 5);
tabPageSpel.Invalidate();
}
}
private void btnHöger_Click(object sender, EventArgs e)
{
//Flytta siktet åt höger
if (chkKnapp.Checked == true)
{
sikte.Flytta(5, 0);
tabPageSpel.Invalidate();
}
}
private void btnSkjut_Click(object sender, EventArgs e)
{
if (chkKnapp.Checked == true)
{
if (antalSkott < (int.Parse(tbxAntalSkott.Text) - 1))
{
if (chkSmallSkott.Checked == true)
{
skott[antalSkott++] = new Skott(sikte.X, sikte.Y, 5);
lblAntalSkott.Text = (int.Parse(tbxAntalSkott.Text) - antalSkott).ToString();
sikte.X = 200;
sikte.Y = 200;
tabPageSpel.Invalidate();
}
if (chkMediumSkott.Checked == true)
{
skott[antalSkott++] = new Skott(sikte.X, sikte.Y, 10);
lblAntalSkott.Text = (int.Parse(tbxAntalSkott.Text) - antalSkott).ToString();
sikte.X = 200;
sikte.Y = 200;
tabPageSpel.Invalidate();
}
if (chkLargeSkott.Checked == true)
{
skott[antalSkott++] = new Skott(sikte.X, sikte.Y, 15);
lblAntalSkott.Text = (int.Parse(tbxAntalSkott.Text) - antalSkott).ToString();
sikte.X = 200;
sikte.Y = 200;
tabPageSpel.Invalidate();
}
else
{
lblAntalSkott.Text = "Pilarna är slut";
btnAvbryt.Enabled = false;
btnSpelaIgen.Enabled = true;
}
}
}
}
private void börjaOm()
{
antalSkott = 0;
sikte.X = 200;
sikte.Y = 200;
tabPageSpel.Invalidate();
}
private void btnSpelaIgen_Click(object sender, EventArgs e)
{
börjaOm();
btnSpelaIgen.Enabled = false;
btnAvbryt.Enabled = true;
}
private void btnAvbryt_Click(object sender, EventArgs e)
{
btnSpela.Enabled = true;
btnSpelaIgen.Enabled = false;
btnAvbryt.Enabled = false;
}
private void timer1_Tick(object sender, EventArgs e)
{
if (rörelseÅtHöger)
{
mål.Flytta(5, 0);
for (int i = 0; i < antalSkott; i++)
{
if (skott[i] != null)
{
skott[i].Flytta(5, 0);
}
}
if (mål.X >= (bredd - mål.Radie))
{
rörelseÅtHöger = false;
}
}
else
{
mål.Flytta(-5, 0);
for (int i = 0; i < antalSkott; i++)
{
if (skott[i] != null)
{
skott[i].Flytta(-5, 0);
}
}
if ((mål.X - mål.Radie) <= 0)
{
rörelseÅtHöger = true;
}
}
tabPageSpel.Invalidate();
}
private void tabPageSpel_MouseMove(object sender, MouseEventArgs e)
{
base.OnMouseMove(e);
if (chkMus.Checked == true && kontrollvärde == true)
{
sikte.X = e.X;
sikte.Y = e.Y;
tabPageSpel.Invalidate();
}
}
private void tabPageSpel_MouseUp(object sender, MouseEventArgs e)
{
if (chkMus.Checked == true && kontrollvärde == true)
{
base.OnMouseUp(e);
if (antalSkott < (int.Parse(tbxAntalSkott.Text) - 1))
{
if (chkSmallSkott.Checked == true)
{
skott[antalSkott++] = new Skott(e.X, e.Y, 5);
lblAntalSkott.Text = (int.Parse(tbxAntalSkott.Text) - antalSkott).ToString();
tabPageSpel.Invalidate();
}
if (chkMediumSkott.Checked == true)
{
skott[antalSkott++] = new Skott(e.X, e.Y, 10);
lblAntalSkott.Text = (int.Parse(tbxAntalSkott.Text) - antalSkott).ToString();
tabPageSpel.Invalidate();
}
if (chkLargeSkott.Checked == true)
{
skott[antalSkott++] = new Skott(e.X, e.Y, 15);
lblAntalSkott.Text = (int.Parse(tbxAntalSkott.Text) - antalSkott).ToString();
tabPageSpel.Invalidate();
}
}
else
{
lblAntalSkott.Text = "Pilarna är slut";
btnSpelaIgen.Enabled = true;
btnAvbryt.Enabled = false;
}
}
}
}
Måltavla.cs
internal class Måltavla
{
//Medlemsdata
private int x = 0;
private int y = 0;
private int radie = 0;
//Konstruktor
public Måltavla(int x, int y, int r)
{
this.X = x;
this.Y = y;
this.Radie = r;
}
//Egenskaper
public int X
{
get
{
return x;
}
set
{
x = value;
}
}
public int Y
{
get
{
return y;
}
set
{
y = value;
}
}
public int Radie
{
get
{
return radie;
}
set
{
if (value > 0)
{
radie = value;
}
else
{
radie = -value;
}
}
}
public Point Position
{
get
{
return new Point(x, y);
}
set
{
x = value.X;
y = value.Y;
}
}
public void Flytta(int dx, int dy)
{
x = x + dx;
y = y + dy;
}
//Metoder
public void Rita(Graphics g)
{
int r = radie;
g.DrawEllipse(Pens.Black, x - r, y - r, r * 2, r * 2);
g.FillEllipse(Brushes.Black, x - r, y - r, r * 2, r * 2);
r = (int)(radie * 0.833);
g.FillEllipse(Brushes.White, x - r, y - r, r * 2, r * 2);
r = (int)(radie * 0.666);
g.FillEllipse(Brushes.Black, x - r, y - r, r * 2, r * 2);
r = (int)(radie * 0.499);
g.FillEllipse(Brushes.White, x - r, y - r, r * 2, r * 2);
r = (int)(radie * 0.333);
g.FillEllipse(Brushes.Black, x - r, y - r, r * 2, r * 2);
r = (int)(radie * 0.166);
g.FillEllipse(Brushes.Red, x - r, y - r, r * 2, r * 2);
}
}
Sikte.cs
internal class Sikte
{
//Medlemsdata
private int x = 0;
private int y = 0;
private int radie = 0;
//Konstruktor
public Sikte(int x, int y, int r)
{
this.X = x;
this.Y = y;
this.Radie = r;
}
//Egenskaper
public int X
{
get
{
return x;
}
set
{
x = value;
}
}
public int Y
{
get
{
return y;
}
set
{
y = value;
}
}
public int Radie
{
get
{
return radie;
}
set
{
if (value > 0)
{
radie = value;
}
else
{
radie = -value;
}
}
}
public Point Position
{
get
{
return new Point(x, y);
}
set
{
x = value.X;
y = value.Y;
}
}
public void Flytta(int dx, int dy)
{
x = x + dx;
y = y + dy;
}
//Metoder
public void Rita(Graphics g)
{
int r = radie;
g.DrawEllipse(Pens.Green, x - r, y - r, r * 2, r * 2);
r = (int)(radie * 0.6);
g.DrawEllipse(Pens.Green, x - r, y - r, r * 2, r * 2);
r = (int)(radie * 0.4);
g.DrawLine(Pens.Green, x - (3 * r), y, x - r, y);
g.DrawLine(Pens.Green, x + (3 * r), y, x + r, y);
g.DrawLine(Pens.Green, x, y - (3 * r), x, y - r);
g.DrawLine(Pens.Green, x, y + (3 * r), x, y + r);
r = (int)(radie * 0.1);
g.DrawLine(Pens.Purple, x - r, y, x + r, y);
g.DrawLine(Pens.Purple, x, y - r, x, y + r);
}
}
Skott.cs
internal class Skott
{
//Medlemsdata
private int x = 0;
private int y = 0;
private int radie = 0;
//Konstruktor
public Skott(int x, int y, int r)
{
this.X = x;
this.Y = y;
this.Radie = r;
}
//Egenskaper
public int X
{
get
{
return x;
}
set
{
x = value;
}
}
public int Y
{
get
{
return y;
}
set
{
y = value;
}
}
public int Radie
{
get
{
return radie;
}
set
{
if (value > 0)
{
radie = value;
}
else
{
radie = -value;
}
}
}
public Point Position
{
get
{
return new Point(x, y);
}
set
{
x = value.X;
y = value.Y;
}
}
public void Flytta(int dx, int dy)
{
x = x + dx;
y = y + dy;
}
//Metoder
public void Rita(Graphics g)
{
int r = radie;
g.FillEllipse(Brushes.Yellow, x - r, y - r, r * 2, r * 2);
}
}
Först och främst! Bra kodat och kul att du gör det. Jag har ju hjälpt dig med flimrandet, men du har kommit långt sedan dess.
Några snabba synpunkter, som du får fundera på och göra vad du vill med. Det är din kod, som du kan, inte min.
Fundera på om Skott[] är rätt typ. Skulle det göra sig bättre med en List<Skott>? En lista kan ta "obegränsat" med element, medan en array sätts till en maxlängd.
Skulle din måltavla kunna hålla alla skjutna skott, istället för att Form1 gör det?
- Måltavlan har ju koll på hur stor den är och alltså hur mycket en träff är värd.
- Då skulle den kunna rita upp skotten när dess metod Rita() anropas: mål.Rita(e.Graphics)
Skulle Skott kunna hålla information om dess poäng?
- Kanske kan den räknas ut när du skapar objektet? I det läget vet du var man siktat.
- Eller så räknas det ut när man lägger det till måltavlans lista över skott (som jag funderade på ovan).
Jag hittar ett tiotal anrop till int.Parse(tbxAntalSkott.Text). Du kommer ju att få exakt samma svar varje gång, så länge inte innehållet ändras. Skulle det inte vara enklare att köra ett enda anrop till int.Parse(), men enbart antalet skott ändras?
- Det gör du väl redan för att kontrollera att man matat in något rimligt. Spara ditt värde då istället för att slänga det.
Duplicera inte kod, är en bra regel. Du har fyra kopior av den här. Den enda skillnaden är vad du skickar in i Flytta().
- Vad tror du om en metod typ den här: void FlyttaSikte(int dX, int dY)
private void btnUpp_Click(object sender, EventArgs e)
{
//Flytta siktet upp
if (chkKnapp.Checked == true)
{
sikte.Flytta(0, -5);
tabPageSpel.Invalidate();
}
}
Du har även två stora metoder chkMus_CheckedChanged och chkKnapp_CheckedChanged. Jag är övertygad om att det räcker med en enda som de anropar.
Det är lätt att glömma att ändra i alla kopior när man fixar en bugg. Därför duplicerar man inte kod i onödan.
När en metod börjar bli så lång att man inte ser den på skärmen utan att scrolla en massa, kan det vara ett tecken på att den innehåller alldeles för mycket. Det finns en princip "single responsibility" som säger att varje klass/metod skall vara ansvarig för en enda sak. Om man splittar upp koden i flera olika metoder, så ökar chansen att de går att återanvända. Däremot skall man ju inte gå till överdrift.
Är du med på att den extra rad jag skrivit här gör samma sak som dina?
//Om checkbox för muskontroll är ikryssad så ska checkbox för knappkontroll vara okryssad och vice versa
if (chkMus.Checked == true)
{
chkKnapp.Checked = false;
}
else
{
chkKnapp.Checked = true;
}
// Denna kod gör samma sak:
chkKnapp.Checked = !chkMus.Checked;