don't click here

Basic Questions & Answers thread

Discussion in 'Engineering & Reverse Engineering' started by Tweaker, May 29, 2008.

  1. Dulappy

    Dulappy

    koronesuki Member
    48
    7
    8
    Greece
    sonic
    Hello, so I've had this issue where with some sprites that I ported from sonic 2 over to sonic 1 these numbers appear in the end. Does anybody know how to fix it, or at least the source of the problem? Here's the image link: [​IMG]
     
  2. Nintorch

    Nintorch

    Just another programmer. Member
    44
    33
    18
    There are a lot actually..
    Seems your sprites doesn't fit in VRAM, Random.
     
  3. Dulappy

    Dulappy

    koronesuki Member
    48
    7
    8
    Greece
    sonic
    Ok, thank you! I did some research just now after you located the problem and I'll try to expand it if possible.
     
    • Informative Informative x 1
    • List
  4. Devon

    Devon

    Down you're going... down you're going... Tech Member
    1,218
    1,374
    93
    your mom
    There's also the fact that the way Sonic 1 loads Sonic's graphics in VRAM is different than in Sonic 2. Sonic 1 loads the frame's tiles into a buffer in RAM that gets DMA'd to VRAM during V-BLANK. The buffer in RAM is limited in size and I don't think it can fit some of the frames in the Sonic 2 sprite set. Sonic 2 uses a DMA queue in the place of that buffer to DMA tiles from multiple sources in the ROM of any size. Part 3 of the spindash tutorial on the wiki here has an implementation of that for Sonic 1.

    However, there's still the aforementioned VRAM space issue. In Sonic 1, it stores the points tiles right after Sonic's tiles, so even if you load all of Sonic's tiles correctly, it'll end up overwriting the points tiles, so you'd probably want to find a new place in VRAM for them.
     
    • Agree Agree x 2
    • Informative Informative x 1
    • Useful Useful x 1
    • List
  5. Dulappy

    Dulappy

    koronesuki Member
    48
    7
    8
    Greece
    sonic
    Do you know of any empty spaces without messing with anything else? I did some research and I couldn’t find anything that doesn’t require freeing space. If there’s no option then I’ll try the methods I found. Thanks by the way!
     
  6. Devon

    Devon

    Down you're going... down you're going... Tech Member
    1,218
    1,374
    93
    your mom
    Unfortunately, no. VRAM is quite packed in Sonic 1.

    I do know that one way to free up some VRAM is to make shield and invincibility stars uncompressed and make it so that when a shield appears, it loads into its VRAM space, and when the stars appear, it loads its art into the same space. You can do this since the shield and stars never appear at the same time. Added bonus if you also make DPLCs for them so that only the art for the current frame of each is loaded, thus saving up even more VRAM.

    With that, though, you'd definitely want to have that DMA queue I mentioned implemented to make it easier.
     
    • Agree Agree x 1
    • Useful Useful x 1
    • List
  7. MarkeyJester

    MarkeyJester

    Original, No substitute Resident Jester
    2,192
    405
    63
    Japan
    You can move the checkpoint post art from VRAM F400 to VRAM D800, it fits perfectly and snuggly in that space in all levels. You can then move the points art from VRAM F2E0 to VRAM F520, it will then fit snuggly there.

    This will open up $520 bytes of VRAM for Sonic (41 decimal tiles).

    If you would like to go a step further, remove the points altogether, I've done that in plenty of projects and no-one notices.
     
    • Agree Agree x 1
    • Informative Informative x 1
    • Useful Useful x 1
    • List
  8. Nintorch

    Nintorch

    Just another programmer. Member
    44
    33
    18
    There are a lot actually..
    If you need to find some free VRAM yourself, you can use some Gens mod
     
  9. Dulappy

    Dulappy

    koronesuki Member
    48
    7
    8
    Greece
    sonic
    Okay! Thank you everyone for your responses! I believe I have already moved the art for the lamppost since I have ported the Spindash along with its smoke so I'll probably use a gens mod! Thanks again.
     
  10. gamerz31w

    gamerz31w

    Banned
    92
    3
    8
    How Shadow the Hedgehog mod in Sonic Rush was made? How many low polygons models in NDS ROMs aesthetics got in the most of Nintendo DS games? How to swap character models, icons, illustrations of dialogues, models from Sonic Rush intro? If you will gonna explain and answer to my questions I'll do it myself, but with your help.
     
  11. Blastfrog

    Blastfrog

    See ya starside. Member
    What's the best way to change the animation speed of Sonic's walking to something that will have roughly the same duration as the 6 frame S1 anim, but using 8 frames like in Sonic 2?

    So far, I've made it subtract 9 instead of 8 (like the Sonic 2 beta) and I set the base duration to $B00.

    I've thought of making the base duration $C00 (which would give me better timing on the slower end of the animation, but is too slow for the faster speeds), and then multiplying Sonic's speed by 1.333, meaning that at speed 6, it would think it's actually speed 8. I have no idea how to do that in ASM, however, not very practiced in it.

    [​IMG]

    ^This is the animation I'm trying to sync up with S1 speed, btw.
     
  12. Aerosol

    Aerosol

    Not here. Moderator
    11,163
    573
    93
    Not where I want to be.
    Sonic (?): Coming summer of 2055...?
    So I just had a mild curiosity of a question, and I may have asked this before so apologies beforehand.

    Generally speaking, how does one go about creating entirely new gimmicks? If an example helps, let's say I wanted to recreate the loop cannons in Spinball's Lava Powerhouse?

    I need Sonic's movement to stop when they collide with the cannon (and possibly be forced into a ball), and I need the cannon to fire Sonic at a constant angle for a certain distance.

    I'm not asking anyone to code this for me, no no. Just in broad strokes what something like this would have entail? Assuming I'm modifying Sonic 1?
     
    Last edited: Sep 1, 2019
  13. MarkeyJester

    MarkeyJester

    Original, No substitute Resident Jester
    2,192
    405
    63
    Japan
    When they collide with the cannon, you will likely force the X and Y positions into place, keeping the X and Y speeds 0 (to prevent things like gravity from interfering). Upon shooting the cannon, you will set Sonic's X and Y speeds to the direction in which he is being fired at. You can either hard code the X and Y speeds to be specific (for example if I want to shoot Sonic up and right in a 45 degree angle, I would set Sonic's X speed to say... 800, and the his Y speed to -800, thus ensuring he moves right and up at the same speed (thus diagonally)). ...or you can do it properly at the expense of some CPU time and memory, this is by means of providing an angle and using a subroutine/function which will calculate the sinewave positions (they call it Sine and Cosine, where Cosine is 90 degrees away from Sine, however, you can refer to these as X and Y if it'd make it easier).

    You specified Sonic 1, this game does not perform the actual calculation, instead, it has the X and Y (Sine and Cosine) values pre-calculated in a table, and the angle will reference the correct value based on the angle, this is to save on CPU time. You place the angle as a byte in d0, this will be from 00 to FF (this is your 360 range), you'll then call the sinewave subroutine (whatever it will be called in the source you are using, probably "CalcSine" or something), and it'll reference the table and return the X and Y sine words into d1 and d0 respectively. If you were to imagine a C function returning a floating point number, it would return between -1.0 and +1.0. Here is quite similar, the words inside the registers are fixed point QQ.FF (upper byte QQ is the quotient/lower byte FF is the fraction), so between FF00 and 0100, though of course, you could just say it's the sine and cosine multiplied by 100, pretty much the same deal, it's all in how you visually interpret it.

    These return words will be multiplied by the speed in which you want to move Sonic, so in our example that's 800, then you will divide by 100 to get only the quotient. The multiplication must be done before the division, otherwise you will lose the fractions role which is necessary for precision. If you are hard coding the speed to a specific speed that's nice and rounded like our 800, then you could just multiply it by 8, perhaps by means of shifting. If however the speed is variable and may change depending on circumstance, you have this speed in d2, you'll then have to use the multiply then divide method, for non-rounded speeds will need to take into account the fraction.

    Here are some crude examples:
    Code (Text):
    1. Angle = ??  ; 00 - FF
    2. Speed = ????    ; QQ.FF
    3.  
    4.         move.b  #Angle,d0
    5.         jsr CalcSine
    6.         muls.w  #Speed,d1       ; multiply by speed
    7.         muls.w  #Speed,d0
    8.         asr.l   #$08,d1         ; divide by 100
    9.         asr.l   #$08,d0
    10.         move.w  d1,Sonic's X Speed
    11.         move.w  d0,Sonic's Y Speed
    Code (Text):
    1. Angle = ??  ; 00 - FF
    2.  
    3.         move.b  #Angle,d0
    4.         jsr CalcSine
    5.         lsl.w   #$03,d1         ; multiply by 8 (100 x 8 = 800)
    6.         lsl.w   #$03,d0
    7.         move.w  d1,Sonic's X Speed
    8.         move.w  d0,Sonic's Y Speed
    Code (Text):
    1.     ; d2 = speed to move at
    2.  
    3. Angle = ??  ; 00 - FF
    4.  
    5.         move.b  #Angle,d0
    6.         jsr CalcSine
    7.         muls.w  d2,d1
    8.         muls.w  d2,d0
    9.         asr.l   #$08,d1
    10.         asr.l   #$08,d0
    11.         move.w  d1,Sonic's X Speed
    12.         move.w  d0,Sonic's Y Speed
    And if you were to manipulate the X and Y positions (not speeds) directly, you would probably do something like:
    Code (Text):
    1.     ; d2 = speed to move at
    2.  
    3. Angle = ??  ; 00 - FF
    4.  
    5.         move.b  #Angle,d0
    6.         jsr CalcSine
    7.         muls.w  d2,d1
    8.         muls.w  d2,d0
    9.         add.l   d1,X POSITION
    10.         add.l   d0,Y POSITION
    Since the X and Y positions of Sonic are 32-bit (upper word is quotient and lower word is fraction, so the division of 100 is not required here).

    It's quite circumstantial, though I would recommend the hard coded method if you know exactly what speed, angle, direction he's meant to be fired at, and will always be fired at that direction every time:
    Code (Text):
    1.         move.w  #$800,Sonic's X Speed
    2.         move.w  #-$800,Sonic's Y Speed
    It's much quicker/efficient.
     
  14. Aerosol

    Aerosol

    Not here. Moderator
    11,163
    573
    93
    Not where I want to be.
    Sonic (?): Coming summer of 2055...?
    Yea that all makes sense. The firing speed and angle of the cannon in Spinball is consistent so I'd probably just go with the easier option, as well as implementing a control lock so that the player can't alter the trajectory until they collide with something (or however those weird rotating cannons in Oil Ocean do it).

    What about actually adding the brand new object into the game?
     
  15. Devon

    Devon

    Down you're going... down you're going... Tech Member
    1,218
    1,374
    93
    your mom
    Sonic 1 has an object pointer table for each ID. For levels, it can only load objects with IDs 00-7F, since the most significant bit is used for some flag (don't remember what it does off the top of my head tbh). Just find an empty slot (empty objects in Sonic 1 either point to ObjectFall or a blank routine), and put in the pointer for your new object code. And with that set up, the game will run your custom object code whenever it finds an object with your ID, with the a0 register set to the object's variable set. On the wiki, there should be a reference for those, just in case you're unsure. Looking at how other objects are set up should help, too.

    Do note that you cannot use d7 when running object code, since it's used by the main object handler as a counter for how many object slots to go through.

    Regarding adding it to a level, I know that with SonLVL, you can just open up the level's object definition INI file and define the ID and graphics data for your object, and you'll be able to add it to your level easily.
     
    • Agree Agree x 1
    • Useful Useful x 1
    • List
  16. MarkeyJester

    MarkeyJester

    Original, No substitute Resident Jester
    2,192
    405
    63
    Japan
    To explain how to program objects in general would be very lengthy, because of there being many variations and many subroutines to call depending on the object, and because these objects will react differently. So to keep it simple, I will explain how you might program an object that reacts in a similar way to the cannon in Sonic Spinball. This will not be a 1:1 match, this will just be an example, and I will give you an object to play around and learn from, I know you're the type to pick these things up and to want to understand them, so I know my time will not be wasted.

    Do follow Novedicus' advice above, it is valuable for your needs. For this I will use object 4F which is blank in Sonic 1. I'm going to assume that the majority of the actual cannon's graphics themselves will be part of the level, and that only the cocking barrel which is moveable are sprites. So I would program the object to display only the moveable barrel. I won't make the graphics for the barrel, but I will make the object use some random sprites/graphics from the game as demonstration of displaying.

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

    Almost all objects in Sonic 1 have a jump table:

    [​IMG]
    Text

    The ID in $24 must be in multiples of 2, this will allow you to run a specific routine for the object depending on circumstance, and some subroutines in the game will manipulate $24 of the object too, for example, Sonic's touch response might increment the ID by 2 when Sonic touches the object, thus allowing the object to run a separate routine when touched.

    The object will start with 00 in $24, so the first routine is always ran first. Many objects will use this routine to setup the object for the first time, with the second routine usually being an idle/display/waiting routine.

    [​IMG]
    Text

    So here you can see that we add 2 to $24 so that the first routine only runs once and next frame the second routine is ran. In this routine I setup only the parts which are necessary for displaying the object. The first "ori" instruction will set the display mode and pattern index at the same time.

    The 14 is the display mode, and in binary the format is: OPSHXXFM.

    • O = On-screen flag (this is set by the sprite rendering routine when the object is displaying on-screen)
    • P = Path A or B (this is for Sonic specifically for loops).
    • S = Single sprite piece (if set, the long-word in $04 points to a single sprite piece, if clear, the long-word points to a list of sprite pieces with a proper frame/array table).
    • H = Sprite specific height (if set, then the byte in $16 will represent the object's display height, if clear the object will use the default height, being clear is quite common).
    • XX = Screen coordinates to follow (00 = Screen/Camera, used for HUD/Title Card items | 01 = Level FG, used for most objects in a level | 10 and 11 = Level BG, used for certain background scrolling items like the pylon in SLZ).
    • F = Flip flag (if set the sprites will all render upside down).
    • M = Mirror flag (if set the sprites will all render horizontally flipped).

    In my example I have set XX to 01 because the object is an in-level object and must scroll with the level. I have set H to 1 so we can specify the height of the displaying object (I don't know how big your cannon is necessarily going to be, so I put this in to allow you more freedom).

    The $F4C0 is the VRAM address, this is set to where the checkpoint post's ball is located as I'm going to use those graphics as the example here. The /$20 is to divide the VRAM address by 20 during assembly, this will convert it the pattern index for you. The 8000 which is just after the "14" and just before the "|($F4C0/$20)" can be manipulated for various pattern indexing modes. For example +800 will perform a mirror, +1000 will perform a flip, +2000/+4000/+6000 will change the palette line with which the sprites will render (palette line 2/3/4 respectively, default is 1), and +8000 will force the sprites to always be in-front of the planes. This together with the VRAM will compile together to form the hardware's pattern index format in binary: PCCFMTTT TTTTTTTT (P = Priority (high/low) | CC = Colour/Palette line | F = Flip | M = Mirror | T's = Tile ID (VRAM divided by 20)). Mine is set to be in-front of the level, because again, if the object is displaying the barrel and the level is displaying the gun itself, and the gun is in-front of Sonic and other objects, then we'll want the barrel to practically be in-front as much as possible.

    The next line is setting the address of the mappings, you can see I've set it to point to "Map_Obj4F", and have created some sprite mappings. Just to brief aside about the mappings, these will usually have a table of pointers (ours only has 1, but you can put more in if you like), the byte in object's $1A controls which frame to use, by default the object is clear, so by default $1A is 00, so the first map frame is being displayed. I will only setup one frame for this example, so you will find I will never manipulate $1A at all throughout the object, it will remain as 00.

    The actual frames' mappings themselves; the first byte is number of sprites, in our example we have 8 sprites. Each sprite consists of the following format; YY 0S PP PP XX:

    • YY = Y relative position (signed byte)
    • S = Shape (won't go into details, but I use 1 as all of these sprites will be two tiles high).
    • PPPP = Pattern index format (this is the binary format I explained above PCCFMTTT TTTTTTTT), this is added to the object's pattern index which we just set above to point to the checkpoint post's graphics, so these are "technically" relative, though technically not. This value is crudely added to the object's pattern index probably to save on CPU time, so the PCCFM bits may mess up unless you are setting them all with care.
    • XX = X relative position (signed byte).

    The checkpoint post's ball art in VRAM is stored as two tiles vertically and is only half the ball. To display the entire ball, we have to use two sprites, one with it's M flag set to mirror the sprite horizontally. In our example I have made four balls, two using the blue graphics, two using the red graphics, each ball requires two sprites to display both halves, so the total is 8. I have spaced them such that they create a sort of... square around the area in which Sonic will interact with the cannon. Of course, you can places these sprites/graphics however you want, this is just a brief demonstration.

    The byte written to $16 is the display height, this is the "radius" and not diameter, so if it's set to $20 in our example, that means $20 pixels above and below the object (total $40 pixels).
    The next word is writing two bytes, one to $18 which is the sprite priority and $19 which is the display width. The sprite priority can be from 0 to 7, of which 0 is in-front and 7 is behind. Note, this priority is only in relation to other sprites. I've set it to 1 so it should be quite in-front of most objects/sprites (including Sonic), which I believe you want the cannon barrel to be. I've set the display width to $20 just like the height, again, it's radius and not diameter.

    [​IMG]

    There is one problem with this object so far, if you go away from the object far enough and come back, after doing this a few times, sprites will start disappearing, and the game will start to slow down. This is because the object position loading engine is loading a brand new object 4F every time Sonic comes into this area, but the one that's already loaded from before is still loaded in object RAM. It is not up to the object position loading engine to delete objects, it will only create them, it is up to the object to delete itself.

    [​IMG]
    Text

    This code highlighted here will take the object's X position, and check to see if it is still within the area where objects are loaded, if it has gone out of this range (or the screen goes away from the area), then the object will branch to the subroutine which will delete the object. You'll notice that on the first setup routine I store away the X and Y word positions of the object to $3C and $3E, the reason is because the barrel is going to move when firing/charging. So we want to make sure it only deletes itself if it's spawn location has gone out of range, otherwise if we used the object's current X position, it might delete itself even though the screen has not gone out of the spawn area enough, and if going back to the area the object won't reload because it's spawn location was technically still on-screen. The opposite can happen to where the screen has gone out of the spawn area, but the object is still on-screen so when going back the object position loading routine will load a second object, even though the first one has not deleted itself. I store the Y position too, but this is for something else later on...

    Now to implement the touch response mechanism:

    [​IMG]
    Text

    The first thing you might notice is that I have created a new routine for when the object is touched, I will explain this routine in a moment, but first I would like to draw your attention to the value being written to $20 of the object during the setup routine.

    This byte sets up the width/height of the collision and the way in which the object/Sonic will respond when the collision occurs. Please note, the values in $16 and $19 are NOT the width and height for collision, these are for display only (they may be used for collision for certain subroutines, but that's another story). In Sonic's "TouchResponse" subroutine there is an array of widths and heights, called "Touch_Sizes":

    [​IMG]

    Here's the way it works, the value in $20 can be from 01 to 24. If it's 00, then the object will NOT collide with Sonic at all. The value from 01 to 24 will correspond to the table above, I have chosen 0F which is $18 width and $18 height (these are radiuses and not diameters as usual). So the object will collide with Sonic if Sonic touches the object within a $30 x $30 box ($18 pixels around it in a square). Now how the Sonic reacts to the object depends on the two most significant bits of $20:

    • 01 - 24 = Enemy collision (for badniks and bosses, Sonic will get hurt if he's not rolling or doesn't have invincibility, he will destroy or damage the boss and reduce the hit counter otherwise).
    • 40 - 64 = Normal collision (will increase the object's $24 routine counter by 2 if Sonic is touching it. 46 is special and is for Monitors, this handles the monitor bouncing when touched from the bottom, and causing it to fall as well as a few other collision specifics for monitors).
    • 80 - A4 = Harmful collision (will always hurt/kill Sonic unless he's invincible).
    • C0 - E4 = For special objects (The caterkill, yadrin, LZ's pole, and pinball bumpers. For example, the yadrin cannot be destroyed from the top due to his spikes, but can from the bottom, so this is a special case).

    I have chosen +40 for normal collision, this will cause the object's routine counter $24 to increment by 2 when Sonic touches it. So the third routine will run.

    Now... the actual routine itself. I first clear $20 to ensure that Sonic does not trigger the collision again, otherwise the routine counter will increment again and again, which we don't want. I then set a variable in RAM to 81, this is a special variable specifically designed to prevent Sonic from following rules like gravity and physics and collision with objects. He will be 100% free from all level/game mechanics at this point and will only animate.

    I next setup a few things in Sonic, such as setting is animation to rolling, and clearing his X, Y and ground speeds. I then setup a few flags in Sonic such that when he's released, he is in rolling mode and counts as being "in the air". I also set Sonic's direction to face the same way the cannon is facing, I assume you want the cannon to be able to face the other way just like in Spinball, this way you can set the Horizontal flip flag in SonED/SonLVL or whatever and have it flipped. The sf.b of $3C in Sonic, when Sonic is "in air" mode, the controllers are checked, if you are still holding A, B or C, Sonic's Y speed remains a certain speed, upon releasing any buttons the Y speed is reduced allowing the player to control how high Sonic can jump. The $3C flag being set allows this function to run, but we do not want it to run because Sonic is being fired manually out of a cannon and we do not want the Y speed to be tampered with, so we clear this byte. Now regardless of whether you are holding A, B, C or not, Sonic's Y speed will remain unchanged. Finally, I force Sonic's mode to normal "control", just as a precaution... Some objects will do this.

    Now that we've setup Sonic, we'll want to slowly align him into place before firing him off. So I will setup another routine for the object to run specifically designed for aligning Sonic into place:

    [​IMG]
    ...and...
    [​IMG]
    Text

    Now this routine is similar to the sinewave explanation I described in my previous post, but this isn't being used for launching Sonic, this is being used for pulling Sonic into the centre of the object. Since Sonic can be anywhere around the object at any angle, and I want Sonic to move in a direct straight line towards the object, I will need to use a sinewave calculation for working out the exact X and Y alignment amounts.

    So first of all, we obtain the arctangent (the angle), this is done in Sonic 1 by getting the X and Y distance between two objects and storing those distances in d1 and d2 as words respectively. When you call "CalcAngle", it will work out the 360 angle between the two points and will return that angle as a byte in d0 (00 - FF). Now that we have the angle, we'll immediately call "CalcSine" to get the X and Y (sine and cosine) amounts using the angle in d0 which we just collected. X will be returned in d1, and Y will be returned in d0.

    A brief bit about an object's X and Y positions in object RAM...

    The X and Y positions are actually a long-word each, where the upper word is the quotient, and the lower word is the fraction. The quotient is used for display and collision of course, but the fraction is necessary for precision and smooth movements. Now as I mentioned in my previous post the X and Y's which are returned in d1 and d0 are QQFF. Sonic's X and Y positions are QQQQFFFF.

    The ext.l instructions will extend QQFF to long-word QQQQQQFF, and the asl of 8 will shift this left 8 bits (a byte), resulting in QQQQFFFF. This is then added to Sonic's X and Y positions to move him slowly towards the object at the equivalent of a pixel each time. This QQQQFFFF value we've calculated will be anywhere between FFFF0000 and 00010000, depending on the angle/position of Sonic. If Sonic is directly below the object, then after the calculations are done the X will be 00000000 and the Y will be FFFF0000, thus causing a direct upwards direction.

    [​IMG]

    Success~

    Do note, after Sonic is moved, I branch back to the idle routine so the object checks if it needs to be deleted, and also saves itself for display. This will ensure the object is always checking and will always display, and there are no moments where it'll randomly disappear.

    Next up is detecting when Sonic has reached the centre of the object, and to prepare a charge:

    [​IMG]
    ...and...
    [​IMG]
    Text

    Now, seeing as we are getting the X and Y distance for the "CalcAngle" subroutine, we might as well use these to determine if Sonic has reached the object successfully, if he has, both X and Y distances should be 0. If true, we'll advance the routine counter to a "charge" routine, request an SFX to play, and we'll use the byte in $3B of the object as a sort of timer for charging (I've chosen $10 as it seems like a reasonable time).

    So Sonic will move towards the object, and only when he gets there will the object go into charging mode.

    [​IMG]
    Text

    Here, you can see the object's Y position is being moved down a pixel, and the X position is moving moved left a pixel, if the object is mirrored horizontally, the object's X position is moved right instead of left. This ensures if the cannon is facing and shooting right, it moves down and left diagonally. If it's facing and shooting left, it moves down and right diagonally.

    Following this is our little charge timer in $3B being decreased by 1 every frame, as long as it has not passed 00, it will simply branch back to check if it should delete itself and to display itself. So as long as the charge timer is still counting, the object will continue to move diagonally down.

    Finally the actual firing itself:

    [​IMG]
    ...and...
    [​IMG]
    Text

    Now, I have added in a "delay" routine, the reason being is we do not want the object to recapture Sonic immediately after firing him, we want to give Sonic enough time to leave the object so he doesn't trigger it again. This routine will be used to delay the object from being collide-able. We'll get to this routine shortly.

    You'll notice I've rearranged the way the routine counter is incremented on the first setup routine, this is just an mild optimisation reason, you don't necessarily have to do this, this is more just a habit on my end. But once the delay routine is finished, it will branch back to Obj4F_Reset which will set the routine counter correctly and reset the collision/touch response value in $20 again, and it'll continue down to the deletion check and display routine conveniently.

    Now, going back down to the charge timer, once it has passed 00, it'll continue down to the blue highlighted code, you'll see that I move the object's X and Y positions back to it's spawn location again, so the object should appear to pull and charge and then snap back as if it's firing (this is why I stored the Y spawn position as well as the X spawn position at the very beginning).

    The long-word move of 0C00F400 is setting Sonic's X and Y speeds (X to 0C00 and Y to F400 (-C00 upwards)). The mirror flag of the object is checked, and if the object is mirrored, the X speed of Sonic is negated so his X speed will be F400 (-C00) instead of +C00. The lock variable we set to 81 to prevent Sonic from reacting with the level and objects is then cleared. The byte $3B is set to $60 and is going to be used as our "delay timer", again, you can set this to whatever you want... I chose $60 at random. The routine counter is incremented to the delay routine, and a release SFX is played. At this point, Sonic has been given a shooting/firing speed, and is now free to move and is released from the object. The object then counts down the delay timer, and as long as the timer has not passed 00, it'll simply branch back to check for deletion and display, no collision is possible here until a value is written into $20 of the object, which will happen once the timer has finished and it branches back to Obj4F_Reset to reset itself for another firing.

    Final result Object 4F.
     
    • Useful Useful x 5
    • Informative Informative x 4
    • List
  17. Aerosol

    Aerosol

    Not here. Moderator
    11,163
    573
    93
    Not where I want to be.
    Sonic (?): Coming summer of 2055...?
    Markey I dunno what to say mate. I'll be studying this for a while to properly understand this, cause that's lots of cool gimmicks I'd like to see in the games. Thanks a million!
     
  18. Pokepunch

    Pokepunch

    Member
    84
    0
    6
    UK
    A Sonic 2 Hack
    Markey, I think this should be a guide on the wiki. Would it be okay with you if I added it?
     
  19. LoneDevil

    LoneDevil

    Eternal Underdog Member
    I didn't expect to see a fun wall of text in this thread of all places.
     
  20. MarkeyJester

    MarkeyJester

    Original, No substitute Resident Jester
    2,192
    405
    63
    Japan
    It's a nice idea, but I think to create such a wiki guide on object making, will require the aspects of an object to be broken up into individual pages. Not all objects display, not all objects have collision, not all objects are loaded in-level. I would strongly suggest creating a main wiki page about the general idea of an object, and having it contain a contents page which links to several sub-pages, each one dealing with a specific function with which an object could use. That way, a person looking to make a specific object which does a specific thing, can look up only the aspects they want.

    However, that's likely a lengthy project and should be done by someone who has the time to do it, if you would like to put the above as a guide on the wiki as a temporary solution until such time the above idea is implemented, then by all means, go for it!