It is currently Sun Oct 22, 2017 5:55 pm

All times are UTC - 7 hours



Forum rules


Related:



Post new topic Reply to topic  [ 291 posts ]  Go to page Previous  1 ... 14, 15, 16, 17, 18, 19, 20  Next
Author Message
PostPosted: Fri Aug 04, 2017 6:07 am 
Offline

Joined: Sun Sep 19, 2004 11:12 pm
Posts: 19115
Location: NE Indiana, USA (NTSC)
Sumez wrote:
sure there are some nice examples of NES games created in C, but I'm sure we can all agree on the massive overhead it creates

And any fan of Koei war sims would consider the overhead worth it.

Now as I find time, I could help solve "g. Less known working demo source code." Now that I've started on my own music engine S-Pently, I plan to do more on this system.

But I'm still drawing a blank for "c-d. Filling 15 colors and 3 layers". Bregalad makes a good point about solo projects. With SMW art quality being the low bar on Super NES, solo developers scale their plans back to the NES, where solo art is more acceptable. Progressing past a solo project requires interpersonal skills to interest pixel artists in your project, which can prove difficult with the autism endemic among hobbyist programmers.

So I guess I have to demonstrate these issues myself by porting several of my old NES projects to Super NES. It'll add some working source code for other programmers to look at. But it'll also show how out-of-place NES-grade solo artwork looks on Super NES outside Williams Arcade's Greatest Hits.


Top
 Profile  
 
PostPosted: Fri Aug 04, 2017 10:42 am 
Offline
User avatar

Joined: Wed Dec 06, 2006 8:18 pm
Posts: 2801
I would agree that artwork and music/dealing with the SPC are the biggest challenges for doing something on the SNES. The standards for audio and visual quality on the SNES can be pretty high among players when compared to the top licensed games.

But if you can get the right people involved that are serious about a project and can devote the time to it, I don't think the SNES is significantly less accessible than similar platforms. Homebrew and licensed games can both suffer from poor quality due to lack of knowledge or time. Of course other platforms can make things easier like the PC since anyone that can make artwork or music in whatever format you can probably convert and use.

To the original topic, I wouldn't say there is "no homebrew scene" for the SNES. There's plenty of homebrew and hacks out there for the SNES.


Top
 Profile  
 
PostPosted: Fri Aug 04, 2017 4:59 pm 
Offline
User avatar

Joined: Thu Sep 15, 2016 6:29 am
Posts: 253
Location: Denmark (PAL)
There's plenty of hacks (which really isn't homebrew, even if a few more creative ones are borderline), and maybe a couple of actual homebrews. :P But is there any "scene" apart from what's present here?


Top
 Profile  
 
PostPosted: Fri Aug 04, 2017 7:09 pm 
Offline

Joined: Sun Nov 23, 2014 12:16 pm
Posts: 165
It would be really great if someone made a easy to use snes game engine and tools for SNES development. And while I know that there are tools and programs that exists it just seems like there really isn't any community of people doing it.

However if you look at some of the SNES hacking scenes, some of them are actually pretty advanced. For example the Super Metroid hacking scene has produced some good hacks. And the one scene which seems to dominate over all is the smw hacking scene. There are literally hundreds of custom sprites, hundreds of custom blocks and hundreds of custom level codes and patches. Combined with a top quality editor and lots of tools, you can literally make all sorts of new games using the smw game engine.


Top
 Profile  
 
PostPosted: Fri Aug 04, 2017 7:55 pm 
Offline

Joined: Sun Sep 19, 2004 11:12 pm
Posts: 19115
Location: NE Indiana, USA (NTSC)
But the SMW hacks also contain substantially all the artwork from SMW. An all-new engine designed to make SMW hacking less necessary would need all-new artwork.


Top
 Profile  
 
PostPosted: Fri Aug 04, 2017 9:12 pm 
Offline

Joined: Wed May 19, 2010 6:12 pm
Posts: 2295
I've been busy today squeezing my animation engine down to as little lines of code as possible. I want it so short that noobies would think I wrote it in just a few minutes.


Top
 Profile  
 
PostPosted: Sat Aug 05, 2017 1:24 am 
Offline
User avatar

Joined: Mon Sep 15, 2014 4:35 pm
Posts: 3074
Location: Nacogdoches, Texas
psycopathicteen wrote:
@Espozo. When you program, do you start from scratch each time, or do you continue where you left off?

I start where I left off. I don't comment anything, but I give everything super-long, descriptive names. I just haven't been programming for a good long while now.

Erockbrox wrote:
you can literally make all sorts of new games using the smw game engine.

It's just unfortunate, because SMW is a really shitty base. :?

Oh yeah, about audio, I've still never gotten around to touching it. I don't even know what responsibilities people generally give the SPC 700; I'd probably let the 65816 actually mix the songs and just send commands to the SPC700.


Top
 Profile  
 
PostPosted: Sat Aug 05, 2017 7:51 am 
Online
User avatar

Joined: Tue Apr 05, 2016 5:25 pm
Posts: 124
Espozo wrote:
Erockbrox wrote:
you can literally make all sorts of new games using the smw game engine.

It's just unfortunate, because SMW is a really shitty base. :?

I have to agree. Just looking at a RAM map of SMW is enough to make me want to shake my head. You're going to get more mileage out of a homebrew engine or even writing your own thing from scratch.

Espozo wrote:
Oh yeah, about audio, I've still never gotten around to touching it. I don't even know what responsibilities people generally give the SPC 700; I'd probably let the 65816 actually mix the songs and just send commands to the SPC700.

This is inadvisable. There's a reason the SPC700 has high resolution timers and is mostly isolated from the rest of the system. It's basically an early example of threaded audio. You don't want to get stuck notes while the main CPU is busy doing other things. That's the sort of stuff you get on the NES and Genesis but is virtually non-existent on the SNES. IMHO, just figure out how the SPC upload protocol works, then toy around with SNESGSS or another existing homebrew sound driver. You're going to get results much faster that way.

_________________
SNES NTSC 2/1/3 1CHIP | serial number UN318588627


Top
 Profile  
 
PostPosted: Sat Aug 05, 2017 7:02 pm 
Offline

Joined: Wed May 19, 2010 6:12 pm
Posts: 2295
If I'm trying to make a code library for others to use, how much shorter do I need to make this code to not look intimidating?

Code:
animation:
ldy {metasprite_request}
bne +            //no animation, if "metasprite_request" is blank
jsr clear_vram_slot
stz {frame_id}
rts
+;
lda {animation_update}      //sprite is animated if "metapsprite" is different from
bne +            //"metasprite_request" or "animation_update" is set
cpy {metasprite}
bne +
rts
+;
lda $000c,y
tax
clc
adc {total_dma_legnth}      //check if there is enough DMA time for sprite
cmp #$0081
bcc ++
lda {first_object_to_dma}
bne +
tdc
sta {first_object_to_dma}
+;
rts
+;
stx {vram_size}
jsr clear_vram_slot      //clear previous animation frame
stz {180_degrees_flip}
lda {animation_update}
cmp #$0002         //if "animation_update" is 2, then frame is rotated 180 degrees
bne +
lda #$c000
sta {180_degrees_flip}
+;
stz {animation_update}
ldy {metasprite_request}
sty {metasprite}

lda $000e,y
clc
adc {animation_index}
inc #2
sta {frame_id}
tax
lda {animation_copies},x
beq +            //if animation_copies is not 0, then no further processing
inc            //is needed
sta {animation_copies},x
rts
+;
inc
sta {animation_copies},x

lda $000a,y         //find the ROM address of sprite graphics
asl #5            //ROM address = metasprite ROM address + (animation frame)*(metasprite ROM size)
sta {vram_width}
sep #$20
lda {animation_index}
lsr
sta $4202
lda $000c,y
sta $4203
nop
rep #$20
lda $4216
asl #5
clc
adc $0006,y
sta {temp3}         //"temp3" is ROM address
lda $0008,y
sta {temp2}         //"temp2" is ROM bank
lda $0010,y
bpl +            //if $0010,y is $7fff or less, it is the metasprite data itself
tya            //if $0010,y is $8000 or more, it is the address pointing to metasprite data
clc
adc {animation_index}
tax
ldy $0010,x
+;
phd
lda #$0000
tcd
ldx #$ffff
-;
   lda $0010,y
   bne +
   txa
invalid_chr:
   pld
   ldx {frame_id}
   sta {animation_chr},x
   lda {vram_size}
   clc
   adc {total_dma_legnth}
   sta {total_dma_legnth}
   rts            //this is where the game exits the routine
   +;
   xba
   and #$000f
   sta.b {temp7}         //"temp7" counts down the vertical sprite run
   lda $0011,y
   and #$0070
   lsr #4
   sta.b {temp8}         //"temp8" counts down the horizontal sprite run
   lda $0018,y
   adc.b {temp3}
   sta.b {temp}            //"temp" is the ROM address of the sprite being added
   sta.b {temp9}            //"temp9" is the ROM address of the top sprite in a vertical run
   lda $0012,y
   sta.b {temp_x}
   lda $0014,y
   sta.b {temp_y}
   sty.b {temp5}
-;
      jmp find_vram_slot
find_vram_slot_done:
      ldy.b {temp5}         //this puts all the "OAM" information
      lda.b {temp6}         //onto the linked list
      ora $0016,y
      sta {sprite_attributes},x
      lda.b {temp4}
      sta {sprite_size},x
      asl
      tay
      lda.b {temp_x}
      sta {sprite_x},x
      lda.b {temp_y}
      sta {sprite_y},x
      dec.b {temp7}         //decreases "temp 7" until all sprites
      bmi +            //in the vertical run are put on linked list
      clc
      adc sprite_size_LUT,y
      sta.b {temp_y}
      ldy.b {temp5}
      bra -
+;
      dec.b {temp8}         //decreases "temp 8" until all sprites
      bmi +            //in the horizontal run are put on linked list
      lda.b {temp_x}
      clc
      adc sprite_size_LUT,y
      sta.b {temp_x}
      lda.b {temp9}
      clc
      adc sprite_size_LUT2,y
      sta.b {temp9}         //this moves the ROM address of the sprites
      sta.b {temp}         //to the next sprite in a horizontal run
      ldy.b {temp5}
      lda $0014,y
      sta.b {temp_y}
      lda $0011,y
      and #$000f
      sta.b {temp7}
      jmp -
+;
   lda.b {temp5}
   clc
   adc #$000a
   tay
   jmp --

sprite_size_LUT:
dw $0010,$0020,$0010,$0020
sprite_size_LUT2:
dw $0040,$0080,$0040,$0080

find_vram_slot:
lda $0010,y
txy
and #$0003
dec
beq small_slot
cmp #$0001
beq large_slot

repeat_slot:         //this finds repeat slots
tsb.b {temp4}
ldx {repeat_slot_stack_index}
dex
dex
bpl +
tya
jmp invalid_chr
+;
lda {repeat_slot_stack},x
stx {repeat_slot_stack_index}
tax
tya
sta {sprite_name},x      //puts it on linked list
jmp find_vram_slot_done

small_slot:         //this finds 16x16 VRAM slot
sta.b {temp4}
ldx {small_slot_stack_index}
dex
dex
bpl +
tya
jmp invalid_chr
+;
lda {small_slot_stack},x
stx {small_slot_stack_index}
tax
tya
sta {sprite_name},x      //adds slot to linked list
lda x16_lut,x
ldy.b {dma_updates}
sta {dma_destination},y      //sets up dma queue
clc
adc #$0100
sta {dma_destination}+8,y
lda.b {temp}
sta {dma_address},y
adc {vram_width}
sta {dma_address}+8,y
adc {vram_width}
sta.b {temp}
lda.b {temp2}
ora #$4000
sta {dma_bank},y
sta {dma_bank}+8,y
tya
clc
adc #$0010
sta.b {dma_updates}
stx.b {temp6}
jmp find_vram_slot_done

large_slot:         //finds open 32x32 VRAM slot
sta.b {temp4}
ldx {large_slot_stack_index}
dex
dex
bpl +
tya
jmp invalid_chr
+;
lda {large_slot_stack},x
stx {large_slot_stack_index}
tax
tya
sta {sprite_name},x      //adds slot to linked list
lda x16_lut,x
ldy.b {dma_updates}
sta {dma_destination},y      //sets up DMA queue
clc
adc #$0100
sta {dma_destination}+8,y
adc #$0100
sta {dma_destination}+16,y
adc #$0100
sta {dma_destination}+24,y
lda.b {temp}
sta {dma_address},y
adc {vram_width}
sta {dma_address}+8,y
adc {vram_width}
sta {dma_address}+16,y
adc {vram_width}
sta {dma_address}+24,y
adc {vram_width}
sta.b {temp}
lda.b {temp2}
ora #$8000
sta {dma_bank},y
sta {dma_bank}+8,y
sta {dma_bank}+16,y
sta {dma_bank}+24,y
tya
clc
adc #$0020
sta.b {dma_updates}
stx.b {temp6}
jmp find_vram_slot_done


x16_lut:
dw $0000,$0020,$0040,$0060,$0080,$00a0,$00c0,$00e0,$0110,$0120,$0140,$0160,$0180,$01a0,$01c0,$01e0
dw $0200,$0220,$0240,$0260,$0280,$02a0,$02c0,$02e0,$0310,$0320,$0340,$0360,$0380,$03a0,$03c0,$03e0
dw $0400,$0420,$0440,$0460,$0480,$04a0,$04c0,$04e0,$0510,$0520,$0540,$0560,$0580,$05a0,$05c0,$05e0
dw $0600,$0620,$0640,$0660,$0680,$06a0,$06c0,$06e0,$0710,$0720,$0740,$0760,$0780,$07a0,$07c0,$07e0
dw $0800,$0820,$0840,$0860,$0880,$08a0,$08c0,$08e0,$0910,$0920,$0940,$0960,$0980,$09a0,$09c0,$09e0
dw $0a00,$0a20,$0a40,$0a60,$0a80,$0aa0,$0ac0,$0ae0,$0b10,$0b20,$0b40,$0b60,$0b80,$0ba0,$0bc0,$0be0
dw $0c00,$0c20,$0c40,$0c60,$0c80,$0ca0,$0cc0,$0ce0,$0d10,$0d20,$0d40,$0d60,$0d80,$0da0,$0dc0,$0de0
dw $0e00,$0e20,$0e40,$0e60,$0e80,$0ea0,$0ec0,$0ee0,$0f10,$0f20,$0f40,$0f60,$0f80,$0fa0,$0fc0,$0fe0
dw $1000,$1020,$1040,$1060,$1080,$10a0,$10c0,$10e0,$1110,$1120,$1140,$1160,$1180,$11a0,$11c0,$11e0
dw $1200,$1220,$1240,$1260,$1280,$12a0,$12c0,$12e0,$1310,$1320,$1340,$1360,$1380,$13a0,$13c0,$13e0
dw $1400,$1420,$1440,$1460,$1480,$14a0,$14c0,$14e0,$1510,$1520,$1540,$1560,$1580,$15a0,$15c0,$15e0
dw $1600,$1620,$1640,$1660,$1680,$16a0,$16c0,$16e0,$1710,$1720,$1740,$1760,$1780,$17a0,$17c0,$17e0
dw $1800,$1820,$1840,$1860,$1880,$18a0,$18c0,$18e0,$1910,$1920,$1940,$1960,$1980,$19a0,$19c0,$19e0
dw $1a00,$1a20,$1a40,$1a60,$1a80,$1aa0,$1ac0,$1ae0,$1b10,$1b20,$1b40,$1b60,$1b80,$1ba0,$1bc0,$1be0
dw $1c00,$1c20,$1c40,$1c60,$1c80,$1ca0,$1cc0,$1ce0,$1d10,$1d20,$1d40,$1d60,$1d80,$1da0,$1dc0,$1de0
dw $1e00,$1e20,$1e40,$1e60,$1e80,$1ea0,$1ec0,$1ee0,$1f10,$1f20,$1f40,$1f60,$1f80,$1fa0,$1fc0,$1fe0

no_slot_to_clear:
rts

clear_vram_slot:   //this routine clears the VRAM slots of the previous animation frame
ldx {frame_id}
beq no_slot_to_clear
lda {animation_copies},x
beq +
dec
sta {animation_copies},x
bne no_slot_to_clear
+;
lda {animation_chr},x
-;
cmp #$ffff
beq no_slot_to_clear
tax
lda {sprite_size},x
beq clear_small_slot
cmp #$0001
beq clear_large_slot
txa
ldx {repeat_slot_stack_index}
sta {repeat_slot_stack},x
inx
inx
stx {repeat_slot_stack_index}
bra +

clear_small_slot:
txa
ldx {small_slot_stack_index}
sta {small_slot_stack},x
inx
inx
stx {small_slot_stack_index}
bra +

clear_large_slot:
txa
ldx {large_slot_stack_index}
sta {large_slot_stack},x
inx
inx
stx {large_slot_stack_index}
+;
tax
lda {sprite_name},x
jmp -


Last edited by psycopathicteen on Sun Aug 06, 2017 4:22 am, edited 1 time in total.

Top
 Profile  
 
PostPosted: Sat Aug 05, 2017 7:33 pm 
Offline

Joined: Tue Mar 01, 2016 8:22 pm
Posts: 21
psycopathicteen wrote:
If I'm trying to make a code library for others to use, how much shorter do I need to make this code to not look intimidating?

Comment as much as possible. There is no such thing as "too obvious" when it comes to beginners.


Top
 Profile  
 
PostPosted: Sat Aug 05, 2017 8:54 pm 
Offline

Joined: Sat Apr 25, 2015 1:47 pm
Posts: 329
Location: FL
If you have almost 350 lines of assembly code with literally zero comments, the length isn't what people are going to find intimidating about it.


Top
 Profile  
 
PostPosted: Sat Aug 05, 2017 9:22 pm 
Offline

Joined: Wed May 19, 2010 6:12 pm
Posts: 2295
I began trying to put comments on my code, but then realized that I should really make diagrams to visualize it too.

Let's see if I can sum this up. It uses linked VRAM slots. Each onscreen metasprite has a chain of VRAM slots with a beginning and end. Each VRAM slot has a metasprite-relative x/y coordinate and attribute tied to it. Several objects can share the same chain at once with a different origin and flip settings. There are special slot numbers that aren't real VRAM locations, but signify if a CHR number is a repeat of the last one, but with a different relative x/y or attributes, which can be useful for making tiled moving platforms.

Is that explanation good?


Top
 Profile  
 
PostPosted: Sun Aug 06, 2017 3:36 am 
Offline
User avatar

Joined: Mon Jan 23, 2006 7:47 am
Posts: 70
psycopathicteen wrote:
I began trying to put comments on my code, but then realized that I should really make diagrams to visualize it too.

Let's see if I can sum this up. It uses linked VRAM slots. Each onscreen metasprite has a chain of VRAM slots with a beginning and end. Each VRAM slot has a metasprite-relative x/y coordinate and attribute tied to it. Several objects can share the same chain at once with a different origin and flip settings. There are special slot numbers that aren't real VRAM locations, but signify if a CHR number is a repeat of the last one, but with a different relative x/y or attributes, which can be useful for making tiled moving platforms.

Is that explanation good?

Mention anything that you'd want to see if you were a user of this code.
- author (name, email, website, accounts on the websites you frequent), version, date, license
- does it require specific assembler(s), hardware (e.g. no SNES MINI) or emulators?
- operating principle
- detailed reference
- example(s)
- links


Top
 Profile  
 
PostPosted: Sun Aug 06, 2017 7:53 am 
Online
User avatar

Joined: Tue Apr 05, 2016 5:25 pm
Posts: 124
A few issues I am noticing with the posted code:

- This looks like one large function that is doing a lot. Separation of concerns is a key principle here. Of course for performance reasons it may be good to bundle many actions together, but if this is only getting called for maybe 16 objects a frame, you can afford to split it up.
- I can't tell which labels are intended to be called from user code, and which ones are internal branch/jump destinations. It doesn't help that the first label is simply titled "animation". Generally you'll want to name your functions after verbs, and also include the scope or target of your action in the name. Is the function processing animation for all objects? Or the current object? You may also want to include notes on when/where it is appropriate to call this function, along with input parameters and side-effects.
- Use of magic numbers ("if "animation_update" is 2, then frame is rotated 180 degrees") You should replace 2 with a constant.
- Maybe personal preference, but it could use more blank lines between groups of instructions so each "step" of the routine is more apparent. Maybe also comment overall what each step (group of instructions) is doing on a high level. Learning code is easier when you understand the general purpose of each segment of code. And personally I would find this more helpful than commenting individual lines (though if an individual line is doing something weird, might want to comment that too).

I feel like this code is trying to do a lot in general, and perhaps I'm paranoid, but it could use some optimization and redesign. That's not necessarily a bad thing - I've reworked my code several times in the past. It's rare to come up with the perfect design on the first try, and this is just the reality of software development. But splitting things up as I mentioned above, and documenting how the different systems work together (what each function expects, the format of the underlying data, etc.) will make that much easier.

Of course, you can still provide the code like it is, and then improve on it later with a new version. User testing may be some of the most valuable testing you can find. Just remember to attach a license to your code so that people can use it.

_________________
SNES NTSC 2/1/3 1CHIP | serial number UN318588627


Top
 Profile  
 
PostPosted: Sun Aug 06, 2017 8:24 am 
Offline

Joined: Wed May 19, 2010 6:12 pm
Posts: 2295
The thing is that it has to decode the meta sprite format in order to find the ROM address of the needed sprite graphics.


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 291 posts ]  Go to page Previous  1 ... 14, 15, 16, 17, 18, 19, 20  Next

All times are UTC - 7 hours


Who is online

Users browsing this forum: HihiDanni and 10 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
Powered by phpBB® Forum Software © phpBB Group