0 Members and 3 Guests are viewing this topic.
0->MobX2->MobY4->MobHPLbl MobAI .r1 is the pointer to the mob's datar1->X .save R1 so function calls don't clobber it.IsWall and similar functions are just made up psuedocode for the example!If IsWall({X + oMobX}r + 1, {X + oMobY}r) .Simple, but it will get messy quickly{X + oMobX}r++End!If IsWall({X + oMobX}r, {X + oMobY}r + 1){X + oMobY}r++End!If {X + oMobHP}rMobDies(X)EndReturn
L1+0->MobX .Put your Mob data at a predetermined spot. I usually use 0x966E (described above in the free ram section) but you can put it wherever you want.L1+2->MobYL1+4->MobHPLbl MobAI .r1 is the pointer to the mob's datar1->X .save the value of r1Copy(X, oMobX, SizeOfMob) .Copies the mob's data to a predetermined spot. Fill in SizeOfMob with however big your mobs are, in bytes.!If IsWall(MobX + 1, MobY) .This is so much easier to read and type than the above example. And it is way faster and uses less space!MobX++End!If IsWall(MobX, MobY + 1)MobY++End!If MobHPMobDies(oMobX)EndCopy(oMobX, X, SizeOfMob) .Copy the data back now that we are doneReturn
Lbl XMagicX:Asm(E5) .Set X as Axe 'Ans' variable and then push it onto the stack5->X .Modify and use X however you wantDisp X>DecAsm(E1)->X .Pop the last entry from the stack and set X to itReturn
.Like TI-BASIC, Axe has a variable which is the result of the previous calculation. However, Axe's version doesn't have a name.X+5 .Add 5 to X but don't do anything with the result. The value is stored in HL which is what Axe's 'Ans' is called.->Y .Store HL to Y. Since the result hasn't changed, we can use HL again+2->Z .Add 2 to HL and then store HL to ZX .Sets HL to the value of XAsm(E5) .Pushes the value of HL onto the stack. You can push and pop whenever you want as long as you know what you are doing+5 .Adds 5 to HLSomeFunction() .Call some function that possibly modifies X. At the start of the function, HL will hold X+5. (so the first line of the function could be '->X' for instance)Asm(E1) .Pops HL from the stack. Now HL holds the same value it did when the most recent Asm(E5) was called->X .And save that value to X, effectively protecting it from any modifications that might happen in SomeFunction. (Called functions can push and pop if they want too).You can push multiple things to the stack at the same timeX:Asm(E5)Y:Asm(E5)MyVariable:Asm(E5)For(x, 0, 5) Disp X>DecEndAsm(E1)->MyVariable .Notice that the order of pops is inverted from the order of pushesAsm(E1)->YAsm(E1)->X...There are some restrictions on when you can push and pop from the stack. Well, you can do it at any time, but if you don't know what you are doing, all you will get is a crashYou must make sure that you call pop the same amount of times you call push before you call 'return'. (This is easy, all it means is that you can't call push a bunch at the start of a function and then call Return without popping everything. You don't need to do anything with the popped results if you don't want to)The stack is used when calling functions. All that means is that you can't push a variable in one function, call another and pop that variable in the function you just calledThe stack is also used for single argument For loops. (3 argument for loops don't have this problem - they use a much less efficient method of looping that doesn't use the stack) That means you can't push a variable outside a For(10) loop and pop it inside the loop. (it is still safe to push and pop inside the loop, just make sure your pushes and pops are balanced inside the loop body.If you just push some variables at the start of a function and pop them at the end, you will always be safe. It also works well inside complex loops....
Lbl UpdateGameIf getKey(2)PlayerX--⁻8→ScrollXOffsetʟUpdatePlayer→UpdateStateEndIf getKey(3)PlayerX++8→ScrollXOffsetʟUpdatePlayer→UpdateStateEndIf getKey(4)PlayerY--⁻8→ScrollYOffsetʟUpdatePlayer→UpdateStateEndIf getKey(1)PlayerY++8→ScrollYOffsetʟUpdatePlayer→UpdateStateEndIf getKey(15)ʟUpdateQuit→UpdateStateEndPause 16ReturnLbl UpdatePlayerIf ScrollXOffset<<0ScrollLeft()EndIf ScrollXOffset>>0ScrollRight()EndIf ScrollYOffset<<0ScrollUp()EndIf ScrollYOffset>>0ScrollDown()EndIf ScrollXOffset=0 ? ScrollYOffset=0ʟUpdateGame→UpdateStateEndReturnLbl UpdateQuit1→QuitReturn
Lbl UpdateGameFor(I,1,4)If getKey(I)PlayerX+sign{I-1+°DirX}→PlayerXPlayerX+sign{I-1+°DirY}→PlayerYsign{I-1°DirX}*8→ScrollXOffsetsign{I-1°DirY}*8→ScrollYOffsetʟUpdatePlayer→UpdateStateEndEndIf getKey(15)ʟUpdateQuit→UpdateStateEndPause 16ReturnLbl UpdatePlayerIf ScrollXOffset<<0ScrollLeft()EndIf ScrollXOffset>>0ScrollRight()EndIf ScrollYOffset<<0ScrollUp()EndIf ScrollYOffset>>0ScrollDown()EndIf ScrollXOffset=0 ? ScrollYOffset=0ʟUpdateGame→UpdateStateEndReturnLbl UpdateQuit1→QuitReturn
If getKey(1)ElseIf getKey(2)ElseIf getKey(3)ElseIf getKey(4)End
1→°KDown+1→°KLeft+1→°KRight+1→°KUp .add some constants for the arrow keys. In my code I define every key like this. Now, I don't have to remember that 2 is left, I just type °KLeft15→°KClearLbl UpdatePlayergetKey(°KClear) or Quit→Quit .getKey returns either 1 or 0. I use 'or' so as not to set Quit to 0 if it was 1 when we got here. This should be moved to the main loop since it isn't player related code.If ScrollXOffset If >>0 ScrollRight() ScrollXOffset-- .-4??PlayerX++ .If you want to make PlayerX change on the boundary of tiles instead of when movement starts, you can uncomment this and remove the PlayerX++ from the getKey block below Else ScrollLeft() ScrollXOffset++ .+4??PlayerX-- End Return .Don't let the player push keys during scrollingElseIf ScrollYOffset .Doesn't need to be an else-if (because of the Return in the line above) but it doesn't hurt anything and makes the intent clearer If >>0 ScrollDown() ScrollYOffset-- .-4??PlayerY++ Else ScrollUp() ScrollXOffset++ .+4??PlayerY-- End ReturnEnd.If execution makes it here, both ScrollXOffset and ScrollYOffset are 0. The screen isn't moving so it is safe to pick a new direction.getKey(num) commands are very quick. Don't be afraid to check the same key multiple times if it makes your code cleaner. It *is* possible that the key state changes between checks but unlikely. As long as you keep that in mind, it is totally fine to do.If getKey(°KDown) ? getKey(°KUp)-1 .getKey(°KUp)-1 is the same as getKey(°KUp)=0. Checking both keys makes the player not move if up and down are both held. It is a preference thing and not needed if you don't like it If Walkable(PlayerX, PlayerY+1) .Or whatever check you use to see if the player is allowed to walk into a given tile. I check this inside the if-else chain so that the walkable status of a tile doesn't impact what direction the player is moving. PlayerY++ 8→ScrollYOffset Goto UpdatePlayer .This is optional. Without it, the player will spend one tick standing still for each tile they move, making movement seem slightly jerky on an actual calc EndElseIf getKey(°KUp) ? getKey(°KDown)-1 If Walkable(PlayerX, PlayerY-1) .You don't check for collision in your code. I assume that will be added later? If it doesn't apply, just remove the 'If Walkable' statements PlayerY-- -8→ScrollYOffset Goto UpdatePlayer EndElseIf getKey(°KRight) ? getKey(°KLeft)-1 If Walkable(PlayerX+1, PlayerY) PlayerX++ 8→ScrollXOffset Goto UpdatePlayer EndElseIf getKey(°KLeft) ? getKey(°KRight)-1 If Walkable(PlayerX-1, PlayerY) PlayerX-- -8→ScrollXOffset Goto UpdatePlayer EndEnd.I only did a couple minor optimizations in this example since my goal was readable code. There is quite a bit that can be done with this code but that is left as an exercise to the reader.Return
Lbl MainInit()Game()ReturnGoto MAINENDLbl Init0→Frame→Quit→ScrollXOffset→ScrollYOffset→PlayerX→PlayerY+6*8→MapX→MapY°TileMap→MapDrawMap()ʟUpdateGame→UpdateStateʟDrawGame→DrawStateReturnLbl UpdateFrame++(UpdateState)()ReturnLbl Draw(DrawState)()ReturnLbl GameWhile 1Update()Draw()EndIf QuitReturn