Hei,
minulla on eräässä projektissani ongelmana ennakon ottaminen ampuessa ja päätin tuoda ongelman foorumin matikkaguruille.
Minulla on kohteen 3-ulotteinen paikkavektori ja 3-ulotteinen nopeusvektori. Haluan saada selville, mihin suuntaan ammus täytyy ampua origosta, kun sen nopeus tiedetään.
A on kohteen paikkavektori
B on kohteen nopeusvektori
t on kohtaamiseen kuluva aika
C on ammuksen nopeusvektori, |C| tiedetään
t ja C ovat tuntemattomia.
Yritin ratkaista yhtälöä mutta en onnistunut kun en keksinyt, miten pystyn hyödyntämään |C|:tä. :(
Ennakkoon ampuminen
Ennakkoon ampuminen
- Attachments
-
- ennakointi.png (9.49 KiB) Viewed 10035 times
CoolBasic henkilökuntaa
Graafikko
Graafikko
Re: Ennakkoon ampuminen
Minun on ei pitäisi kysyä mitään, sillä en osaa kuitenkaaa vastata, mutta ihan uteliaisuuttani kysyn...
Tarkoitatko, että ampujalla A on kohde B. B:n sijainti, suunta ja nopeus tiedetään.
Pitäisi laskea kuinka paljon pitäisi ampua eteenpäin, jotta ammus osuisi B:tä.
Tarkoitatko, että ampujalla A on kohde B. B:n sijainti, suunta ja nopeus tiedetään.
Pitäisi laskea kuinka paljon pitäisi ampua eteenpäin, jotta ammus osuisi B:tä.
Re: Ennakkoon ampuminen
legend, luulen että tässä tarkoitetaan että ampuja on origossa O, eli kohteen sijainti on A, eli O+A, ja kohteen tuleva sijainti seuraavassa updatessa on A+B.
En ole vektoreita pitkään aikaan laskenut, mutta... Jos törmäyskohta on piste D, niin eikö D = A + rB ja D = tC, tai jotain vastaavaa... Tuostahan saisi yhtälöryhmällä t:n ja r:n, eikö...?
Edit. ainii eiku C:tä ei tiedetty... No jos teet siitä yksikkövektorin tai jotain... En tiiä
En ole vektoreita pitkään aikaan laskenut, mutta... Jos törmäyskohta on piste D, niin eikö D = A + rB ja D = tC, tai jotain vastaavaa... Tuostahan saisi yhtälöryhmällä t:n ja r:n, eikö...?
Edit. ainii eiku C:tä ei tiedetty... No jos teet siitä yksikkövektorin tai jotain... En tiiä
Re: Ennakkoon ampuminen
Tuota... mistäs tuo r pöllähti tuonne? B:llähän on tietenkin sama kerroin kuin C:llä, eli aika ampumisesta osumiseen (kuten Pate5:n kuvassa olikin). Tästä seuraa, että A + tB = tC. Vielä en keksinyt, miten C:n pituuden tietäminen auttaa, mutta selvästi se on ratkaisevassa roolissa.Jonez wrote:legend, luulen että tässä tarkoitetaan että ampuja on origossa O, eli kohteen sijainti on A, eli O+A, ja kohteen tuleva sijainti seuraavassa updatessa on A+B.
En ole vektoreita pitkään aikaan laskenut, mutta... Jos törmäyskohta on piste D, niin eikö D = A + rB ja D = tC, tai jotain vastaavaa... Tuostahan saisi yhtälöryhmällä t:n ja r:n, eikö...?
-
- Moderator
- Posts: 1583
- Joined: Mon Aug 27, 2007 11:24 pm
- Location: Otaniemi - Mikkeli -pendelöinti
Re: Ennakkoon ampuminen
Ongelma on varsin mielenkiintoinen, mutta lähestymistapa ei ehkä se kaikista helpoin. Kuten kaavastasi näkee, t|C| muodostaa origokeskisen pallon, jonka voi lausua myös seuraavasti: sqrt(x²+y²+z²) = r <=> x²+y²+z² = r² <=> (ax+bx*t)²+(ay+by*t)²+(az+bz*t)² = t²|C|² <=> ax²+ax*bx*t+bx²t²+ay²+ay*by*t+by²t²+az²+az*bz*t+bz²t² - t²|C|² = 0 <=> t²(bx²+by²+bz²-|C|²)+t(ax*bx+ay*by+az*bz)+ax²+ay²+az², joka on toisen asteen yhtälö muotoa at²+bt+c=0, jossa a,b ja c ovat kaikki vakiollisia, joten sen menee suoraan t = (-b(+-)sqrt(b²-4ac))/2a, mihin kannattaa ohjelmoidessa käyttää jopa välimuuttujia. Neliöjuuren sisäinen diskriminantti (kiitos cce:lle terminologiamuistutuksesta!) b²-4ac kertoo törmäyksistä, sen ollessa negatiivinen ei ammus ehdi enää mitenkään osumaan, sen ollessa 0 se ehtii juuri yhteen pisteeseen ja diskriminantin positiivisilla arvoilla mahdollisia törmäyskohtia on kaksi. Kannattanee myös tarkistaa, että osuminen tapahtuu varmasti tulevaisuudessa, muuten kaava voi antaa t:lle negatiivisenkin arvon. Parhaan tuloksen takaamiseksi kannattanee myös kahden mahdollisuuden tapauksessa valita aiempi vielä tulevaisuudessa oleva jotta osuma tapahtuu mahdollisimman pian. Ajan laskemisen jälkeen tunnetaankin etäisyys (a+b*t) ja aika (t), joten ammuksen nopeusvektori saadaan yksinkertaisesti näistä jakolaskulla (s = vt <=> v = s/t). Esimerkki seuraa.
Code: Select all
SCREEN 640, 480
Type pari
Field tx#
Field ty#
Field tz#
Field txv#
Field tyv#
Field tzv#
Field px#
Field py#
Field pz#
Field pxv#
Field pyv#
Field pzv#
Field t0#
Field ct#
EndType
start = Timer()
Repeat
ft# = (Timer()-start)*.001
If Timer()>t
p.pari = New(pari)
p\tx = Rnd(-80,-40)
p\ty = Rnd(-10, 10)
p\tz = Rnd(-10, 10)
p\txv = Rnd(5, 10)
p\tyv = Rnd(-2, 2)
p\tzv = Rnd(-2, 2)
p\px = Rnd(-5, 5)
p\py = Rnd(-16,-15)
p\pz = Rnd(-15,-13)
ax# = p\tx-p\px
ay# = p\ty-p\py
az# = p\tz-p\pz
bx# = p\txv
by# = p\tyv
bz# = p\tzv
s# = Rnd(8,20) // projectile speed
a# = bx*bx+by*by+bz*bz-s*s
b# = ax*bx+ay*by+az*bz
c# = ax*ax+ay*ay+az*az
d# = b*b-4*a*c
If d<.0 Then
Delete p // no hits, don't shoot
Else
If d>.0 Then
ct1# = (-b-Sqrt(d))/(2*a)
ct2# = (-b+Sqrt(d))/(2*a)
If ct1>.0 Then
p\ct = ct1
If ct2>.0 And ct2<ct1 Then p\ct = ct2
Else
p\ct = ct2
EndIf
ElseIf d = .0 Then
p\ct = -b/(2*a)
EndIf
p\pxv = (p\tx+p\txv*p\ct-p\px)/p\ct
p\pyv = (p\ty+p\tyv*p\ct-p\py)/p\ct
p\pzv = (p\tz+p\tzv*p\ct-p\pz)/p\ct
p\t0 = ft
SetWindow Str(p\ct)
If p\ct < .0 Then Delete p // no point in shooting
EndIf
t = Timer()+1000
EndIf
k = 0
For p.pari = Each pari
pt# = ft-p\t0
s1# = 50.0/(20.0+p\tz+p\tzv*pt)
s2# = 50.0/(20.0+p\pz+p\pzv*pt)
Circle 320+s1*(p\tx+p\txv*pt-3), 240-s1*(p\ty+p\tyv*pt-3), 6*s1
Circle 320+s2*(p\px+p\pxv*pt-3), 240-s2*(p\py+p\pyv*pt-3), 6*s2
If pt>p\ct Then Delete p
k = k + 1
Next p
DrawScreen
Forever
-
- Devoted Member
- Posts: 718
- Joined: Wed Nov 03, 2010 7:56 pm
- Location: Joku piste pohjoisessa.
Re: Ennakkoon ampuminen
Epic solve, dear koodaaja. Epic solve indeed.koodaaja wrote:Ongelma on varsin mielenkiintoinen, mutta lähestymistapa ei ehkä se kaikista helpoin. Kuten kaavastasi näkee, t|C| muodostaa origokeskisen ympyrän, jonka voi lausua myös seuraavasti: sqrt(x²+y²+z²) = r <=> x²+y²+z² = r² <=> (ax+bx*t)²+(ay+by*t)²+(az+bz*t)² = t²|C|² <=> ax²+ax*bx*t+bx²t²+ay²+ay*by*t+by²t²+az²+az*bz*t+bz²t² - t²|C|² = 0 <=> t²(bx²+by²+bz²-|C|²)+t(ax*bx+ay*by+az*bz)+ax²+ay²+az², joka on toisen asteen yhtälö muotoa at²+bt+c=0, jossa a,b ja c ovat kaikki vakiollisia, joten sen menee suoraan t = (-b(+-)sqrt(b²-4ac))/2a, mihin kannattaa ohjelmoidessa käyttää jopa välimuuttujia. Neliöjuuren sisäinen diskriminantti (kiitos cce:lle terminologiamuistutuksesta!) b²-4ac kertoo törmäyksistä, sen ollessa negatiivinen ei ammus ehdi enää mitenkään osumaan, sen ollessa 0 se ehtii juuri yhteen pisteeseen ja diskriminantin positiivisilla arvoilla mahdollisia törmäyskohtia on kaksi. Kannattanee myös tarkistaa, että osuminen tapahtuu varmasti tulevaisuudessa, muuten kaava voi antaa t:lle negatiivisenkin arvon. Parhaan tuloksen takaamiseksi kannattanee myös kahden mahdollisuuden tapauksessa valita aiempi vielä tulevaisuudessa oleva jotta osuma tapahtuu mahdollisimman pian. Esimerkki seuraa.
Code: Select all
SCREEN 640, 480 Type pari Field tx# Field ty# Field tz# Field txv# Field tyv# Field tzv# Field px# Field py# Field pz# Field pxv# Field pyv# Field pzv# Field t0# Field ct# EndType start = Timer() Repeat ft# = (Timer()-start)*.001 If Timer()>t p.pari = New(pari) p\tx = Rnd(-80,-40) p\ty = Rnd(-10, 10) p\tz = Rnd(-10, 10) p\txv = Rnd(5, 10) p\tyv = Rnd(-2, 2) p\tzv = Rnd(-2, 2) p\px = Rnd(-5, 5) p\py = Rnd(-16,-15) p\pz = Rnd(-15,-13) ax# = p\tx-p\px ay# = p\ty-p\py az# = p\tz-p\pz bx# = p\txv by# = p\tyv bz# = p\tzv s# = Rnd(8,20) // projectile speed a# = bx*bx+by*by+bz*bz-s*s b# = ax*bx+ay*by+az*bz c# = ax*ax+ay*ay+az*az d# = b*b-4*a*c If d<.0 Then Delete p // no hits, don't shoot Else If d>.0 Then ct1# = (-b-Sqrt(d))/(2*a) ct2# = (-b+Sqrt(d))/(2*a) If ct1>.0 Then p\ct = ct1 If ct2>.0 And ct2<ct1 Then p\ct = ct2 Else p\ct = ct2 EndIf ElseIf d = .0 Then p\ct = -b/(2*a) EndIf p\pxv = (p\tx+p\txv*p\ct-p\px)/p\ct p\pyv = (p\ty+p\tyv*p\ct-p\py)/p\ct p\pzv = (p\tz+p\tzv*p\ct-p\pz)/p\ct p\t0 = ft SetWindow Str(p\ct) If p\ct < .0 Then Delete p // no point in shooting EndIf t = Timer()+1000 EndIf k = 0 For p.pari = Each pari pt# = ft-p\t0 s1# = 50.0/(20.0+p\tz+p\tzv*pt) s2# = 50.0/(20.0+p\pz+p\pzv*pt) Circle 320+s1*(p\tx+p\txv*pt-3), 240-s1*(p\ty+p\tyv*pt-3), 6*s1 Circle 320+s2*(p\px+p\pxv*pt-3), 240-s2*(p\py+p\pyv*pt-3), 6*s2 If pt>p\ct Then Delete p k = k + 1 Next p DrawScreen Forever
<Ize> Pitäs tehä allekirjotus..
<Ize> Vois keksiä jonkin nasahtavan sanonnan..
<Ize> Siitä tulis upea legenda ja kaikki vaihtaisivat allekirjoituksensa siihen.
<Ize> Ehkä ei kuitenkaa...
<Ize> Vois keksiä jonkin nasahtavan sanonnan..
<Ize> Siitä tulis upea legenda ja kaikki vaihtaisivat allekirjoituksensa siihen.
<Ize> Ehkä ei kuitenkaa...
Re: Ennakkoon ampuminen
Mietinkin että ongelmalle olisi varmasti jokin helposti ymmärrettävä ratkaisu ja olin oikeassa olen iloinen kun kerrankin ymmärsin kaiken selityksestä alusta loppuun asti. Lihavoin ja suurensin muuten koodaaja yhtä kohtaa laskuistasi, jossa olit vielä kerran unohtanut merkitä lausekkeen olevan yhtäsuuri nollan kanssa.koodaaja wrote:Ongelma on varsin mielenkiintoinen, mutta lähestymistapa ei ehkä se kaikista helpoin. Kuten kaavastasi näkee, t|C| muodostaa origokeskisen pallon, jonka voi lausua myös seuraavasti: sqrt(x²+y²+z²) = r <=> x²+y²+z² = r² <=> (ax+bx*t)²+(ay+by*t)²+(az+bz*t)² = t²|C|² <=> ax²+ax*bx*t+bx²t²+ay²+ay*by*t+by²t²+az²+az*bz*t+bz²t² - t²|C|² = 0 <=> t²(bx²+by²+bz²-|C|²)+t(ax*bx+ay*by+az*bz)+ax²+ay²+az², joka on toisen asteen yhtälö muotoa at²+bt+c=0, jossa a,b ja c ovat kaikki vakiollisia, joten sen menee suoraan t = (-b(+-)sqrt(b²-4ac))/2a, mihin kannattaa ohjelmoidessa käyttää jopa välimuuttujia. Neliöjuuren sisäinen diskriminantti (kiitos cce:lle terminologiamuistutuksesta!) b²-4ac kertoo törmäyksistä, sen ollessa negatiivinen ei ammus ehdi enää mitenkään osumaan, sen ollessa 0 se ehtii juuri yhteen pisteeseen ja diskriminantin positiivisilla arvoilla mahdollisia törmäyskohtia on kaksi. Kannattanee myös tarkistaa, että osuminen tapahtuu varmasti tulevaisuudessa, muuten kaava voi antaa t:lle negatiivisenkin arvon. Parhaan tuloksen takaamiseksi kannattanee myös kahden mahdollisuuden tapauksessa valita aiempi vielä tulevaisuudessa oleva jotta osuma tapahtuu mahdollisimman pian. Ajan laskemisen jälkeen tunnetaankin etäisyys (a+b*t) ja aika (t), joten ammuksen nopeusvektori saadaan yksinkertaisesti näistä jakolaskulla (s = vt <=> v = s/t). Esimerkki seuraa.
Code: Select all
... koodia ...
cbEnchanted, uudelleenkirjoitettu runtime. Uusin versio: 0.4.1 — Nyt myös sorsat GitHubissa!
NetMatch - se kunnon nettimättö-deathmatch! Avoimella lähdekoodilla varustettu
vesalaakso.com
NetMatch - se kunnon nettimättö-deathmatch! Avoimella lähdekoodilla varustettu
vesalaakso.com
-
- Moderator
- Posts: 1583
- Joined: Mon Aug 27, 2007 11:24 pm
- Location: Otaniemi - Mikkeli -pendelöinti
Re: Ennakkoon ampuminen
Haa, tiesihän sen että joku virhe sinne jää! Hatunnosto VesQlle siitä, että ylipäänsä luit kaavan johtamisen noin tarkasti. Huomionarvoista on myös, että kun pallon säde pidetään vakiona, ei tapahdu muuta kuin että -|C|² hyppää t²-termistä vakiotermiin, ja saadaan pallon ja säteen törmäyksen kaava, jonka tajusin lopullisen kaavan saatuani myös johtaneeni muutamaan kertaan raytrace-juttuja viritellessäni, joten ongelma oli ainakin alitajuisesti tuttu.
Mutta kuten sanottua, ongelma on usein helpoin ratkaista muuttamalla sitä!
Mutta kuten sanottua, ongelma on usein helpoin ratkaista muuttamalla sitä!