Jump to content
IGNORED

Collision detection


LX.NET

Recommended Posts

I need a bit of help on this one. I am working on the collision detection for Pitfall and have got most of it set up. The lynx-160-102-16.tgi driver sets up the collision detection buffer at $A058 and the collision depository offset at $FFFE (minus 2 I believe) automatically. Collision detection is started by myself by using:

asm("lda #$04");

asm("sta $fc92");

 

The collisions are detected, but I notice some weird, unexpected behavior. Imagine Harry walking in the underground from left to right. He turns around before he encounters the scorpion and runs to the left again. As the scorpion approaches Harry, but before it reaches him collisions start occurring with the scorpion (coll number 4) hitting Harry (coll number 15) at places where Harry has been. Not every frame, but every other frame. It seems to me that the collision buffer is not cleared. I do a call to tgi_clear() whenever I redraw the screen.

 

My questions:

  • Am I correct in the assumptions that the buffer is not cleared?
  • How do you clear the collision buffer officially if not via tgi_clear() ?
  • What are possible reasons that the scorpion sprite has a changing collision depository value every other frame?
  • Is there a neat trick to visualize the collision buffer? I tried a quick and dirty hack with the collision base address and also with the collision build buffer:

if (kbhit())

{

switch (cgetc())

{

case 'P': // Swap around collision build buffer with video build buffer

asm("lda $FC0E");

asm("sta $FC0C");

asm("lda $FC0F");

asm("sta $FC0D");

while (true);

But that did not seem to work.

  • Is there a timing restriction on when you can read the collision depositories from the sprites? Specific moments?
  • Why is the collision depository at -2, not -1. There is only a 4 bit value written to it, so why use an int value?

 

Thanks in advance for any advice or hints. Source code available on demand.

 

Alex

Link to comment
Share on other sites

You have to clean the collision buffer every time you redraw the screen. When you draw something the same would be added to the collisionbuffer.

 

in the old c it looks like this

 

 

 

extern char clsSCB[];

extern uchar cls_color;

 

#asm

 

; sprite used to clear the collision buffer

dc.w 0 ; collision depository

_clsSCB: dc.b $c0,$90,$00 ; collision number is 0!

dc.w 0,cls_data

dc.w 0,0 ; X,Y

dc.w 255*$100,102*$100 ; scaled to 255*102 pixels original 160 cause we use more space scrolled

_cls_color: dc.b $00

 

; data: 1*1 pixel

cls_data dc.b 2,$10,3

 

#endasm

 

/***********************************************/

/* Clears the screen _and_ the collsion buffer */

/***********************************************/

CLS(nColor)

uchar nColor;

{

cls_color = nColor; // Quick and dirty

DrawSprite(clsSCB);

}

Link to comment
Share on other sites

  • Is there a timing restriction on when you can read the collision depositories from the sprites? Specific moments?

 

Yes., after the last sprite has been finished dfrawing and before you start to draw it again.

 

  • Why is the collision depository at -2, not -1. There is only a 4 bit value written to it, so why use an int value?

 

because the SCB can have different sizes. thus is easier to have negative offsets or you would have to use the maximum size for each SCB and waste a lot of memory.

Link to comment
Share on other sites

because the SCB can have different sizes. thus is easier to have negative offsets or you would have to use the maximum size for each SCB and waste a lot of memory.

Hi Sage,

Yes, I understand why it is negative. What I do not understand is why the default is -2. Since the collision number is just a 4 bit number set in the SPRCOLL of the SCB, is there a reason to reserve 2 bytes for the depository? I would think that you could use a single byte.

Do you know why (not)?

Link to comment
Share on other sites

Hi Sage,

Yes, I understand why it is negative. What I do not understand is why the default is -2. Since the collision number is just a 4 bit number set in the SPRCOLL of the SCB, is there a reason to reserve 2 bytes for the depository? I would think that you could use a single byte.

Do you know why (not)?

 

I do nott know why you think -2 is a "default" value here?

Link to comment
Share on other sites

It's not a hardware default, but a chosen one in CC65.

In the libsrc for lynx-160-102-16.s you can find:

 

INIT:

; Enable interrupts for VBL

lda #$80

tsb VTIMCTLA

; Set up collision buffer to $A058

lda #$58

sta COLLBASL

lda #$A0

sta COLLBASH

; Put collision index before sprite data

lda #$FE

sta COLLOFFL

lda #$FF

sta COLLOFFH

 

which makes a "default" of FFFE for the COLLOFF collision depository offset. You must create a struct like this:

 

typedef struct

{

int collision;

sprite_sizable sprite;

} sprite_entity_collidable;

 

to work with the correct value. At least, that is what I think. Correct?

 

So, I still wonder: why an int and -2 as default? Any particular reason for that?

Link to comment
Share on other sites

There is actually an ioctl command for starting the collision detection.

 

tgi_ioctl(5, 0/1);

 

Or use the more convenient form tgi_setcollisiondetection(active); where active=0 or 1.

 

--

Karri

Thanks Karri,

I forgot about that one. I will add it to my code and the upcoming tutorial.

Link to comment
Share on other sites

It's not a hardware default, but a chosen one in CC65.

In the libsrc for lynx-160-102-16.s you can find:

 

as it seems, only there, neither newcc65 nor bll have this strange init values.

 

So, I still wonder: why an int and -2 as default? Any particular reason for that?

 

Nah, just looks waste of memory.

Link to comment
Share on other sites

You have to clean the collision buffer every time you redraw the screen. When you draw something the same would be added to the collisionbuffer.

in the old c it looks like this

...

Thanks matashen,

Tried this in a cc65 way and it works. It does seem though that this slows down rendering considerably (at least in Handy emulation) up to the point where I start missing frames. I will look at that.

 

As it turns out the implementation of tgi_clear draws non-collidable sprites to clear only the visible screen. Makes sense, as you would only want to clear the collision buffer when you are using it. It does beg for an implementation of tgi_clearcollisionbuffer() or an overload method tgi_clear(true) where the Boolean indicates whether to clear the collision buffer as well. Karri?

Link to comment
Share on other sites

It's not a hardware default, but a chosen one in CC65.

In the libsrc for lynx-160-102-16.s you can find:

 

INIT:

; Enable interrupts for VBL

lda #$80

tsb VTIMCTLA

; Set up collision buffer to $A058

lda #$58

sta COLLBASL

lda #$A0

sta COLLBASH

; Put collision index before sprite data

lda #$FE

sta COLLOFFL

lda #$FF

sta COLLOFFH

 

which makes a "default" of FFFE for the COLLOFF collision depository offset. You must create a struct like this:

 

typedef struct

{

int collision;

sprite_sizable sprite;

} sprite_entity_collidable;

 

to work with the correct value. At least, that is what I think. Correct?

 

So, I still wonder: why an int and -2 as default? Any particular reason for that?

 

The reason is that the length of the sprite struct is not constant. So it is very difficult to place it after the sprite. Instead I placed it before the sprite so that the tgi-driver does not have to know how large the sprite struct is.

 

But why is it -2 and not -1? Perhaps I thought that it needs on int and not a byte. I can change that.

Edited by karri
Link to comment
Share on other sites

As it turns out the implementation of tgi_clear draws non-collidable sprites to clear only the visible screen. Makes sense, as you would only want to clear the collision buffer when you are using it. It does beg for an implementation of tgi_clearcollisionbuffer() or an overload method tgi_clear(true) where the Boolean indicates whether to clear the collision buffer as well. Karri?

 

tgi_clear() is reserved as it is. Do we need a separate command for clearing the collision buffer or is it enough if the active flag from activating the collision detection would change the the tgi_clear() to clear both buffers?.

Link to comment
Share on other sites

I would say your suggestion is very good. tgi_clear will also clear the collision buffer when it is enabled. Would a separate method for explicitly clearing the buffer be useful? You wouldn't have to depend on the collision detection to be enabled. Just thinking out loud.

Link to comment
Share on other sites

I vote for the specialized tgi_clearcollisionbuffer method.

I have few reasons connected to my coding habits but most importantly I believe, is trying to keep the API away from being bloated.

I know that on our latest computers it does not sound armful, but CPU cycles and memory are very precious on Lynx, if I do not use the hard collision buffer I would prefer not to loose memory to store the unnecessary code and cpu on each frame to test if the collision buffer is activated.

Link to comment
Share on other sites

I changed to offset to -1 for the collision index of a sprite. I also changed the behaviour of tgi_clear. Normal tgi_clear works without collision buffer erasing. If you activate collision detection through the tgi_setcollisiondetection(1) then the sprite type of tgi_clear() is changed so that it will also erase the collision detection screen.

 

Changing the collision away will reurn the standard tgi_clear() operation back again.

 

There is no extra code run in tgi_clear() due to this change.

 

Unfortynately I have not had the time to test this code yet. But I hope it works.

--

Karri

Edited by karri
Link to comment
Share on other sites

The collision detection demo has the same stack bug as my pong game. The C-stack and the collision buffer are now sharing he same memory are. So the stack is filled with zeroes on every round. To fix this you need to add "-C lynx-coll.cfg" to the linker command line.

 

Here is the fixes sources.

collision.zip

Link to comment
Share on other sites

Is the clearing of the collision buffer (for a full screen) a particular long operation? I thought it would be as cycle-consuming as a full screen paint times two (at most). I notice that when I do a draw of the full-screen sprite that I start getting frame-drops.

 

This also begs the question: what if you want to do a partial collision buffer clearing? A tgi_clearcollisionbuffer(0, 0, 160, 51) would be great for that. Right now, the tgi_clear always does a full screen clear, right?

Link to comment
Share on other sites

Is the clearing of the collision buffer (for a full screen) a particular long operation? I thought it would be as cycle-consuming as a full screen paint times two (at most). I notice that when I do a draw of the full-screen sprite that I start getting frame-drops.

 

This also begs the question: what if you want to do a partial collision buffer clearing? A tgi_clearcollisionbuffer(0, 0, 160, 51) would be great for that. Right now, the tgi_clear always does a full screen clear, right?

 

As clearing the buffer is done on drawing a sprite (like 1*1 pixel scaled to screen size), it will take roughly two times the time for drawing the sprite without collision. the time is consumed by the memory writes, not the sprite decoding in this case.

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...