A Flash Developer Resource Site

Results 1 to 12 of 12

Thread: Complete AI Code

  1. #1
    Senior Member
    Join Date
    Apr 2001
    Posts
    190
    Hi! Great AI code! But it's not Actionscript, although the langauge is VERY similar. It's also VERY long. Tell me if you have problems with anything, and tell me what you think abotu the code.

    Let me explain a few things:

    "%" stands for mod which works like this a%b and returns the remainder of a / b. eg. 10%3 = 1

    Built for a level that is 64 by 64, but that can be changed

    the random works like this random(a,b), it returns a floating point >= a and < b.

    playerscount is the ammount of players in the room.

    onwall is like a hit detection for walls.
    the command is:
    if (onwall(x,y)) {
    blah();
    }

    "^" is equal to power
    eg. 9^.5=3

    setcharani is a command that set the characters animation. This can easily be changed to gotoAndStop("moving") or whatever.

    The properties are set up like this:
    players[index].property,the properties used in this code are id (which is either 0 or 1, if it's 0 it's a baddy, of it's 1 it's a human player), and hearts (how many hearts the player has). The properties of the NPC that has the code are simply x, y, dir (ranges from 0 to 3), ect.

    Timeout is a countdown (makes a very good loop)
    eg.
    if (playerenters) {
    timeout = 0.05;
    }
    if (timeout) {
    stuff();
    timeout = 0.05;
    }

    There are many flags there are set by the game, ie playerenters, playertouchsme, wasthrown, ect. They're pretty self explanatory.

    the message command print something above the NPCs head.

    Well.... here we go!

    Code:
    if (created) {
      // Initialize the attributes
      showcharacter;
      setcharprop #3,head735.gif;
      setcharprop #C0,orange;
      setcharprop #C1,white;
      setcharprop #C2,blue;
      setcharprop #C3,red;
      setcharprop #C4,black;
      setcharprop #2,shield1.gif;
      shieldpower = 1;
      dir = 2;
      swordpower = 1;
      hurtdx = 0;
      hurtdy = 0;
      hearts = 3;
    }
    if (playerenters || wasthrown) {
      // Initialize the this. variables
      message;
      this.huntspeed = 0.5;
      dirgo = {0,-1,-1,0,0,1,1,0};
      timeout = 0.05;
      this.walkmode = 1;
      if (wasthrown && this.walkmode>1) this.walkmode = 1;
      this.x1 = 0;
      this.x2 = 63;
      this.y1 = 0;
      this.y2 = 63;
      this.speed = 0.4;
      if (hearts<=0) {
        this.mode = 5; // RESPAWN
        this.runcounter = 0;
        timeout = 5;
      } else {
        this.mode = 0;
        setcharani idle,;
        this.runcounter = int(random(10,40));
      }
    }
    
    // Walking stuff
    if (timeout && this.mode==0) { // WALKING
      setcharani walk,;
      newx = x + dirgo[dir*2] * this.speed;
      newy = y + dirgo[dir*2+1] * this.speed;
      this.runcounter--;
      if (this.walkmode==1) { // RANDOM
        if (this.runcounter>0) {
          testx = newx + 1.5 + dirgo[dir*2];
          testy = newy + 2+ dirgo[dir*2+1];
          if (onwall(testx,testy)) {
            dir = (dir+2)%4;
            this.runcounter = int(random(0,60));
          } else {
            x = newx;
            y = newy;
          }
        } else {
          this.runcounter = int(random(10,40));
          dir = (dir+1+int(random(0,2))*2)%4;
        }
      } else if (this.walkmode==2) { // LEFTRIGHT
        if (dir!=1 && dir!=3) dir = 3;
        else {
          x = newx;
          y = newy;
          if ((dir==1 && x<=this.x1) || (dir==3 && x>=this.x2))
            dir = (dir+2)%4;
        }
      } else if (this.walkmode==3) { // UPDOWN
        if (dir!=0 && dir!=2) dir = 2;
        else {
          x = newx;
          y = newy;
          if ((dir==0 && y<=this.y1) || (dir==2 && y>=this.y2))
            dir = (dir+2)%4;
        }
      } else if (this.walkmode==4) { // RECTANGLE
        x = newx;
        y = newy;
        if ((dir==0 && y<=this.y1) || (dir==1 && x<=this.x1) ||
            (dir==2 && y>=this.y2) || (dir==3 && x>=this.x2))
          dir = (dir+3)%4;
      }
      if (this.walkmode>1 && this.runcounter<=0)
        this.runcounter = 20;
      message;
      timeout = 0.05;
    }
    
    // Sword attacking stuff
    if (timeout && (this.mode==0 || this.mode==2)) {
      // Look for players
      mindist = 1000;
      for (index=0; index<playerscount; index++)
          if (players[index].hearts>0 && players[index].id>=0) {
        dx = players[index].x - x;
        dy = players[index].y - y;
        if (abs(dx)>abs(dy)) {
          if (dx>0) pdir=3; else pdir=1;
        } else {
          if (dy>0) pdir=2; else pdir=0;
        }
        if (pdir==dir) {
          dist = (dx*dx+dy*dy)^0.5;
          if (dist<mindist) {
            cansee = 1;
            if (abs(dx)>abs(dy)) k = int(abs(dx));
            else k = int(abs(dy));
            for (j=0; j<=k-2; j++)
              if (onwall(x+1.5+dx*j/k,y+2+dy*j/k)) cansee = 0;
            if (cansee!=0) {
              mindist = dist;
              aimplayer = index;
              this.aimx = players[index].x;
              this.aimy = players[index].y;
            }
          }
        }
      }
      if (mindist<=3) {
        this.runcounter = -1;
        this.mode = 3; // SLAYING
        setcharani sword,;
        timeout = 0.05;
      } else if (mindist<20) {
        if (this.mode!=2) message Stop!;
        this.runcounter = 100;
        this.mode = 2; // HUNTING
      } else timeout = 0.05;
    }
    if (timeout && this.mode==3) { // SLAYING
      this.runcounter++;
      if (this.runcounter>4) {
        this.runcounter = 100;
        this.mode = 2; // HUNTING
        setcharani idle,;
      }
      message;
      timeout = 0.05;
    }
    if (timeout && this.mode==2) { // HUNTING
      setcharani walk,;
      this.runcounter--;
      if (this.runcounter>0 && aimplayer<playerscount && players[aimplayer].hearts>0) {
        // Get new direction
        dx = players[aimplayer].x-x;
        dy = players[aimplayer].y-y;
        if (abs(dx)>abs(dy)) {
          if (dx>0) dir=3; else dir=1;
        } else {
          if (dy>0) dir=2; else dir=0;
        }
    
        // Test if we can do a step
        dx = this.aimx-x;
        dy = this.aimy-y;
        if (abs(dx)<=1 && abs(dy)<=1) {
          this.aimx = players[aimplayer].x;;
          this.aimy = players[aimplayer].y;
          dx = this.aimx-x;
          dy = this.aimy-y;
        }
        if (abs(dx)>abs(dy)) {
          if (dx>0) testdir=3; else testdir=1;
        } else {
          if (dy>0) testdir=2; else testdir=0;
        }
        len = (dx*dx+dy*dy)^0.5;
        addx = (dx/len)*this.huntspeed;
        addy = (dy/len)*this.huntspeed;
        testx = x + 1.5;
        testy = y + 2;
        if (!onwall(testx+addx,testy+addy)) {
          // Do a step
          x += addx;
          y += addy;
       } else if (!onwall(testx+addx,testy)) x += addx;
       else if (!onwall(testx,testy+addy)) y += addy;
      } else {
        this.mode = 0; // WALKING
        this.walkmode = 1; // RANDOM
        this.runcounter = int(random(10,40));
        setcharani idle,;
        dir = (dir+2)%4;
        message;
      }
      timeout = 0.05;
    }
    
    // Hurting stuff
    if (wa**** && this.mode!=1 && hearts>0) {
      dx = x-playerx;
      dy = y-playery;
      len = (dx*dx+dy*dy)^0.5;
      hurtdx = dx/len;
      hurtdy = dy/len;
      setcharani hurt,;
      hideimg 1;
      hearts -= playerswordpower/2;
    }
    if ((hurtdx!=0 || hurtdy!=0) && isleader && this.mode!=4) {
      this.hurtdx = hurtdx;
      this.hurtdy = hurtdy;
      hurtdx = 0;
      hurtdy = 0;
      this.mode = 1; // HURTED
      this.runcounter = 20;
      setcharani hurt,;
      if (hearts<=0) {
        this.mode = 4; // DYING
        this.runcounter = 24;
        setcharani dead,;
      }
      timeout = 0.05;
    }
    if (timeout && this.mode==1) { // HURTED
      this.runcounter--;
      if (this.runcounter>10) {
        testx = x + 1.5 + this.hurtdx*2;
        testy = y + 2+ this.hurtdy*2;
        if (!onwall(testx,testy)) {
          x += this.hurtdx;
          y += this.hurtdy;
        }
      }
      if (this.runcounter<=0) {
        if (swordpower>0) this.mode = 2; // HUNTING
        else this.mode = 0; // WALKING
        this.runcounter = 100;
        setcharani idle,;
      }
      timeout = 0.05;
    }
    if (timeout && this.mode==4) { // DYING
      if (this.runcounter>0) {
        message;
        if ((this.runcounter%2)==0) dir = (dir+3)%4;
        this.runcounter--;
        if (this.runcounter<=0) {
          gift = random(0,100);
          if (gift<10) lay greenrupee;
          else if (gift<15) lay bluerupee;
          else if (gift<30) lay heart;
        } else timeout = 0.05;
      }
    }
    Hope you liked it,
    Somar
    [Edited by Somar on 06-12-2001 at 06:13 PM]

  2. #2
    Senior Member Mad-Sci's Avatar
    Join Date
    Mar 2000
    Posts
    2,756
    Can you give us the bare bones the idea behind

    this reminds me the movie " Analyse This " with R.DeNiro

    " Enlish, English..." ha ha haha I love that movie..

    mad_sci

  3. #3
    Senior Member
    Join Date
    Jul 2000
    Posts
    198
    Thats some nice code... did you make that yourself?

  4. #4
    Senior Member Mad-Sci's Avatar
    Join Date
    Mar 2000
    Posts
    2,756
    If I get this correctly the basic walk code is hit-turn based. Basicaly the guys keeps walking till it hits something then turns. Is that correct ?

    mad_sci

  5. #5
    Senior Member
    Join Date
    Apr 2001
    Posts
    190
    Booya Climber: Someone made a very simple code, so i just used the same vars, and hugely expanded it =]

    Mad-Sci: Well there are a bunch of modes

    stand complete still (not used)
    moving (has 3 sub modes)
    attacking
    getting hurt
    dying

    the mode starts walking. While walking, it'll do a random to find out whether it's moving up and down, left and right or in a rectangle. Mean while, a counter (the var is runcounter) is random composed, it then begisn to counbt downset. When it hits 0 a random new walking method is selected. The NPC also checks the x's and y's of all the players in the room, if the hero gets in the site of the NPC, and the hero is not behind a wall, the attacking mode is initiated. The NPC will follow the hero, and if it gets close enough, will attack, and possibly, kill >=].If the hero hits the NPC, the getting hurt mode is activated, but before the animation of getting hurt, it checks to see if the NPC's hearts are <=0. If they are, the dying animation is instituted.

    I'll convert it to actionscript soon.

  6. #6
    Senior Member Mad-Sci's Avatar
    Join Date
    Mar 2000
    Posts
    2,756
    Im interested in moving thing in a maze. Solving a maze is very cool exersise. here is what I came up with.

    1. check wich directions are available for moving.

    Pseudo code:

    if ( Im currantly going up ){
    if ( hero_x < my_x and I can move left){ move left}else
    if ( hero_x > my_x and I can move right){ move right)else
    if ( I can move left){ move left}else
    if ( I can move right){ move right}}else

    if ( Im currantly goin down){ etc..etc.. for all 4 dirs.

    now I have one variable dir wich is 1=up,-1=down,2=right,-2=left. each time I change dir I change one var..

    http://members.nbci.com/savco/tutorials/mazeAI.swf

    now it looks like the red_buddy chooses strange way of finding the green ball it eventually will..just stay on one place.

    mad_sci


  7. #7
    Senior Member
    Join Date
    Apr 2001
    Posts
    190
    Well one of your problems, that you probably haven't enountered is if the AI is lower and far to the right then
    and it can go up and left. Since "I am currently going up" flag is first, he will ALWAYS turn left and never up, in this perdicament. Plus your AI, started to follow me after a while! Accept when it had the choice to go down or left, down and to the left of it, it went down, instead of left, which was closer. but fear not! I have THE most amazing code for detecting direction, (scripted by me of course) MUAHAHA! I'll post it when i get back from school.

    now I have one variable dir wich is 1=up,-1=down,2=right,-2=left. each time I change dir I change one var..
    I don't quite understand what those vars correspond to.


    IMO, theres no point in the else if's, since it's either on one side or the other, you could you simply use an else.

    You might want to impliment this too:

    //inizialize
    // Find a random number above .3
    while (counter<.3) {
    counter = random();
    }
    counter*=50;

    if (counter>0) {
    if ( hero._x < my_x and Icanmoveleft = true) {
    moveleft();
    }
    ...
    } else {
    changedir();
    while (counter<.3) {
    counter = random();
    }
    counter*=50;
    }
    ...
    counter--;

  8. #8
    Senior Member
    Join Date
    Apr 2001
    Posts
    190

    Here it is!

    There are two ways of finding the direction superbly. These codes is 100% mine, and i converted it to ActionScript
    just for you ;] Just paste either one inside of your AI MC.

    This is the ABS one:

    Code:
    if (Math.abs(Math.abs((_root.hero._y)-(y))) < Math.abs(Math.abs((_root.hero._x)-(_x)))){
      if ((_root.hero._x)<(_x)){
        dir = 1;
      }
      if ((hero._x)>=(_x)){
        dir = 3;
      }
    }
    if (Math.abs(Math.abs((_root.hero._y)-(_y))) >= Math.abs(Math.abs((_root.hero._x)-(_x)))){
      if ((_root.hero._y)<(_y)){
        dir = 0;
      }
      if ((_root.hero._y)>=(_y)){
         dir = 2;
      }
    }
    And this is the trigonometerical one (I programmed it to work with any number of directions, as long as they all have equal angle (4 directions has 90 degrees while 3 directions has 120 degrees) works with any number of directions):
    Code:
    dir = 4; //number of directions
    dir = 360 / dir;
    dx = _root.hero._x-_x;
    dy = _root.hero._y-_y;
    distance = Math.sqrt(dx*dx+dy*dy);
    movex = dx/distance;
    movey = dy/distance;
    if (_root.hero._x<_x) {
      if (_root.hero._y<_y) {		
        angle = Math.asin(movex);
        angle = 180/Math.PI*angle;
        angle += 360;
      }
      if (_root.hero._y>_y) {
        angle = Math.acos(movey);
        angle = 180/Math.PI*angle;
        angle += 180;
      }
    }
    if (_root.hero._x>_x) {
      if (_root._ymouse<_y) {
        angle = Math.asin(movex);
        angle = 180/Math.PI*angle;
      }
      if (_root.hero._y>_y) {
        angle = Math.acos(movex);
        angle = 180/Math.PI*angle;
        angle += 90;
      }
    }
    side = int(angle/dir)+1;
    Hope this helps too,
    Somar

  9. #9
    Senior Member Mad-Sci's Avatar
    Join Date
    Mar 2000
    Posts
    2,756
    Ok been there, check this out:

    http://members.nbci.com/savco/games/snake/snake2.swf

    now lets put this in the maze situation. See in your code you will force the baddie to go towards the hero, but this is not always the optimal way. Sometimes going away from the hero if preferable then strait to it for example if you want to go arround a wall.. how do you deal with it ? A+ algorithm for example will explore all posible nodes for their fitness.

    Otherwise the code is perfect..
    mad_sci

  10. #10
    Senior Member
    Join Date
    Apr 2001
    Posts
    190
    I don't know algorithm, but I do know that that snake game, doesn't use it, and if it does it shouldn't have, and I also know that it's very proccessor intensive.

    BTW do you like my direction scripts?

  11. #11
    Senior Member Mad-Sci's Avatar
    Join Date
    Mar 2000
    Posts
    2,756
    Yes of course. You have working examples BTW..I want to see it in action.

    mad_sci

  12. #12
    Senior Member
    Join Date
    Apr 2001
    Posts
    190

    A few things

    This AI script is NOT for a tile-based world, The AI should be able to move around freely, unless of course it hits a wall or tree or what not.

    A working example of directional movement using trigonmeterical formula can be found here (It's Sidra, I'm not sure if you've seen the beta yet =\)

    And i I said I don't know alogrithm, lol, I meant I don't know A+ Alogrithm, what is it? Just an advanced alogrithm?

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  




Click Here to Expand Forum to Full Width

HTML5 Development Center