Language…
4 users online: bry, Ringo,  shovda, TheOrangeToad - Guests: 86 - Bots: 117
Users: 57,117 (2,267 active)
Latest user: NotGob

Cluster Spriting Tutorial

ASM CodingCustom Sprites

This tutorial was made for semi-advanced SMW hackers, who:

- Know the basics / intermediate stuff of ASM.
Required: Know how LDA/STA/RTS/CLC/ADC/SEC/SBC/INC/DEC/CMP/basic branch commands & jump commands/stack/indexing work.
- Know how to do regular spriting (not a requirement, but it would help greatly)
- Have the patience to learn this type of spriting and to insert the sprites through a patch.



1. What exactly are the possibilities of cluster sprites?
Remember SMW's reappearing ghosts? The fact that there can be up to 8 1UPs in the bonus room? That you can place 2 Boo rings, and they all move seperately? The Sumo brother flames?
These are all cluster sprites. The main advantages of cluster sprites is that there can be up to 20 (!) different cluster sprites on the same screen, as opposed to 12 at max for regular sprites. Furthermore, cluster sprites cause minimal slowdown. Having 20 of them won't or will barely generate slowdown, whereas putting more than 6 regular sprites usually already generates a lot of slowdown.

The feature of cluster sprites had been discovered by Roy, 26th-27th August 2009. So, by the time of writing this, it is indeed relatively new.

2. So, how do I create and insert these cluster sprites?
Well, first you need the following things:

- Like stated before, ASM knowledge.
- Custom Cluster Sprite patch, can be found in the Patches section.
- Sprite Tool (optional, but for the method we're going to use now, a requirement)

As you might've guessed by now, cluster sprites are in NO MEANS regular sprites.
You cannot insert them through Lunar Magic, for example. You need to generate them with ASM routines - right now, we're going to use a custom sprite's init code to do just that.
In that init, you can generate up to 20 of them cluster sprites. Of course, you don't HAVE to generate 20. It can be any arbitrary number between 0 (why would you want that, though) and 20.
I'll explain how to do that, but first let me mention the most important tables regarding cluster sprites:

Quote
$15E9 : Just like in regular sprites, you can load this RAM address to get the index of the currently processed cluster sprite.

$1892-$18A5 : Cluster sprite type. This basically functions as the sprite number for your cluster sprite.
Setting it to 00 means no cluster sprite for that slot. Values 01-08 are the regular cluster sprites, used in SMW. (Check the RAM map for more information on those.)
Values 09-88 (could be expanded easily on a later patch, but I thought 128 slots was enough) are slots which you could use for the custom cluster sprites.
Values 89-FF are actually invalid at the time of writing this, but they probably are a copy of 09-7F. (Since I made the patch work like that.) Basically there's no reason to use them though.

$1E02-$1E15 : A free cluster sprite table. Basically, you can use this table for just about anything.
SMW's cluster sprites and spike hell use it as Y low position.
We will use it as Y position here too, but you're not restricted to do it within your own sprites.
The rest of the tables I'll mention are also free.

$1E16-$1E29 : Another free table. Often used as X low position.

$1E2A-$1E3D : Another free table. Often used as Y high position.

$1E3E-$1E51 : Another free table. Often used as X high position.

$1E52-$1E65 : Another free table. Used for a lot of things. Which things exactly? Check the RAM map.

$1E66-$1E79 : See $1E52-$1E65.

$1E7A-$1E8D : See $1E52-$1E65.

$1E8E-$1EA1 : See $1E52-$1E65.


As you can see, there aren't many "predefined" tables. No ground interaction, no X or Y speed, heck, not even X or Y position have predefined RAM tables.
You all have to set it up yourself per sprite.



The generating sprite.
The generating sprite is the one you insert through Sprite Tool.
We'll take the spike_hell.asm from the cluster sprite patch:

Code
!SpikeCount = $13 ; Amount of spikes to fall down, -1. Values outside of 00-13 are not recommended.

;--------------;
; Init Routine ;
;--------------;

print "INIT ",pc
PHY              ; \ Wrapper.
PHB              ;  |
PHK              ;  |
PLB              ; /
LDY #!SpikeCount  

Loop:
LDA #$09         ; \ Custom cluster sprite 09.
STA $1892,y      ; /
LDA InitXY,y	 ; \ Initial X and Y position of each spike.
PHA		 ;  | Is relative to screen border.
AND #$F0	 ;  |
STA $1E16,y	 ;  | Store into X pos.
PLA		 ;  |
ASL		 ;  |
ASL		 ;  |
ASL		 ;  |
ASL              ;  |
STA $1E02,y      ;  | Store into Y pos.
DEY              ;  | Loop until all slots are done.
BPL Loop	 ; /
LDA #$01         ; \ Run cluster sprite routine.
STA $18B8        ; /
PLB              ;
PLY              ;
RTL              ; Return.

InitXY:
db $06,$45,$9E,$E2,$A7,$BC,$59,$40,$61,$F5,$D6,$24,$7B,$33,$C6,$0B,$00,$39,$70,$A1
; Initial X and Y position table of sprites.
; Relative to screen border.
; Format: $xy

;--------------;
; Main Routine ;
;--------------;

print "MAIN ",pc
RTL


We only want to generate each spike once, right? Therefore, we should only be putting this code in the INIT. Leave the MAIN code as-is.
As you can see in this sprite, we're using a loop. This is handy, because the INIT only runs once, and we want to generate all cluster sprites at the same time.
Rather important note: Cluster sprites ONLY HAVE A MAIN ROUTINE, so if you want to put something initial for them, do it inside this generating sprite, like I did with initial X and Y position.

So we LDY #SpikeCount. #SpikeCount is the amount of spikes to generate - 1, which in this case is set to be #$13 ($14, thus 20 sprites).

LDA #$09 STA $1892,y sets the sprite number to the cluster sprite table. After my explaination on $1892,y, this should be obvious by now. Change #$09 to the number you inserted the cluster sprite as. (You can see it in the label inside the patch 'ClusterX', where X = cluster sprite number.)

The routine after that simply stores the values from a table to the cluster sprite's X and Y positions. I made the routine work like this to compress the table as much as possible. Saves another few bytes, I guess.

Now we keep running that code for each cluster sprite that is going to be generated, until the loop is done.

Last, but certainly not least, LDA #$01 STA $18B8 enables cluster sprites to be processed. If you do not set this, then the cluster sprites will simply not show up. So it's very important to keep in mind.



The actual cluster sprite. (Patch)

An important note is that cluster sprites use the Y index for their tables inside the custom cluster sprite patch. So do : LDA $1E02,y, NOT LDA $1E02,x.
So, like with normal sprites, do not touch this index, unless you really have to. (In that case, preserve Y.)

Every cluster sprite is different. You can tell that from normal custom sprites already - for example, Maxx's Newbie Boss is in no means similar to edit1754's dynamic Ptooie.
But what most sprites (and thus also cluster sprites) share is:

- Movement.
- Graphics. (OAM.)
- Interaction.

These three things cover what I'm going to explain now. They're basically the fundament for what we would call a sprite. (There are exceptions to this, of course.)

How to set up movement, graphics and interaction:
You will need to create X and Y position routines. (Eventually X and Y speed, I'll explain that in a bit.)
These X and Y position registers should affect graphics and interaction too, of course. For example, if the sprite's Y position (relative to the screen border) is $10, then the graphical Y position should also be $10, and not something like $B8.
So, how exactly will you set these up? It's quite simple really.
Let's use $1E02-$1E15 for setting the Y position up, and $1E16-$1E29 for the X position.

Code
LDA $1E02,y ; \ Move cluster sprites 2 pixels per frame.
CLC                ;  |
ADC #$02           ;  |
STA $1E02,y        ; /


This will make all cluster sprites of the same type move with speed = 2 pixels per frame. But what if you want to move each single cluster sprite with a different speed? It's quite simple - you read from a table instead:

Code
SpeedTable:
db $01,$02,$FF,$FE,$F9,$05,$01,$03,$06,$FD,$04,$02,$FE,$FE,$01,$08,$FA,$FC,$03,$04

LDA $1E02,y ; \ Move cluster sprites seperately. x pixels per frame, depending on the table.
CLC                ;  |
ADC.w SpeedTable,y ;  | Different speed for each cluster sprite slot.
STA $1E02,y        ; /


In the same way, you could affect $1E16,y or in fact any table, if you want to do so.
So, now you know how to increment $1E02,y for all cluster sprites of that type, or for each slot seperately. But does this make it an Y position RAM address yet? No! You still need to make it store it's Y position (relative to screen border) to OAM, and if you want to make it interact - which you usually do - you will need it in your interaction routines.

Here's how you do it in the graphics routine. It's actually rather simple. From Spike Hell:

Code
OAMStuff:
db $40,$44,$48,$4C,$D0,$D4,$D8,$DC,$80,$84,$88,$8C,$B0,$B4,$B8,$BC,$C0,$C4,$C8,$CC

LDX.w OAMStuff,y 		; Get OAM index for each cluster sprite.
LDA $1E02,y			; \ Copy Y position relative to screen Y to OAM Y.
SEC                             ;  |
SBC $1C				;  |
STA $0201,x			; /
LDA $1E16,y			; \ Copy X position relative to screen X to OAM X.
SEC				;  |
SBC $1A				;  |
STA $0200,x			; /


Comments should be obvious enough. You subtract $1C from $1E02,y and $1A from $1E16,y to get Y and X positions relative to the screen border.
It's recommendable to make it relative to the screen border - otherwise you might get some weird result.

$0200,x and $0201,x are the X and Y position of the OAM tile. We use the $02xx area here because that's a trend extended sprites usually follow anyway. On top of that, there's usually much more space you can use in this area.

LDX.w OAMStuff,y gets each cluster sprite's OAM slot. This is a rather messy way to do it, but it's effective for most OAM slots.
You really have to go and look for free OAM slots, though - I did that for spike hell. Usually those slots aren't used, not even by extended sprites.
So far I found a few score sprites that use it, though.
Making a routine that gets a free OAM slot out of the blue is a little bit more complicated, since there's no such thing as an OAM index RAM table for cluster sprites, unlike regular sprites. That doesn't mean it's impossible, though.
I may add some more on this part in the future, if I - or someone else - find out how to do it, without having side-effects. (A simple loop won't work, for example.)

Now we're busy with the OAM routine anyway, let's finish it.

Code
LDA #$E0			; \ Tile = #$E0.
STA $0202,x                     ; / (Spike.)
LDA Properties,y		; \ Properties per spike, some are rising so this needs a seperate table.
STA $0203,x			; /
PHX
TXA
LSR
LSR
TAX
LDA #$02
STA $0420,x
PLX


If you know how to work with OAM in normal spriting, this should be easy to follow. We use tile E0 -> that goes to $0202,x, which holds the tile value.
Then, we have the Properties table. It doesn't need to be a table, but for Spike Hell, I made it a table, because some of these sprites are upside down. If you want to make them all use the same properties, just use a direct value like:

Code
LDA #$35
STA $0203,y


Then we store the tile size to $0420,x. 00 = 8x8, 02 = 16x16. "$0420,x?", you might think. "Most custom sprites use $0460,x, don't they?" Yes, that's true. That's because they use OAM $0300-$03FF, so they will need the second half ($0460-$049F) of the tile size table. $0200-$02FF will thus require $0420-$045F.

And that's all regarding OAM.



Interaction I.

Interaction is probably the most difficult part for any sprite - cluster sprites are no exception. They don't have clipping values or anything like that, so you all need to do it "manually".

Quoting the following routine directly from Spike Hell:
Code
!YInteractSmOrDu = $20 ; How many pixels to interact with small or ducking Mario, vertically.
!YInteractSmNorDu = $30 ; How many pixels to interact with powerup Mario (not ducking), vertically.

LDA $94				; \ Sprite <-> Mario collision routine starts here.
SEC                             ;  | X collision = #$18 pixels. (#$0C left, #$0C right.)
SBC $1E16,y                     ;  |
CLC                             ;  |
ADC #$0C			;  |
CMP #$18			;  |
BCS Immobile			; /
LDA #!YInteractSmOrDu           ; Y collision routine starting here.
LDX $73
BNE StoreToNill
LDX $19
BEQ StoreToNill
LDA #!YInteractSmNorDu

StoreToNill:
STA $00
LDA $96
SEC
SBC $1E02,y
CLC
ADC #$20
CMP $00
BCS Immobile
JSL $00F5B7			; Hurt Mario if sprite is interacting.

Immobile:                       ; OAM routine starts here.


This is typically what a Mario <-> cluster sprite interaction routine would look like. Optionally you could add a LDA $187A (on Yoshi) check in, but I decided it was not necessary in Spike Hell.

What the first part does is simple. It subtracts the cluster sprite X position from Mario's X position (low).
Then it adds #$0C to the result and compares it to #$18. If the result is equal to or higher than #$18, it means Mario is not interacting with the sprite.
The CLC ADC #$0C CMP #$18 means that the sprite is supposed to have an interaction field of $0C pixels on both left and right.

The Y interaction routine is a little bit more complicated, but should certainly not be too hard to follow.
By default, it loads the value for when Mario is small or ducking (#$20).
This is because the interaction field is 2 blocks. (Small / Ducking Mario = 1 block + the spike = 1 block.)
If he's neither, then the other value will be loaded (#$30).
This is because the interaction field is 3 blocks. (Big Mario = 2 blocks, the spike = 1 block.)
We then subtract cluster sprite Y position from Mario's Y low position, add #$20 and then check with either #$20 or #$30, depending on if Mario was either small or ducking, or neither one of them.
If the result was equal to or bigger than the comparison, Mario is not interacting with the sprite.
However, if it was smaller, then Mario was interacting with the sprite.

Here is where we throw JSL $00F5B7 in - a routine to hurt Mario.
Alternatively, you could use JSL $00F606 to kill Mario.

Interaction II.

To kill the sprite instead, use LDA #$00 STA $1892,y. (This will make him disappear instantly.)
Say you want to get a 1UP when collecting the sprite. How do you do it? It's rather simple.

Code
LDA #$00
STA $1892,y
PHY
TYX
JSL $02AD34
LDA #$0D
STA $16E1,y
LDA $1E02,x
SEC
SBC #$08
STA $16E7,y
LDA $97
STA $16F9,y
LDA $1E16,x
STA $16ED,y
LDA $95
STA $16F3,y
LDA #$30
STA $16FF,y
PLY


At LDA #$00 STA $1892,y, we kill the sprite.
Then, we preserve Y and get the cluster sprite index into X, because we need to have it set in X for the score sprite set-up routine.
When we prepared an index for the score sprite, we store the appropiate values.
Score sprite type = #$0D. (1UP. Higher values for more lifes or a mess, lower values for score additions.)
Make Y position 8 pixels higher than the cluster sprite's Y position. ($16E7,y.)
Since this cluster sprite doesn't have a high Y position, just make the Y high relate to Mario's Y high. ($16F9,y.)
The same method is used with X position, with the only difference that the X coördinate is the same for the score sprite as it is for the cluster sprite.
Then we set up a speed (#$30), and pull Y back. There - we just made a collectable 1UP cluster sprite.

Interaction III.

Say, you want to make the cluster sprite hurt you when you're underneath it, but when you're on top of it, you can stomp on it and bounce off the top. (Eventually killing the sprite.)
How do you do this? Well, it's not very hard.
The interaction routine will look like this:

Code
LDA $94				; \ Sprite <-> Mario collision routine starts here.
SEC                             ;  | X collision = #$18 pixels. (#$0C left, #$0C right.)
SBC $1E16,y                     ;  |
CLC                             ;  |
ADC #$0C			;  |
CMP #$18			;  |
BCS ImmoJump			; /
LDA #!YInteractSmOrDu           ; Y collision routine starting here.
LDX $73
BNE StoreToNill
LDX $19
BEQ StoreToNill
LDA #!YInteractSmNorDu

StoreToNill:
STA $00
LDA $96
SEC
SBC $1E02,y
CLC
ADC #$20	
CMP $00
BCS ImmoJump
LDA $7D			; \ If Mario falling, kill sprite.
CMP #$10                ;  |
BPL KillSpriteInstead   ; /
JSL $00F5B7

ImmoJump:
JMP Immobile

KillSpriteInstead:
LDA #$00
STA $1892,y
JSL $01AA33
JSL $01AB99
PHY
TYX
JSL $02AD34
LDA #$05
STA $16E1,y
LDA $1E02,x
SEC
SBC #$08
STA $16E7,y
LDA $97
STA $16F9,y
LDA $1E16,x
STA $16ED,y
LDA $95
STA $16F3,y
LDA #$30
STA $16FF,y
PLY

Immobile:


The first part until ADC #$20 CMP $00 is no different from the original routine, so that part has already been explained.
We don't need to do it again, I just included it so you would see the complete picture.

Next, we check if Mario has a reasonable falling speed. If that is not the case, hurt Mario.
However, if he is falling at a passable rate, go to the routine that will eventually kill the sprite.

We see this at LDA #$00 STA $1892,y - erasing the cluster sprite. JSL $01AA33 makes Mario boost up, JSL $01AB99 will display contact graphics.
Next, we see the score sprite generating routine again. This is nothing new, except for the fact we're using a different value now - #$05.
This will add up 100 points to your total.

Interaction IV.

There are many, many more codes I could add up to this list, like how to only make it die on spin-jump or star kill.
However, I want to make this one the last section: each cluster sprite having a different kind of interaction.
Let's take Spike Hell as example. Say, you want to make the falling spikes vulnerable to any kind of jump, but the rising spikes should be completely invincible.
How do you do that? Quite simple.
You add up a table somewhere at the beginning of the sprite, which consists of 20 bytes - 1 byte per slot.
It could be done with a lesser amount of bytes, but for the sake of simplicity - hey, this is a tutorial after all - let's keep it at 20.

Code
Invincible: ; These two tables should be at the top of the sprite. Running tables is a bad idea. >_> <_<
db $01,$00,$00,$00,$00,$01,$00,$00,$00,$00,$00,$00,$01,$00,$00,$00,$00,$00,$00,$00

Properties:
db $B5,$35,$35,$35,$35,$B5,$35,$35,$35,$35,$35,$35,$B5,$35,$35,$35,$35,$35,$35,$35 ; Properties table, per sprite. YXPPCCCT.

;etc.
CLC
ADC #$20	
CMP $00
BCS ImmoJump
LDA $7D
CMP #$10
BPL KillSpriteInstead

HurtMarioAnyway:
JSL $00F5B7

ImmoJump:
JMP Immobile

KillSpriteInstead:
LDA.w Invincible,y        ; \ If the value is not zero, spike is a rising spike.
BNE HurtMarioAnyway       ; / Hurt Mario in that case.
LDA #$00
STA $1892,y
;etc.


Properties: was a table which was already in there.
By that table, we found out which spikes were rising ($B5 -> Y flip bit set.), and which ones were not. ($35 -> Y flip bit clear.)
For rising spikes, we set each value to $01, and for falling spikes, we set each value to $00.
Now when we read from that table, Mario will be hurt if the table value is $01 (rising), but the sprite will be killed if the table value is $00 (falling).

That's all for interaction. I believe I have said enough. Too much, if you will.

Other random, but rather handy codes:
Cluster sprites stop reappearing at generator 2 or level end.

Put the following code after the OAM routine:

Code
LDA $18BF                                       ; \ If generator 2 is active...
ORA $1493					; / ...or level is ending...
BEQ ReturnToTheRTSCommandMyChocolate            ; Change BEQ to BRA if you don't want it to disappear at generator 2, sprite D2.
LDA $0201,x
CMP #$F0                                        ; As soon as the spike is off-screen...
BCC ReturnToTheRTSCommandMyChocolate
LDA #$00					; KILL IT! KILL IT!!.
STA $1892,y					;


More to follow maybe.



tl;dr This was the cluster spriting tutorial. I hope you enjoyed reading through it, even if not completely.
If you know any part which I could give a touch-up, please do tell.
I myself plan to add more to this tutorial in the future, when I get more experienced with cluster spriting.
At the time of writing, cluster spriting is still not very much utilized, so there may be a lot to come yet.

Also, I and several other staff members have agreed on the fact that cluster sprites may be submitted to the sprite section. If you have anything to show - don't keep it to yourself, submit it! :D
I LOVE YOU.

Okay, seriously, thanks a ton. I'll definitely use this tutorial, and I'm sure others will too. *looks at Ladida*

I have a few things to say. First, I'm planning to use a single sprite to generate ALL of my cluster sprites that aren't generated within the code of another sprite (such as a boss). I have a routine that uses the XY position and a pointer table to determine which cluster sprite to generate. Should I put that out here (even though I haven't actually tested it)?

Second, we will most certainly run out of free sprite tables, especially if you ever design an X/Y speed routine. What say we create new cluster sprites in free RAM, like...$7F8300? Of course, we would have to TYX or LDX $15E9 before using any 24-bit tables, so we could use something in the $0695 range, but that would fill up pretty fast. We'd get $0695,y, $06A9,y, $06BD,y, $06D1,y, $06E5,y...and that would be it. $06F9-$0700 would still be empty. (I know for a fact that $06FE is used by dsx.asm, for one thing.) Then again, I guess $7F8300 wouldn't be much better; we'd have $7F8300,x, $7F8314,x, $7F8328,x, $7F833C,x, $7F8350,x, and $7F8364,x. $7F9C7B...now stuff in that area would be substantial. Since mikeyk started some sprite tables at $7FAB10...what say we make some more cluster sprite tables at...$7FA900 or something? We'd get 12 (well, 12.8) tables out of every 256/0x100 bytes of RAM. $7FA900-$7FAB07 would give us 26 20-byte tables. If we wanted 64 like edit1754 and smkdan had, we could start at $7FA600. (Yes, I like round numbers.) Then there's the option of starting at $7FABAA or somewhere later...

Third, I'm already inventing things like "Tweaker bits" for the cluster sprites. (Heck, if I get decent enough at programming, who knows...I might even be able to make a cheap .cfg editor for them.) I'm going to attempt to design a subroutine—combined with some of these "Tweaker bits"—that sets X and Y interaction based on clipping values. In fact, I'm going to try to design a couple different subroutines that use stuff like that. Should I post whatever I come up with here?

Anyway, nice job and keep it up. In fact, we should get more people in on this kind of stuff.

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

I'm working on a hack! Check it out here.
Thanks Roy! I always wanted a more clear understanding of cluster sprites, and now I have a nice tutorial on how to make them.

Just what I needed :D

Well, this tutorial at least helped me clear up most of the code.

However, if I wanted to make the cluster sprites use different tiles instead of just one universal tile, how would I do it? Would I just make it use a table like with the properties and the speeds?

Also, is there a way for the cluster sprites to move any slower? A speed of 01 or FF is kinda fast D:
Originally posted by imamelia
I have a few things to say. First, I'm planning to use a single sprite to generate ALL of my cluster sprites that aren't generated within the code of another sprite (such as a boss). I have a routine that uses the XY position and a pointer table to determine which cluster sprite to generate. Should I put that out here (even though I haven't actually tested it)?


Sure, although I would recommend you actually go and test it out before anything.

Originally posted by imamelia
Second, we will most certainly run out of free sprite tables, especially if you ever design an X/Y speed routine. What say we create new cluster sprites in free RAM, like...$7F8300? Of course, we would have to TYX or LDX $15E9 before using any 24-bit tables, so we could use something in the $0695 range, but that would fill up pretty fast. We'd get $0695,y, $06A9,y, $06BD,y, $06D1,y, $06E5,y...and that would be it. $06F9-$0700 would still be empty. (I know for a fact that $06FE is used by dsx.asm, for one thing.) Then again, I guess $7F8300 wouldn't be much better; we'd have $7F8300,x, $7F8314,x, $7F8328,x, $7F833C,x, $7F8350,x, and $7F8364,x. $7F9C7B...now stuff in that area would be substantial. Since mikeyk started some sprite tables at $7FAB10...what say we make some more cluster sprite tables at...$7FA900 or something? We'd get 12 (well, 12.8) tables out of every 256/0x100 bytes of RAM. $7FA900-$7FAB07 would give us 26 20-byte tables. If we wanted 64 like edit1754 and smkdan had, we could start at $7FA600. (Yes, I like round numbers.) Then there's the option of starting at $7FABAA or somewhere later...


Good idea, I think I shall include this in a later version of the cluster sprites installing patch. Also, just a comment on the X/Y speed thing: It has already been created in SMW, with the original tables. Perhaps I should put that routine up in the first post, too.

Random note: I myself prefer $7EC100-$7EC67F.

Originally posted by imamelia
Third, I'm already inventing things like "Tweaker bits" for the cluster sprites. (Heck, if I get decent enough at programming, who knows...I might even be able to make a cheap .cfg editor for them.) I'm going to attempt to design a subroutine—combined with some of these "Tweaker bits"—that sets X and Y interaction based on clipping values. In fact, I'm going to try to design a couple different subroutines that use stuff like that. Should I post whatever I come up with here?


If you get anything out of this, that would be fantastic, of course. I say 'yes' to that.

Originally posted by Ladida
However, if I wanted to make the cluster sprites use different tiles instead of just one universal tile, how would I do it? Would I just make it use a table like with the properties and speeds?


Correct. Something like LDA Tile,y STA $0202,x should do.

Originally posted by Ladida
Also, is there a way for the cluster sprites to move any slower? A speed of 01 or FF is kinda fast.


You could move it every X frames.
I.e. instead of LDA $1E02,y CLC ADC SpeedTable,y STA $1E02,y, you use something like:

Quote
LDA $13
AND #$03 ; Run only once per 4 frames. Move four times as slow.
BNE Branch
LDA $1E02,y
CLC
ADC SpeedTable,y
STA $1E02,y


Other than that, see my reply to imamelia's second reaction. I should show the speed RAM table set-up code.
--------> Don't follow "Find Roy's Dignity", my hack. Because it's pretty outdated. <--------
Hm...hey, do you have a routine that will find a given number of free slots for cluster sprites? Like, say I need 6 free cluster sprite slots. How would I set that up? I could easily make a routine to check for one free slot, but...? Also, I can think of at least three more possible interaction routines: making the sprite solid (like a message block), making it act like a platform (like the timed lifts), and making it carriable. Any of those might be harder than heck to do, but I don't know.

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

I'm working on a hack! Check it out here.
Originally posted by imamelia
Hm...hey, do you have a routine that will find a given number of free slots for cluster sprites? Like, say I need 6 free cluster sprite slots. How would I set that up? I could easily make a routine to check for one free slot, but...?

Why not just simply make a loop where you check for a free slot, spawn the sprite, and repeat those two steps the needed number of times?

About making a sprite solid, I would suggest doing like the wooden spike does:
- check for Mario/sprite interaction
- if interacting, use sprite and Mario x position to determine which side of the sprite Mario is on
- check Mario's x speed to determine if Mario is moving towards the sprite
- if so, zero out Mario x speed and set his position as right next to the sprite
- [insert last four steps with y replacing x here]
- if Mario on top of sprite, set $1471?
If you want to make it act like a platform, it should be the same thing, except you only check if Mario is above the platform.
My YouTube channel
Get the official ASMT resource pack here!

Hmm...the latter could work. Interesting. I'll have to try that at some point. Maybe it could even help me with that @#$%! carryable sprite I was trying to make a while back.

As far as the first thing goes, that wouldn't really achieve what I wanted. If I need 6 free sprite slots but there were only 5 available, then only 5 sprites would spawn. I wouldn't want some of them to appear; if I can't have them all, I'd prefer none of them spawning at all. And I can't just increment Y when a free slot is found, compare that value later, return if it isn't high enough, and if it is, use it to index, because the free slots might not all be in a row.

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

I'm working on a hack! Check it out here.
Really nice tutorial, Royshame. Now if I stopped being lazy I could create some cluster sprites. D:

I'll give a shot at it sometime.
My blog. I could post stuff now and then

My Assembly for the SNES tutorial (it's actually finished now!)
Originally posted by myself in response to Roy's original post showing off custom cluster sprites
Danmaku Mario, anyone? *shot*




:D


Thank you very much for this tutorial.
My YouTube channel
Get the official ASMT resource pack here!

Finally.
6th Cluster Spriter

Click

Now to turn this into a homing bullet bill.

And spawn 19 more.

edit: For now, we have a bouncy platform.
Clicky
I own a community of TF2 servers!

ASMT - A new revolutionary ASM system, aka 65c816 ASseMbly Thing
SMWCP - SMW Central Presents a Product- tion long name

frog

http://esolangs.org/wiki/MarioLANG
sorry to bump, but seeing as there isn't any other cluster tutorials, I figured this was the place to ask my question.

have any of the things discussed in this thread (more cluster sprite tables, a "find-cluster-sprite-slot subroutine", etc.) been created yet? or are things pretty much the same? I want to learn how to do this but I don't want to accidentally use an outdated method or something :P
Originally posted by jesus
more cluster sprite tables

Just pick a block of freeRAM and use it for your additional tables. There's a lot of it in the $7FC000 range.

Originally posted by jesus
find-cluster-sprite-slot subroutine

Easily done by just looping through the table at $1892 and checking for empty slots.
My YouTube channel
Get the official ASMT resource pack here!

Originally posted by yoshicookiezeus
Originally posted by jesus
more cluster sprite tables

Just pick a block of freeRAM and use it for your additional tables. There's a lot of it in the $7FC000 range.

Originally posted by jesus
find-cluster-sprite-slot subroutine

Easily done by just looping through the table at $1892 and checking for empty slots.


Thanks!

What about the routine to find a free OAM slot though? Does that exist yet?




EDIT:

I'm also kind of confused about how the Main wrapper works for cluster sprites. in the Cluster Sprite Tool readme it said that print commands don't work, so I don't see how it's supposed to be set up.

Also, I don't see the reasoning behind some of the values used in that first interaction routine.
Code
SBC $1E16,y
CLC
ADC #$0C
CMP #$18
BCS Immobile

...

SBC $1E02,y
CLC
ADC #$20
CMP $00
BCS Immobile


why #$0C and #$18? isn't the sprite this is for 16x16? I would imagine those values would be #$08 and #$10. for the vertical hit detection, #$20 is used, which makes even LESS sense to me.

finally, there is no mention of the subroutine library and things like that. What do I use in place of SUB_OFFSCREEN and GET_DRAW_INFO? do cluster sprites just continue being processed forever?
You can also use $0F4A, $0F5E, $0F72, $0F86, and $0F9A as misc. cluster sprite tables.

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

I'm working on a hack! Check it out here.
I am currently working on a Custom Boss in the "Mega Man" vein.
What code can I use to recreate the effect when the Boss Disappears?

You Tube

Please look at "DeathEffectCut.asm" in the Cut Man folder and tell me where to write the code for the extinction effect!
What about making Cluster Sprites interact with blocks such as breaking the block or killing the cluster sprite when the cluster sprite hits a certain block? How would you do that?

Click the character on the right side of my layout to visit my Discord server and discuss and play and look at and get updates and sneak peeks of the games and other things I'm making.

The authors of these 2 My Little Pony fan games have removed their games from the Internet.
Rise of the Clockwork Stallions has been updated! Download My Little Pony: Rise of the Clockwork Stallions DX: Director's Cut and My Little Pony: Magic Shards now! Spread this link!

ASM CodingCustom Sprites