Why no SNES homebrew scene?

Discussion of hardware and software development for Super NES and Super Famicom. See the SNESdev wiki for more information.

Moderator: Moderators

Forum rules
  • For making cartridges of your Super NES games, see Reproduction.
calima
Posts: 1745
Joined: Tue Oct 06, 2015 10:16 am

Re: Why no SNES homebrew scene?

Post by calima »

Another example I discovered today. This KS for a simple SNES game was estimated to take 6 months; now it's taken two years and three months, and it's still not complete.

https://www.kickstarter.com/projects/43 ... ns-of-dea/
User avatar
HihiDanni
Posts: 186
Joined: Tue Apr 05, 2016 5:25 pm

Re: Why no SNES homebrew scene?

Post by HihiDanni »

So, like most Kickstarter projects then? You also neglected to mention that they said they were building the engine from scratch. Which, yeah, is going to take longer. This really just highlights the importance of having engines available for people to use.
SNES NTSC 2/1/3 1CHIP | serial number UN318588627
User avatar
Bregalad
Posts: 8055
Joined: Fri Nov 12, 2004 2:49 pm
Location: Divonne-les-bains, France

Re: Why no SNES homebrew scene?

Post by Bregalad »

calima wrote:Another example I discovered today. This KS for a simple SNES game was estimated to take 6 months; now it's taken two years and three months, and it's still not complete.

https://www.kickstarter.com/projects/43 ... ns-of-dea/
The NES game I'm working on started development in early 2005, and it's still not complete.
tepples
Posts: 22705
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Re: Why no SNES homebrew scene?

Post by tepples »

The thing about "engines" is that the Super NES probably isn't powerful enough for something as generic as, say, Unity or Unreal. Feel free to prove me wrong, but though an RPG, a platformer, and a vertical shmup could share a large set of hardware libraries, their engines would probably be structured very differently.
calima
Posts: 1745
Joined: Tue Oct 06, 2015 10:16 am

Re: Why no SNES homebrew scene?

Post by calima »

Writing a platformer engine that doesn't even scroll would be a matter of weeks, not years.
psycopathicteen
Posts: 3140
Joined: Wed May 19, 2010 6:12 pm

Re: Why no SNES homebrew scene?

Post by psycopathicteen »

calima wrote:Another example I discovered today. This KS for a simple SNES game was estimated to take 6 months; now it's taken two years and three months, and it's still not complete.

https://www.kickstarter.com/projects/43 ... ns-of-dea/
I laughed when I saw that guy in the video. How many unfinished SNES games has that guy advertised?
User avatar
dougeff
Posts: 3078
Joined: Fri May 08, 2015 7:17 pm

Re: Why no SNES homebrew scene?

Post by dougeff »

now it's taken two years and three months
But, that's how long I would expect a game like this to take to develop. '6 months' was just foolishly optimistic.
nesdoug.com -- blog/tutorial on programming for the NES
User avatar
HihiDanni
Posts: 186
Joined: Tue Apr 05, 2016 5:25 pm

Re: Why no SNES homebrew scene?

Post by HihiDanni »

tepples wrote:The thing about "engines" is that the Super NES probably isn't powerful enough for something as generic as, say, Unity or Unreal. Feel free to prove me wrong, but though an RPG, a platformer, and a vertical shmup could share a large set of hardware libraries, their engines would probably be structured very differently.
Engines can be different sizes. Unreal and Unity are designed around modern systems with a lot more complexity to manage under the hood because they're designed to scale to environments that take 8,000x as much RAM as the SNES actually has. They're also designed around a lot of micro optimizations that are only found in newer hardware and simply doesn't apply to the SNES. Word alignment? Haha, no need for that here.

The entire reason I'm making an argument for engines is that I only ever see people talking about how to implement DMA queues instead of actually making games. A lot of this is infrastructure that applies to a wide variety of genres and can easily be made reusable, just like the existence of code libraries, only an engine is more tightly integrated.

When it comes to genres, much of my initial inspiration for my SNES engine comes from Alien Soldier, which fits both "platformer" and "shmup". Action games share a surprising amount of infrastructure and are easily generalizable. If it's overhead from unused stuff that concerns you, then one of my design goals has been to allow objects to only do as much processing as they need to. If an object needs to move, it calls MoveObject. Same idea for drawing sprites and animation. An object that doesn't need to draw a moving sprite simply doesn't call the movement or animation functions. I have recently introduced an optimization so that an empty scene capable of having 128 objects only uses 7% CPU (excluding time spent in Vblank). That's pretty good if you ask me.

(I realize that there are some smaller details that users might want to tweak, and I'd like to help them do so via proper documentation and allowing user adjustment of object list sizes, etc. Still, I want to keep options open which is why I always do performance testing with high object counts, but also try to design my systems around flexibility.)
SNES NTSC 2/1/3 1CHIP | serial number UN318588627
psycopathicteen
Posts: 3140
Joined: Wed May 19, 2010 6:12 pm

Re: Why no SNES homebrew scene?

Post by psycopathicteen »

I'm also trying to do an Alien Soldier type game, but I'm also doing a hell of a lot of sprite animation, which is why that animation code is so long. It has to figure out how a constantly changing combination of sprites onscreen are going to fit into VRAM.

I'm still trying to crunch the code down. I hope this is a noticeable improvement.

Code: Select all

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
inc
sta {animation_copies},x
dec
beq +				//if animation_copies is not 0, then no further processing is needed
rts
+;

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
	+;
	sty.b {temp5}
	lda $0012,y
	sta.b {temp_x}
	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 $0014,y
		sta.b {temp_y}
		lda $0011,y
		and #$000f
		sta.b {temp7}			//"temp7" counts down the vertical sprite run
		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
		lda.b {temp_y}
		sta {sprite_y},x
		clc
		adc.b {temp10}
		sta.b {temp_y}
		lda.b {temp_x}
		sta {sprite_x},x
		dec.b {temp7}			//decreases "temp 7" until all sprites
		bpl find_vram_slot		//in the vertical run are put on linked list
		dec.b {temp8}			//decreases "temp 8" until all sprites
		bmi +				//in the horizontal run are put on linked list
		clc
		adc.b {temp10}
		sta.b {temp_x}
		lda.b {temp10}
		asl #2
		adc.b {temp9}
		jmp -
+;
	tya
	clc
	adc #$000a
	tay
	jmp --


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

macro add_and_store(a,b) {
adc {a}
sta {b},y
}

macro find_slot(stack_index,stack) {
sta.b {temp4}
ldx {stack_index}
dex
dex
bpl +
tya
jmp invalid_chr
+;
lda {stack},x
stx {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
add_and_store(#$0100,{dma_destination}+8)
}


small_slot:			//this finds 16x16 VRAM slot
find_slot({small_slot_stack_index},{small_slot_stack})
lda.b {temp}
sta {dma_address},y
add_and_store({vram_width},{dma_address}+8)
adc {vram_width}
sta.b {temp}
lda.b {temp2}
ora #$4000
sta {dma_bank},y
sta {dma_bank}+8,y
lda #$0010
jmp ++

large_slot:			//finds open 32x32 VRAM slot
find_slot({large_slot_stack_index},{large_slot_stack})
add_and_store(#$0100,{dma_destination}+16)
add_and_store(#$0100,{dma_destination}+24)
lda.b {temp}
sta {dma_address},y
add_and_store({vram_width},{dma_address}+8)
add_and_store({vram_width},{dma_address}+16)
add_and_store({vram_width},{dma_address}+24)
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
lda #$0020
+;
sta.b {temp10}
clc
adc.b {dma_updates}
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:
plb
rts

macro clear_slot(stack_index,stack) {
ldx {stack_index}
sta {stack},x
inx
inx
stx {stack_index}
}

clear_vram_slot:	//this routine clears the VRAM slots of the previous animation frame
pea $807e
plb
ldy {frame_id}
beq no_slot_to_clear
lda {animation_copies}-$7e0000,y
beq +
dec
sta {animation_copies}-$7e0000,y
bne no_slot_to_clear
+;
lda {animation_chr}-$7e0000,y
-;
cmp #$ffff
beq no_slot_to_clear
tay
ldx {sprite_size}-$7e0000,y
beq clear_small_slot
cpx #$0001
beq clear_large_slot
clear_slot({repeat_slot_stack_index},{repeat_slot_stack})
bra +

clear_small_slot:
clear_slot({small_slot_stack_index},{small_slot_stack})
bra +

clear_large_slot:
clear_slot({large_slot_stack_index},{large_slot_stack})
+;
lda {sprite_name}-$7e0000,y
jmp -
[/size]
Last edited by psycopathicteen on Tue Aug 08, 2017 7:57 pm, edited 1 time in total.
User avatar
GradualGames
Posts: 1106
Joined: Sun Nov 09, 2008 9:18 pm
Location: Pennsylvania, USA
Contact:

Re: Why no SNES homebrew scene?

Post by GradualGames »

I've considered moving to SNES at some point in the future, but I'm reluctant just due to the implicit, rather large jump in scope. We're a 2 person operation and each NES game we've made clocks in right around 3.5 to 4 years at the pace we work (this is with me doing everything but the art, so music for instance is of manageable scope). I think that's about the limit of my patience for a large project which has extra difficulty (working with old hardware) imposed on it. If I made a SNES game I'd probably take 6, maybe 7 years on the type of game we might make. I think it's more realistic I may jump to gameboy, potentially. The graphics format was so similar I was able to make small modifications to my NES tools to output data for gameboy just tinkering one weekend. That plus the growing number of people in the gameboy scene makes it an attractive second option (more resources, tools, game jams, etc.). I think the reality boils down to SNES projects need larger teams (or just a lot more time), and as hobbyists keeping together large teams is obscenely difficult. It's difficult for all indie devs, probably, but with modern dev it's much easier to change out members of a team who can easily ramp up on some modern language codebase versus obscure old hardware.
93143
Posts: 1715
Joined: Fri Jul 04, 2014 9:31 pm

Re: Why no SNES homebrew scene?

Post by 93143 »

Just about all of the projects I want to do on the SNES are either primitive practice games, one-shot tech demos, or ports. The only exception is a full-scale SA-1/MSU1 F-Zero game, which is so far down the list that I don't expect to ever start. Maybe I'm subconsciously trying to push back against the scope overload that seems to plague everything I do... or maybe I'm simply protected by my lack of artistic initiative. Either way, I've been laying the groundwork for my first SNES project for over three years now. Hopefully once I'm out of grad school things will loosen up a bit...
calima
Posts: 1745
Joined: Tue Oct 06, 2015 10:16 am

Re: Why no SNES homebrew scene?

Post by calima »

I was also looking at getting on the Gameboy, when Krikzz announced the GB-X everdrive some time ago. It has lower power consumption, and a RTC, so you can finally play 2nd gen pokemon as intended :P
Of course there are plenty of z80 C compilers.
tepples
Posts: 22705
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Re: Why no SNES homebrew scene?

Post by tepples »

That'd work for the ColecoVision, Master System, or Game Gear. But I'll open another topic in GBDev about C on the LR35902.
User avatar
Bregalad
Posts: 8055
Joined: Fri Nov 12, 2004 2:49 pm
Location: Divonne-les-bains, France

Re: Why no SNES homebrew scene?

Post by Bregalad »

GradualGames wrote:I've considered moving to SNES at some point in the future
Same here, I planned to move to SNES once I released some 3-4 games on NES. Exept I'm still at 0 games for the NES.
syboxez
Posts: 32
Joined: Tue Mar 01, 2016 8:22 pm

Re: Why no SNES homebrew scene?

Post by syboxez »

I've been wanting to get into SNES development for a while now, but really don't know where to start. I know x86 assembly fairly well (enough to write some functions in ASM for use in C code and to have an understanding of how to structure and write ASM code) and have learned most of the commonly used 65816 opcodes. I've been following bazz's tutorial on superfamicom.org and got to the point where I put a 1x1 tile image on the screen while understanding about half of what I was doing. Haven't really gotten much further than that.

I love coding in assembly, and making a SNES game has been a lifelong dream of mine. Some pointers would be much appreciated.
Post Reply