nmoog Posted July 3, 2006 Share Posted July 3, 2006 Some unfocused, wishy-washy questions for you! I want to have a "jumping" sprite, and I'm confused on the best way to do it. For other languages/machines I've always done gravity kind of like this: YVelocity = 10 ; Set initial jumping velocity UpdatePlayerPos: ; Called every frame PlayerY = PlayerY - YVelocity YVelocity = YVelocity - 1 So that for the first frame after jumping the player moves up 10 pixels, then 9,8,7,6,5,4,3,2,1,0 then -1,-2,-3,-4,-5,-6.... Giving a nice looking effect of gravity as a player jumps, then lands. Implementing this for the 2600 is harder then I imagined - I can't move a player 10 pixels a frame, that'd look crazy. The way I imagine would look correct would be that I move the player up one pixel after 1 frame, then up one pixel again after 2 frames, then 3,4,5,6,7,8,9,10 then 9,8,7,6,5,4,3,2,1 frames (maybe not 10 frames... that'd be quite a pause mid air) I've been trying to implement something like this, but it's looking verrry messy (codewise), and not very impressive. Its easy when everything on screen moves 1 pixel per frame, but I can't figure out how timing can be done nicely. Are there any "standard" ways to do timing for games? How would you do it if some sprites need to move quickly (say, 3 pixels per frame) and others need to move slowly (say, 1 pixel every 3 frames)? How do you handle these timing issues?! Quote Link to comment Share on other sites More sharing options...
jbanes Posted July 3, 2006 Share Posted July 3, 2006 (edited) If you're using Batari BASIC, you can use fixed point math to give sub-pixel accuracy. That would allow your character to jump, say, with 3 pixels of force against a gravity of 0.2 pixels per frame. This is more or less what I did in Deimos Lander. (I posted the code in the homebrew thread.) If you're not using bBASIC, then it's still fairly easy to do. Use one variable to represent the number of pixels, and another variable to represent the sub-pixels. For example, you can use 10 subpixels for every pixel. Every frame you add or subtract the gravity number from the subpixel counter. If the subpixel counter goes over 10 (or whatever number you use to represent a full pixel) you add to the pixel counter and subtract 10 from the subpixel counter. If the subpixel counter goes below -10, you subtract one from the pixel counter and add 10 to the subpixel counter. Does that help? Edited July 3, 2006 by jbanes Quote Link to comment Share on other sites More sharing options...
nmoog Posted July 4, 2006 Author Share Posted July 4, 2006 Yep! That's the answer alright! That's the elegant solution I was looking for to clean up my mess of counter variables. And "subpixel" sounds likes a good keyword to search the forums and stella archives on too. Thanks! Quote Link to comment Share on other sites More sharing options...
Thomas Jentzsch Posted July 4, 2006 Share Posted July 4, 2006 (edited) Yup, subpixel is the way to go. Then you just have to define a constant gravity value and add that to your vertical speed every frame. BTW: Depending on what you want to do, it is often also good to use friction as an opposite power to gravity (or other forces like e.g. thrust). Just divide the speed by some power of 2 factor and subtract that from the current speed. That way you will also limit the maximum speed (when gravity becomes equal to subtracted value) which might become useful (e.g. for collision detection). I did that in Thrust and my three SWOOPS! minigames and IMO the result "feels" very good. Edited July 4, 2006 by Thomas Jentzsch Quote Link to comment Share on other sites More sharing options...
+xucaen Posted July 4, 2006 Share Posted July 4, 2006 Use one variable to represent the number of pixels, and another variable to represent the sub-pixels. For example, you can use 10 subpixels for every pixel. Every frame you add or subtract the gravity number from the subpixel counter. If the subpixel counter goes over 10 (or whatever number you use to represent a full pixel) you add to the pixel counter and subtract 10 from the subpixel counter. Hi, I just want to make sure I understand. I've been working on something similar and came up with a frame counter to decrement before moving my sprite. So, subpixel is the number of frames to skip before you change the pixel, or scanline, position. Correct? Jim Quote Link to comment Share on other sites More sharing options...
+batari Posted July 4, 2006 Share Posted July 4, 2006 Use one variable to represent the number of pixels, and another variable to represent the sub-pixels. For example, you can use 10 subpixels for every pixel. Every frame you add or subtract the gravity number from the subpixel counter. If the subpixel counter goes over 10 (or whatever number you use to represent a full pixel) you add to the pixel counter and subtract 10 from the subpixel counter. Hi, I just want to make sure I understand. I've been working on something similar and came up with a frame counter to decrement before moving my sprite. So, subpixel is the number of frames to skip before you change the pixel, or scanline, position. Correct? Jim Not necessarily. A frame counter will only delay an integer number of frames. A subpixel counter can move a non-integer number, and also a value greater than 1. For example, 0.4375 pixels per frame, or around 2.29 frames per pixel would appear as usually moving every second frame but sometimes it would take 3 frames. 1.0675 pixels per frame would appear as moving one pixel per frame except every 16th frame it would move two. Using subpixel movement gives more flexibility and makes the games appear smoother. Quote Link to comment Share on other sites More sharing options...
Thomas Jentzsch Posted July 4, 2006 Share Posted July 4, 2006 Hi, I just want to make sure I understand. I've been working on something similar and came up with a frame counter to decrement before moving my sprite. So, subpixel is the number of frames to skip before you change the pixel, or scanline, position. Correct? No exactly. Your solution doesn't allow e.g. movements every 1.5 frames or smooth accelerations. Fractional postioning/movement uses two variables (Lo/Hi) for each direction (X/Y). The Hi variables describe the position on the screen. The Lo variables describe the subpixel position. Each frame you add a constant 16bit value to the 16bit positions (e.g. For moving every 1.5th frame, you add 256/1.5 = ~171). For accelerated movement (e.g. due to gravity), you don't use speed constants, but add acceleration constants to speed variables (which will finally be added to the position variables). Hope that makes sense. Quote Link to comment Share on other sites More sharing options...
jbanes Posted July 4, 2006 Share Posted July 4, 2006 Hi, I just want to make sure I understand. I've been working on something similar and came up with a frame counter to decrement before moving my sprite. So, subpixel is the number of frames to skip before you change the pixel, or scanline, position. Correct? Hi Jim! If I understand you correctly, the answer is 'no'. You're describing a similar, but altogether different concept. What you're doing is effectively reducing the framerate by skipping frames between updates. What I described is a form of fixed point math, but with an arbitrary amount of overflow. If you define the maximum to be a number divisible by 10, then you pretty much have fixed-point math. For example, if the second byte overflows at 100, then: Byte1: 3 Byte2: 20 Is equivalent to 3.20. After 3.99 would come 4.00 or 4 and 0 for bytes 1 and 2. The advantage to the fixed-point method is that your accurately computing the exact position at the full framerate of 60FPS. This makes high speeds work a lot better as you have more updates each second. That way you will also limit the maximum speed (when gravity becomes equal to subtracted value) which might become useful (e.g. for collision detection). I usually use a preset terminal velocity myself, but I imagine that including air friction would make it feel more accurate. Quote Link to comment Share on other sites More sharing options...
+xucaen Posted July 4, 2006 Share Posted July 4, 2006 Ahh.. Thank you all for your responses. This is great stuff. I did a search and found Kirk's demo for calculating the subpixel. It is also a great example of how to do exact horizontal positioning. http://alienbill.com/2600/cookbook/subpixel.html Question, would you ever want to use a subpixel for moving horizontally? Jim Quote Link to comment Share on other sites More sharing options...
jbanes Posted July 5, 2006 Share Posted July 5, 2006 Question, would you ever want to use a subpixel for moving horizontally? Sure! If you're going to make the character move at a fixed rate, then there isn't much point to it. However, if you want the character to accelerate, it works great. An example of this sort of acceleration is 7800 Centipede. The longer you hold the contoller, the faster your "gnome" moves. In shoot-em' ups, using acceleration (usually with some sort of cap on the maximum velocity) can give the controls a much better feel than using a fixed rate of motion. In platformers it can make the character seem to move much more realistically. (Think: Sonic the Hedgehog) In car games, it can make a car seem more like a car. Quote Link to comment Share on other sites More sharing options...
Thomas Jentzsch Posted July 5, 2006 Share Posted July 5, 2006 Asteroids, Gravitar, Thrust or even Splatform (SWOOPS!) are other examples. Quote Link to comment Share on other sites More sharing options...
djmips Posted July 5, 2006 Share Posted July 5, 2006 Yup, subpixel is the way to go. Then you just have to define a constant gravity value and add that to your vertical speed every frame. BTW: Depending on what you want to do, it is often also good to use friction as an opposite power to gravity (or other forces like e.g. thrust). Just divide the speed by some power of 2 factor and subtract that from the current speed. That way you will also limit the maximum speed (when gravity becomes equal to subtracted value) which might become useful (e.g. for collision detection). I did that in Thrust and my three SWOOPS! minigames and IMO the result "feels" very good. Very interesting and quite illuminating I might add. I've never used friction in my 'space' games because I never thought it was needed, but I can see how it does add a nice touch to the control. It's good to have some damping in the system even on these 8 bit physics systems. I will always remember this and the next time I'm working on a simple physics system I'm going to experiment with this!! If you don't do this you will get that very watery feel but maybe you really want a little mud. Quote Link to comment Share on other sites More sharing options...
Heaven/TQA Posted July 5, 2006 Share Posted July 5, 2006 it is very simple so don't be afraid to use it... i entered another "galaxy" when i captured how fix point maths works (e.g. subpixel) and how it can add a professional touch to games... welcome to the next level. Quote Link to comment Share on other sites More sharing options...
Thomas Jentzsch Posted July 5, 2006 Share Posted July 5, 2006 Very interesting and quite illuminating I might add. I've never used friction in my 'space' games because I never thought it was needed, but I can see how it does add a nice touch to the control. Sometime it is good and sometimes it is essential. E.g. my Cave1k minigame wouldn't work without damping. If you assemble it without FRICTION enabled, the helicopter control becomes almost impossible. Quote Link to comment Share on other sites More sharing options...
+xucaen Posted July 5, 2006 Share Posted July 5, 2006 I think I got it. In the attached example, I am using subpixels to handle Y positioning, and rotation. Ok, the code is messy, and I haven't figured out all the switch-draw variations out there, the subpixeling I understand. And now I can see how using a subpixel to control the X position would be useful. Left and Right rotate, Up moves forward. Down does nothing. player.zip Thanks! Jim Quote Link to comment Share on other sites More sharing options...
nmoog Posted July 8, 2006 Author Share Posted July 8, 2006 That subpixel movement is awesome! I don't know if this is related, but is there a sneaky clever way to do animation timing? I am using two variables PlayerFrame and FrameCounter - I set FrameCounter to some value, decrement it each frame, and when it is zero increment the PlayerFrame and reset the counter. Then in a horribly complex and ugly looking "switch" statement I point the SpritePointer to the correct frame (depending if the player is walking or jumping etc) Is this the best way to handle animation timing? The 16 bit math cleaned up my movement code nicely, and now my animation code looks really ugly Any animation tips?! Thanks! Quote Link to comment Share on other sites More sharing options...
jbanes Posted July 8, 2006 Share Posted July 8, 2006 I don't know if this is related, but is there a sneaky clever way to do animation timing? I am using two variables PlayerFrame and FrameCounter - I set FrameCounter to some value, decrement it each frame, and when it is zero increment the PlayerFrame and reset the counter. Then in a horribly complex and ugly looking "switch" statement I point the SpritePointer to the correct frame (depending if the player is walking or jumping etc) With the 2600's constraints, I don't think there's any "right" way to do most things. However, it sounds like what you want is tables. i.e. You'd have a list of pointers to the animation frames somewhere in memory. When you increment the animation frame, you simply do a lookup in the table to get the address of the sprite. Since I assume you'll want to use 2 bytes instead of 1 for each address (unless ALL your sprites fit within a single page of memory) you'll want to shift the counter value left by one bit. This will multiply the value by 2. Store the value in X, use a LDA Absolute,X to get the first byte, INX to point to the second byte, then a LDA Absolute,X again to transfer the second byte. Bam. All done. Of course, this won't work in bBASIC. Switch-style statements are your only option unless you're willing to embed a bit of assembler. Is that what you had in mind? Quote Link to comment Share on other sites More sharing options...
nmoog Posted July 9, 2006 Author Share Posted July 9, 2006 That's a cool idea - could you give me an example of what the lookup table would look like? How do you do a table of addresses for dasm? I'm learning assembler, so I haven't had a look at batari basic - it kind of seems like cheating In regards to the actually "counters" for animation, is that how you do your timing for animation frames - Store a timer counter variable and decrement each loop, when it's zero increment the animation frame? I can see what you mean about there not being a "right" way. I've only got about 3/4 of game logic working in the vertical blank area and I've run out of cycles! That's why I'm looking for more efficient methods of doing things like timing. My first efforts are working, but aren't very elegant Quote Link to comment Share on other sites More sharing options...
jbanes Posted July 9, 2006 Share Posted July 9, 2006 That's a cool idea - could you give me an example of what the lookup table would look like? How do you do a table of addresses for dasm? No assembler handy to test, but it would look something like this: Frame = $80 SpriteAddress1 = $81; Low byte of the address! SpriteAddress2 = $82; High byte of the address! [...] ; Load the frame of animation. This would normally be done by incrementing or decrementing "Frame" LDA #1 ; Load the second frame - remember that this is zero based! 0 is 1, 1 is 2, and 2 is 3! STA Frame [...] ; Load the address LDA Frame ROL; When you shift left in binary, you effectively multiply by 2 TAX LDA MySpriteFrames,X STA SpriteAddress1 INX LDA MySpriteFrames,X STA SpriteAddress2 [...] ; Somewhere in the kernal... ; Someone set us up the sprite! kernal LDA (SpriteAddress1),X; Load the current line stored in X STA GRP0 STA WSYNC DEX BNE kernal; As long as we've got lines to render, keep going! [...] ; Lookup table for the different frames. The code below stores the address with the low-byte first, high-byte second. MySpriteFrames .byte #<MySpriteFrame1, #>MySpriteFrame1 .byte #<MySpriteFrame2, #>MySpriteFrame2 .byte #<MySpriteFrame3, #>MySpriteFrame3 [...] org $FF00 MySpriteFrame1 ; sprite data MySpriteFrame2 ; sprite data MySpriteFrame3 ; sprite data Presumably you're doing this because (unlike the example) your frames are either out-of-order, of an unpredictable size, cross pages, or are otherwise too weird to compute the offset. Also, that's pretty generic up above. If you know certain things about your data, there are probably a billion and one ways to optimize it. In regards to the actually "counters" for animation, is that how you do your timing for animation frames - Store a timer counter variable and decrement each loop, when it's zero increment the animation frame? Without knowing a lot more about what you're doing than I want to know, I can't really give you any good advice. All I can say is that if you animate sprites at less than 60fps, then what you're doing sounds fine. My only suggestion would be to make sure you're using a unified counter rather than having a different counter for each sprite. Of course, your game may not allow for a unified counter, so take that with a grain of salt. Quote Link to comment Share on other sites More sharing options...
nmoog Posted July 10, 2006 Author Share Posted July 10, 2006 I had my "walk cycles" using an offset to the sprite data, but special other frames (like jumping, and ducking) will be much nicer using the lookup table approach I think. And no, I wasn't using a unified counter to control any of the animation - thats a good idea! Thanks for your help Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.