Ignore:
Timestamp:
11/03/09 03:50:41 (4 years ago)
Author:
knowknowledge
Message:

Cleaned up the TAG game

Created two global tables: swarm and it to make things more packaged.
Pulled the decision making into a set of stand alone function 'plans'.
Each ship has their own plan, and since the plans are partially state
based, each ship moves unpredictably. This plan model could be adapted
to work for much more complex

Added a Window that gives live feedback on which ship is IT.
This window reflects the rotation of the IT ship.

Unlike the earlier version, users should be able to figure out what's
going on now. Like the earlier version, the AI do not do the smart
thing and just flee, since that would be boring.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • Lua/scripts/universe.lua

    r76 r79  
    44-- Lua Global variables 
    55shipList = {}  -- The ships that Lua has access to.  TODO: This list should probably be generated at each tick from a c++ call. 
    6 frozen=0 -- Setting this to 1 causes all AI to stop 'thinking' and just drift. 
    7 ticks=0 
    86player  = Epiar.player() 
    97shipList[0] = player 
    10 it_countdown=100 
     8AIPlans = {} 
    119 
    1210function CreateShips(number_of_ships, X, Y) 
     
    2119                                ) 
    2220                table.insert(shipList, cur_ship ) 
    23         end 
    24  
     21                table.insert(AIPlans, newPlan() ) 
     22        end 
    2523        io.write("Ships Total: ", #shipList ,"\n") 
    2624end 
    2725 
    28 function SwarmAverage() 
    29         -- Find the swarm center 
    30         avg_x,avg_y = 0,0 
    31         avg_angle = 0 
    32         avg_vector= 0 
    33         avg_speed = 0 
     26-- The swarm is the net average of all non-player ships 
     27swarm = {} 
     28swarm.reset = function() 
     29        swarm.avg_x= 0 
     30        swarm.avg_y= 0 
     31        swarm.avg_angle = 0 
     32        swarm.avg_vector= 0 
     33        swarm.avg_speed = 0 
     34end 
     35swarm.findAverage = function() 
     36        local avg_x= 0 
     37        local avg_y= 0 
     38        local avg_angle = 0 
     39        local avg_vector= 0 
     40        local avg_speed = 0 
     41        -- Average the statistics of each ship 
    3442        for s =1,#shipList do 
    3543                cur_ship = shipList[s] 
     
    4452                avg_speed = avg_speed + speed 
    4553        end 
    46         avg_x = avg_x / #shipList 
    47         avg_y = avg_y / #shipList 
    48         avg_angle = avg_angle / #shipList 
    49         avg_vector = avg_vector / #shipList 
    50         avg_speed = avg_speed / #shipList 
    51     return avg_x,avg_y,avg_angle,avg_vector,avg_speed 
    52 end 
     54        swarm.avg_x = avg_x / #shipList 
     55        swarm.avg_y = avg_y / #shipList 
     56        swarm.avg_angle = avg_angle / #shipList 
     57        swarm.avg_vector = avg_vector / #shipList 
     58        swarm.avg_speed = avg_speed / #shipList 
     59end 
     60swarm.reset() 
    5361 
    5462function distfrom( pt1_x,pt1_y, pt2_x,pt2_y) 
     
    5866end 
    5967 
    60 function closestToIT() 
    61         target=-1 
    62         mindist = 100000 
    63         min_x,min_y = 10000,10000 
    64         it_x,it_y = EpiarLua.Ship.GetPosition(shipList[it]) 
     68 
     69it = {} 
     70it.ship =0 
     71it.countdown=100 
     72it.pic = EpiarLua.UI:newPicture(60,30,100,30,"terran-frigate.png") 
     73it.label = EpiarLua.UI:newLabel(90,100,"default") 
     74it.findClosest = function() 
     75        it.target=-1 
     76        it.target_dist= 100000 
     77        it.target_x,target_y= 10000,10000 
     78        it.x,it.y = EpiarLua.Ship.GetPosition(shipList[it.ship]) 
    6579 
    6680        -- Find the closest ship to whomever is IT 
    6781        for other=0, #shipList do  
    68                 if not(other == it) then 
     82                if other ~= it.ship then 
    6983                        other_x,other_y = EpiarLua.Ship.GetPosition(shipList[other]) 
    70                         dist = distfrom(other_x,other_y,it_x,it_y) 
    71                         if dist < mindist then 
    72                                 target = other 
    73                                 mindist = dist 
    74                                 min_x,min_y = other_x,other_y 
     84                        dist = distfrom(other_x,other_y,it.x,it.y) 
     85                        if dist < it.target_dist then 
     86                                it.target = other 
     87                                it.target_dist= dist 
     88                                it.target_x,it.target_y = other_x,other_y 
    7589                        end 
    7690                end 
    7791        end 
    78         return target, min_x, min_y, mindist 
     92end 
     93it.tag = function(target) 
     94        io.write("Making "..target.." IT") 
     95        if target >= #shipList then 
     96                io.write('Cannot') 
     97                return 1 
     98        end 
     99        -- the old IT now runs 
     100        AIPlans[it.ship] = {} 
     101        AIPlans[it.ship].time=20 
     102        AIPlans[it.ship].plan=aimAwayFromIT 
     103        -- The new it doesn't become active for 100 ticks 
     104        it.ship=target 
     105        it.countdown = 100 
     106        AIPlans[it.ship] = {} 
     107        AIPlans[it.ship].time=0 
     108        AIPlans[it.ship].plan=chaseClosest 
     109end 
     110 
     111-- 
     112-- AI Plans 
     113-- 
     114 
     115function chaseClosest(cur_ship,timeleft) 
     116        -- in the game of tag, this is 'it' 
     117        EpiarLua.Ship.Rotate(cur_ship,  
     118                EpiarLua.Ship.directionTowards(cur_ship, it.target_x, it.target_y) ) 
     119        EpiarLua.Ship.Accelerate(cur_ship ) 
     120end 
     121 
     122function aimCenter(cur_ship,timeleft) 
     123        -- direction towards the center or the universe 
     124        if timeleft%3 ==0 then 
     125                EpiarLua.Ship.Rotate(cur_ship, 
     126                        EpiarLua.Ship.directionTowards(cur_ship, 0,0) ) 
     127        end 
     128        EpiarLua.Ship.Accelerate(cur_ship ) 
     129end 
     130 
     131function aimTowardsIT(cur_ship,timeleft) 
     132        -- direction towards the ship that is IT 
     133        EpiarLua.Ship.Rotate(cur_ship, 
     134                EpiarLua.Ship.directionTowards(cur_ship, it.x, it.y) ) 
     135        if timeleft %2 == 0 then 
     136                EpiarLua.Ship.Accelerate(cur_ship ) 
     137        end 
     138end 
     139 
     140function aimAwayFromIT(cur_ship,timeleft) 
     141        -- direction away from the ship that is IT 
     142        EpiarLua.Ship.Rotate(cur_ship, 
     143                -EpiarLua.Ship.directionTowards(cur_ship, it.x, it.y) ) 
     144        EpiarLua.Ship.Accelerate(cur_ship ) 
     145end 
     146 
     147function aimSwarmCenter(cur_ship,timeleft) 
     148        -- direction towards the center of the swarm 
     149        if timeleft %2 == 0 then 
     150                EpiarLua.Ship.Rotate(cur_ship,  
     151                        EpiarLua.Ship.directionTowards(cur_ship, swarm.avg_x, swarm.avg_y) ) 
     152        end 
     153        EpiarLua.Ship.Accelerate(cur_ship ) 
     154end 
     155 
     156function aimSwarmDirection(cur_ship,timeleft) 
     157        -- direction away from the ship that is IT 
     158        EpiarLua.Ship.Rotate(cur_ship, 
     159                EpiarLua.Ship.directionTowards(cur_ship, swarm.avg_angle) ) 
     160        EpiarLua.Ship.Accelerate(cur_ship ) 
     161end 
     162 
     163function zigzag(cur_ship,timeleft) 
     164        -- direction away from the ship that is IT 
     165        if timeleft % 10 <=3 then 
     166                EpiarLua.Ship.Rotate(cur_ship, 1) 
     167        elseif timeleft % 10 >=7 then 
     168                EpiarLua.Ship.Rotate(cur_ship, -1) 
     169        end 
     170        EpiarLua.Ship.Accelerate(cur_ship ) 
     171end 
     172 
     173-- Generate a new plan from the list above 
     174function newPlan() 
     175        randomChoice = math.random(100) 
     176        theNewPlan = {} 
     177        theNewPlan.time = math.random(30) 
     178        if randomChoice <30 then 
     179                theNewPlan.plan=aimAwayFromIT 
     180        elseif randomChoice<40 then 
     181                theNewPlan.plan=zigzag 
     182        elseif randomChoice<75 then 
     183                theNewPlan.plan=aimSwarmCenter 
     184        elseif randomChoice<95 then 
     185                theNewPlan.plan=aimSwarmDirection 
     186        else 
     187                theNewPlan.plan=aimTowardsIT 
     188        end 
     189        return theNewPlan 
    79190end 
    80191 
     
    83194-- This function is responsible for directing all of the game AI. 
    84195function Update () 
    85         if frozen>0 then 
    86                 return 1 
    87         end 
    88  
    89  
    90         avg_x,avg_y,avg_angle,avg_vector,avg_speed = SwarmAverage() 
    91  
    92         player_x,player_y = EpiarLua.Ship.GetPosition(player) 
    93         it_x,it_y = EpiarLua.Ship.GetPosition(shipList[it]) 
    94  
    95         -- Move 
     196        -- Calculate variables 
     197        swarm.findAverage() 
     198        it.findClosest() 
     199        -- Move Non-Player ships 
    96200        for s =1, # shipList do 
    97201                cur_ship = shipList[s] 
    98                 x,y = EpiarLua.Ship.GetPosition(cur_ship) 
    99  
    100                 if s == it then -- IT 
    101                         dir_closest = EpiarLua.Ship.directionTowards(cur_ship, min_x,min_y) -- direction towards the closest target 
    102                         EpiarLua.Ship.Rotate(cur_ship, dir_closest) 
    103                 else -- Not IT 
    104                         if math.sqrt(x*x + y*y) >3000 then  
    105                                 dir_center = EpiarLua.Ship.directionTowards(cur_ship, 0,0) -- direction towards the center of the universe 
    106                                 EpiarLua.Ship.Rotate(cur_ship, dir_center) 
     202                --zigzag(cur_ship,tick) 
     203                AIPlans[s].plan( cur_ship, AIPlans[s].time ) 
     204                AIPlans[s].time = AIPlans[s].time -1 
     205                -- When the current plan is complete, pick a new plan 
     206                if AIPlans[s].time == 0 then  
     207                        AIPlans[s] = newPlan() 
     208                end 
     209        end 
     210 
     211        -- Rotate the itpic to match the ship that's it 
     212        EpiarLua.UI.rotatePicture(it.pic, EpiarLua.Ship.GetAngle(shipList[it.ship]) ) 
     213 
     214        if it.countdown==0 then 
     215                -- Show who's it 
     216                if it.ship==0 then 
     217                        EpiarLua.UI.setText(it.label,"You're IT!") 
     218                else 
     219                        EpiarLua.UI.setText(it.label,"Player "..(it.ship).." is IT!") 
     220                end 
     221                -- Is someone else it now? 
     222                if it.target_dist < 200 then  
     223                        it.tag(it.target) 
     224                end 
     225        else 
     226                it.countdown= (it.countdown)-1 
     227                -- Update the countdown only every 10th tick 
     228                if it.countdown%10==0 then 
     229                        if it.ship==0 then 
     230                                EpiarLua.UI.setText(it.label,"You're IT in: "..(it.countdown/10)) 
    107231                        else 
    108                                 if math.random(100) <10 then 
    109                                         dir_it = EpiarLua.Ship.directionTowards(cur_ship, it_x, it_y) -- direction towards the ship that is IT 
    110                                         EpiarLua.Ship.Rotate(cur_ship, dir_it) 
    111                                 elseif math.random(100) <40 then 
    112                                         dir_it = EpiarLua.Ship.directionTowards(cur_ship, it_x, it_y) -- direction away from the ship that is IT 
    113                                         EpiarLua.Ship.Rotate(cur_ship, -dir_it) 
    114                                 elseif math.random(100) <70 then 
    115                                         dir_swarm_center = EpiarLua.Ship.directionTowards(cur_ship, avg_x, avg_y) -- direction towards the center of the swarm 
    116                                         EpiarLua.Ship.Rotate(cur_ship, dir_swarm_center) 
    117                                 else 
    118                                         dir_swarm_aim = EpiarLua.Ship.directionTowards(cur_ship, avg_angle ) -- direction towards the swarm direction 
    119                                         EpiarLua.Ship.Rotate(cur_ship, dir_swarm_aim) 
    120                                 end 
     232                                EpiarLua.UI.setText(it.label,"Player "..(it.ship).." is IT in: "..(it.countdown/10)) 
    121233                        end 
    122  
    123                 end 
    124                 EpiarLua.Ship.Accelerate(cur_ship ) 
    125         end 
    126  
    127         if it_countdown==0 then 
    128                 -- Is someone else it now? 
    129                 target, min_x, min_y, mindist = closestToIT() 
    130                 if mindist < 200 then  
    131                         setIt(target) 
    132                 end 
    133         else 
    134                 it_countdown= it_countdown-1 
    135                 if it_countdown==0 then 
    136                         Epiar.echo("Let the games begin") 
    137                 elseif it_countdown%10==0 then 
    138                         Epiar.echo("Player "..it.." is counting down: "..it_countdown/10) 
    139                 end 
    140         end 
    141  
     234                end 
     235        end 
    142236end 
    143237 
    144238-- Functions to use from the console. ( Enter the console by hitting backtick. ) 
    145 -- TODO: Remove these functions, they are only interesting for debugging and even very useful then. 
    146 function stop() 
    147         frozen=1 
    148 end 
    149  
    150 function go() 
    151         frozen=0 
    152 end 
    153  
    154 function open(x,y,w,h,someString) -- Create an Arbitrary Window 
    155         EpiarLua.UI:newWindow(x,y,w,h,someString) 
    156 end 
    157239 
    158240function close() -- Close all the windows 
    159241        EpiarLua.UI:close() 
    160 end 
    161  
    162 -- Tag Functions 
    163 function setIt(target) 
    164         it=target 
    165         it_countdown = 100 
    166         if it==0 then 
    167         Epiar.echo("TAG!  You're now it!") 
    168         --pauseMessage("TAG!  You're now it!") 
    169         else 
    170         Epiar.echo("Ship "..target.." is now IT.") 
    171         --pauseMessage("Ship "..target.." is now IT.") 
    172         end 
    173 end 
    174 function whosit() 
    175         if it==0 then 
    176                 Epiar.echo("You are it") 
    177         else 
    178                 Epiar.echo("Player "..it.." is it.") 
    179         end 
    180 end 
    181 function whosClosest() 
    182         it_x,it_y = EpiarLua.Ship.GetPosition(shipList[it]) 
    183         target, min_x, min_y, mindist = closestToIT() 
    184         Epiar.echo("Closest ship to IT "..it.." at ("..it_x..","..it_y..") is ".. target.." at ("..min_x..","..min_y..") "..mindist) 
    185242end 
    186243 
     
    193250end 
    194251 
    195 function menu() -- Generate a test window 
    196         -- Create windows 
    197         menuWin = EpiarLua.UI:newWindow( 900,200,120,450,"Menu", 
    198                 EpiarLua.UI:newButton(10,40,100,30,"Pause","Epiar.pause()"), 
    199                 EpiarLua.UI:newButton(10,90,100,30,"Unpause","Epiar.unpause()"), 
    200                 EpiarLua.UI:newButton(10,140,100,30,"AI Drift","stop()"), 
    201                 EpiarLua.UI:newButton(10,190,100,30,"AI Think","go()"), 
    202                 EpiarLua.UI:newButton(10,240,100,30,"IT","setIt(0)"), 
    203                 EpiarLua.UI:newButton(10,290,100,30,"NOT IT","setIt(math.random(#shipList))") 
    204                 ) 
    205 end 
     252-- Create windows 
     253menuWin = EpiarLua.UI:newWindow( 900,200,120,250,"Menu", 
     254        EpiarLua.UI:newButton(10,40,100,30,"Pause","Epiar.pause()"), 
     255        EpiarLua.UI:newButton(10,90,100,30,"Unpause","Epiar.unpause()"), 
     256        EpiarLua.UI:newButton(10,140,100,30,"IT","it.tag(0)"), 
     257        EpiarLua.UI:newButton(10,190,100,30,"NOT IT","it.tag(math.random(#shipList))") 
     258        ) 
     259tagWin = EpiarLua.UI:newWindow( 830,450,180,130,"Who's IT?", 
     260        it.pic, 
     261        it.label 
     262        ) 
    206263         
    207264-- Create Some ships around the planets 
    208265-- TODO, Lua should create these ships based off of information found in the planets-default.xml 
    209 if 1 >0 then 
    210         CreateShips(3,345,215) 
    211         CreateShips(6,-40,-135) 
    212         CreateShips(6,4640,-735) 
    213 end 
    214 it=math.random(#shipList) 
    215 it=0 
    216  
    217  
     266CreateShips(3,345,215) 
     267CreateShips(6,-40,-135) 
     268CreateShips(6,4640,-735) 
     269 
Note: See TracChangeset for help on using the changeset viewer.