Java 2D-kollision, vattentätt, kameran följer karaktären

Permalänk

Java 2D-kollision, vattentätt, kameran följer karaktären

Halloj!

Har stött på ett problem som jag inte lyckas lösa.

Har kodat ett spel som skall likna link to the past. Allt har gått bra tills nu. Har nyligen lagt in en kod som gör så att det ser ut som om användaren följer karaktären från ovan. Dvs "kameran följer karaktären". Det innebär att jag måste flytta alla andra objekt i motsatt riktning mot karaktären, med karaktärens hastighet och samtidigt låsa karaktären vid sin aktuella position, eller åtminstonne sätta en position åt denne för varje uppdatering.

Jag har även en kod som loopar igenom alla olika objekt som rör sig för att se om någon krockar. Tex. if(character.getX() < enemy.getX().getIconWidth()) etcetc. ni förstår säkert, jag kollar om de båda rektangulära bilderna överlappar varandra.

Jag utvecklade vidare kollisionen för att alla objekt skulle kunna ha större hastighet än vad själva ikonen i själva verket var genom att förutse en krock innan jag flyttar på karaktären. Går igenom varje pixel tex. från x = 150 til och med 150 + aktuell hastighet på objektet. Genom den metoden kunde jag förutse en krock INNAN karaktären flyttade på sig. Det var skitbra tills jag började med ovanstående, att låta kameran följa karaktäre, vilket bidrog till uppdateringar av objekten, vilket bidrog avv jag läckte in vatten så att säga.

Har någon något förslag på hur jag kan komma runt detta problem? Det måste finnas nåt sätt att ha i princip 100000 i pixelhastighet hos objekten men ändå kunna krocka med ett objekt som ligger endas 3 pixlar ifrån, OCH kunna följas av kameran (dvs. att alla andra objekt runt omkring flyttas i motsatt riktning)

Tack för svar!

EDIT: Själva problemet med att kameran följer karaktären är ju att om jag kollar alla pixlar framför karaktären till och med karaktärens storlek på hastigheten och inte upptäcker en krock så ber jag denne flytta sig framåt med så många pixlar som denne har hastighet. Sedan ber jag alla objekt runt omkring att flytta sig i motsatt riktning med karaktärens hastighet. DÅ kommer en krock uppstå fastän att ajg inte registrerat det. Så objektet flyter rätt igenom karaktären, eller mer "hoppar över"

Permalänk
Medlem

Har du din karta i en objektmatris eller är det en stor statisk bild med en "kollisionsmap" i bakgrunden eller.. ja hur gör du egentligen?

Det vanliga gissar jag är att karaktären har en x-/y-position i förhållande till en större karta med fiender och statiska objekt. Om det är fallet här så är det ologiskt att flytta både karaktär och statiska objekt, eftersom man då får "vandrande stenar och buskar". Ett sätt att se på saken är att tänka sig att man har ett papper med en urklippt fyrkant i mitten. Detta hål-i-papper representerar spelfältet -- kartan bakom är mycket större men man ser inte allt på en gång. När karaktären förflyttar sig över kartan följer fyrkanten med honom. Det ser ut som om omgivningen är den som förflyttas (i alla fall tills fyrkanten är vid kartans slut; då ser man att karaktären rör sig), men i själva verket är den helt statisk.

Visa signatur

Kom-pa-TI-bilitet

Permalänk

Japp, precis så är det, men jag kan väl inte flytta JPaneln? :S utan jag måste flytta innehållet i JPaneln så att säga. När karaktären rör sig nedåt skall omgivningen flyttas uppåt.

Permalänk
Medlem

Du flyttar gubben 1 pixel upp, alla andra objekt är stilla.

Eller du flyttar alla objekt 1 pixel ner, gubben är stilla.

Resten är bara en fråga om vilken del av banan som syns.

----* (utanför skärmen, bara för att du skall se nästa frame)
skärmen slutar
*****
*****
**#**
*--**
*---*

Hade gubben (#) gått 1 pixel upp, så hade inga objekt rört på sig (- är objekt, * är gräs) utom gubben rör sig, och sedan ritar man upp de pixlarna som syns på skärmen. Då hade den sett ut såhär:

----*
*****
**#**
*****
*--**
skärmen slutar
*---* (syns inte längre).

Notera att gubben alltid är mitt i skärmen.

Vad jag förstår av din exempel är typ att du gör flyttning 2 gånger per frame/tidsenhet. Det är väl fel gjort av dig?

Visa signatur

Intel Core 2 Q9450 2.66GHz @ 3.2GHz | Gigabyte GA-X48T-DQ6 | Corsair TWIN3X4096-1600C7DHX G 2x2048MB DDR3 7-7-7-20 | Sapphire Radeon HD4870 | Noctua NH-U12P Quadra-heatpipe | Zalman ZM850 HP Silent 850W | 2x Raptor WD1500 150GB RAID 0 | Intel M80G2 SSD | Cooler Master Cosmos 1000

Permalänk
Medlem

För att tillägga, låt oss säga att din gubbe flyttar sig 10 pixlar per sekund.

Det är hans hastighet, 10 pixlar / sekund.

Men som du gör är faktiskt att gubben rör sig 20 pixlar per sekund (såvida de andra objekt inte är andra monster som också rör sig med 10 pixlar per sekund i motsatt riktning).

Så det verkar vara fel på logiken som du har använt.

Visa signatur

Intel Core 2 Q9450 2.66GHz @ 3.2GHz | Gigabyte GA-X48T-DQ6 | Corsair TWIN3X4096-1600C7DHX G 2x2048MB DDR3 7-7-7-20 | Sapphire Radeon HD4870 | Noctua NH-U12P Quadra-heatpipe | Zalman ZM850 HP Silent 850W | 2x Raptor WD1500 150GB RAID 0 | Intel M80G2 SSD | Cooler Master Cosmos 1000

Permalänk

Precis, nejmen det är jag med på. Det är inga problem med själva bakgrunden eller de objekt som inte kan röra sig. Problemet kommer när det är fiender som rör på sig samtidigt som karaktären rör på sig.

Om en fiende är på väg nerför banan så att säga, samtidigt som karaktären rör sig uppåt, skall ju fienden självklart "röra sig" nedåt med sin hastighet+ hastigheten som karaktären har uppåt (eftersom den hastigheten påverkar alla objekt att röra sig nedåt). Då uppstår problemet att fienden inte längre bara har sin rörelsehastighet nedåt, utan den har även karaktärens uppåtrörelse , fast omvänd då. Det medför att kollisionshantering inte längre kan lita på att fiende endast har sin hastighet, utan måste ta hänsyn till om karaktären rör sig.

Permalänk
Medlem

Men det har den inte.

Om Fiende flyttar sig ett steg nedåt, från x/y-position [10:10] så hamnar han på [10:11] oavsett vad spelkaraktären har för hastighet och riktning. Du pratar om den visuella representationen av aktörerna, dvs. hur spelfältet scrollar när din gubbe rör sig och hur detta påverkar den synliga delen av kartan. Karaktärens rörelse påverkar ju inte den faktiska positionen av vare sig fiende eller objekt såvida man inte kan knuffa omkring dem.

Visa signatur

Kom-pa-TI-bilitet

Permalänk

Nej det stämmer, men problemet är hur jag ska få ihop det hela. Min JPanel måste manipulera karaktärens position för att den skall vara centrerad mitt i JPaneln? och "inte" manipulera positionen då kanterna av bakgrunden syns i JPaneln.

Hm...borde int vara så mycket svårare :S

Permalänk
Medlem

Du väljer själv vad din JPanel ska rita upp. Om du har en karta på 100x100 rutor (tiles) och vill rita upp de 16x10 tiles närmast din karaktär så startar du vid karaktärens [xPos - 8] samt [yPos - 5] för din första tile och loopar tills du hämtat och ritat ut 16*10 tiles. När du rör dig neråt (yPos ökar) står karaktären still i mitten och kartan glider under honom... tills du får IndexOutOfBoundsException

Visa signatur

Kom-pa-TI-bilitet

Permalänk

det vill säga att jag måste flytta alla objekt åt motsatt håll mot vad karaktären springer mot för att få en effekt som speglar att fönstret följer honom?

EDIT: I och med att kollisionshanteringen endast tittar op objektens positioner i JPAneln....kanske går att skriva deras positioner med avseende på bakgrunden

Permalänk

Tänkte dock på...om jag nu ritar upp den del av bakrunden då karaktären är centrerad i JPaneln...då kommer bakgrunden glida under honom...men den kommer även glida under alla enemies?

Permalänk
Medlem

Du verkar flytta objekten neråt istället för att flytta "skärmens synfält".

Så du har en statisk karta på typ 10 x 10 pixlar, istället för ett tittfönster på 10 x 10 pixlar och en karta på låt oss säga 1000 x 1000 pixlar (dock så är typ bara 16 x 16 utritade för att du skall kunna snabbt flytta kameran).

Men din kod borde se ut typ såhär:

int charNextXleft = character.getX() + charMoveX;
int charNextXright = charNextXleft + character.getWidth();
int enemyNextXleft = enemy.getX() + enemyMoveX;
int enemyNextXright = enemyNextXleft + enemy.getWidth();
(Samma för y)
if (charNextXleft <= enemyNextXright && charNextXright >= enemyNextXleft && samma för Y)
{
// kollision
}
else if ((charNextXleft > enemyCurrentXright && enemyNextXright <= enemyCurrentXright && charCurrentXleft < enemyCurrentXright || charNextXright < enemyCurrentXleft && enemyNextXleft >= enemyCurrentXleft && charCurrentXright > enemyCurrentXleft) && (samma for Y))
{
// kollision, objekt gick om varandra
}
else
{
// ingen kollision
}

Typ så borde kollisions koden se ut. Hoppas jag fick rätt på alla left och right och > och <. Men du fattar poängen.

Observera att varje objekt, inklusive din gubbe har en riktning och en hastighet.

Dvs din gubbe går med hastighet 4 åt höger och är 3 pixlar bred.
Motståndare går åt vänster med hastighet 2 och är 2 pixlar bred.

******###**--** (# = din gubbe, - = motståndare)
Nästa frame:
*****-$##****** ($ = kollision)

Men om vi säger att motsåndaren hade hastighet 3 pixlar, då hade det sett ut såhär:
****--###******
Utan "else if" hade ditt program inte hittat kollisionen.

Men det du gör fel är att du flyttar objektet två gånger.
*--***###****** (2 pixlar på monstret + 4 i motsat gubbriktning)
eller
--****###****** (3 pixlar på monstret + 4 i motsat gubbriktning)

Du ser nu att du gör fel.

Du måste ha gubben statisk (flytta inte den alls!) när du flyttar alla objekt.
Eller så flyttar du endast gubben sedan kameran. Och alla objekt står still.

Annars får du dubbel flyttning.

Visa signatur

Intel Core 2 Q9450 2.66GHz @ 3.2GHz | Gigabyte GA-X48T-DQ6 | Corsair TWIN3X4096-1600C7DHX G 2x2048MB DDR3 7-7-7-20 | Sapphire Radeon HD4870 | Noctua NH-U12P Quadra-heatpipe | Zalman ZM850 HP Silent 850W | 2x Raptor WD1500 150GB RAID 0 | Intel M80G2 SSD | Cooler Master Cosmos 1000

Permalänk

aaah nu ser jag vad du menar!

Om jag gör så att jag först och främst uppdaterar alla rörliga objekts positioner och kollar kollisioner....Sedan precis innan utritning flyttar jag ALLA objekt inklusive karaktären åt det håll som karaktären gått med karaktärens hastighet, detta innebär ju att karaktären fortfarande är centraliserad men att jag endast flyttat titthålet såa tt säga

Permalänk
Medlem
Citat:

Ursprungligen inskrivet av Addeman_88
det vill säga att jag måste flytta alla objekt åt motsatt håll mot vad karaktären springer mot för att få en effekt som speglar att fönstret följer honom?

EDIT: I och med att kollisionshanteringen endast tittar op objektens positioner i JPAneln....kanske går att skriva deras positioner med avseende på bakgrunden

Nej det stämmer inte. Precis som det Elaie skriver ovan och jag skrev i min förra post tänker du grafiskt istället för koordinellt (om det nu är ett ord..) Visst ser det ut som att en sten rör sig mot karaktären när du springer mot den, men det gör den inte! Dess X- och Y-position på kartan förblir oändrad, det är karaktären som rör sig och spelfältet eftersom vyn är centrerad rakt över karaktären.

Tänk dig att en kompis cyklar till stan samtidigt som du spårar honom på GPS. På en webbsida ser du hur han, representerad av en prick, närmar sig staden. Staden i sig rör sig inte, men ur hans synvinkel ser det ut som om den kommer närmare honom. Det är samma sak med spelet: om du har en tile-karta över din värld och spelfiguren springer omkring på denna så flyttar sig inte de statiska objekten på kartan. Du verkar tänka rent grafiskt, att karaktären är världens centra och att allting ska flytta sig runt honom. Om det är så du ska ha det så får du se till att ha en värld där spelkaraktären är statiskt satt till 0,0 och objekten är definierade som ett avstånd från origo (dvs. din karaktär).

Visa signatur

Kom-pa-TI-bilitet

Permalänk
Medlem
Citat:

Ursprungligen inskrivet av Addeman_88
aaah nu ser jag vad du menar!

Om jag gör så att jag först och främst uppdaterar alla rörliga objekts positioner och kollar kollisioner....Sedan precis innan utritning flyttar jag ALLA objekt inklusive karaktären åt det håll som karaktären gått med karaktärens hastighet, detta innebär ju att karaktären fortfarande är centraliserad men att jag endast flyttat titthålet såa tt säga

Nästan precis så, fast du fick fel på steg 4 (se nedan).

Vi säger 10 pixlar upp på karaktären:

Steg 1: Flytta karaktär 10 pixlar upp.
Steg 2: Flytta alla objekt som rör sig med deras egna hastighet (utom karaktären då, eftersom du flyttade på den i steg 1, du kan såklart slå ihop steg 1 och 2 till ett steg för alla objekt inklusive karaktären).
Steg 3: Kör collision detection.
Steg 4: Flytta allt inklusive karaktären 10 pixlar ner (motsatt riktning).

Då hamnar karaktären på samma ställe som förr, dvs mitt i skärmen. Och allt annat flyter på.

Visa signatur

Intel Core 2 Q9450 2.66GHz @ 3.2GHz | Gigabyte GA-X48T-DQ6 | Corsair TWIN3X4096-1600C7DHX G 2x2048MB DDR3 7-7-7-20 | Sapphire Radeon HD4870 | Noctua NH-U12P Quadra-heatpipe | Zalman ZM850 HP Silent 850W | 2x Raptor WD1500 150GB RAID 0 | Intel M80G2 SSD | Cooler Master Cosmos 1000

Permalänk

Jaa :S men hur tusan flyttar jag synfältet "JPaneln" utan att flytta objektet innuti JPaneln? :S

EDIT: Svarade på fel inlägg

Permalänk

Ja råkade visst skriva fel! provade det precis och insåg att det måste vara så jag ska göra för att varje objekt skall bibehålla "sin" position på kartan

Permalänk

Tack som tusan för feedback! Nu losnar det rejält haha. Ska sätta mig in i den kollisionshanteringen du skrev ovan. Vore skönt om man kan ha en fiende som kan, om man vill, dra 100 pixlar/steg, men ändå krocka med karaktären eller andra objekt oavsett deras storlek

Permalänk
Medlem
Citat:

Ursprungligen inskrivet av Addeman_88
Jaa :S men hur tusan flyttar jag synfältet "JPaneln" utan att flytta objektet innuti JPaneln? :S

EDIT: Svarade på fel inlägg

Jag skulle inte ha addat några grafiska objekt alls till JPanel.

Rent tekniskt skulle jag ha en Image som representerar all renderad spelgrafik. På denna Image hade jag ritat upp området runt karaktären i två eller flera pass: åtminstone ett pass för statiska objekt och ett till pass för monster, karaktären, flygande kaststjärnor eller annat som ska vara i förgrunden. När hela scenen renderats skulle jag ha swappat den med den föregående scenen och sagt åt JPanel att uppdatera sig.

Jag skulle alltså inte ha kört en massa JPanel.getContentPane().add(tile1..n + character + enemy1..10); om det är så du gör.

Visa signatur

Kom-pa-TI-bilitet

Permalänk
Medlem
Citat:

Ursprungligen inskrivet av Addeman_88
Jaa :S men hur tusan flyttar jag synfältet "JPaneln" utan att flytta objektet innuti JPaneln? :S

EDIT: Svarade på fel inlägg

Din JPanel är återspegling av fragment av hela kartan.

Vi säger detta är hela kartan där * = karta som inte syns och ¤ = återspegling av kartan på din JPanel (anta din skärm är 2x3 pixlar stor):

******
******
******
***¤¤*
***¤¤*
***¤¤*
******

När gubben går 1 pixel åt vänster, så ändras inte världen (själva kartan) utom endast det din JPanel ritar. Vet inte hur du får det till men antar att det är som en canvas som du ritar dina objekt på.
******
******
******
**¤¤**
**¤¤**
**¤¤**
******

Så tittfönstret ändrades, och du måste återspegla det i din JPanel.

Lättast är väl att:

1: Flytta gubben 1 pixel vänster.
2: Flytta alla objekt så som dem skall flytta sig.
3: Kollisions detektering.
4: Flytta hela grafiken i fönstret 1 pixel höger (gubbe fortfarande centrerad).
5: Rita 1 pixel bred grafik från kartan (det nya som nu syns). Oftast så har man ingen grafisk representation för kartan i minnet, utom endast data som säger at det finns si och sådan tile här och där. Så du får rita upp grafiken baserat på den informationen.

Oftast så är det så att din gubbe rör sig 1 tile, en tile är X * Y bred (typ 16 * 16). Så du ritar bara tilen som numera syns.

Visa signatur

Intel Core 2 Q9450 2.66GHz @ 3.2GHz | Gigabyte GA-X48T-DQ6 | Corsair TWIN3X4096-1600C7DHX G 2x2048MB DDR3 7-7-7-20 | Sapphire Radeon HD4870 | Noctua NH-U12P Quadra-heatpipe | Zalman ZM850 HP Silent 850W | 2x Raptor WD1500 150GB RAID 0 | Intel M80G2 SSD | Cooler Master Cosmos 1000

Permalänk
Citat:

Ursprungligen inskrivet av Teknocide
Jag skulle inte ha addat några grafiska objekt alls till JPanel.

Rent tekniskt skulle jag ha en Image som representerar all renderad spelgrafik. På denna Image hade jag ritat upp området runt karaktären i två eller flera pass: åtminstone ett pass för statiska objekt och ett till pass för monster, karaktären, flygande kaststjärnor eller annat som ska vara i förgrunden. När hela scenen renderats skulle jag ha swappat den med den föregående scenen och sagt åt JPanel att uppdatera sig.

Jag skulle alltså inte ha kört en massa JPanel.getContentPane().add(tile1..n + character + enemy1..10); om det är så du gör.

Nej så gör jag itne Har ju en class Game extends JPanel...i denna skapar jag objekt av olika slag. Character new Character etc.

Permalänk
Avstängd

http://sv.wikipedia.org/wiki/Model-View-Controller

Rekommenderar MVC om du inte redan använder dig utav denna modellen!

Permalänk
Medlem
Citat:

Ursprungligen inskrivet av Addeman_88
Tack som tusan för feedback! Nu losnar det rejält haha. Ska sätta mig in i den kollisionshanteringen du skrev ovan. Vore skönt om man kan ha en fiende som kan, om man vill, dra 100 pixlar/steg, men ändå krocka med karaktären eller andra objekt oavsett deras storlek

Tänk på att jag är trött och det var bara ett exempel.

"else if" satsen bör ses över så du får kolla om jag tagit med alla scenario.
Jag tror inte att den kommer fungera om båda går i samma riktning, men ändå går om varandra. Men som sagt, för lite tid och för trött för att tänka nu!

Jag kan kolla lite på det imorgon efter jobb om jag har tid och är uttråkad.

Visa signatur

Intel Core 2 Q9450 2.66GHz @ 3.2GHz | Gigabyte GA-X48T-DQ6 | Corsair TWIN3X4096-1600C7DHX G 2x2048MB DDR3 7-7-7-20 | Sapphire Radeon HD4870 | Noctua NH-U12P Quadra-heatpipe | Zalman ZM850 HP Silent 850W | 2x Raptor WD1500 150GB RAID 0 | Intel M80G2 SSD | Cooler Master Cosmos 1000

Permalänk
Medlem

Kollade genom lite när jag ändå måste torka efter jag har duschat

Borde vara:
else if (((charNextXleft > enemyNextXright && charCurrentXleft < enemyCurrentXright) || (charNextXright < enemyNextXleft && charCurrentXright > enemyCurrentXleft)) || (samma for Y)) {
// kollision, gått om varandra
}

Men detta gäller ENDAST om objekt och gubbe rör sig i riktningen: upp ELLER ner ELLER vänster ELLER höger.

Det fungerar alltså inte om de rör dig på sned.

Dvs. om x-hastighet = -10 så måste y-hastighet = 0.

Om du vill göra detta även för sneda rörelser så får du tänka till själv

Visa signatur

Intel Core 2 Q9450 2.66GHz @ 3.2GHz | Gigabyte GA-X48T-DQ6 | Corsair TWIN3X4096-1600C7DHX G 2x2048MB DDR3 7-7-7-20 | Sapphire Radeon HD4870 | Noctua NH-U12P Quadra-heatpipe | Zalman ZM850 HP Silent 850W | 2x Raptor WD1500 150GB RAID 0 | Intel M80G2 SSD | Cooler Master Cosmos 1000

Permalänk

Har löst det men tackar ändå för inlägget!