Author Topic: Figuring out what's in front of you (RayCaster)  (Read 5682 times)

0 Members and 1 Guest are viewing this topic.

Offline ACagliano

  • LV8 Addict (Next: 1000)
  • ********
  • Posts: 919
  • Rating: +32/-2
    • View Profile
    • ClrHome Productions
Figuring out what's in front of you (RayCaster)
« on: January 18, 2015, 03:17:03 pm »
So, for my game, I'm trying to come up with a quick way to take a player's current location, and check a set distance, like say 20 units, away from them, and maybe like 10 units either direction at that distance (kind of like the field of vision), and determine what objects are in viewing range. I have a scaled sprite routine that I've figured out how to work, so now I just have to draw a tree, a house, a car, a few oil tanks, and a note. Once this bit is done, I'm ready to compile and test!

That being said, anyone any ideas? I have an 8.8 FP number for your current location and a 1-byte angle for your direction.
« Last Edit: January 27, 2015, 11:50:38 am by ACagliano »

Offline Xeda112358

  • they/them
  • Moderator
  • LV12 Extreme Poster (Next: 5000)
  • ************
  • Posts: 4704
  • Rating: +719/-6
  • Calc-u-lator, do doo doo do do do.
    • View Profile
Re: Figuring out what's in front of you.
« Reply #1 on: January 18, 2015, 04:16:51 pm »
So do you have the coordinates of the objects?

Offline chickendude

  • LV8 Addict (Next: 1000)
  • ********
  • Posts: 817
  • Rating: +90/-1
  • Pro-Riot Squad
    • View Profile
Re: Figuring out what's in front of you.
« Reply #2 on: January 18, 2015, 07:08:38 pm »
This should probably be under the asm help section. If you have the coordinates of your objects, you just need to establish what your field of vision is (based on how far away they are) and check whether the coordinates fall in line.

Offline ACagliano

  • LV8 Addict (Next: 1000)
  • ********
  • Posts: 919
  • Rating: +32/-2
    • View Profile
    • ClrHome Productions
Re: Figuring out what's in front of you.
« Reply #3 on: January 18, 2015, 07:29:50 pm »
So do you have the coordinates of the objects?

Yes, the coordinates of the objects are in a tilemap

Offline shmibs

  • しらす丼
  • Administrator
  • LV11 Super Veteran (Next: 3000)
  • ***********
  • Posts: 2132
  • Rating: +281/-3
  • try to be ok, ok?
    • View Profile
    • shmibbles.me
Re: Figuring out what's in front of you.
« Reply #4 on: January 18, 2015, 10:39:03 pm »
use LUTs. if you have a tilemap, it won't have to account for every single angle. just make a hash from the angle values to the shape, in tiles, it can see

Offline ACagliano

  • LV8 Addict (Next: 1000)
  • ********
  • Posts: 919
  • Rating: +32/-2
    • View Profile
    • ClrHome Productions
Re: Figuring out what's in front of you.
« Reply #5 on: January 21, 2015, 11:44:11 am »
I hate when someone says "make a hash" lmao jk.

I really do need to get to work on this now that the static is out of the way.

I was considering looping the angle you are standing at and scanning the distance for objects, but that might be harder than some of the proposed solutions, that I don't entirely get. I may also be able to use trig functions to figure out the area that is viewable, and then check nearby objects to see if points fall in range. If this is indeed ray-casting, I have zero experience. What is the quickest way to do it?
« Last Edit: January 26, 2015, 09:33:05 am by ACagliano »

Offline ACagliano

  • LV8 Addict (Next: 1000)
  • ********
  • Posts: 919
  • Rating: +32/-2
    • View Profile
    • ClrHome Productions
Re: Figuring out what's in front of you (RayCaster)
« Reply #6 on: January 27, 2015, 11:54:57 am »
Edit: so with a little nudge, and a helpful resource, I am trying to develop my own raycasting engine, portable, and with configurable render distance (bc I'm not entirely sure what my render distance will be yet until I test). What I've have gathered so far is:

- RayStart becomes the X and Y position of the player, the "camera". Render distance is the camera plane, the farthest the routine will render to.
- You are basically following the direct line from you to the camera plane, incrementing by 1 "unit" per iteration and testing for an object.
- continue this until you hit the camera plane.

Which is great. I get that. But where does it come in where I'm going from POV-left to POV-right, not just directly in front of you? Unless I'm missing part of the explanation that talks about that.

Here's the start of what I have:

Code: [Select]
#define rayStart Op8
#define rayEnd Op8+2
#define renderDistance 10 ; change this to tweak render distance
#define rcStack Op8+4


engine_rayCaster_Init:
ld hl,smallEditCol
ld (raycastStack),hl ; reset pointer to start of raycaster stack
ld e,(playerPosY)
ld (rayStart),e
ld (rayEnd),e ; initialize player position as start and current end of ray
ld d,(playerPosX)
ld (rayStart+1),d
ld (rayEnd+1),d ; initialize player position as start and current end of ray
ld e,l
ld d,h ; ray End temp (may delete ram if i can)  de = ray start, hl = ray end
ld bc,(playerVectorX)
push bc
_rc_loop:
add hl,bc
ld a,l
push hl
multAbyWidth ; out hl
ld c,b
ld b,0
add hl,bc ; offset in map to get
jr _rc_loop_test
_rc_test_exit:
pop hl
call _rc_push



_rc_loop_test:
; yes, i know i didnt actually put in the pointer to the map data. pretend, i did that.
ld a,(hl)
or a
jr nz,{1@}
pop bc
jr _rc_loop
@:
jr _rc_test_exit


_rc_push:
ld de,(rcStack)
ld (de),a ; map object pushed to stack
inc de
ld (de),hl ; object position push to stack
ld hl,(rayStart)
inc de
inc de
ld (de),hl ; your position pushed to stack (i will throw in a distance calc here, bc this is multiple data entries)
inc de
inc de
ld (rcStack),de
ret
« Last Edit: January 27, 2015, 12:50:42 pm by ACagliano »

Offline Runer112

  • Moderator
  • LV11 Super Veteran (Next: 3000)
  • ***********
  • Posts: 2289
  • Rating: +639/-31
    • View Profile
Re: Figuring out what's in front of you (RayCaster)
« Reply #7 on: January 27, 2015, 02:10:57 pm »
You simply loop through angle values between the left edge of the field of view and the right edge. If you're raycasting for rendering purposes, the step size should usually be set such that one ray is cast for each column of pixels in the output. If you're raycasting for other purposes, it should usually be the largest value that is still small enough not to "miss" seeing objects between two rays.

Offline ACagliano

  • LV8 Addict (Next: 1000)
  • ********
  • Posts: 919
  • Rating: +32/-2
    • View Profile
    • ClrHome Productions
Re: Figuring out what's in front of you (RayCaster)
« Reply #8 on: January 27, 2015, 02:18:27 pm »
My angle is +/- 5 byte degrees. So in pseudo-code:

Code: [Select]
for (a,  from angle-5 to angle+5, 1 ) {
     calc (x,y) vectors of a
     figure out all points on line from player (x,y), in increments of above (x,y), till render distance
     push any objects found onto a stack
     }
render stack

Offline Runer112

  • Moderator
  • LV11 Super Veteran (Next: 3000)
  • ***********
  • Posts: 2289
  • Rating: +639/-31
    • View Profile
Re: Figuring out what's in front of you (RayCaster)
« Reply #9 on: January 27, 2015, 02:20:18 pm »
5 binary degrees seems like it could work to me. If not, you can just decrease it easily enough.

Offline ACagliano

  • LV8 Addict (Next: 1000)
  • ********
  • Posts: 919
  • Rating: +32/-2
    • View Profile
    • ClrHome Productions
Re: Figuring out what's in front of you (RayCaster)
« Reply #10 on: January 27, 2015, 02:22:50 pm »
Ok sounds good. Now to convert that pseudo-code into assembly... LET THE 200 PAGES OF CODE COMMENCE!!!!!!

Offline ACagliano

  • LV8 Addict (Next: 1000)
  • ********
  • Posts: 919
  • Rating: +32/-2
    • View Profile
    • ClrHome Productions
Re: Figuring out what's in front of you (RayCaster)
« Reply #11 on: January 27, 2015, 03:43:28 pm »
Update: Got a routine. Let me know if I goofed up anywhere:

The routine should create an 11-entry stack for the rendering-routine to process. Each "entry" corresponds to a section of the "screen". Entry 1 is far left, 2 is next to that, and so on. If the renderer hits a $ff, it skips that section of screen. Otherwise, it renders the masked greyscale sprite (which is based through a scale-down routine, based on distance) for that section and moves on.

Feel free to correct/optimize, but let me know what I did wrong so I learn from it :p

Code: [Select]
#define distance tempSwapArea ; 1 byte
#define rayCurrent distance+1 ; 2 bytes
#define angleCurrent rayEnd+2 ; 1 byte
#define angleStart angleCurrent+1 ; 1 byte
#define angleStop angleStart+1 ; 1 byte
#define iterVector angleStop+1  ; 2 bytes
#define rcStack iterVector+2 ; 2 bytes, a pointer to the start of the raycaster object stack
#define renderDistance 10 ; adjust this to change the render distance
#define priorAngle rcStack+2 ; 1 byte


engine_raycaster_Init:
ld hl,smallEditCol
ld (rcStack),hl ; reset pointer to start of raycaster stack
ld a,(playerDirection)
ld hl,priorAngle
cp (hl)
jr z,{1@}
ld a,b
ld b,5
add a,b
ld (angleStop),a
ld b,-10
add a,b
ld (angleStart),a
@: ld a,(angleStart) ; sorry about this bit, but needs to be here for the jump to work
ld (angleCurrent),a ; shouldnt be too time-consuming to do that
rc_loop_angle:
call _getTempVector
ld a,(playerPosX)
ld h,a
ld a,(playerPosY)
ld l,a
ld bc,(iterVector)
rc_loop_ray:
add hl,bc
call rc_getDistance
ld (distance),a
ld a,l
multAbyWidth
ld c,h
ld b,0
add hl,bc
call rc_getMap
ld a,(hl)
or a
jr z,rc_tilepush_skip
; rc_tilepush: if tile is something, push this object onto rcStack, renderer will handle it
ld de,(rcStack)
ld (de),a ; object type Id
inc de
ld a,(distance)
ld (de),a
inc de
ld (rcStack),de
jr rc_skip_writeempty
rc_tiletest_skip:
ld a,(distance)
cp renderDistance
jr z,rc_loop_angle_next
jr c,rc_loop_angle_next
jr rc_loop_ray
rc_loop_angle_next:
ld de,(rcStack)
ld a,$ff
ld (de),a
inc de
ld (rcStack),de
rc_skip_writeempty:
ld a,(angleCurrent)
inc a
ld (angleCurrent),a
jr rc_loop_angle








rc_getTempVector:
; using current angle, gets vectors. each vector is in 8.8 FP format, so we only save the .8 part
; input: a = angle
; output: new vectors loaded into (iterVector) word
push af
call calcSin ; a = angle
ld (iterVector),l ; hl = 8.8 FP
pop af
call calcCos
ld (iterVector+1),l
ret

rc_getMap:
; input: hl = offset in map
; output: hl points to tile
ld bc,(SlendMapPtr)
add hl,bc
ret

rc_getDistance:
; input: hl = current testing location
; output: a = distance from origin
ret
« Last Edit: January 28, 2015, 09:25:10 am by ACagliano »

Offline chickendude

  • LV8 Addict (Next: 1000)
  • ********
  • Posts: 817
  • Rating: +90/-1
  • Pro-Riot Squad
    • View Profile
Re: Figuring out what's in front of you (RayCaster)
« Reply #12 on: January 28, 2015, 04:46:37 am »
Um.. have you even tried to assemble that code? Don't you have the other necessary portions of the program already written to be able to check if the code works or not? I'm not sure why you're working on this if the other portions of the code haven't been written yet ;)

The code you gave won't compile, there are several invalid instructions. The only 8-bit register that can read from/write to an address is a, so you can't do "ld b,(addr)" or "ld (addr),l". You have to load the value into a first.

This:
Code: [Select]
ld a,(priorAngle)
ld b,(playerDirection)
cp b
jr z,rc_loop_angle
ld a,b
ld b,5
add a,b
ld (angleStop),a
ld b,-10
add a,b
ld (angleCurrent),a
Could be:
Code: [Select]
ld a,(playerDirection)
ld hl,priorAngle
cp (hl)
jr z,rc_loop_angle
add a,5
ld (angleStop),a
sub 10
ld (angleCurrent),a
That does what your code does (and will actually assemble). But i'm not sure if you really wanted to be using playerDirection to add those values to or priorAngle. Probably priorAngle. Shouldn't you at least try to assemble your code first?

I can't comment on the code as a whole because i don't really understand raycasting or what you're trying to do, sorry...

Offline ACagliano

  • LV8 Addict (Next: 1000)
  • ********
  • Posts: 919
  • Rating: +32/-2
    • View Profile
    • ClrHome Productions
Re: Figuring out what's in front of you (RayCaster)
« Reply #13 on: January 28, 2015, 09:17:40 am »
That does what your code does (and will actually assemble). But i'm not sure if you really wanted to be using playerDirection to add those values to or priorAngle. Probably priorAngle. Shouldn't you at least try to assemble your code first?

I can't comment on the code as a whole because i don't really understand raycasting or what you're trying to do, sorry...

I know there are certain technicalities within it like the ld b,** stuff. However, I want to get the routine conceptually working, then i fix that.
To answer your question about priorAngle, that is actually just a check if whether the current angle and the last angle we calculated are the same. If they are, then we skip the part where we figure out angleStop and the starting angle (which I just found a mistake... angle current needs to be manually set if we do that, or angleStart and angleCurrent need to be separate).

***Edit*** fixed all instances of that, and amended my code to above to reflect

***Edit 2 *** found another mistake. As of now, the raycaster, when calculating the vectors for the present angle, only saves the .8 part of the 8.8FP number. However, in the routine, i add hl (where h= x origin integer and l= y origin integer) to bc (where b is the .8 part of the x vector and c is the .8 part of the y vector). Clearly, that's a mistake, but short of adding more RAM and using the full 8.8 location, i don't see a workaround.
« Last Edit: January 28, 2015, 01:16:49 pm by ACagliano »

Offline ACagliano

  • LV8 Addict (Next: 1000)
  • ********
  • Posts: 919
  • Rating: +32/-2
    • View Profile
    • ClrHome Productions
Re: Figuring out what's in front of you (RayCaster)
« Reply #14 on: January 31, 2015, 09:35:00 am »
bump