Velena Skrevet 18. oktober 2008 Del Skrevet 18. oktober 2008 OK, har nå hatt dette problemet ganske lenge uten ha funnet en løsning. Situasjonen: Jeg holder på med et TopDown RPG i 2D, hvor spilleren skal kunne bevege seg i åtte himmelretninger. Spilleren må selvsagt ikke kunne gå igjennom de hindringer som er på "banen", og jeg trenger derfor hittesting. Dette er så langt jeg har kommet: //Import [DllImport("user32")] public static extern int IntersectRect(ref RECT lpDestRect, ref RECT lpSrc1Rect, ref RECT lpSrc2Rect); ...... ....... public static void HittestPlayer(Form world, Rectangle[] obstacles, int numOfObstacles,ref Rectangle Player, int playerDir) { // Hittesting av de ytre grensene på "Banen". if (Player.Location.Y < 53)// 53 = StatusPanel.Height ( Statuspanelet befinner seg på toppen av banen) Player.Y = 53; else if (Player.Location.Y + Player.Size.Height > world.Height) Player.Y = world.Height - Player.Size.Height; if (Player.Location.X < 0) Player.X = 0; else if (Player.Location.X + Player.Size.Width > world.Width) Player.X = world.Width - Player.Size.Width; //Hittestingen av hindringene RECT dest = new RECT(); RECT playerRECT = new RECT(); RECT obstacleRECT = new RECT(); playerRECT.Top = Player.Y; playerRECT.Left = Player.X; playerRECT.Bottom = Player.Y + Player.Height; playerRECT.Right = Player.X + Player.Width; for (int i = 0; i<numOfObstacles;i++) { obstacleRECT.Top = obstacles[i].Y; obstacleRECT.Left = obstacles[i].X; obstacleRECT.Bottom = obstacles[i].Y + obstacles[i].Height; obstacleRECT.Right = obstacles[i].X + obstacles[i].Width; IntersectRect(ref dest,ref playerRECT,ref obstacleRECT); if (dest.Top != 0 && dest.Bottom != 0) { // 1= N 2=S W=3 E=4 NW=5 SW=6 NE=7 SE=8 switch (playerDir) { case 1: Player.Y = obstacles[i].Location.Y + obstacles[i].Size.Height; break; case 2: Player.Y = obstacles[i].Location.Y -Player.Height; break; case 3: Player.X = obstacles[i].Location.X + obstacles[i].Size.Width; break; case 4: Player.X = obstacles[i].Location.X -Player.Size.Width; break; case 5:// Her starter problemene break; case 6: break; case 7: break; case 8: break; } } } } Koden ovenfor virker forsåvidt, men om spilleren beveger seg diagonalt vil han selvsagt gå rett igjennom hindringene. Grunnen til at jeg ikke har lagt til noe i case 5-8, er at jeg ikke vet hvordan jeg skal skille mellom horisontal og vertikal kollisjon mellom spilleren og hindringene, noe som gjør det umulig å sette spillerposisjonen riktig. Vet noen hvordan jeg kan gjøre dette, eller har råd/forslag vil jeg veldig gjerne høre dem. Lenke til kommentar
GeirGrusom Skrevet 18. oktober 2008 Del Skrevet 18. oktober 2008 Du er klar over at det finnes en Rectangle.Intersects og Rectangle.Contains funksjon? Jeg ville ihvertfall bare sjekket hva som er på neste posisjonen spilleren prøver å bevege seg i, og dersom det er noe i f.eks. Y retning, så hindrer du bare spilleren i å bevege seg i den retningen. Lenke til kommentar
Velena Skrevet 19. oktober 2008 Forfatter Del Skrevet 19. oktober 2008 (endret) Har nå prøvd det som du sa GeirGrusom, men denne koden virker overhodet ikke av en eller annen grunn: public enum Direction { None = 0; North = 1, South = 2, West = 4, East = 8, NorthWest = North | West, SouthWest = South | West, NorthEast = North | East, SouthEast = South | East } public static void MovePlayer(ref List<Rectangle> Player, int walkingSpeed,int runningSpeed,List<Rectangle> obstacles,int numOfObstacles, ref Direction playerDir, bool hittestObstacles ) {// 1= N 2=S W=3 E=4 NW=5 SW=6 NE=7 SE=8 int YSpeed; int XSpeed; if (High(GetKeyState((int)Keys.Space)) == 1) { YSpeed = runningSpeed; XSpeed = runningSpeed; } else { YSpeed = walkingSpeed; XSpeed = walkingSpeed; } if (hittestObstacles) { foreach (Rectangle obstacle in obstacles) { if (obstacle.X < Player.Right+XSpeed && obstacle.right > Player.X-XSpeed) { if (Player.Right <= obstacle.X) { XSpeed = obstacle.X - Player.Right; } else if (Player.X >= obstacle.Right) )// Hvis spilleren ikke kolliderer før han beveger seg ( Fra høyre mot venstre) { XSpeed = Player.X - obstacle.Right; } else {} } if (obstacle.Y < Player:Bottom && obstacle.Bottom > Player.Y) { if (Player.Bottom <= obstacle.Y) { YSpeed = obstacles[i].Y - Player.Bottom; } else if (Player.Y >= obstacle.Bottom ) { YSpeed = Player.Y - obstacle.Bottom; } else {} } } } playerDir = Direction.None; if (High(GetKeyState((int)Keys.W)) == 1) { Player.Y += -1 * YSpeed; playerDir = Direction.North; } if (High(GetKeyState((int)Keys.S)) == 1) { Player.Y += YSpeed; playerDir = Direction.South; } if (High(GetKeyState((int)Keys.A)) == 1) { Player.X += -1 * XSpeed; if (playerDir == Direction.North) playerDir = Direction.NorthWest; else if (playerDir == Direction.South) playerDir = Direction.SouthWest; else playerDir = Direction.West; } if (High(GetKeyState((int)Keys.D)) == 1) { Player.X += XSpeed; if (playerDir == Direction.North) playerDir = Direction.NorthEast; else if (playerDir == Direction.South) playerDir = Direction.SouthEast; else playerDir = Direction.East; } } Hva er det jeg gjør galt? Edit: Visste forresten ikke om Rectangle.Intersect, takk for tipset =). Endret 19. oktober 2008 av Velena Lenke til kommentar
GeirGrusom Skrevet 19. oktober 2008 Del Skrevet 19. oktober 2008 (endret) Vel, du burde ikke flytte spilleren før du vet at det er trygt å flytte den dit, ellers får du en "spretteffekt" hvor spilleren spretter imellom mulige posisjoner, som kan sees på som ugunstig. Dessuten kan det føre til at spilleren setter seg lett fast i hinder. edit: Så du burde prøve å regne ut neste posisjon, gi den til en funksjon som deretter sier hvor langt det var mulig å flytte spilleren (ved å for eksempel returnere en gyldig posisjon) Endret 19. oktober 2008 av GeirGrusom Lenke til kommentar
Velena Skrevet 19. oktober 2008 Forfatter Del Skrevet 19. oktober 2008 Vel, du burde ikke flytte spilleren før du vet at det er trygt å flytte den dit, ellers får du en "spretteffekt" hvor spilleren spretter imellom mulige posisjoner, som kan sees på som ugunstig. Men det gjør jeg da jo heller ikke? Koden var ment å sjekke om spilleren kolliderer i noe hvis han/hun beveger seg, og hvis han/hun gjorde det, trekke ifra avstanden som spilleren kolliderer med fra farten spilleren har i kollisjonsretningen. edit:Så du burde prøve å regne ut neste posisjon, gi den til en funksjon som deretter sier hvor langt det var mulig å flytte spilleren (ved å for eksempel returnere en gyldig posisjon) Som sagt er det dette koden var tiltenkt å gjøre ( bare i en og samme funksjon). Har jeg tenkt feil, ettersom du svarer slik? Lenke til kommentar
GeirGrusom Skrevet 19. oktober 2008 Del Skrevet 19. oktober 2008 (endret) Nei, sikkert ikke, bare jeg som ikke leste godt nok igjennom. Det ser nogenlunde riktig ut, men koden kan være enklere å få oversikt over dersom du deler den opp i flere funksjoner, og rett og slett gjør koden mindre, da kan det bli enklere å se hva du gjør feil. 1: Bruk List<Rectangle> fremfor Rectangle[] på grunn av effektivitet 2: Bruk foreach(Rectangle rect in Obstacles) fordi du slipper Array operatøren i hver forbanna linje med kode 3: Bruk Rectangle.Bottom (og Rectangle.Right) istedet for Rectangle.Y + Rectangle.Height fordi det gjør koden din enklere å lese, som igjen gir deg bedre mulighet til å få oversikt. 4: Lag gjerne en enumeration istedet for å deklarere verdier i en kommentar for retninger: public enum Direction { North = 1 South = 2, East = 4, West = 8, NorthEase = North | East, NorthWest = North | West, SouthEast = South | East, SouthWest = South | West } For å sjekke denne om bit er satt, bruker du & operatøren: Direction dir = Direction.NorthEast; if((dir & Direction.East) == Direction.East) (...) // East bit er satt if((dir & Direction.North) == Direction.North) (...) // North bit er satt Endret 19. oktober 2008 av GeirGrusom Lenke til kommentar
Bytex Skrevet 19. oktober 2008 Del Skrevet 19. oktober 2008 Ett spørsmål, vil piltastene fungere eller mappes det KUN opp til numpad 1-8? For jeg vet ikke om mange som spiller med keypad frivillig, hvertfall. Og isåfall, vil NE NW SE SW detekteres riktig hvis man trykker venstrepil+opp f.eks.? Lenke til kommentar
Velena Skrevet 19. oktober 2008 Forfatter Del Skrevet 19. oktober 2008 (endret) Bytex: Jeg bruker da ikke Numpaden i det hele tatt i koden min? Du styrer med WASD, og ja, hvis du trykker f.eks W + A vil spilleren bevege seg i Nord-vestlig retning. GierGrusom: Takker igjen for gode råd. To spørsmål: 1: Hvorfor er List mer effektiv enn Array? 2: Jeg vet fortsatt ikke hva som er galt . Edit: Ryddet på koden jeg postet tidligere. Endret 19. oktober 2008 av Velena Lenke til kommentar
BlueEAGLE Skrevet 19. oktober 2008 Del Skrevet 19. oktober 2008 Ikke at dette er et direkte svar på spørsmålet, men om du skal kunne bevege deg i åtte himmelretninger er det ikke da bedre å bruke oktagonale ruter fremfor firkantede? Lenke til kommentar
GeirGrusom Skrevet 19. oktober 2008 Del Skrevet 19. oktober 2008 Ikke at dette er et direkte svar på spørsmålet, men om du skal kunne bevege deg i åtte himmelretninger er det ikke da bedre å bruke oktagonale ruter fremfor firkantede? Godt poeng! men er ikke det litt mer komplisert en nødvendig for et program av denne sorten? Uansett angående arrays så må du nesten bare lese de tekniske artiklene rundt dette som er tilgjengelig på MSDN, det har noe med duplikate arrays og slikt å gjøre. Ok, litt av poenget med å bruke enumen fikk du ikke helt med deg hehe public enum Direction { None = 0; North = 1, South = 2, West = 4, East = 8, NorthWest = North | West, SouthWest = South | West, NorthEast = North | East, SouthEast = South | East } public static void MovePlayer(ref Rectangle Player, int walkingSpeed,int runningSpeed, List<Rectangle> obstacles, ref Direction playerDir, bool hittestObstacles ) { int YSpeed; int XSpeed; if (High(GetKeyState((int)Keys.Space)) == 1) { YSpeed = runningSpeed; XSpeed = runningSpeed; } else { YSpeed = walkingSpeed; XSpeed = walkingSpeed; } if (hittestObstacles) { foreach (Rectangle obstacle in obstacles) { if (obstacle.X < Player.Right+XSpeed && obstacle.right > Player.X-XSpeed) { if (Player.Right <= obstacle.X) XSpeed = obstacle.X - Player.Right; else if (Player.X >= obstacle.Right) XSpeed = Player.X - obstacle.Right; } if (obstacle.Y < Player.Bottom && obstacle.Bottom > Player.Y) { if (Player.Bottom <= obstacle.Y) YSpeed = obstacle.Y - Player.Bottom; else if (Player.Y >= obstacle.Bottom ) YSpeed = Player.Y - obstacle.Bottom; } } } playerDir = Direction.None; if (High(GetKeyState((int)Keys.W)) == 1) { Player.Y -= YSpeed; playerDir = Direction.North; } if (High(GetKeyState((int)Keys.S)) == 1) { Player.Y += YSpeed; playerDir = Direction.South; } if (High(GetKeyState((int)Keys.A)) == 1) { Player.X -= XSpeed; playerDir |= Direction.West; } if (High(GetKeyState((int)Keys.D)) == 1) { Player.X += XSpeed; playerDir |= Direction.East; } } Du må kanskje kjøre en (Player + (XSpeed, YSpeed).Intersect(obstacle) for ellers kan vel dette triggre så lenge spilleren foreksempel er i samme X posisjon, men ikke i Y posisjonen? Lenke til kommentar
Velena Skrevet 19. oktober 2008 Forfatter Del Skrevet 19. oktober 2008 Du må kanskje kjøre en (Player + (XSpeed, YSpeed).Intersect(obstacle) for ellers kan vel dette triggre så lenge spilleren foreksempel er i samme X posisjon, men ikke i Y posisjonen?Hva mener du med (Player + (XSpeed, YSpeed).Intersect(obstacle))? Mener du at jeg skal legge til posisjonen til Player med så mye som den kolliderer med? Dette virker ikke logisk, hvis f.eks spilleren er 2 enheter fra en obstacle, og vil kollidere med 3 enheter så vil han jo ende opp 1 enhet inne i hindringen. Lenke til kommentar
GeirGrusom Skrevet 19. oktober 2008 Del Skrevet 19. oktober 2008 Det jeg mente meddet var bare for å sjekke hvor brukeren ville flytte seg, ikke egentlig så veldig relevant til det jeg mente. Men hele idéen var at for hver hindring så må du først sjekke om hindringen faktisk intersecter der spilleren ville havnet før du sjekker om de krysser X eller Y aksene. Får håpe jeg er til hjelp da, og at jeg har lest koden korrekt :S jeg har en tendens til å få dårlig oversikt over andres kode. Lenke til kommentar
Bytex Skrevet 19. oktober 2008 Del Skrevet 19. oktober 2008 Uff, er det så vanskelig bare å få karen til å treffe items som er rundt på brettet, tør jeg ikke TENKE på hva slags atomrakettfysikk som skal til for å lage en hel 3d engine. Lenke til kommentar
GeirGrusom Skrevet 19. oktober 2008 Del Skrevet 19. oktober 2008 (endret) Det er verre når en skal drive mmed polygonkollisjon, da må en først sjekke om et annet polygon (forutsatt polygon-polygon kollisjon) først krysser planet til det andre polygonet, deretter må sjekke om en faktisk er innenfor plygonet, og alt må sjekkes om noen av kantene til det første polygonet treffer - mye jobb! Nå pleier ikke polygon-polygon å være det vanligste i simple motorer, oftere sjekker en med kuber, cylindere eller kuler krysser polygoner. Det enkleste er kule-kule kollisjon hvor det eneste som kreves er å kunne pythagoras' a2 + b2 = c2 men svært sjeldent noe en bruker. Endret 19. oktober 2008 av GeirGrusom Lenke til kommentar
Bytex Skrevet 19. oktober 2008 Del Skrevet 19. oktober 2008 Tør ikke tenke på hva som foregår i hodet til John Carmack engang.. Lenke til kommentar
GeirGrusom Skrevet 19. oktober 2008 Del Skrevet 19. oktober 2008 3D programmeringg synes jeg er veldig interessant fordi det krever at en har hodet med seg til enhver tid, særlig når en jobber med selve grafikkmotoren. Lenke til kommentar
Velena Skrevet 21. oktober 2008 Forfatter Del Skrevet 21. oktober 2008 Det virker nå sånn ca. Har bare et "lite" problem med at når jeg kolliderer i et hjørne vil spilleren noen ganger gi blaffen i det ene hinderet og gå rett i gjennom. Skal se litt mer på det idag. Lenke til kommentar
Svish Skrevet 23. oktober 2008 Del Skrevet 23. oktober 2008 @GeirGrusom: Må ikke den enum saken din være merket med [Flags]? Lenke til kommentar
GeirGrusom Skrevet 23. oktober 2008 Del Skrevet 23. oktober 2008 @GeirGrusom: Må ikke den enum saken din være merket med [Flags]? Nei, [Flags] betyr bare at dersom du ikke skriver eksplisitt =1, =2, =4, =8 etc. så vil enumen telle dette selv istedet for standarden som er =1, =2, =3, =4, =5... Lenke til kommentar
Svish Skrevet 23. oktober 2008 Del Skrevet 23. oktober 2008 (endret) FlagsAttribute Class Indicates that an enumeration can be treated as a bit field; that is, a set of flags. trodde det da var åpenbart at om en ikke hadde denne FlagsAttributen, så kunne en ikke "treate it as a bit field"? http://msdn.microsoft.com/en-us/library/sy...sattribute.aspx. men jeg har tatt feil før jeg, så tar det ikke tungt om jeg har trodd feil om den nummererer selv 1, 2, 4, 8 osv, så er jo det strålende da... må jeg teste ut en dag Endret 23. oktober 2008 av Svish Lenke til kommentar
Anbefalte innlegg
Opprett en konto eller logg inn for å kommentere
Du må være et medlem for å kunne skrive en kommentar
Opprett konto
Det er enkelt å melde seg inn for å starte en ny konto!
Start en kontoLogg inn
Har du allerede en konto? Logg inn her.
Logg inn nå