bspymaster wrote:
Hi!
I'm currently working on an AXE program, and all is going well (I would add photos/video, but the TI recording program doesn't work with it). I can't figure out the AI portion. My program is an adventure/ space shooter where you are in a spaceship flying around and you have to do... something (not sure yet) but you will go through different stages where there are obstacles on the screen and enemies you have to destroy. The only way to leave the current "arena" is to destroy all he enemies. I want the enemies to be able to just maneuver around the outside until you com within X spaces of it, then It will follow and shoot at you until you destroy it. Any suggestions? Like I said, I would show you a video of what I have, but the TI recording program doesn't work while the AXE program is running.
Sounds like a good concept I suggest using Wabbitemu to record your program, it's an actual emulator so it works just like your real life calculator, but on a computer and with features like recording on-screen things to .gif pictures.
AI isn't a simple topic, but it definitely isn't the black magic everyone makes it out to be
One thing to consider when having multiple objects on screen (or multiple enemies) is to use an object queue. An object queue is just like it sounds -- a line of objects in memory that are updated in order based on their slot positions in the queue buffer. Once you understand this, everything is a lot easier. So, I'll try and describe it to the best of my ability.
For the first example, let's say we have a queue buffer of 16 bytes, starting with the byte pointed to by L1 (SaveSScreen, for you assembly nerds). Let's start simple by filling up these 16 bytes with 4 objects, each 4 bytes in data (type of monster thing, x position, y position, and direction, each 1 byte in memory). We can set up the blank queue for this like so:
Code: 0 -> {L1}
Fill(L1,15)
To change a value for an object, yu can do it either manually, or go the unoptimized but easier way of making a subroutine for it:
Code: Lbl CHG
r3 -> {r1*4+r2+L1}
Return
the arguments for this would be r1 = which_object, r2 = which byte to edit, and r3 = what the byte would now be equal to.
Now that you have this, you can have a looping statement that will do all of the code for each object inside:
Code: For(A,0,3)
(A*4+L1) -> B
... now B = the start of data for each object,
and to do something like access byte 3 of
the current object you would simply do
{B+2}
...
.put your code here!
End
Now, you can put what you want each object to do in the loop, and it makes it pretty easy. Now, you can do simple stuff like make enemies move left (assuming the first byte for each object is the x position) by doing this in the loop:
Code: For(A,0,3)
(A*4+L1) -> B
{B}-1 -> {B}
End
This code in the loop would make each object in the queue move left at one pixel per frame.
From here, you keep adding more on and experiment around to make highly sophisticated enemy patterns
If you want more help on more specific matters, I'll be glad to explain in more depth. This was more of a nutshell of the whole idea.
For your convenience, I'll post a few examples of what object queues make look like. Here's a rather simple one, ripped from TaNF (it handles the rendering of the items like potions and the like on screen and detects collisions):
Code: :Lbl ITM
:For(A,0,1
: If {A*4+{L1}+300}
: If ((X≥({A*4+{L1}+301}-8)) and (X≤({A*4+{L1}+301}+8))) and ((Y≥({A*4+{L1}+302}-8)) and (Y≤({A*4+{L1}+302}+8)))
: !If {A*4+{L1}+300}-1
: {{L1}}+{A*4+{L1}+303}→{{L1}}
: If {{L1}}>{{L1}+1}
: {{L1}+1}→{{L1}}
: End
:Else!If {A*4+{L1}+300}-3
:{{L1}+6}+1→{{L1}+6}
:Else!If {A*4+{L1}+300}-4
:sub(EXP,50+(450*(rand^8=7))+(9950*(rand^64=63))
: ElseIf {A*4+{L1}+300}=2
: {{L1}+2}+{A*4+{L1}+303}→{{L1}+2}
: If {{L1}+2}>{{L1}+3}
: {{L1}+3}→{{L1}+2}
: End
: End
:0→{A*4+{L1}+300}
: Return
:End
:Plot1{A*4+{L1}+301},{A*4+{L1}+302}+8,{A*4+{L1}+300}-1*16+Str5
:End
:End
:Return
And here's what a more advanced enemy system may look like, also ripped from the TaNF source code:
Code: :Lbl ENE
:{L1}+400→B
:For(A,0,2
:(A*8+B)→H
:If {H}=1 or ({H}=2) or ({H}=3)
:!If {H+7}
:!If {H+6}
:rand^4→{H+5}
:0→C
:{H+1}/8→F
:{H+2}/8→G
:!If {H+5}
:!If {G-1*12+F*2+θ+1}
:1→C
:End
:Else!If {H+5}-1
:!If {G*12+F+1*2+θ+1}
:1→C
:End
:Else!If {H+5}-2
:!If {G+1*12+F*2+θ+1}
:1→C
:End
:Else
:!If {G*12+F-1*2+θ+1}
:1→C
:End
:End
:If C
:8→{H+6}
:End
:Else
:!If {H+5}
:{H+2}-1→{H+2}
:Else!If {H+5}-1
:{H+1}+1→{H+1}
:Else!If {H+5}-2
:{H+2}+1→{H+2}
:Else
:{H+1}-1→{H+1}
:End
:{H+6}-1→{H+6}
:!If {H}-1
:8→{H+7}
:Else!If {H}-2
:5→{H+7}
:Else
:2→{H+7}
:End
:
:If ({{L1}+216}{^r})
:{H+7}*2→{H+7}
:End
:
:End
:Else
:{H+7}-1→{H+7}
:End
:If X≥{H+1}
:If X≤({H+1}+8)
:If Y≥{H+2}
:If Y≤({H+2}+8)
:!If {{L1}+212}
:!If {H}-1
:sub(DMG,1
:Else!If {H}-2
:sub(DMG,2
:Else
:sub(DMG,rand^2+3
:End
:End:End:End:End:End
:If {{L1}+204} or {{L1}+206}
:!If {H+4}
:sub(DEN
:End
:End
:If {H+4}
:{H+4}-1→{H+4}
:End
:If {H+4}
:If rand^2
:Plot1{H+1},{H+2}+8,({H}-1*32)+({H+6}/4*16)+Str6
:End
:Else
:Plot1{H+1},{H+2}+8,({H}-1*32)+({H+6}/4*16)+Str6
:End
:End
:
:
:
:End
:Return
:
:Lbl DEN
:0→M
:{H+3}→{{L5}}
:!If {{L1}+214}
:If {H+1}≥X and ({H+1}≤(X+8))
:If {H+2}≥(Y-16) and ({H+2}≤Y)
:1→M
:End:End
:Else!If {{L1}+214}-1
:If {H+1}≥(X+8) and ({H+1}≤(X+16))
:If {H+2}≥(Y-16) and ({H+2}≤(Y-8))
:1→M
:End:End
:Else!If {{L1}+214}-2
:If {H+1}≥(X+8) and ({H+1}≤(X+16))
:If {H+2}≥Y and ({H+2}≤(Y+8))
:1→M
:End:End
:Else!If {{L1}+214}-3
:If {H+1}≥(X+8) and ({H+1}≤(X+16))
:If {H+2}≥(Y+8) and ({H+2}≤(Y+16))
:1→M
:End:End
:Else!If {{L1}+214}-4
:If {H+1}≥X and ({H+1}≤(X+8))
:If {H+2}≥(Y+8) and ({H+2}≤(Y+16))
:1→M
:End:End
:Else!If {{L1}+214}-5
:If {H+1}≥(X-16) and ({H+1}≤(X-8))
:If {H+2}≥(Y+8) and ({H+2}≤(Y+16))
:1→M
:End:End
:Else!If {{L1}+214}-6
:If {H+1}≥(X-16) and ({H+1}≤(X-8))
:If {H+2}≥Y and ({H+2}≤(Y+8))
:1→M
:End:End
:Else
:If {H+1}≥(X-16) and ({H+1}≤(X))
:If {H+2}≥(Y-16) and ({H+2}≤(Y))
:1→M
:End:End
:End
:If M
:If S≤{H+3}:{H+3}-S→{H+3}:Else:0→{H+3}:End
:End
:!If {H+3}
:!If {H}-1
:sub(EXP,1
:Else!If {H}-2
:sub(EXP,2
:Else!If {H}-3
:sub(EXP,5
:End
:If (rand^64)=63
:4→{{L1}+300}
:{H+1}→{{L1}+301}
:{H+2}→{{L1}+302}
:Else!If rand^8-7
:!If {{L1}+300}
:1→{{L1}+300}
:{H+1}→{{L1}+301}
:{H+2}→{{L1}+302}
:{H}→{{L1}+303}
:Else!If {{L1}+304}
:1→{{L1}+304}
:{H+1}→{{L1}+305}
:{H+2}→{{L1}+306}
:{H}→{{L1}+307}
:End
:Else!If rand^8-6
:!If {{L1}+300}
:2→{{L1}+300}
:{H+1}→{{L1}+301}
:{H+2}→{{L1}+302}
:{H}→{{L1}+303}
:Else!If {{L1}+304}
:2→{{L1}+304}
:{H+1}→{{L1}+305}
:{H+2}→{{L1}+306}
:{H}→{{L1}+307}
:End
:End
:0→{H}
:End
:If {{L5}}>{H+3}
:50→{H+4}
:End
:Return