TheouAegis
Member
I thought about putting this in Off-Topic, but it's still technically a programming issue and Off-Topic tends to be waaaaay off-topic. I'm trying to code something that would still be doable on an NES and I'm also trying to restrict myself to a few particular formulas to retain the feels of the inspirations for my projects. First, let me give some foundation for my issue. I apologize for how long-winded this will be.
As a couple of you may perhaps know, for some of my little projects, instead of using the trigonometric functions for wave patterns, I use a dynamic deceleration code used by coders at Konami (I'm sure other programmers have used it as well). Admittedly, it's quite limited in its applications, but the code is basically
The wave pattern can be modified by setting an initial speed, shifting the starting position, modifying the divisor (256 by default because the code was intended for an 8bit system), or even performing additional operations inside the parentheses.This code worked flawlessly to reproduce the same results as the source material when using the following code to actually handle movement
This was already discussed in another topic, so it's of no concern to me here. However, it is significant to my primary issue:
I got to thinking, what would happen if I applied both horizontal and vertical components to the object (essentially removing the "//or..." from the first code block); and after some fiddling with the starting coordinates and speeds, I deduced how to form ellipses using that code structure. However, I came across a significant, persistent problem: gradually, very slowly unless I set the room_speed to 999, the ellipse would traverse across its x-axis almost as though it were rotating about it. After some exhausting debugging, I traced it to one basic aspect -- shifting the starting coordinate. Just to clarify, here are a couple Create Event settings:
Now, it's that x+=32 (or y+=32 if we change orientation) that ultimately was giving me headaches, as it was causing deviations which shifted -- I'm assuming -- hspd or vspd gradually. I went back to the source material, modified the source code so it shifted the starting y-coordinate with a vspd of 0, then tested the code on an NES emulator. Sure enough, that shift was present there as well.
I narrowed down the source of my problem, so I tried to find a fix for it. In my GM code, I came up with two "solutions". The first was to simply remove the integer movement from the formula.
That... just wasn't acceptable for me, however. It got me thinking, too, why does it work with that movement and not with integer movement. I was like, if the source code only used integer coordinates to calculate 16bit reals, shouldn't the same hold true with integer coordinates in GM? Then I remembered the source code was flawed as well and it had nothing to do with my integer movement code. This then lead me to my alternate solution and the one I need advice on:
This worked with my integer movement code, but it was clearly a significant deviation from the source code. It's a significant step from (64-32)/256 to (64-32.125)/256, since we're now including even more bytes in the calculation. Brainstorming, I considered an ASM equivalent of something like
And that's an ugly concept, since we now turned vspd and hspd into 32bit values (only used 24bits here, though).
Basically, I'm looking for any ideas on how to make the code work properly (i.e., no wobbling or compression along the axis) whilst retaining only 16bit values for vspd and hspd? Or maybe it's just not even possible.
I have an enemy planned out, but currently it would have 4 instances which would need this code. In keeping with the source material, I think I'd only have 2 extra bytes per instance, but with what I've come up with so far here, my current code requires 4 extra bytes per instance PLUS an additional basic movement subroutine. That just doesn't feel acceptable to me, so I'm hoping one of you guys can come up with something better.
Edit: Redid the ASM to verify how many variables I'd need to create and streamlined the movement code to make it a little more viable. Looking at it again, it may actually be viable now. So really, I guess I'm looking for any ideas on how to optimize this code or the mechanics in such a way that it would be even more streamlined on an NES. I mean, temp[1] and temp[3] shouldn't even be temporary variables, so I went back and checked for any avaialbe address ranges I could hopefully use. The code is still slower than I would like, though.
As a couple of you may perhaps know, for some of my little projects, instead of using the trigonometric functions for wave patterns, I use a dynamic deceleration code used by coders at Konami (I'm sure other programmers have used it as well). Admittedly, it's quite limited in its applications, but the code is basically
Code:
vspd += (ystart - y) / 256;
//or...
hspd += (xstart - y) / 256;
Code:
yfr += vspd;
y += floor(yfr);
yfr -= floor(yfr);
xfr += vspd;
x += floor(xfr);
xfr -= floor(xfr);
I got to thinking, what would happen if I applied both horizontal and vertical components to the object (essentially removing the "//or..." from the first code block); and after some fiddling with the starting coordinates and speeds, I deduced how to form ellipses using that code structure. However, I came across a significant, persistent problem: gradually, very slowly unless I set the room_speed to 999, the ellipse would traverse across its x-axis almost as though it were rotating about it. After some exhausting debugging, I traced it to one basic aspect -- shifting the starting coordinate. Just to clarify, here are a couple Create Event settings:
Code:
xfr = 0;
yfr = 0;
//The following settings would create a r32 circle
x += 32;
vspd = 2;
Code:
xfr = 0;
yfr = 0;
//The following settings would create 128x64 ellipse
x += 64;
vspd = 2;
Code:
xfr = 0;
yfr = 0;
//The following settings would create a 71x65 SKEWED ellipse
x += 32;
hspd = 1;
vspd = 2;
I narrowed down the source of my problem, so I tried to find a fix for it. In my GM code, I came up with two "solutions". The first was to simply remove the integer movement from the formula.
Code:
x += hspd;
y += vspd;
Code:
vspd += (ystart - (y + yfr) )/256;
hspd += (xstart - (x + xfr) )/256;
Code:
LDA object_index
CMP obj_chainlink
BEQ new_movement_subroutine
CMP obj_spikeball
BEQ new_movement_subroutine
SEC
LDA #00
SBC yfr //included
TAY
LDA ystart //created @ 0x0606
SBC y //included
STA temp[0]
STY temp[1] //maybe create @ 0x06B7 ?
SEC
LDA #00
SBC xfr //included
TAY
LDA xstart //created @ 0x061E
SBC x //included
STA temp[2]
STY temp[3] //maybe create @ 0x06CC ?
CLC
LDA vspd[2] //created @ 0x0633
ADC temp[1]
STA vspd[2]
JSR
LDA vspd[1] //included
ADC temp[0]
STA vspd[1]
LDA vspd[0] //included
ADC #00
STA vspd[0]
RTS
LDA temp[2]
STA temp[0]
CLC
LDA hspd[2] //created @ 0x0682 ???
ADC temp[3]
STA hspd[2]
JSR
LDA hspd[1] //included
ADC temp[0]
STA hspd[1]
LDA hspd[0] //included
ADC #00
STA hspd[0]
RTS
Basically, I'm looking for any ideas on how to make the code work properly (i.e., no wobbling or compression along the axis) whilst retaining only 16bit values for vspd and hspd? Or maybe it's just not even possible.
I have an enemy planned out, but currently it would have 4 instances which would need this code. In keeping with the source material, I think I'd only have 2 extra bytes per instance, but with what I've come up with so far here, my current code requires 4 extra bytes per instance PLUS an additional basic movement subroutine. That just doesn't feel acceptable to me, so I'm hoping one of you guys can come up with something better.
Edit: Redid the ASM to verify how many variables I'd need to create and streamlined the movement code to make it a little more viable. Looking at it again, it may actually be viable now. So really, I guess I'm looking for any ideas on how to optimize this code or the mechanics in such a way that it would be even more streamlined on an NES. I mean, temp[1] and temp[3] shouldn't even be temporary variables, so I went back and checked for any avaialbe address ranges I could hopefully use. The code is still slower than I would like, though.
Last edited: