[AS/algemeen] Collision afhandeling

Pagina: 1
Acties:

Acties:
  • 0 Henk 'm!

Verwijderd

Topicstarter
Ik ben bezig met het programmeren van een simpele Flash-game.
Met behulp van de Collision Detection Kit class kan ik pixelbased collision detecteren. So far so good. Ter inleiding;

Game info
- Je bent een vis
- Je kunt alleen naar links, recht en boven bewegen
- Je zakt automatisch naar beneden (yFriction)
- Je remt x-waards af als je niet beweegt met het keyboard (xFriction)
- Vis wordt bewogen met behulp van zijn xSpeed en ySpeed (positieve of negatieve waarden)

Een afbeelding (een mens moet wat in de nachtelijke uren) om het e.e.a. te verduidelijken, met daaronder de probleemstelling;

Afbeeldingslocatie: http://i46.tinypic.com/bjh5z6.png

De collision detection gaat goed. Op het moment dat vis (rood vierkant: in werkelijkheid een GIF-afbeelding waarbij pixel based collision gedetecteerd wordt) een muur raakt, moet ik de collision afhandelen. Met andere woorden, wat te doen als vis een muur raakt?
De enige informatie die ik heb zijn:
- de properties van vis (x, y, width, height) en vis als object
- de muur als object
- de x en y waarden van de pixels waar collision plaatsvindt
- de angle van de collision

De angles van de collisions zijn corresponderend met de scenes in de afbeelding:
45, 90, 135,
0, 180,
-45, -90, -135

Mijn probleem is dat ik niet weet hoe de muur "eruit ziet" waarmee collision plaatsvindt. Ik weet slechts de hoek(angle) waarmee vis de muur geraakt heeft. Ik kan dus, afhankelijk van de hoek, bepaalde properties van vis wijzigen. Toch dient vis, afhankelijk van de hoek van de muur (niet van de collision!), op een bepaalde manier te reageren. Zo zal hij, als hij in scene 2 de muur raakt (met een collision angle van laat zeggen 45 graden), simpelweg al zijn ySpeed verliezen en zich naar rechts blijven bewegen (positieve xSpeed-waarde).
Echter, als hij in scene 1 de muur raakt (met dezelfde collision angle van 45 graden), dan zal hij niet zijn ySpeed verliezen maar, afhankelijk van zijn xSpeed, omhoog bewegen (negatieve ySpeed).

Het probleem is dus dat ik niet weet hoe de muur "eruit ziet" en wat ik dien te doen.
Heeft iemand hier een nuttige opmerking over?
Met andere woorden, hoe dien ik de collision af te handelen met de waarden die ik heb in deze omstandigheid?

Acties:
  • 0 Henk 'm!

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 11-09 19:58

.oisyn

Moderator Devschuur®

Demotivational Speaker

Verwijderd schreef op vrijdag 29 januari 2010 @ 02:31:
Het probleem is dus dat ik niet weet hoe de muur "eruit ziet"
Jawel, dat weet je wel :). Die hoek van collision definieert namelijk hoe de muur er lokaal (bij het collision point) uitziet. Die hoek wil je trouwens omzetten in een vector - dit is de normaal van de muur op dat punt. Wat je moet berekenen is de hoeveelheid energie die overblijft na de botsing. De beweging wordt namelijk in de richting van de normaal tegengehouden. Die hoeveel is de lengte van je bewegingsvector v geprojecteert op de gespiegelde normaal n: (v ∙ -n). Als je dat vermenigvuldigt met je bewegingsvector, dan krijg je eruit hoeveel de beweging stopt. Wat er overblijft (dus dat wat je net berekent hebt van je bewegingsvector aftrekken) is hoe je object door blijft bewegen, oftewel:
v - v∙(v∙-n) =
v + v∙(v∙n)

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


Acties:
  • 0 Henk 'm!

Verwijderd

Topicstarter
.oisyn schreef op vrijdag 29 januari 2010 @ 02:48:
[...]

Jawel, dat weet je wel :). Die hoek van collision definieert namelijk hoe de muur er lokaal (bij het collision point) uitziet. Die hoek wil je trouwens omzetten in een vector - dit is de normaal van de muur op dat punt. Wat je moet berekenen is de hoeveelheid energie die overblijft na de botsing. De beweging wordt namelijk in de richting van de normaal tegengehouden. Die hoeveel is de lengte van je bewegingsvector v geprojecteert op de gespiegelde normaal n: (v ∙ -n). Als je dat vermenigvuldigt met je bewegingsvector, dan krijg je eruit hoeveel de beweging stopt. Wat er overblijft (dus dat wat je net berekent hebt van je bewegingsvector aftrekken) is hoe je object door blijft bewegen, oftewel:
v - v∙(v∙-n) =
v + v∙(v∙n)
Het wordt me door je (snelle ;) ) antwoord duidelijk dat het me aan bepaalde basiskennis ontbreekt. Zo heb ik geen idee wat een normaal is, alhoewel het me wel begint te dagen door je uitleg. Ik zal eens wat meer info opzoeken, bedankt.
Je zegt overigens 'die hoek dien je om te zetten in een vector'. Zou je daar iets duidelijker over kunnen zijn? Ik stel me voor dat de normaal (collision vector) een soort pijl is die zich in de muur bevindt, en die aangeeft welke 'krachten' er in werking treden (de muur stoot als het ware kracht uit zodra hij geraakt wordt, of, met andere woorden, ontneemt bewegingskracht van objecten die hem raken - krachten worden geabsorbeerd).

Acties:
  • 0 Henk 'm!

  • Mischa_NL
  • Registratie: Mei 2004
  • Laatst online: 01-02-2023
Verwijderd schreef op vrijdag 29 januari 2010 @ 03:50:
[...]


Het wordt me door je (snelle ;) ) antwoord duidelijk dat het me aan bepaalde basiskennis ontbreekt. Zo heb ik geen idee wat een normaal is, alhoewel het me wel begint te dagen door je uitleg. Ik zal eens wat meer info opzoeken, bedankt.
Je zegt overigens 'die hoek dien je om te zetten in een vector'. Zou je daar iets duidelijker over kunnen zijn? Ik stel me voor dat de normaal (collision vector) een soort pijl is die zich in de muur bevindt, en die aangeeft welke 'krachten' er in werking treden (de muur stoot als het ware kracht uit zodra hij geraakt wordt, of, met andere woorden, ontneemt bewegingskracht van objecten die hem raken - krachten worden geabsorbeerd).
Zie de 'normaal' in dit geval als volgt:

je hebt de vis die bv met een hoek van 45* tegen de muur botst. Logischerwijs botst de vis met 45* graden terug. De normaal is een vector die loodrecht op je muur staat. Deze staat dus op 90*. De hoek van terugkaatsing is gelijk aan de hoek van inval (basis natuurkunde :P). Dus bots je met 80* dan bots je met 80* terug: De normaal is 90*, hoek van inval = 80*, hoek van terugkaatsing = 80*. Enzovoort.

edit/
Een vector is een - in jou geval - 2D float/int/whatever die bijvoorbeeld je snelheid aangeeft: in dat geval is je vector een X en Y coordinaat en een lengte, (hoe groot X en Y zijn). de XY geven de richting aan, de lengte de hoeveelheid.
Een normaal vector staat dus zoals eerder gezegd loodrecht (hoek 90*) op de muur.

edit2/
Vergeet vooral NIET om je vis 'terug te zetten' als bij een controle al door de muur heen zit. Je gaat uit van positie = muur en neemt die lengte mee bij je positie in de volgende frame. Nou ga ik ervan uit dat je met een vis en een muur dergelijke framerates behaald, en relatief zo een lage snelheid hebt dat je zo goed als iedere pixel die de vis verschuift wel een test hebt. Als dit het geval is: disregard dit verhaaltje!

[ Voor 27% gewijzigd door Mischa_NL op 29-01-2010 04:32 ]


Acties:
  • 0 Henk 'm!

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 11-09 19:58

.oisyn

Moderator Devschuur®

Demotivational Speaker

Mischa_NL schreef op vrijdag 29 januari 2010 @ 04:26:
[...]

Zie de 'normaal' in dit geval als volgt:

je hebt de vis die bv met een hoek van 45* tegen de muur botst. Logischerwijs botst de vis met 45* graden terug. De normaal is een vector die loodrecht op je muur staat. Deze staat dus op 90*. De hoek van terugkaatsing is gelijk aan de hoek van inval (basis natuurkunde :P).
Dan heb je het wel over een full elastic collision, volgens mij is dat niet wat Ivy2009 wil. Die wil alleen dat je gewoon niet door de muur heen kan bewegen. Als je dus met vector (1, 1) op een rechte muur afkomt met normaal (0, -1), dan wil je dat je gewoon naar rechts blijft bewegen, maar dat je verticale beweging stopt. Je glijdt dan als het ware langs de muur.
Verwijderd schreef op vrijdag 29 januari 2010 @ 03:50:
[...]


Het wordt me door je (snelle ;) ) antwoord duidelijk dat het me aan bepaalde basiskennis ontbreekt.
Fair enough, dat vond ik lastig in te schatten :). Je kent blijkbaar wel het concept van een vector.
  • Een richting (hoek) omzetten in een vector kun je doen door simpelweg (cos(hoek), sin(hoek)) te nemen. Dit is dus een punt op de cirkel met radius 1.
  • Een normaal van een lijn is de vector die loodrecht op de lijn staat. Als het gaat om objecten met oppervlakte (zoals je muur) dan wijst hij in de regel naar de buitenkant. Tevens heeft hij lengte 1.
  • De lengte van een vector v = (x,y) is ||v|| = √(x2 + y2).
  • Een vector v kun je vermenigvuldigen met een scalar (getal) s door simpelweg elk component van de vector te vermenigvuldigen met s, dus s∙v = (s * v.x, s * v.y). De vector wordt dan s keer zo lang.
  • Het inproduct (engels: dot product) van vectoren a en b, oftewel a∙b, is (a.x * b.x + a.y * b.y), en levert dus een scalar op. Merk op dat a∙a gelijk is aan ||a||2, het inproduct is dus een goedkope manier om de kwadraat van de lengte van een vector uit te rekenen.
  • De lengte van de projectie van een vector w op een andere vector v krijg je door w∙v / ||v||2 te doen.
    Afbeeldingslocatie: http://nixweb.com/critters/figs/vproj.gif

    Hier wordt w op v geprojecteert. Het antwoord dat je krijgt is de lengte van de projectie relatief aan de lengte van v (dus 0.5 betekent een halve lengte van v, projecties groter dan 1 zijn uiteraard ook mogelijk). Door deze te vermenigvuldigen met v zelf krijg je uiteindelijk de vector u in dit plaatje. Als de lengte van v gelijk is aan 1, zoals bij normalen over het algemeen het geval is, dan is de deling door ||v||2 natuurlijk gewoon een deling door 1 en kun je dat weglaten.
Wat je uiteindelijk wil doen is de motion vector vanaf het punt van de botsing wilt projecteren op de omgekeerde normal. Dit is uiteindelijk wat er wordt tegengehouden door de muur. Wat je overhoudt (dus je originele vector minus wat je net hebt uitgerekend) is de richting waarop je object door moet bewegen.

Afbeeldingslocatie: http://oisyn.nl/pics/colresponse.png

Dus helemaal uitgeschreven:
  v - n∙(v∙-n / ||n||2)
||n||2 is 1, dus:
  v - n∙(v∙-n)
dubbele min wegwerken
  v + n∙(v∙n)

[ Voor 15% gewijzigd door .oisyn op 03-02-2010 01:33 ]

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


Acties:
  • 0 Henk 'm!

Verwijderd

Topicstarter
Duizendmaal dank. Na uren speur- en probeerwerk heb ik de onderstaande code als resultaat.
Zoals te zien heb ik de vector van hero (vis) en de vector/normaal van de muur:
(note: de angle van hero kan ik slechts berekenen met zijn xSpeed en ySpeed. Ik neem aan dat dit op de juiste wijze gebeurt nu? atan2() retourneert een angle in de range -pi/pi)

PHP:
1
2
3
4
5
6
var muurAngle           = collisions[0]["angle"];
var muurVector          = [Math.cos(muurAngle), Math.sin(muurAngle)];
var muurVectorLen   = Math.sqrt(muurVector[0]*muurVector[0] + muurVector[1]*muurVector[1]);
var heroAngle           = Math.atan2(hero.ySpeed, hero.xSpeed) * 180/Math.PI;
var heroVector          = [Math.cos(heroAngle), Math.sin(heroAngle)];
var heroVectorLen   = Math.sqrt(heroVector[0]*heroVector[0] + heroVector[1]*heroVector[1]);


Zou je kunnen aangeven hoe ik nu de nieuwe vector van hero kan berekenen? En als ik die vector heb, hoe ik die kan omzetten in een nieuwe x- en ySpeed van hero? Neem van me aan dat ik - letterlijk - uren heb zitten proberen omdat m.b.v. je uitleg te realiseren, maar ik loop aardig dood op het moment. Veel dank daarvoor, ik heb het gevoel dat ik er bijna ben - en het nog snap ook :)

/edit: Ik zie nu pas je laatste edit (dubbele min wegwerken etc.). Ik stoei zelf ook nog even verder...

[ Voor 5% gewijzigd door Verwijderd op 29-01-2010 15:06 ]


Acties:
  • 0 Henk 'm!

  • Mischa_NL
  • Registratie: Mei 2004
  • Laatst online: 01-02-2023
Verwijderd schreef op vrijdag 29 januari 2010 @ 15:00:
[...]


Duizendmaal dank. Na uren speur- en probeerwerk heb ik de onderstaande code als resultaat.
Zoals te zien heb ik de vector van hero (vis) en de vector/normaal van de muur:
(note: de angle van hero kan ik slechts berekenen met zijn xSpeed en ySpeed. Ik neem aan dat dit op de juiste wijze gebeurt nu? atan2() retourneert een angle in de range -pi/pi)

PHP:
1
2
3
4
5
6
var muurAngle           = collisions[0]["angle"];
var muurVector          = [Math.cos(muurAngle), Math.sin(muurAngle)];
var muurVectorLen   = Math.sqrt(muurVector[0]*muurVector[0] + muurVector[1]*muurVector[1]);
var heroAngle           = Math.atan2(hero.ySpeed, hero.xSpeed) * 180/Math.PI;
var heroVector          = [Math.cos(heroAngle), Math.sin(heroAngle)];
var heroVectorLen   = Math.sqrt(heroVector[0]*heroVector[0] + heroVector[1]*heroVector[1]);


Zou je kunnen aangeven hoe ik nu de nieuwe vector van hero kan berekenen? En als ik die vector heb, hoe ik die kan omzetten in een nieuwe x- en ySpeed van hero? Neem van me aan dat ik - letterlijk - uren heb zitten proberen omdat m.b.v. je uitleg te realiseren, maar ik loop aardig dood op het moment. Veel dank daarvoor, ik heb het gevoel dat ik er bijna ben - en het nog snap ook :)

/edit: Ik zie nu pas je laatste edit (dubbele min wegwerken etc.). Ik stoei zelf ook nog even verder...
Is de angle van inval niet gewoon normalize(hero_vector) je krijgt dan de unit length van de x en y, en dat zou toch de vector van de hero moeten opleveren?

Ik snap ook niet helemaal wat je probeert van vectors te maken. Je positie + snelheid is je verplaatsings-vector! Normalize je deze dan krijg je automatisch de unit length vector van de relatieve beweging in een richting

edit/ do dus:

code:
1
2
3
var heroAngle             = Math.atan2(hero.ySpeed, hero.xSpeed) * 180/Math.PI;
var heroVector             = vector2(hero.xSpeed, hero.ySpeed);
heroVector.Normalize();

[ Voor 7% gewijzigd door Mischa_NL op 29-01-2010 15:50 ]


Acties:
  • 0 Henk 'm!

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 11-09 19:58

.oisyn

Moderator Devschuur®

Demotivational Speaker

Ik zie trouwens dat m'n formule niet klopte. Heb 'm even aangepast in m'n vorige post.
Verwijderd schreef op vrijdag 29 januari 2010 @ 15:00:
[...]


Duizendmaal dank. Na uren speur- en probeerwerk heb ik de onderstaande code als resultaat.
Zoals te zien heb ik de vector van hero (vis) en de vector/normaal van de muur:
(note: de angle van hero kan ik slechts berekenen met zijn xSpeed en ySpeed. Ik neem aan dat dit op de juiste wijze gebeurt nu? atan2() retourneert een angle in de range -pi/pi)

PHP:
1
2
3
4
5
6
var muurAngle           = collisions[0]["angle"];
var muurVector          = [Math.cos(muurAngle), Math.sin(muurAngle)];
var muurVectorLen   = Math.sqrt(muurVector[0]*muurVector[0] + muurVector[1]*muurVector[1]);
var heroAngle           = Math.atan2(hero.ySpeed, hero.xSpeed) * 180/Math.PI;
var heroVector          = [Math.cos(heroAngle), Math.sin(heroAngle)];
var heroVectorLen   = Math.sqrt(heroVector[0]*heroVector[0] + heroVector[1]*heroVector[1]);
Hier heb je niet zo heel veel aan :). muurVectorLen is gewoon 1 dus die hoef je niet uit te rekenen (de vector (cos(hoek), sin(hoek)) is per definitie lengte 1). heroAngle is iets waar je helemaal niet in geïnteresseerd bent, zijn bewegingsvector is gewoon (hero.xSpeed, hero.ySpeed). heroVectorLen is de bijbehorende snelheid, maar die is voor de formule niet van belang.

(ik ben niet bekend met actionscript, maar van wat ik ervan begrepen heb lijkt het op javascript, dus ik doe het maar even daarmee)

JavaScript:
1
2
3
4
5
6
7
8
9
10
11
12
function vec(x, y) { return { x: x, y: y }; }
function vec_dot(v1, v2) { return v1.x * v2.x + v1.y * v2.y; }
function vec_scale(v, s) { return { x: v.x * s, v.y * s }; }
function vec_add(v1, v2) { return { x: v1.x + v2.x, y: v1.y + v2.y }; }

var muurAngle   = collisions[0]["angle"];
var muurVector   = vec(Math.cos(muurAngle), Math.sin(muurAngle));
var heroVector   = vec(hero.xSpeed, hero.ySpeed);

var newHeroVector = vec_add(heroVector, vec_scale(muurVector, vec_dot(heroVector, muurVector)));
hero.xSpeed = newHeroVector.x;
hero.ySpeed = newHeroVector.y;

[ Voor 3% gewijzigd door .oisyn op 03-02-2010 01:34 ]

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.

Pagina: 1