Jump to content

Photo

Session 23: Moving Sprites Vertically


42 replies to this topic

#26 SpiceWare OFFLINE  

SpiceWare

    Draconian

  • 12,263 posts
  • Medieval Mayhem
  • Location:Planet Houston

Posted Sat May 27, 2006 8:20 PM

Your Air CSS Battle is quite impressive!

#27 nmoog OFFLINE  

nmoog

    Space Invader

  • 44 posts

Posted Sun May 28, 2006 12:07 AM

Thanks SpiceWare! I actually thought making a game using DOM scripting would be pretty challenging. Then I started following Andrew's tutorial here. Turns out I didn't know the meaning of challenging :)

#28 SpiceWare OFFLINE  

SpiceWare

    Draconian

  • 12,263 posts
  • Medieval Mayhem
  • Location:Planet Houston

Posted Sun May 28, 2006 8:01 AM

I was lucky in that I already knew 6502 from my C= days. That made it a lot easier to get Medieval Mayhem started.

#29 nmoog OFFLINE  

nmoog

    Space Invader

  • 44 posts

Posted Mon May 29, 2006 2:24 AM

Hey Guys,

Although I'm having a great time messing around with this stuff, I was hoping you could give me a hand as I think if I keep going by Im going to be leading myself into a path of pain.

I've got a lil' guy moving up and down... kind of. He magically gets a hat when going down and a podium when going up. THough this isn't the bit thats really troubling me. I don't know where in each frame (before the frame starts, after the vertical syncs, during the screen drawing etc) I should be doing:
* Joystick checking
* Horizontal Positioning
* vertical positioning

In the horizontal positioning subroutine that Andrew listed it starts with "sta WSYNC" - does that mean I don't do the wsync at the end of the main loop as well?

Thank for your help

Attached Files



#30 Thomas Jentzsch OFFLINE  

Thomas Jentzsch

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

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

Posted Mon May 29, 2006 2:50 AM

I don't know where in each frame (before the frame starts, after the vertical syncs, during the screen drawing etc) I should be doing:
* Joystick checking
* Horizontal Positioning
* vertical positioning

Joystick: best before positioning, since you want to react to the players input immediately.
Positioning: before the display kernel, after stuff like joystick, collision checking etc.

Actually, there is no strict pattern you have to follow. Just do it in some logical order. Later on, you might discover that reordering your code may make things easier.

In the horizontal positioning subroutine that Andrew listed it starts with "sta WSYNC" - does that mean I don't do the wsync at the end of the main loop as well?

The RESPx commands have to be timed exactly, so you need a WSYNC before. But that doesn't mean you have to do it inside the kernel. You can do everything whereever you want (except HMOVEs during vertical sync).

#31 nmoog OFFLINE  

nmoog

    Space Invader

  • 44 posts

Posted Mon May 29, 2006 4:43 PM

Yes! Thanks Thomas!

I was trying to run the xpositioning code during the screen draw. Whoops! Now I've got a lil' guy running round the screen - on an atari 2600!!!

I have another query on the WSYNC thing though - if I do the 37 vertical blank WSYNC before drawing, then one WSYNC for the X Positioning code - then 192 WSYNCS for the screen then 30 WSYNCS for the overscan... don't I have 1 WSYNC too many? Doesn't that WSYNC I called for the X positioning push everything down one line?

#32 SpiceWare OFFLINE  

SpiceWare

    Draconian

  • 12,263 posts
  • Medieval Mayhem
  • Location:Planet Houston

Posted Mon May 29, 2006 9:47 PM

Yep, but most TVs are forgiving if you provide too many or too few lines, provided it's the same number of lines each time. ie sending 263, 263, 263 would be OK, but sending 262, 263, 262 will cause the screen to jiggle up/down.

You'll probably want to next look at replacing the 37 vertical blank WSYNCs and 30 overscan WSYNCs with the timer. Check this sample code from khryssun where he's using the timer for the vertical blank. The key things are setting the timer using TIM64T and checking if the timer is done using INTIM.

Edited by SpiceWare, Mon May 29, 2006 9:48 PM.


#33 nmoog OFFLINE  

nmoog

    Space Invader

  • 44 posts

Posted Tue May 30, 2006 6:08 AM

That's really cool - I was wondering where the game logic went!
I love your Medieval Mayhem game too - great idea.

#34 SpiceWare OFFLINE  

SpiceWare

    Draconian

  • 12,263 posts
  • Medieval Mayhem
  • Location:Planet Houston

Posted Tue May 30, 2006 8:46 AM

I love your Medieval Mayhem game too - great idea.

Thanks! I decided to do it after getting my nephew's friends hooked on Warlords when I was visiting this past Xmas. Having grown up with PS2s, they'd been been slamming the Atari's graphics. They changed their tune once they realized graphics weren't everything :lol:.

If you'd like to see the source for it, it's available in my blog.

#35 Moose1900 OFFLINE  

Moose1900

    Space Invader

  • 13 posts

Posted Mon Dec 21, 2015 9:48 AM

does anyone have a working example of a skipdraw routine?  I have seen many postings of the code for just the routine, but never a simple program that draws a sprite on the screen using skip draw.  I have tried for the past few weeks, but can't seem to get it to work. I think if I saw a simple example that works, then I could see where I am going wrong.  Any help would be much appreciated.

 Thanks.



#36 zilog_z80a OFFLINE  

zilog_z80a

    Chopper Commander

  • 102 posts

Posted Thu Sep 14, 2017 9:25 PM

does anyone have a working example of a skipdraw routine?  I have seen many postings of the code for just the routine, but never a simple program that draws a sprite on the screen using skip draw.  I have tried for the past few weeks, but can't seem to get it to work. I think if I saw a simple example that works, then I could see where I am going wrong.  Any help would be much appreciated.

 Thanks.

 

I'm asking my self the same,

i have the same problem with this skipdraw routine, and can't understand how it works just for a few lines 

how's possible to write pointer content to GRP0 register if A register isn't transferred to Y regsiter as index?

a little confused, even i saw this url: 
 

http://www.biglist.c...9/msg00059.html

and there's a tay instruction before loading accumulator with pointer

 

TAY
LDA (ZERO_PAGE_PTR),y

STA GRP0

 

BUMP...


Edited by zilog_z80a, Fri Sep 15, 2017 10:50 PM.


#37 zilog_z80a OFFLINE  

zilog_z80a

    Chopper Commander

  • 102 posts

Posted Fri Sep 15, 2017 9:31 PM

ok, think it's done, now will take the bin and run into stella's debugger to understand in a more detailed way what's going on with carry and brach.

 

cheers.

 

 

   processor 6502

   include "vcs.h"
   include "macro.h"
   
   seg.u uninitialized
   org $80
 
SpriteEnd ds 1
SPRITEHEIGHT equ 8
spriteP0 ds 2
 
   SEG DATA
   ORG $F000
Reset
 
   lda #0
   ldx #0
clear_mem
   sta $0,x   
   inx
   bne clear_mem
   
   lda #30
   sta COLUP0
   lda #60
   sta SpriteEnd ; SPRITE Y POSITION
 
   lda #<Sprite0Data
   sta spriteP0
   lda #>Sprite0Data
   sta spriteP0+1 
   
Start_of_frame:
   lda #0
   sta VBLANK 
   lda #2
   sta VSYNC
   sta WSYNC
   sta WSYNC
   sta WSYNC
   lda #0
   sta VSYNC
   
   ldy #36
vertical_blank
   sta WSYNC
   dey
   bne vertical_blank
   
   ldx #191
scan_lines:   
   sta WSYNC
   sec
   txa
   sbc SpriteEnd
   adc #SPRITEHEIGHT
   bcc .skipDraw
   tay
   lda (spriteP0),y
   sta GRP0
.skipDraw
   dex
   bne scan_lines
   
   lda #%01000010
   sta VBLANK
   
   ldy #29
overscan
   sta WSYNC
   dey
   bne overscan
   
   jmp Start_of_frame
 
Sprite0Data
  .byte #%00000000
  .byte #%11111111
  .byte #%00000000
  .byte #%11111111
  .byte #%00000000
  .byte #%11111111
  .byte #%11111111
  .byte #%11111111
        
   ORG $FFFA
InterruptVectors
   .word Reset
   .word Reset
   .word Reset
   END

Edited by zilog_z80a, Fri Sep 15, 2017 10:33 PM.


#38 zilog_z80a OFFLINE  

zilog_z80a

    Chopper Commander

  • 102 posts

Posted Fri Sep 15, 2017 9:57 PM

the only way i found to make Andrew's solution work was adding one instruction TAY please correct me if i'm wrong.  

 

Andrew's solution

   sec;                                        ;2  can often be guaranteed, and omitted

   tya                                         ; 2
   sbc SpriteEnd                       ; 3
   adc #SPRITE_HEIGHT        ; 2
   bcs .MBDraw3                      ; 2(3)
   nop                                        ; 2
   nop                                        ; 2
   sec                                        ; 2
   bcs .skipMBDraw3                ; 3
   .MBDraw3
   lda (Sprite),y                         ; 5
   sta GRP0                              ; 3
  .skipMBDraw3

-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

   ldx #191
scan_lines:   
   sta WSYNC
   sec
   txa
   sbc SpriteEnd
   adc #SPRITEHEIGHT
   bcs .draw
   nop
   nop
   nop
   sec
   bcs .skipdraw
.draw
   tay   ; <······························································ EXTRA INSTRUCTION
   lda (spriteP0),y   ; use indirect loading here
   sta GRP0
.skipdraw
   dex
   bne scan_lines
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
 
Cheers.

Edited by zilog_z80a, Fri Sep 15, 2017 10:21 PM.


#39 Thomas Jentzsch OFFLINE  

Thomas Jentzsch

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

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

Posted Sat Sep 16, 2017 3:41 AM

No, that's not the way it is meant to be.

 

SkipDraw is optimized for CPU time, therefore you have to setup the sprite pointers correctly outside the kernel.  Also SkipDraw assumes that Y contains your current scanline and not X. Only then you can use Y directly for pointer reads and X is completely free for other stuff.

 

Also the branch to .draw wastes one cycle. To avoid that, branch the non-draw to somewhere outside the kernel and then return to .skipDraw.


Edited by Thomas Jentzsch, Sat Sep 16, 2017 3:43 AM.


#40 zilog_z80a OFFLINE  

zilog_z80a

    Chopper Commander

  • 102 posts

Posted Sat Sep 16, 2017 8:26 AM

 

 

No, that's not the way it is meant to be.

 

SkipDraw is optimized for CPU time, therefore you have to setup the sprite pointers correctly outside the kernel.  Also SkipDraw assumes that Y contains your current scanline and not X. Only then you can use Y directly for pointer reads and X is completely free for other stuff.

 

Also the branch to .draw wastes one cycle. To avoid that, branch the non-draw to somewhere outside the kernel and then return to .skipDraw.

 

Hi Thomas, ty for your fast reply, please can you show me some url with example code?
 
do you mean with, outside kernel, to set something outside the 192 scanlines? i have arranged pointers outside the 192 scanlines. am i right? (code bellow)
 
  processor 6502
   include "vcs.h"
   include "macro.h"
   
   seg.u uninitialized
   org $80
 
SpriteEnd ds 1
SPRITEHEIGHT equ 8
spriteP0 ds 2
 
   SEG DATA
   ORG $F000
Reset
 
   lda #0
   ldx #0
clear_mem
   sta $0,x   
   inx
   bne clear_mem
   
   lda #30
   sta COLUP0
   lda #60
   sta SpriteEnd ; SPRITE Y POSITION

;--------------------------------------------------------------------------------------------------------------------------- 
   lda #<Sprite0Data
   sta spriteP0
   lda #>Sprite0Data
   sta spriteP0+1
;--------------------------------------------------------------------------------------------------------------------------- 

I saw here: http://www.biglist.c...9/msg00060.html

 

this:
 

> .contDrawPlayer:
>     dey
>     tya
>     sbc yPosP0
>     adc #H_TANK
>     bcs.doDrawP0
>     lda #0
>     NOP_W
> .doDrawP0:
>     lda (ptrP0),y
>     sta.w GRP0

The key is the NOP_W, which is an equate for $0C, which is the opcode NOP
abs.  (An illegal/undocumented version of NOP.  The documented way is to use
$2C which is BIT abs)  So if the bcs is not taken the lda (ptrP0),y gets
absorbed into the NOP and is not executed.
 

Is sta.w another undocumented opcode too or just a type error?
i have found undocumented opcodes for 6502 but dunno if it works with 6507
 

http://nesdev.com/un...ted_opcodes.txt

 

returning about this subject, vertical position,

Dear Thomas, any example code would be really really appreciated.
 

Thanks again and thanks in advance.
 

 

 

Subject: [stella] Usefull illegal opcodes (part 1)
From: "Thomas Jentzsch" <tjentzsch@xxxxxx>
Date: Fri, 23 Feb 2001 08:59:28 +0100
Hi,
yesterday, i was thinking about a faster way to decide in a kernel if you are on a sprite drawing line or not.

The best way, i knew until now, was (if y contains linecounter):
  tya                   ; 2
 (sec                   ; 2) <- this can sometimes be avoided
  sbc SpriteEnd         ; 3
  adc #SPRITEHEIGHT     ; 2
  bcx .skipDraw         ; 2 = 9-11 cycles
  ...

If you like using illegal opcodes, you can use dcp (dec,cmp) here:
  lda #SPRITEHEIGHT     ; 2
  dcp SpriteEnd         ; 5     initial value has to be adjusted
  bcx .skipDraw         ; 2 = 9
  ...

Advantages:
- state of carry flag doesn't matter anymore (may save 2 cycles)
- a remains constant, could be useful for a 2nd sprite
- you could use the content of SpriteEnd instead of y for accesing sprite data
- ???

Have fun!
Thomas

 


Edited by zilog_z80a, Sat Sep 16, 2017 10:57 AM.


#41 Thomas Jentzsch OFFLINE  

Thomas Jentzsch

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

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

Posted Sat Sep 16, 2017 11:56 AM

:idea: Check this post.

.w just tells the assembler to create a 3 byte instruction when you access a zero page address, which is useful if you want to waste 1 cycle.



#42 zilog_z80a OFFLINE  

zilog_z80a

    Chopper Commander

  • 102 posts

Posted Sun Sep 17, 2017 10:19 PM

:idea: Check this post.

.w just tells the assembler to create a 3 byte instruction when you access a zero page address, which is useful if you want to waste 1 cycle.

 

 

Ty Thomas, was searching around the web for skipdraw and have found a lot of info, once my brain be able to process it... will post something here to receive your blessing.

pd: ty 4 da url.

 

cheers.


Edited by zilog_z80a, Sun Sep 17, 2017 10:20 PM.


#43 Sheldon Sims OFFLINE  

Sheldon Sims

    Chopper Commander

  • 117 posts
  • Location:Burkeville, TX USA

Posted Sat May 12, 2018 7:42 PM

 

2) Create another data table, and use a variable to determine which of the two data tables to display. You might like to have it switch between these tables every second, or perhaps use the joystick button to determine which is displayed. As a hint - remember, you need to setup the zero page pointer to point to the table for your sprite draw to use - so all you need to do is change this pointer, and leave your kernel code alone.

 

I am back after a 13-year hiatus.  I was about to give up on this one, but after having a little talk with Jesus, I figured it out.  I was beginning to think that my 47-year old brain didn't work well anymore.  Anyway, I borrowed a little code from Kirk Israel and nmoog, and came up with the attached solution to Exercise 2.  It uses a variable to point to one of 6 tables based on input (or lack thereof) from the joystick.  Programming the Atari VCS is definitely challenging, but I am determined.

 

The program reacts accordingly to joystick left, right, up, down, button or no input at all.  Now on to exercise 3.   :grin:

Attached Files


Edited by Sheldon Sims, Sat May 12, 2018 8:32 PM.





0 user(s) are browsing this forum

0 members, 0 guests, 0 anonymous users