Jump to content

Photo

Learning assembly - porting Thrust to the TI-99/4a


72 replies to this topic

#26 palmheads OFFLINE  

palmheads

    Chopper Commander

  • Topic Starter
  • 205 posts
  • Location:Christchurch, New Zealand

Posted Sat Mar 28, 2015 7:47 PM

 

Yup think I found how, something like this

*------------------------------------------------------------
* VDP read status. Result will be in R0 MSB
*------------------------------------------------------------
VRDSTA MOV  @>8802,R0    Read status register, resets bits 0-2.
       B    *R11         Delay

Just quickly tried it in my code before my proximity checking - sprite collision already feels more accurate

 

cheers

Daryn



#27 Opry99er ONLINE  

Opry99er

    Quadrunner

  • 10,370 posts
  • Location:Hustisford, WI

Posted Sat Mar 28, 2015 9:39 PM

Awesome...

#28 Tursi OFFLINE  

Tursi

    Quadrunner

  • 5,420 posts
  • HarmlessLion
  • Location:BUR

Posted Sat Mar 28, 2015 10:11 PM

Be aware that there are two issues with reading the status register directly from the VDP.

 

The first one is software - every time the status register is read, it clears the sprite collision and vertical interrupt bits. So when you read it manually, there is a chance you can interfere with the interrupt routine (which only matters if you are using it - allowing LIMI 2 in your code). The interference is that sometimes you'll grab the bit, and sometimes it will, all depends who gets there first. ;) If you get it first, the interrupt may not happen on that frame. (No real negative consequences, but if you are using it for motion or music, they may slow down).

 

The second is hardware - if you read the bit at the exact time it is set, the update is sometimes lost. This is usually only an issue for collision if your sprite is only one row tall or only one row collides, since it's pretty much impossible on the TI to interfere with two sequential scanlines in a row.

 

If you aren't using the interrupt routine at all, feel free to carry on as you are - it's just sometimes helpful to have the information above in your back pocket in case you see unexpected behavior later. if you want to work around those issues, AND you /are/ using interrupts, the interrupt routine stores a copy of the status register every frame at >837B - you can read it from there instead of from the VDP directly. (Again, only if interrupts are enabled every frame).

 

Don't be afraid of directly polling - hundreds of programs have run just fine for years doing so. Even Extended BASIC does it that way (for CALL COINC). It's only recently we've really dug down deep enough to start understanding those things.



#29 Asmusr OFFLINE  

Asmusr

    River Patroller

  • 2,997 posts
  • Location:Denmark

Posted Sun Mar 29, 2015 5:04 AM

I would suggest to use a routine like this for your main loop timing that also saves the coincidence flag. You need to turn off interrupts (LIMI 0) for this to work.

*********************************************************************
*
* Wait for vsync 
* 
VDPSTA EQU  >8802            * VDP status

VSYNC  MOVB @VDPSTA,R0       * Clear interrupt flag if already set
       ANDI R0,>2000
       MOV  R0,@COINC        * Save coincidence flag
*      Wait for next vsync
VSYNC1 MOVB @VDPSTA,R0
       MOV  R0,R1
       ANDI R1,>2000
       SOC  R1,@COINC        * Save coincidence flag
       ANDI R0,>8000
       JEQ  VSYNC1           * Loop if interrupt flag not set
       B    *R11
*// VSYNC

COINC  DATA >0000


#30 palmheads OFFLINE  

palmheads

    Chopper Commander

  • Topic Starter
  • 205 posts
  • Location:Christchurch, New Zealand

Posted Sun Mar 29, 2015 9:22 PM

 

I would suggest to use a routine like this for your main loop timing that also saves the coincidence flag. You need to turn off interrupts (LIMI 0) for this to work.

*********************************************************************
*
* Wait for vsync 
* 
VDPSTA EQU  >8802            * VDP status

VSYNC  MOVB @VDPSTA,R0       * Clear interrupt flag if already set
       ANDI R0,>2000
       MOV  R0,@COINC        * Save coincidence flag
*      Wait for next vsync
VSYNC1 MOVB @VDPSTA,R0
       MOV  R0,R1
       ANDI R1,>2000
       SOC  R1,@COINC        * Save coincidence flag
       ANDI R0,>8000
       JEQ  VSYNC1           * Loop if interrupt flag not set
       B    *R11
*// VSYNC

COINC  DATA >0000

 

Awesome Rasmus - wee investigate this snippet more & see how it could integrate with my (shitty) code!

 

cheers

Daryn



#31 palmheads OFFLINE  

palmheads

    Chopper Commander

  • Topic Starter
  • 205 posts
  • Location:Christchurch, New Zealand

Posted Sun Mar 29, 2015 9:24 PM

Be aware that there are two issues with reading the status register directly from the VDP.

 

The first one is software - every time the status register is read, it clears the sprite collision and vertical interrupt bits. So when you read it manually, there is a chance you can interfere with the interrupt routine (which only matters if you are using it - allowing LIMI 2 in your code). The interference is that sometimes you'll grab the bit, and sometimes it will, all depends who gets there first. ;) If you get it first, the interrupt may not happen on that frame. (No real negative consequences, but if you are using it for motion or music, they may slow down).

 

The second is hardware - if you read the bit at the exact time it is set, the update is sometimes lost. This is usually only an issue for collision if your sprite is only one row tall or only one row collides, since it's pretty much impossible on the TI to interfere with two sequential scanlines in a row.

 

If you aren't using the interrupt routine at all, feel free to carry on as you are - it's just sometimes helpful to have the information above in your back pocket in case you see unexpected behavior later. if you want to work around those issues, AND you /are/ using interrupts, the interrupt routine stores a copy of the status register every frame at >837B - you can read it from there instead of from the VDP directly. (Again, only if interrupts are enabled every frame).

 

Don't be afraid of directly polling - hundreds of programs have run just fine for years doing so. Even Extended BASIC does it that way (for CALL COINC). It's only recently we've really dug down deep enough to start understanding those things.

 

 

Will definitely keep this in mind. At the moment this small change seems to have made the collisions way more accurate, even without tweaking the proxmity stuff for a particular sprite - so much fun getting stuff to work! I feel like a game could actually come out of this! :)

 

cheers

Daryn



#32 palmheads OFFLINE  

palmheads

    Chopper Commander

  • Topic Starter
  • 205 posts
  • Location:Christchurch, New Zealand

Posted Fri Apr 3, 2015 4:26 AM

Got another update! Source code attached

 

I implemented the snippet of code Rasmus suggested above for loop timing & sprite collision. Worked great! Have got far more accurate sprite collision thanks to being able to read the status register for collisions. Also was able to remove my dodgy delay loop. Thanks Rasmus!

 

The other thing I was able to figure out was cavern walls. Figured out how to read in the data & display, as well as designing the chars that make them.

 

I have to now figure out how my sprite can trigger a collision with the walls. Thats my next step.

 

Again, thank you everyone for your great advice on this. Been putting in time most days on this, and am enjoying it.

 

 

cheers

Daryn

Attached Files



#33 Opry99er ONLINE  

Opry99er

    Quadrunner

  • 10,370 posts
  • Location:Hustisford, WI

Posted Sat Apr 4, 2015 9:56 AM

Looking good!

#34 palmheads OFFLINE  

palmheads

    Chopper Commander

  • Topic Starter
  • 205 posts
  • Location:Christchurch, New Zealand

Posted Sat Apr 18, 2015 6:21 PM

Hi all

 

Got my nanoPEB working, so here is a vid of my game working on real hardware. Only a black & white TV until I get my PAL modulator modded for my Commodore 1702 monitor.

 

 

Am currently working on getting Sprite->wall collision.

 

Have been thinking through what todo. Does this make sense?

 

  • The main thrust sprite uses VDP 300/301 locations for its position.
  • These locations are HEX
  • The walls are characters. So they are the 32x24 matrix. Bottom right cnr being 768
  • To register a collision, would I needed to do a HEX-DECIMAL conversion of the VDP 300/301 locations, then test if the resulting location has a character code located there?

 

I think I am on the right track, just confirming this is the right logic?

 

cheers

Daryn


Edited by palmheads, Sat Apr 18, 2015 6:22 PM.


#35 Asmusr OFFLINE  

Asmusr

    River Patroller

  • 2,997 posts
  • Location:Denmark

Posted Sun Apr 19, 2015 1:00 AM

I think I am on the right track, just confirming this is the right logic?

 

I'm not sure about the hex-demical stuff. Those number systems are for presentation, but inside the computer the numbers are all the same.

 

What you need to do is to read your sprite position (x,y) into two registers. You can use call @VSBR to read a VDP byte into R1 and then MOV it to the right register. You also need a SWPB to get it into the low byte.

 

Then you can convert the sprite position to a character position by dividing each register by 8 (using SRL Rx,3).

 

To get from a character position to an address in the name table you multiply the y character position by 32 (SLA Rx,5), add the x position, and add the base address of the name table. 

 

When you have the name table address you can read the content using @VSBR.

 

Note that you usually don't want to check the location the sprite are at, but a location next to it, so you need to make some adjustments depending on which direction the sprite is moving.

 

This above just a rough sketch. It would be better to keep the sprite position and a copy of the map in CPU RAM at all times, so you don't have to go to the VDP to look it up. There is also an issue with the sprite y position being off by 1 (top row is not 0 but -1) that you have to deal with. 



#36 Opry99er ONLINE  

Opry99er

    Quadrunner

  • 10,370 posts
  • Location:Hustisford, WI

Posted Sun Apr 19, 2015 1:16 AM

Good advice...

Reading the VDP for boundary checks is similar to using GCHAR in XB. If you have a copy of the map in RAM (as Rasmus suggests) it is much faster and easier to detect.

I have a bad habit of using the "screen" to dictate boundaries... It is much better to use your actual "map data" for this purpose... Keep the "display" separate from your determining logic.

#37 palmheads OFFLINE  

palmheads

    Chopper Commander

  • Topic Starter
  • 205 posts
  • Location:Christchurch, New Zealand

Posted Sun Apr 19, 2015 5:26 PM

 

I'm not sure about the hex-demical stuff. Those number systems are for presentation, but inside the computer the numbers are all the same.

 

What you need to do is to read your sprite position (x,y) into two registers. You can use call @VSBR to read a VDP byte into R1 and then MOV it to the right register. You also need a SWPB to get it into the low byte.

 

Then you can convert the sprite position to a character position by dividing each register by 8 (using SRL Rx,3).

 

To get from a character position to an address in the name table you multiply the y character position by 32 (SLA Rx,5), add the x position, and add the base address of the name table. 

 

When you have the name table address you can read the content using @VSBR.

 

Note that you usually don't want to check the location the sprite are at, but a location next to it, so you need to make some adjustments depending on which direction the sprite is moving.

 

This above just a rough sketch. It would be better to keep the sprite position and a copy of the map in CPU RAM at all times, so you don't have to go to the VDP to look it up. There is also an issue with the sprite y position being off by 1 (top row is not 0 but -1) that you have to deal with. 

 

Cheers, thanks Rasmus - will see if I can figure this out given your advice. Will report back when done!

 

Thanks mate!

 

Daryn



#38 palmheads OFFLINE  

palmheads

    Chopper Commander

  • Topic Starter
  • 205 posts
  • Location:Christchurch, New Zealand

Posted Fri Jun 5, 2015 11:02 PM

Sorry guys, been a bit lazy lately. Thought I had some sprite/wall collisions working at one stage, but was proved wrong! Still looking at getting it working.

 

cheers

Daryn



#39 palmheads OFFLINE  

palmheads

    Chopper Commander

  • Topic Starter
  • 205 posts
  • Location:Christchurch, New Zealand

Posted Mon Jun 22, 2015 1:59 AM

OK made some progress. I know its nowhere near perfect, but at least I have the thrust ship recognising collisions with a least 'some' of the walls! Needs alot more work, but can see some progress. 

 

 

Will continue to work on it. Have a bit more of a handle on how to get this working now.

 

cheers

Daryn



#40 Vorticon OFFLINE  

Vorticon

    River Patroller

  • 3,495 posts
  • Location:Eagan, MN, USA

Posted Tue Jun 23, 2015 8:30 AM

Nice work! This is going to be a sweet game when it's finished  :thumbsup:



#41 CantStopClicking OFFLINE  

CantStopClicking

    Moonsweeper

  • 316 posts
  • Location:Pacific Northwest (and I hate it)

Posted Tue Jul 21, 2015 12:34 PM

OK made some progress. I know its nowhere near perfect, but at least I have the thrust ship recognising collisions with a least 'some' of the walls! Needs alot more work, but can see some progress. 

 

Will continue to work on it. Have a bit more of a handle on how to get this working now.

 

cheers

Daryn

 

Wow, great job on your learning assembly.

 

Christ, I've been trying to write my name on the screen in assembly and it's taken me 20+ years.  I finally did it the other day!  Nothing else worked but I did get that far...

 

Looking forward to your updates and thanks for sharing your progress!

 

-Dano



#42 mjnurney OFFLINE  

mjnurney

    Space Invader

  • 22 posts
  • Location:Yorkshire - Milton Keynes

Posted Thu Jul 23, 2015 5:00 PM

Really good work, keep it up - it's a great game.

Will getting the gravity correct be hard do you think ?

#43 --- Ω --- OFFLINE  

--- Ω ---

    Sunbaenim

  • 13,479 posts

Posted Thu Jul 23, 2015 7:13 PM

@ mjnurney,

   You have a real interesting Avatar.  I love those eyes, and the rest isn't bad either.  :grin:



#44 palmheads OFFLINE  

palmheads

    Chopper Commander

  • Topic Starter
  • 205 posts
  • Location:Christchurch, New Zealand

Posted Fri Jul 24, 2015 12:20 AM

Really good work, keep it up - it's a great game.

Will getting the gravity correct be hard do you think ?

 

Oh yeah, thats gonna be nasty! Gonna have to learn me some maths! :)

 

cheers

Daryn 



#45 Thomas Jentzsch OFFLINE  

Thomas Jentzsch

    Thrust, Jammed, SWOOPS!, Boulder Dash, THREE·S, Star Castle

  • 23,843 posts
  • Always left from right here!
  • Location:Düsseldorf, Germany, Europe, Earth

Posted Fri Jul 24, 2015 1:01 AM

Gonna have to learn me some maths!  :)

Gravity is very easy. Assuming you have the vertical speed separated from the horizontal speed, you just have to subtract a constant gravity value from the vertical speed each frame. Very similar to applying thrust to the movement.

 

However, the tow bar physics are a completely different beast.



#46 palmheads OFFLINE  

palmheads

    Chopper Commander

  • Topic Starter
  • 205 posts
  • Location:Christchurch, New Zealand

Posted Sat Jul 25, 2015 4:12 AM

Gravity is very easy. Assuming you have the vertical speed separated from the horizontal speed, you just have to subtract a constant gravity value from the vertical speed each frame. Very similar to applying thrust to the movement.

 

However, the tow bar physics are a completely different beast.

 

Think this might be the next thing I try Thomas, now that I have got more of a handle on wall collisions. Will get gravity & thrust acceleration working.

 

I might need your help with the tow bar physics in the future. That has always seems to be to be the hardest thing. Quite interesting how such a seemingly simple game is actually so complex behind the scenes. Jeremy Smith the original author deserves alot of credit huh?

 

cheers

Daryn



#47 palmheads OFFLINE  

palmheads

    Chopper Commander

  • Topic Starter
  • 205 posts
  • Location:Christchurch, New Zealand

Posted Mon Oct 12, 2015 3:38 AM

Hi Team!

 

Made some more progress on 'Thrust'

 

Its not quite a working "gravity", but I've got a subroutine now that forces my ship down, and you have to react to that by pressing up/left/right etc.

 

I needed to also change my wall collision stuff because of different pixel/character locations, but I think I also made that a bit more versatile.

 

 

cheers

Daryn



#48 Willsy OFFLINE  

Willsy

    River Patroller

  • 3,100 posts
  • Location:Uzbekistan (no, really!)

Posted Mon Oct 12, 2015 6:38 AM

Marvelous !!!  :thumbsup: 

And I've got to say I love your use of lowercase and semicolons for comments - have to look at it twice not to confuse it with my own code.

Me too! I do the same thing!
 

I'm beginning to have the labels on separate lines (no code) to more easily insert code and move blocks around - with or without the label.


I've also started to recently do that, as I'm now adopting the use of labels with > 6 characters. Finding unique 6 character labels for TurboForth sometimes required some inventive thinking! Not surprising when you see how many labels are in it:

 

Spoiler

:-o



#49 Willsy OFFLINE  

Willsy

    River Patroller

  • 3,100 posts
  • Location:Uzbekistan (no, really!)

Posted Mon Oct 12, 2015 6:42 AM

It's got a very nice ZX Spectrum/Retro feel to it. Love it! :thumbsup:

 

I see it says EK! when you hit something, I assume, therefore, that it's written by a Yorkshireman :P



#50 Vorticon OFFLINE  

Vorticon

    River Patroller

  • 3,495 posts
  • Location:Eagan, MN, USA

Posted Mon Oct 12, 2015 8:16 AM

Looking great  :thumbsup:  It would seem however that the downward force is a bit too strong, requiring very frequent corrections. I think it would play better if that force was reduced a bit. Of course ideally, you could implement full gravity using the formula v=-0.5gt and play with values of g to achieve a pleasing result. That way, the drop would start slowly and gradually build up. t could be based off of a manually incremented counter somewhere in your main game loop which resets when upward thrust is applied. Keep everything as integers of course. Dividing by half is simply shifting a register to the right once using SRL. Ignore the formula's negative sign and simply replace the downward force with the result of the calculation for each increment of t.






0 user(s) are browsing this forum

0 members, 0 guests, 0 anonymous users