C# XNA - Hjälp mig få dessa sprites att åka i en perfekt diagonal bana!

Permalänk
Medlem

C# XNA - Hjälp mig få dessa sprites att åka i en perfekt diagonal bana!

Behöver lite hjälp med mitt Blackjack spel då jag har fastnat lite. Det som jag har problem med är att få korten att åka från kortleken som är deras ursprungliga position till spelarens hand när spelaren drar ett kort. Här är den koden jag har just nu för att flytta ett kort från kortleken till spelarens hand:

if (card.Position == deck.Position) card.CardsPlaceInHand = new Vector2(clientBounds.Width / 2 - 100 + 17 * Hand.IndexOf(card), clientBounds.Height / 2 + cardPositionY); //Ger kortet dess mål som den ska åka till. if (card.Position.X > card.CardsPlaceInHand.X) card.Position = new Vector2(card.Position.X - 50, card.Position.Y); if (card.Position.X < card.CardsPlaceInHand.X) card.Position = new Vector2(card.Position.X + 50, card.Position.Y); if (card.Position.Y > card.CardsPlaceInHand.Y) card.Position = new Vector2(card.Position.X, card.Position.Y - 50); if (card.Position.Y < card.CardsPlaceInHand.Y) card.Position = new Vector2(card.Position.X, card.Position.Y + 50); if (Vector2.Distance(card.Position, card.CardsPlaceInHand) < 100) card.Position = card.CardsPlaceInHand; //Utan denna rad hamnar korten aldrig riktigt perfekt.

Så här åker korten just nu med koden ovan:

Så här vill jag att de ska åka:

Vore väldigt tacksam om någon kan säga hur jag kan ändra koden för att få korten att åka i en perfekt diagonal bana till handen!
Och säg till om jag varit otydlig på något sätt.

Permalänk
Medlem

Nu har jag aldrig riktigt rört XNA eller spelprogrammering alls, men det kan inte va så att flytta positionen med +-50 (om jag nu inte läser något fel) är för mycket? Ser det bättre ut om du ändrar det till 5 eller 10 istället?

Edit: Det ser ut som det är längre vågrätt än lodrätt att färdas, så för att få en perfekt diagonal kan du nog inte flytta både X och Y med samma värde.

Permalänk
Medlem
Skrivet av blakkz:

Nu har jag aldrig riktigt rört XNA eller spelprogrammering alls, men det kan inte va så att flytta positionen med +-50 (om jag nu inte läser något fel) är för mycket? Ser det bättre ut om du ändrar det till 5 eller 10 istället?

5 eller 10 blir alldeles för långsamt (korten kryper fram). +50 i position per frame är en hastighet som jag tycker blir ganska bra.

Permalänk
Medlem
Skrivet av Murloc:

5 eller 10 blir alldeles för långsamt (korten kryper fram). +50 i position per frame är en hastighet som jag tycker blir ganska bra.

Jo, tänkte nog lite fel, vet inte om du såg min edit.
Testa att flytta Y(tror jag det blir) med 25 varje gång och X med 50, eller vad för värden som nu kan bli bra, allra helst skulle man väl på nått vis räkna ut avstånden och sedan räkna efter det.

Permalänk
Medlem
Skrivet av blakkz:

Jo, tänkte nog lite fel, vet inte om du såg min edit.
Testa att flytta Y(tror jag det blir) med 25 varje gång och X med 50, eller vad för värden som nu kan bli bra, allra helst skulle man väl på nått vis räkna ut avstånden och sedan räkna efter det.

Hur kunde jag inte se att jag bara behövde sänka flyttningen i Y-led för att det skulle gå rakt? Skyller på trötthet (sent på kvällen)

Permalänk
Medlem
Skrivet av Murloc:

Behöver lite hjälp med mitt Blackjack spel då jag har fastnat lite. Det som jag har problem med är att få korten att åka från kortleken som är deras ursprungliga position till spelarens hand när spelaren drar ett kort. Här är den koden jag har just nu för att flytta ett kort från kortleken till spelarens hand:

if (card.Position == deck.Position) card.CardsPlaceInHand = new Vector2(clientBounds.Width / 2 - 100 + 17 * Hand.IndexOf(card), clientBounds.Height / 2 + cardPositionY); //Ger kortet dess mål som den ska åka till. if (card.Position.X > card.CardsPlaceInHand.X) card.Position = new Vector2(card.Position.X - 50, card.Position.Y); if (card.Position.X < card.CardsPlaceInHand.X) card.Position = new Vector2(card.Position.X + 50, card.Position.Y); if (card.Position.Y > card.CardsPlaceInHand.Y) card.Position = new Vector2(card.Position.X, card.Position.Y - 50); if (card.Position.Y < card.CardsPlaceInHand.Y) card.Position = new Vector2(card.Position.X, card.Position.Y + 50); if (Vector2.Distance(card.Position, card.CardsPlaceInHand) < 100) card.Position = card.CardsPlaceInHand; //Utan denna rad hamnar korten aldrig riktigt perfekt.

Så här åker korten just nu med koden ovan:
http://forumbilder.se/images/a44201211320716b1.jpg

Så här vill jag att de ska åka:
http://forumbilder.se/images/ab420121132472dae.jpg

Vore väldigt tacksam om någon kan säga hur jag kan ändra koden för att få korten att åka i en perfekt diagonal bana till handen!
Och säg till om jag varit otydlig på något sätt.

Ok, det börjar bli sent (eller tidigt beroende på hur man ser det).
Det enklaste / mest matematiskt korrekta måste väl vara att skapa en ny vektor som pekar i samma riktning som din raka pil i bild 2. Sen i varje update adderar du vektorn till positionen på det kortet som ska flyttas. För att justera hur fort kortet ska flyttas ändrar du bara längden på vektorn.

Kan ju även rekommendera dig i att köpa en bok om C# och även Xna, då du verkar ha många frågor om ämnet. Finns mycket bra att välja mellan och finns även många bra tutorials på nätet :).

Skickades från m.sweclockers.com

Permalänk
Medlem
Skrivet av Mempatch:

Ok, det börjar bli sent (eller tidigt beroende på hur man ser det).
Det enklaste / mest matematiskt korrekta måste väl vara att skapa en ny vektor som pekar i samma riktning som din raka pil i bild 2. Sen i varje update adderar du vektorn till positionen på det kortet som ska flyttas. För att justera hur fort kortet ska flyttas ändrar du bara längden på vektorn.

Kan ju även rekommendera dig i att köpa en bok om C# och även Xna, då du verkar ha många frågor om ämnet. Finns mycket bra att välja mellan och finns även många bra tutorials på nätet :).

Skickades från m.sweclockers.com

Tänkte exakt samma sak.
Då man vet positionerna för var kortet ska hamna, och var det kommer ifrån, är det riktigt enkelt att räka ut det. Linjär Algebra FTW.

Permalänk
Medlem
Skrivet av Mempatch:

Ok, det börjar bli sent (eller tidigt beroende på hur man ser det).
Det enklaste / mest matematiskt korrekta måste väl vara att skapa en ny vektor som pekar i samma riktning som din raka pil i bild 2. Sen i varje update adderar du vektorn till positionen på det kortet som ska flyttas. För att justera hur fort kortet ska flyttas ändrar du bara längden på vektorn.

Kan ju även rekommendera dig i att köpa en bok om C# och även Xna, då du verkar ha många frågor om ämnet. Finns mycket bra att välja mellan och finns även många bra tutorials på nätet :).

Skickades från m.sweclockers.com

Skrivet av NickoB:

Tänkte exakt samma sak.
Då man vet positionerna för var kortet ska hamna, och var det kommer ifrån, är det riktigt enkelt att räka ut det. Linjär Algebra FTW.

Jo det är nog jättebra och lätt att göra det om man nu har studerat linjär algebra vilket jag inte har, ni kanske skulle kunna visa med kod hur jag gör så kan jag lära mig något nyttigt

Permalänk
Medlem

Säg att kortets start-position på X-axeln är x_start och dess slut-position är x_slut. Skillnaden x_diff blir då x_start - x_slut. Om du bara adderar x_diff till x_start så får du då direkt x_slut. För att få kortet att röra sig saktare så kan du dela upp x_diff i små delar och lägga till dem en efter en till x_start. Så för att få kortet att ta N steg innan det är framme så adderar du bara x_diff / N till x_start N gånger.

Men det är inte säkert att du kan lagra x_diff / N exakt, vilket kan orsaka att du får ett litet fel vid varje addition. Detta kan orsaka att kortet inte hamnar exakt där du vill. Du kan istället använda formeln x_pos = x_start + p * x_diff, och låta p gå från 0 till 1 så snabbt som du önskar. Dvs. du utgår ifrån start-positionen och lägger till en viss procent av x_diff till den. När p är 0 så får du start-positionen, och när p är 1 så lägger du till hela x_diff och får slut-positionen.

Rörelsen längs Y-axeln hanteras sedan på samma sätt.

Permalänk
Medlem
Skrivet av perost:

Säg att kortets start-position på X-axeln är x_start och dess slut-position är x_slut. Skillnaden x_diff blir då x_start - x_slut. Om du bara adderar x_diff till x_start så får du då direkt x_slut. För att få kortet att röra sig saktare så kan du dela upp x_diff i små delar och lägga till dem en efter en till x_start. Så för att få kortet att ta N steg innan det är framme så adderar du bara x_diff / N till x_start N gånger.

Men det är inte säkert att du kan lagra x_diff / N exakt, vilket kan orsaka att du får ett litet fel vid varje addition. Detta kan orsaka att kortet inte hamnar exakt där du vill. Du kan istället använda formeln x_pos = x_start + p * x_diff, och låta p gå från 0 till 1 så snabbt som du önskar. Dvs. du utgår ifrån start-positionen och lägger till en viss procent av x_diff till den. När p är 0 så får du start-positionen, och när p är 1 så lägger du till hela x_diff och får slut-positionen.

Rörelsen längs Y-axeln hanteras sedan på samma sätt.

Tack så mycket det var en bra förklaring (förutom att det skulle vara x_slut - x_start och inte tvärtom), nu ser koden för att flytta korten ut så här:

card.Position = new Vector2(card.Position.X + (card.CardsPlaceInHand.X - deck.Position.X)/10, card.Position.Y + (card.CardsPlaceInHand.Y - deck.Position.Y)/10);

Det funkar hur bra som helst

Och denna rad kod löser ju det där med att korten inte garanterat hamnar exakt där jag vill:

if (Vector2.Distance(card.Position, card.CardsPlaceInHand) < 10) card.Position = card.CardsPlaceInHand;

Permalänk
Medlem

Om man inte har några förkunskaper i Linjär Algebra, så skulle jag väl först visa hur man räknar (manuellt).
De två platserna du har korten på, kan vi säga är punkter.
En punkt har ett x och y värde, detta skrivs som (x, y). Säg Kortets startplats ligger på x=400, och y=100. Detta skrivs då som (400, 100) [vi kallar den för p1].
Punkten där kortet ska placeras, har x och y koordinaten (100, 500) [vi kallar den för p2].

Nu då så har vi:
p1 = (400, 100)
p2 = (100, 500)

För att räkna, hur kortet ska röra sej från p1 till p2, så skapar vi en så kallad vektor (kan även säga rörelsevektor).
Denna vektor, används så om vi tar och adderar p1 med denna vektorn, så får vi p2. Formeln för att räkna ut detta är:
Rörelsevektorn = p2 - p1

Hur räknar vi p2 - p1. Jo, vi tar p2.x - p1.x, för att få x värdet. Och p2.x - p1.x, för att få y värdet. Så här skrivs det:
rörelsevektorn = (p2x - p1x, p2y - p1y)
RV = (100 - 400, 500 - 100)
RV = (-300, 400)
(tips, addition med en punkt/vektor fungerar likadant, multiplikation och division annorlunda).

Om du nu skulle ta och addera p1 med RV, så skulle du få direkt p2. Men då du vill att kortet ska "röra" sej i steg, så vill vi att RV ska vara mindre. Här kommer multiplikation och division in.
RV * 1 = RV
RV * 2 = 2RV (enkelt eller hur)
Hur fungerar då detta. Jo, det som RV multipliceras med kallas för en skalär. Och vid denna multiplikationen/divisionen så multiplicerar/dividerar du RV.x och RV.y med samma skalär. Så säg skalären är 1/2, då får vi:
RV.x = -300 * 1/2 = -150
RV.y = 400 * 1/2 = 200

Eller så kan vi skriva såhär:
RV/2 = (-300/2, 400/2) = (-150, 200)

Så, 1/2 * RV = (-150, 200).

Detta är ändå väldigt grundligt.
Men detta är vektor algebra, och används hela tiden i spelprogrammering. Då du inte har utbildats i Linjär Algebra, så rekommenderar jag dej starkt att köpa en bok i detta. Du kan klara utan det i 2D spel (men det kommer inte vara lätt), men då du går in i 3D, så kommer du verkligen behöva kunna din Linjära Algebra.

Att tänka och använda vektor algebra i din spelprogrammering, kommer underlätta för dej. Ex. säg du skapar ett spel med en gubbe som rör sej. Då kan man köra med att gubben har en punk som säger dess position, samt en vektor som säger var gubben rör sej. Många spelbibliotek har sedan färdiga operatorer för denna form av uträkning, men man behöver ändå känna till hur det fungerar (speciellt om det inte går automatiskt).

Men nu då så kan du utföra dina beräkningar.
p1 är där ditt kort finns just nu på skärmen.
p2 är dit du vill att ditt kort ska hamna.
RV räknar du ut genom p2 - p1.
Sedan får du ta fram en egen variabel, som används för hur snabbt du vill att kortet ska röra sej från p1 till p2. Sedan tar du och dividerar RV med denna skalär.
Sist, vid varje update(), så tar du bara kortets punkt + nyaRV. Och sedan ritar detta.

Hur du gör detta i koden tycker jag du ska fundera på lite själv. Se det som en bra tankeövning.
Men först, prova att räkna detta på papper, så du förstår hur detta ska kunna lösas i koden.

Permalänk
Medlem
Skrivet av Murloc:

Jo det är nog jättebra och lätt att göra det om man nu har studerat linjär algebra vilket jag inte har, ni kanske skulle kunna visa med kod hur jag gör så kan jag lära mig något nyttigt

Skrivet av NickoB:

Om man inte har några förkunskaper i Linjär Algebra, så skulle jag väl först visa hur man räknar (manuellt).
De två platserna du har korten på, kan vi säga är punkter.
En punkt har ett x och y värde, detta skrivs som (x, y). Säg Kortets startplats ligger på x=400, och y=100. Detta skrivs då som (400, 100) [vi kallar den för p1].
Punkten där kortet ska placeras, har x och y koordinaten (100, 500) [vi kallar den för p2].

Nu då så har vi:
p1 = (400, 100)
p2 = (100, 500)

För att räkna, hur kortet ska röra sej från p1 till p2, så skapar vi en så kallad vektor (kan även säga rörelsevektor).
Denna vektor, används så om vi tar och adderar p1 med denna vektorn, så får vi p2. Formeln för att räkna ut detta är:
Rörelsevektorn = p2 - p1

Hur räknar vi p2 - p1. Jo, vi tar p2.x - p1.x, för att få x värdet. Och p2.x - p1.x, för att få y värdet. Så här skrivs det:
rörelsevektorn = (p2x - p1x, p2y - p1y)
RV = (100 - 400, 500 - 100)
RV = (-300, 400)
(tips, addition med en punkt/vektor fungerar likadant, multiplikation och division annorlunda).

Om du nu skulle ta och addera p1 med RV, så skulle du få direkt p2. Men då du vill att kortet ska "röra" sej i steg, så vill vi att RV ska vara mindre. Här kommer multiplikation och division in.
RV * 1 = RV
RV * 2 = 2RV (enkelt eller hur)
Hur fungerar då detta. Jo, det som RV multipliceras med kallas för en skalär. Och vid denna multiplikationen/divisionen så multiplicerar/dividerar du RV.x och RV.y med samma skalär. Så säg skalären är 1/2, då får vi:
RV.x = -300 * 1/2 = -150
RV.y = 400 * 1/2 = 200

Eller så kan vi skriva såhär:
RV/2 = (-300/2, 400/2) = (-150, 200)

Så, 1/2 * RV = (-150, 200).

Detta är ändå väldigt grundligt.
Men detta är vektor algebra, och används hela tiden i spelprogrammering. Då du inte har utbildats i Linjär Algebra, så rekommenderar jag dej starkt att köpa en bok i detta. Du kan klara utan det i 2D spel (men det kommer inte vara lätt), men då du går in i 3D, så kommer du verkligen behöva kunna din Linjära Algebra.

Att tänka och använda vektor algebra i din spelprogrammering, kommer underlätta för dej. Ex. säg du skapar ett spel med en gubbe som rör sej. Då kan man köra med att gubben har en punk som säger dess position, samt en vektor som säger var gubben rör sej. Många spelbibliotek har sedan färdiga operatorer för denna form av uträkning, men man behöver ändå känna till hur det fungerar (speciellt om det inte går automatiskt).

Men nu då så kan du utföra dina beräkningar.
p1 är där ditt kort finns just nu på skärmen.
p2 är dit du vill att ditt kort ska hamna.
RV räknar du ut genom p2 - p1.
Sedan får du ta fram en egen variabel, som används för hur snabbt du vill att kortet ska röra sej från p1 till p2. Sedan tar du och dividerar RV med denna skalär.
Sist, vid varje update(), så tar du bara kortets punkt + nyaRV. Och sedan ritar detta.

Hur du gör detta i koden tycker jag du ska fundera på lite själv. Se det som en bra tankeövning.
Men först, prova att räkna detta på papper, så du förstår hur detta ska kunna lösas i koden.

Något som dessutom kan vara bra är att normalisera riktningsvektorn innan du börjar utföra beräkningar med den, dvs. sätt dess längd till 1. Vector2 har en färdig metod som kirrar detta. Det är imo enklare att jobba med en normaliserad riktningsvektor, då man får ett bra utgångsläge. Sen är det bara att multiplicera på. 0.5*RV halverar farten, 2*RV dubblerar den osv. osv.

När det kommer till att räkna med vektorer så är papper och penna din bästa vän. Du får en så mycket bättre överblick över vad du gör och kan i många fall direkt se saker som kanske inte är lika öppenbara om man bara sitter med siffror framför sig.

Permalänk
Medlem
Skrivet av Mempatch:

Något som dessutom kan vara bra är att normalisera riktningsvektorn innan du börjar utföra beräkningar med den, dvs. sätt dess längd till 1. Vector2 har en färdig metod som kirrar detta. Det är imo enklare att jobba med en normaliserad riktningsvektor, då man får ett bra utgångsläge. Sen är det bara att multiplicera på. 0.5*RV halverar farten, 2*RV dubblerar den osv. osv.

När det kommer till att räkna med vektorer så är papper och penna din bästa vän. Du får en så mycket bättre överblick över vad du gör och kan i många fall direkt se saker som kanske inte är lika öppenbara om man bara sitter med siffror framför sig.

Tyckte att normalisera riktningsvektorn va lite "överkurs", med tanke på att han inte hade studerat Linjär Algebra tidigare.
Men det är bra att du nämnde det.
Om det låter intressant med att normalisera riktningsvektorn, så utförs det ganska lätt.

Enhetsvektorn för RV får man ut genom följande formel:
RVN = RV * 1/|RV|

Och nu då, va står |RV| för? Jo, det är längden av vektorn RV, även känt som absolutbeloppet, vilket är en skalär (dvs. inte en punkt eller vektor).
|RV|² = RV * RV
|RV|² = RV.x² + RV.y²
|RV| = √(RV.x² + RV.y²)

Detta är i 2 dimensioner. Men skulle det vara i 3 dimensioner (eller mer) så blir formeln:

OBS! I bilden står det nedhöjda tecknet bredvid x:en för vilket värde man använder, dvs. 1 => x, 2 => y, 3 => z, osv. Då denna formel fungerar utöver bara 2D och 3D grafik, och är enklare att representera på detta sättet. Du kan läsa mer här.

Om man fått den korrekta enhetsvektorn av RV, så kommer absolutbeloppet (|RVN|) vara 1.

Permalänk
Medlem
Skrivet av NickoB:

Tyckte att normalisera riktningsvektorn va lite "överkurs", med tanke på att han inte hade studerat Linjär Algebra tidigare.
Men det är bra att du nämnde det.
Om det låter intressant med att normalisera riktningsvektorn, så utförs det ganska lätt.

Enhetsvektorn för RV får man ut genom följande formel:
RVN = RV * 1/|RV|

Och nu då, va står |RV| för? Jo, det är längden av vektorn RV, även känt som absolutbeloppet, vilket är en skalär (dvs. inte en punkt eller vektor).
|RV|² = RV * RV
|RV|² = RV.x² + RV.y²
|RV| = √(RV.x² + RV.y²)

Detta är i 2 dimensioner. Men skulle det vara i 3 dimensioner (eller mer) så blir formeln:
http://upload.wikimedia.org/wikipedia/sv/math/4/9/b/49b7bd3b5...

OBS! I bilden står det nedhöjda tecknet bredvid x:en för vilket värde man använder, dvs. 1 => x, 2 => y, 3 => z, osv. Då denna formel fungerar utöver bara 2D och 3D grafik, och är enklare att representera på detta sättet. Du kan läsa mer här.

Om man fått den korrekta enhetsvektorn av RV, så kommer absolutbeloppet (|RVN|) vara 1.

Som jag sa så finns det en Normalize() -metod i Vector2 så det är ganska enkelt att glra det i xna. Tänkte inte heller tvinga han/hon att gräva sig djupare i det :).

Skickades från m.sweclockers.com

Permalänk
Medlem
Skrivet av Mempatch:

Som jag sa så finns det en Normalize() -metod i Vector2 så det är ganska enkelt att glra det i xna. Tänkte inte heller tvinga han/hon att gräva sig djupare i det :).

Skickades från m.sweclockers.com

Däremot finns det kanske inte i alla andra språk/bibliotek.
Men sen är det också bra att veta vad Normalize() metoden gör för något.

Permalänk
Medlem
Skrivet av NickoB:

Däremot finns det kanske inte i alla andra språk/bibliotek.
Men sen är det också bra att veta vad Normalize() metoden gör för något.

Jajo, men lite måste ju sparas till vektoralgebra-kursen

Permalänk
Medlem
Skrivet av Mempatch:

Jajo, men lite måste ju sparas till vektoralgebra-kursen

Hehe, nejdå. Värsta som finns för en mattelärare, är en elev som redan kan matten