Author Topic: Yet another shooter  (Read 72983 times)

0 Members and 1 Guest are viewing this topic.

Offline Darl181

  • «Yo buddy, you still alive?»
  • CoT Emeritus
  • LV12 Extreme Poster (Next: 5000)
  • *
  • Posts: 3408
  • Rating: +305/-13
  • VGhlIEdhbWU=
    • View Profile
    • darl181.webuda.com
Re: Yet another shooter
« Reply #345 on: November 04, 2011, 06:23:41 pm »
This is a little late, but...
0.o
What's the theory behind that?  I've been trying to get aiming like that working since something like January...
« Last Edit: November 04, 2011, 06:23:55 pm by Darl181 »
Vy'o'us pleorsdti thl'e gjaemue

Offline Deep Toaster

  • So much to do, so much time, so little motivation
  • Administrator
  • LV13 Extreme Addict (Next: 9001)
  • *************
  • Posts: 8206
  • Rating: +758/-15
    • View Profile
    • ClrHome
Re: Yet another shooter
« Reply #346 on: November 04, 2011, 06:29:42 pm »
And another thing: the topic title is still "Yet another shooter." Methinks that's an enormous understatement O.O




Offline Geekboy1011

  • The Oneironaut
  • Project Author
  • LV11 Super Veteran (Next: 3000)
  • ***********
  • Posts: 2028
  • Rating: +119/-2
  • Dream that Awakening dream
    • View Profile
Re: Yet another shooter
« Reply #347 on: November 04, 2011, 07:17:26 pm »
This is a little late, but...
0.o
What's the theory behind that?  I've been trying to get aiming like that working since something like January...


well we move bullet based off an angle and velocity. so all he really does is use an arctan routine with the enimies pos and your pos to get an angle and plugs that into the bullets trajectory and thus it flyies at you ;p

he does some crazy fucking shit with it though to get it to be that accurate though...

you should ask him for more info though :p
« Last Edit: November 05, 2011, 11:00:48 pm by Geekboy1011 »

Offline ztrumpet

  • The Rarely Active One
  • CoT Emeritus
  • LV13 Extreme Addict (Next: 9001)
  • *
  • Posts: 5712
  • Rating: +364/-4
  • If you see this, send me a PM. Just for fun.
    • View Profile
Re: Yet another shooter
« Reply #348 on: November 04, 2011, 07:26:15 pm »
he does some crazy fucking shit with it though to get it to be that accurate though...
And this is why we love him.

Offline Iambian

  • Coder Of Tomorrow
  • LV8 Addict (Next: 1000)
  • ********
  • Posts: 737
  • Rating: +215/-3
  • Cherry Flavoured Nommer of Fishies
    • View Profile
Re: Yet another shooter
« Reply #349 on: November 04, 2011, 08:36:21 pm »
This is a little late, but...
0.o
What's the theory behind that?  I've been trying to get aiming like that working since something like January...

To begin, let us go ahead and set what we mean by "angle". In our nice happy normal lives, we know that there are 360 degrees or 2*pi radians in a circle. We will assume that the zeroth degree is a line starting from the center of the circle drawn to the right most point (the 3 'o clock position). Draw another line from the center out to any other point on the circle and we can measure how far away it is from that starting point. That will be our angle, and it is measured in... wait? What? No, we're not going to use degrees for this. Neither are we going to use radians! Instead, we'll just make up our own unit of measurement. Let's call this a "binary degree" and set the number of these binary degrees that can exist in a circle from zero to 255. Why do we do this? Because it fits nicely in a single 8-bit register and lets us calculate these things faster. After all, we're in it for the speed.

The bullet's path is in polar coordinates, so that means we've got an angle and a radius. Since the bullet's radius is a function of time, we can omit having a radius altogether and just let it fly at a velocity.

To aim at something, you have to ask yourself "What angle do I need to shoot at in order to intersect at the player's position?" To get this answer, you will need an inverse trigonometric function. Given the starting point, which is the enemy's firing position, and the end point, which is the player's position, you have an X and Y. You have three basic inverse trigonometric functions to choose from: arcsine, arccosine, and arctangent. Absolutely FORGET about the other three. When you run your arguments through those functions, you will obtain an angle that you can then use to shoot at the enemy. But wait!

You only have information readily available to use the arctangent function, since it only needs the X and the Y. The other two functions want a hypotenuse (or rather, the radius, which we never kept track of) so they're right out, unless you want to go ahead and calculate them using Pythagorean's theorem. When you need to perform high speed calculations, you don't need to do more than you have to, so now let's forget about arcsine and arccosine. Let's just use arctangent.

So, now we picked our function. We get the angle from arctan(y/x). So now we've got to do division, right? Wrong! CaDan does absolutely no division, at least, not in the way a "normal" person would think of it. In fact, we don't actually do the function at all! Instead, we create a lookup table (LUT) that contains all the coordinates we can input, and have all the angles we need to output. Now, let's go ahead and say right now that we can strip the signs off of the X and Y to make using this table a bit easier. You still need to keep record of what those signs were; we'll need them for later.

For CaDan, since the screen is 64 x 64, I can get away with having X's and Y's go from 0 to 63 (zero inclusive), in such a manner that each column (data in a single row) enumerates all X's given a certain Y, and going from row to row, enumerates all Y's. But such a table, given 64*64, would total 4KB. We do NOT want to spend that much memory on such a table, so let's cheap this one out. We'll pick every 4th value, going from 0 to 60 in both directions. Keep in mind that you can't have 0 as an X value, so you're just going to have to assume that as X approaches zero, the angle approaches 64 binary degrees (pi/2 = 64 binary degrees). In the code box below is such a table, ranging from 0 to 64 binary degrees.

Code: [Select]
ArcTanTable:
.db 00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00 ;|00 00|
.db 64,32,19,13,10,08,07,06,05,05,04,04,03,03,03,03 ;|01 04|
.db 64,45,32,24,19,16,13,11,10,09,08,07,07,06,06,05 ;|02 08|
.db 64,51,40,32,26,22,19,16,15,13,12,11,10,09,09,08 ;|03 12|
.db 64,54,45,38,32,27,24,21,19,17,16,14,13,12,11,11 ;|04 16|
.db 64,56,48,42,37,32,28,25,23,21,19,17,16,15,14,13 ;|05 20|
.db 64,57,51,45,40,36,32,29,26,24,22,20,19,18,16,16 ;|06 24|
.db 64,58,53,48,43,39,35,32,29,27,25,23,22,20,19,18 ;|07 28|
.db 64,59,54,49,45,41,38,35,32,30,27,26,24,22,21,20 ;|08 32|
.db 64,59,55,51,47,43,40,37,34,32,30,28,26,25,23,22 ;|09 36|
.db 64,60,56,52,48,45,42,39,37,34,32,30,28,27,25,24 ;|10 40|
.db 64,60,57,53,50,47,44,41,38,36,34,32,30,29,27,26 ;|11 44|
.db 64,61,57,54,51,48,45,42,40,38,36,34,32,30,29,27 ;|12 48|
.db 64,61,58,55,52,49,46,44,42,39,37,35,34,32,30,29 ;|13 52|
.db 64,61,58,55,53,50,48,45,43,41,39,37,35,34,32,31 ;|14 56|
.db 64,61,59,56,53,51,48,46,44,42,40,38,37,35,33,32 ;|15 60|

To fetch values off this table at a good speed, let's go ahead and align this table to a high byte. Say, this table is to be copied to 0x8000. Now, let's construct the low byte in the following manner: Since the low 4 bits (16 entries wide) represents X, let's shove the X value in the low 4 bits, and since each row represents a Y value, it should be the upper 4 bits, so let's shove that in the upper nibble of the low byte. You set the resulting value as the low byte of the address, then fetch from that address.

And this is where geekboy says it starts getting crazy, but I would like to disagree.
Now that we've gotten an angle from the table, you'll want to notice the values as you approach the axes. See how they're getting rather... granular? That's one weakness to this approach. The angles you get as you approach the X or Y axes tend to suck and your shots will tend to miss simply because it can't aim properly. Especially since we've used a table that doesn't cover every single point, so what do we do? We go ahead and interpolate those values. I sure hope you didn't discard the sign-stripped X and Y values you calculated earlier between you and the enemy. We're going to need those bits you shuffled out in order to use the LUT. In fact, those are the ONLY bits you need for this part. What we're going to do is pick the angle you're at and find the next angle to the right and below you and find out how "close" you are to those angles. In our scheme, we stripped the lowest 2 bits of our X and Y, so that means there are 4 values to choose from. If you're sitting exactly on the boundary in the LUT (those two bits are zero), then you can skip the step for either the X or Y. What you do with those two bits is count how many times you are at the first angle you have, and then count how many times you are away from the next angle, then take the average of that. I like to do the X and Y calculation separately so that I can stick with 8 bit math. When you take a total average, you end up with an angle that is about as close as you can get without actually having to have those values in your table. It's not magic. It's just making a straight line that closely matches the curve, and then taking a point off that line... okay, so we're stretching that concept but hey. It works.

"But wait," you might ask after that hefty paragraph. "That's only one quadrant! I spent all that time listening to you whine on and on about the accuracy of the angle, but I want to be able to aim anywhere!" That's right. You *do* want to be able to aim anywhere within that full circle. Remember when I asked you to save what signs the X and Y were? You get to use those signs to correct what the angle should be. Now, since this is a circle, once you've got one quadrant, you basically have all four of them with just a little bit of manipulation. I'm going to leave it as an exercise to you as to *how* the angle is to be modified given the sign. Here's a hint: With one, you negate the angle. With the other, you add pi (128 binary degrees).

So, all in all... that's the theory. Or explanation. Or whatever.
That's what I do. And the aiming still sucks around the X and Y axes. I mean, it's good enough to not give you a safe spot but still. Not as good as I'd like it to be.

EDIT: I think I forgot to mention that almost all instances of X and Y are supposed to be calculated from your position and the enemy's position, so I suppose that would make it a delta X and delta Y? I dunno.

EDIT2: If you didn't get much out of that, perhaps you could get a little more out of the routine that CaDan uses. Because of the way the routine uses its pointers, it's not necessary to have the arctangent LUT page-aligned. That's just a side-effect of using IX in a manner that ensures compatibility with the Nspire or other half-broken emulators that doesn't support undocumented instructions.

Also keep in mind that the character's X and Y coordinates (in routine's DE) are formatted as (%xxxxxx00,%yyyyyy00) with the lowest two bits being subpixel bits, which aren't used in the calculation. I'm sure I could squeeze a little more accuracy during the interpolation phase if I *did* include those bits, but I did not. Anyway, below is the routine that CaDan uses:
Code: [Select]
;Warning: Loads and loads of register-juggling ahead.
r.arctan: ;in: HL=(x1,y1) DE=(x2,y2)
 ld b,0        ;initializing...
 ld a,e        ;
 rrca \ rrca \ and %00111111
 sub L    ;y1-y2
 jr nc,_  ;result is negative. Set B for flags (bit 0) and adjust Y for pos.
 set 0,b
 neg
_:
 ld e,a      ;D=Y for later
 rlca \ rlca ;shifting so that %00yyyynn is %yyyynn00 for later. n matters not
 ld L,a      ;half-result in L now
 ld a,d
 rrca \ rrca \ and %00111111
 sub H     ;x1-x2
 jr nc,_   ;result is negative. Set B for flags (bit 1) and adjust X for pos.
 set 1,b
 neg
_:
 ld c,a    ;C=X for results later
 rrca \ rrca ;shifting so that %00xxxxnn is %nn00xxxx. n still matters not.
 xor L     ;combine with Y
 and $0F   ;mask out to keep old X low bits
 xor L     ;and we have %yyyyxxxx
 ld L,b    ;saving flags into L for now.
 ld h,e    ;restore H for... stuffs
 ld ix,ArcTanTable
 ld e,a
 ld d,0
 add ix,de ;We have our offset now.
;So at this point, C=X, H=Y, L=flags.
;Let's go ahead and do X-interpolation first.
 ld a,c
 and %00000011 ;value-ranking
 ld c,(ix+0)   ;storing non-adjusted "output" value into C
 jr z,r.arctan.skipx
 ld e,a  ;Loop for second half of X interpolate
 cpl     ;ranking first value on inverse of distance to next number
 add a,5 ;So 1=3,2=2,3=1
 ld b,a
 xor a
_:
 add a,c
 djnz -_
 ld c,(ix+1)
 ld b,e
_:
 add a,c
 djnz -_
 rra \ rra
 and %00111111
 ld c,a       ;out by the time we're done with everything.
r.arctan.skipx:
 ld a,h
 ld H,c     ;H=InterpolatedX
 and %00000011 ;value-ranking
 ld c,(ix+0)   ;storing non-adjusted "output" value into C
 jr z,r.arctan.skipy
 ld e,a  ;Loop for second half of Y interpolate
 cpl     ;ranking first value on inverse of distance to next number
 add a,5 ;So 1=3,2=2,3=1
 ld b,a
 xor a
_:
 add a,c
 djnz -_
 ld c,(ix+16)
 ld b,e
_:
 add a,c
 djnz -_
 rra \ rra    ;Also trying to get any leftovers from too many values of 64
 cp 64
 jr z,_
 and %00111111
_:
 ld c,a       ;added. Since 64*4 is a 9 bit number, getting that back.
r.arctan.skipy:
 ld a,c
 add a,H
 rra
 cp 64
 jr z,_
 and %00111111 ;and NOW we have our final angle. (if it wasn't 64...)
_:
 ld b,0        ;Set to 128 if X is negative. For additions later on.       
 bit 1,L
 jr z,_
 ld b,128
 neg           ;negate angle
_:
 bit 0,L
 jr z,_
 neg           ;negate angle again if (-,-) else first neg. Still correct :)
_:
 add a,b       ;completing the angle
 ld c,a        ;saving the completed angle to C
 ret

EDIT3: If you're trying to get a routine like this to work on a 96x64 buffer, I could suggest doubling your area by halving the input X/Y coordinates. There will be some loss of accuracy, but if you're putting this in a game where your "hitbox" is the full 8x8 or larger sprite, then this won't be much of a concern. In fact, I don't think there will be any concern now that with a 128x128 firing range in all directions around the sprite (256x256 total area), then you could safely fire from off-screen. The angle that is output will be all the same.

If you somehow need the radius as well, I'd consider saving whatever's in C and use Pythagorean's Theorem to obtain the radius. You'd just double (square) the X and Y, add them together, and then pass that value through some sort of square root algorithm. You can find a good routine that does square roots around here: http://baze.au.com/misc/z80bits.html
« Last Edit: November 07, 2011, 01:46:29 pm by Iambian »
A Cherry-Flavored Iambian draws near... what do you do? ...

Offline Darl181

  • «Yo buddy, you still alive?»
  • CoT Emeritus
  • LV12 Extreme Poster (Next: 5000)
  • *
  • Posts: 3408
  • Rating: +305/-13
  • VGhlIEdhbWU=
    • View Profile
    • darl181.webuda.com
Re: Yet another shooter
« Reply #350 on: November 06, 2011, 11:15:20 am »
Ok, that's a bit more detailed than I was thinking of 0.o
I'm not sure if that would even be possible in Axe XD
Vy'o'us pleorsdti thl'e gjaemue

Offline Yeong

  • Not a bridge
  • LV12 Extreme Poster (Next: 5000)
  • ************
  • Posts: 3739
  • Rating: +278/-12
  • Survivor of Apocalypse
    • View Profile
Re: Yet another shooter
« Reply #351 on: November 07, 2011, 07:26:21 am »
wow Iambian that should go to a tutorial section :D
Sig wipe!

Offline Iambian

  • Coder Of Tomorrow
  • LV8 Addict (Next: 1000)
  • ********
  • Posts: 737
  • Rating: +215/-3
  • Cherry Flavoured Nommer of Fishies
    • View Profile
Re: Yet another shooter
« Reply #352 on: November 16, 2011, 03:52:22 am »
Sorry there hasn't been an update in ages. The resource table thinger is kicking my butt... and I felt kinda burnt out on the project in the past week or so. I'm gonna try to pick it up later "tomorrow" (technically today) and see how far I can get into a test scenario. I mean, pulling together a miniature file system isn't the easiest thing in the world, but who knows how things'll turn out.
A Cherry-Flavored Iambian draws near... what do you do? ...

Offline LincolnB

  • Check It Out Now
  • LV9 Veteran (Next: 1337)
  • *********
  • Posts: 1115
  • Rating: +125/-4
  • By Hackers For Hackers
    • View Profile
Re: Yet another shooter
« Reply #353 on: November 16, 2011, 10:17:44 am »
hmm...good luck! We're all behind you here.
Completed Projects:
   >> Spacky Emprise   >> Spacky 2 - Beta   >> Fantastic Sam
   >> An Exercise In Futility   >> GeoCore

My Current Projects:

Projects in Development:
In Medias Res - Contest Entry

Talk to me if you need help with Axe coding.


Spoiler For Bragging Rights:
Not much yet, hopefully this section will grow soon with time (and more contests)



Offline Geekboy1011

  • The Oneironaut
  • Project Author
  • LV11 Super Veteran (Next: 3000)
  • ***********
  • Posts: 2028
  • Rating: +119/-2
  • Dream that Awakening dream
    • View Profile
Re: Yet another shooter
« Reply #354 on: November 16, 2011, 05:55:01 pm »
I have not had anyfree time lately. Lifes been crazy.  >.<  whan i do post an update tho hopefully i will have some eyecandy ^_^


Offline Iambian

  • Coder Of Tomorrow
  • LV8 Addict (Next: 1000)
  • ********
  • Posts: 737
  • Rating: +215/-3
  • Cherry Flavoured Nommer of Fishies
    • View Profile
Re: Yet another shooter
« Reply #355 on: November 23, 2011, 10:14:59 am »
Alright. I'm trying to get this project back on track. What I've decided on tackling right now is the mini-menu for the danmaku mode. Doing this will give me a basis on which I can enter and exit danmaku mode without having to rely on a "debug" stretch of code. This will also help facilitate other instances where a menu or menu-like situation needs to happen while still co-existing with the danmaku system.

I've already coded the sections needed for the graphical aspect of the transition, and one maintenance routine needed for re-entering danmaku mode. Here's hoping they all work out.
A Cherry-Flavored Iambian draws near... what do you do? ...

Offline annoyingcalc

  • LV10 31337 u53r (Next: 2000)
  • **********
  • Posts: 1950
  • Rating: +140/-72
  • Found in Eclipse.exe
    • View Profile
Re: Yet another shooter
« Reply #356 on: November 23, 2011, 11:05:43 am »
YES! more progress
This used to contain a signature.

Offline Iambian

  • Coder Of Tomorrow
  • LV8 Addict (Next: 1000)
  • ********
  • Posts: 737
  • Rating: +215/-3
  • Cherry Flavoured Nommer of Fishies
    • View Profile
Re: Yet another shooter
« Reply #357 on: November 26, 2011, 06:26:14 am »
Got the mini menu up and running.

What I've got to do now is put together something involving resource creation and management so I can finally put together some stages. OR... handle the high scores. Whichever works best for me at the time.

EDIT: Changed screenshot. Added a white backing on menu title to make it more visible under extreme circumstances.
« Last Edit: November 26, 2011, 07:07:14 am by Iambian »
A Cherry-Flavored Iambian draws near... what do you do? ...

Offline Yeong

  • Not a bridge
  • LV12 Extreme Poster (Next: 5000)
  • ************
  • Posts: 3739
  • Rating: +278/-12
  • Survivor of Apocalypse
    • View Profile
Re: Yet another shooter
« Reply #358 on: November 26, 2011, 07:51:31 am »
:D looks nice!
Are you planning to add more characters?
Sig wipe!

Offline Iambian

  • Coder Of Tomorrow
  • LV8 Addict (Next: 1000)
  • ********
  • Posts: 737
  • Rating: +215/-3
  • Cherry Flavoured Nommer of Fishies
    • View Profile
Re: Yet another shooter
« Reply #359 on: December 05, 2011, 06:14:07 pm »
Minor update: Working on the menu used to input your name for the high score screen / replay save screen. The screen shot below shows a test condition layered on top of the title screen. Note the small 's' is in black to show that it has been selected. The space below the lowercase 'z' is the space character. You have to back out of the menu by pressing MODE to finalize your selection. The DEL button moves the cursor backwards but does not erase anything. If you go back too far, just keep hitting the DEL key as it wraps around to the other side. Perhaps I can use the Y= button for moving the cursor forward? Now that's an idea...

[post attempt 3; forum attachment system appears to be broken. Using RFG for this.]


EDIT: Will modify this routine later on to make the spacing between the characters more like the rest of the game. Should be prettier.
« Last Edit: December 05, 2011, 06:15:31 pm by Iambian »
A Cherry-Flavored Iambian draws near... what do you do? ...