Problem with monster AI
BlitzMax Forums/BlitzMax Programming/Problem with monster AI
| ||
| Hello my friends, I am creating the monster artificial intelligence functions and I have a little problem. I have my monsters moving in the dungeons and I try to make them collide with each other. What I mean , when some monster crawls in the dungeon , collides with the environment (Walls , doors , etc..) but when it arrives in square with other monster I want to change direction and never one square occupies 2 or monsters. (Monster overlapping). The type of the monster is:
Type My_Monster
Field X:Byte 'position X on the map
Field Y:Byte 'position Y on the map
Field Direction:Byte 'The direction the monster goes
Field Graphic:String 'the graphic of the monster "01"=Skeleton
Field State:Byte '1=Walk 2=Attack 3=Guard 4=Patrol
Field Square_Transition_frame:Int
Field Walking:Byte 'If the monster is walking
Field Attacking:Byte
Field Attack_animation:Byte
Field Frame:Byte 'Animation frame
.
.
.
End Type
Global Monster:My_Monster[max_levels + 1, Max_Monsters + 1]
For LVL = 1 To Max_Levels
For All_Monsters = 0 To Max_Monsters
Monster[LVL, All_Monsters] = New My_Monster
Next
Next
The monster when it moves change squares smoothly. There is a variable with name Square_Transition_frame. This square_Transition_frame variable takes values from -2 to 2 The monster when it enters in the square have an animation sequence and move its sprite: When it goes NORTH it moves from square_Transition_frame -2 then -1 and then finally 0. At the square_Transition_frame 0 the monster is at the absolute center position of the square. If the monster continue go to the NORTH then the monster will go from the square_Transition_frame 0 to 1 until arrives at the square_Transition_frame 2 after then the square_Transition_frame becomes -2 again and the monster changes its position y on the map. The opposite happens when the monster goes SOUTH the square_Transition_frame increases its value from -2 to -1 to 0. At the 0 the monster is at the center of the square. If it continue going SOUTH the square_Transition_frame becomes -1 to -2 and finally becomes 2 again and the monster increases ins y position on the map. The same happens when the monster goes WEST or EAST. In few words the 0 is the center position of the square and -2 -1 0 1 2 are 5 smooth animation transitions for the monster. The monster always before decide which direction will go , must arrive in square_Transition_frame =0 and then checks the AI if there are obstacles around like doors , statues or even other monsters. Everything are ok when I check non movable things , but when I am checking if there is another monster I have problem. I tried to check if the monster+1 and monster-1 is at the same position but it doesn't seems to work. I use this
For All_Monsters = 1 To Max_Monsters
If Monster[Party.Level, All_Monsters].X > 0 And Monster[Party.Level, All_Monsters].Y > 0 Then
'Check the previous monster
If Monster[Party.Level, All_Monsters].X = Monster[Party.Level, All_Monsters - 1].X And Monster[Party.Level, All_Monsters].Y - 1 = Monster[Party.Level, All_Monsters - 1].Y Then
'Stop this monster
Monster[Party.Level, All_Monsters].Walking = 0
'Stop and the previous monster
Monster[Party.Level, All_Monsters - 1].Walking = 0
Monster[Party.Level, All_Monsters].Deadline_time = Current_time + Monster[Party.Level, All_Monsters].Time_Delay
Monster[Party.Level, All_Monsters].Go_Direction = Rnd(1, 3)
If Monster[Party.Level, All_Monsters].Go_Direction = 1 Then Monster[Party.Level, All_Monsters].Direction = 2 Continue
If Monster[Party.Level, All_Monsters].Go_Direction = 2 Then Monster[Party.Level, All_Monsters].Direction = 3 Continue
If Monster[Party.Level, All_Monsters].Go_Direction = 3 Then Monster[Party.Level, All_Monsters].Direction = 4 Continue
'Check the next monster
If Monster[Party.Level, All_Monsters].X = Monster[Party.Level, All_Monsters + 1].X And Monster[Party.Level, All_Monsters].Y - 1 = Monster[Party.Level, All_Monsters + 1].Y Then
'Stop this monster
Monster[Party.Level, All_Monsters].Walking = 0
'Stop and the previous monster
Monster[Party.Level, All_Monsters + 1].Walking = 0
Monster[Party.Level, All_Monsters].Deadline_time = Current_time + Monster[Party.Level, All_Monsters].Time_Delay
Monster[Party.Level, All_Monsters].Go_Direction = Rnd(1, 3)
If Monster[Party.Level, All_Monsters].Go_Direction = 1 Then Monster[Party.Level, All_Monsters].Direction = 2 Continue
If Monster[Party.Level, All_Monsters].Go_Direction = 2 Then Monster[Party.Level, All_Monsters].Direction = 3 Continue
If Monster[Party.Level, All_Monsters].Go_Direction = 3 Then Monster[Party.Level, All_Monsters].Direction = 4 Continue
EndIf
Next
The quick code above tells to check if the all_monsters-1 and all_monsters+1 will going to have equal positions with all_monsters It doesn't seems to work. The only thing I try to do , when the monster see if there is other monster in front (Depends which direction the monster travels) will change direction and the other monster will change direction to. If monster goes NORTH check Y-1 and goes other random direction except NORTH If monster goes SOUTH check Y+1 and goes other random direction except SOUTH If monster goes WEST check X-1 and goes other random direction except WEST If monster goes EAST check X+1 and goes other random direction except EAST |
| ||
| Theres a lot of (poorly) formatted text to read there but I think I know what the problem is. The underlying method you are using should be fine - and probably is working under the hood but just looks wrong visually. The common problem with a method like this is that even though the monsters are in different cells their visual representation may overlap because the collision check is between two points while visually the monster takes up an area. The solution is to provide a radial checking distance for each monster which it uses when checking the grid cells instead. It gets complex when you introduce monsters that are larger than a grid cell however. I hope that adds some light. |
| ||
| Theres a lot of (poorly) formatted text to read there but I think I know what the problem is. It seems the code tag wasn't activated and the text code wasn't appear well :) Better now? The common problem with a method like this is that even though the monsters are in different cells their visual representation may overlap because the collision check is between two points while visually the monster takes up an area. Yes my monsters moves in squares and each monster see what it have in front of it. But when both monsters look at the counter direction , then both monsters will look or land in square which don't have monster so my collision believes there is no monster and then the monsters will overlap each other. (checking a monster -1 and monster +1 doesn't help much). The collision works with monster and static object. Click here! to downlaod game demo to see how the monsters overlapping The solution is to provide a radial checking distance for each monster which it uses when checking the grid cells instead. My game moves in squares so I don't know if radial checking will help because if I check in a radius of distance between squares , I have and other obstacles , like the walls or the environment , which need the monster to check too , not the other monster , but if there is any closed door or any them moving or static object. (Spells , decoration). I use a similarity of distance checking (Look the square in front) Example: if Monsters[Party.level,All_monsters].y-1 = Monsters[Party.level,All_monsters-1].y If the current monster in all_monsters loop position Y - 1 is equal with the Y of the all_monsters - 1 loop count.(The previous one) and loop +1 for the next one. This method is buggy when I want to turn my monster and if the space is small , for example narrow corridors or a lots of monsters coalition. in small rooms , if for example one small room with for squares have 3 monsters , the monsters when they try to turn or check all of those other monsters they will loose their collision and will continue to walk and then overlap. If you can translate your idea with code? It gets complex when you introduce monsters that are larger than a grid cell however. There is no problem here , none of my monsters are larger than a grid cell , all monsters occupies only one cell (Square) everything fits in one square no larger. So present your idea you are welcome. |
| ||
| Im not at a pc at the moment (on holidays by the beach) - but im sure there is something similar in the code archives....I seem to remember an entry with keywords "shifted grid collisions". Re radial distance - I was implying use it in conjunction with the grid. |
| ||
I found one nice code which calculate the distance between to points.Function Monster_Distance:Int(x0:Int, y0:Int, x1:Int, y1:Int) Local dx:Int = x0 - x1 Local dy:Int = y0 - y1 Return Sqr(dx * dx + dy * dy) End Function Global m_dist_previous:Byte[101] Global m_dist_next:Byte[101] for all_monsters=1 to 100 m_dist_previous[All_Monsters]= Monster_Distance(Monster[Party.Level, All_Monsters].X, Monster[Party.Level, All_Monsters].Y, Monster[Party.Level, All_Monsters - 1].X, Monster[Party.Level, All_Monsters - 1].Y) m_dist_next[All_Monsters]= Monster_Distance(Monster[Party.Level, All_Monsters].X, Monster[Party.Level, All_Monsters].Y, Monster[Party.Level, All_Monsters + 1].X, Monster[Party.Level, All_Monsters + 1].Y) next This code calculates the distance in squares between my next and previous but I don't know exactly how to calculate the next and previous. This is an illustration. I am near to the solution |
| ||
| I am very near. The monsters stops when the distance between monsters is 1 But the problem is they remain stopped because when 2 monsters are near to each other they have always the distance 1 and the monster remains stopped. So it needs to check if there is another monster in front of the monster regardless the collision. My previous function. |
| ||
| After I made a lots of test and I recreated my whole AI code more than 7 times , then it still doesn't work. When 2 monsters simultaneously try to take advance in the same square , the monster overlaps each other again. The distance code doesn't help much. If you have some idea how to avoid each monster arrive in the same X and Y position. Before each monster arrive in the next square , there is a smooth transition , I described it in the first post. But when 2 or more monsters are in transition progress from 4 different directions they are going to occupy the same square again. I thought ,not use smooth transition between monster moves , but then the monster will move convulsive or skip frames between squares , like to move a piece on chess. In worst case if I will not achieve it , I will use the convulsive monster movement like chess. If you have some idea , I will describe you what I want to do exactly. |
| ||
| If you have tried several different ways and still no joy, then I would suggest putting the code you are working on 'to bed' - and do a brand new simple project just to get this issue sorted. So, taking that approach you can throw away all complex code and focus on the problem: * square tile based map * tiles (an int)are either free (floor)(0) or not free (wall, door)(1) * monsters that man move on the map (this is a list or array?) draw it to screen Assuming the monster are an array of 10 and are at unique map positions that are free - their starting positions draw them (in a different colour) to the map * get a primitive ai working that treat anything above 0 at a wall and get them to move **** avoidance **** * in the monster update (the move routine) a monster will either be on a tile, or on 2 tiles - so reflect this in your map. make the tile(or tiles) 2 * as we now have the map updated, when you move the monster it will leave a trail where other monster can go (because the map is above 0 - it will also block the source monster too) * so when you update each monster - remove the previous 2 (or 2 2s) from the map Not sure if i'm clear here? But give it a go |
| ||
| I made one prototype and it seems worked. Whole code of the prototype all monsters are moving and none of them overlap. AdamStrange you gave me a good idea and I changed whole monster AI functions and it worked. The code:
SuperStrict
'Eye of the Beholder IV - monster AI prototype
Import brl.bank
Import pub.zlib
Import brl.filesystem
Import brl.standardio
Import brl.bankstream
Import brl.filesystem
Import BRL.Retro
Import klepto.klpacker
Import maxgui.drivers
Import brl.Audio
Import brl.Map
Import brl.FreeTypeFont
Import brl.PNGLoader
Import brl.timer
Import brl.eventqueue
Import brl.textstream
Import brl.oggloader
Import brl.wavloader
Import brl.jpgloader
Import brl.bmploader
Import brl.stream
Global map_grid:TImage
Global spider_icon_n:TImage
Global spider_icon_s:TImage
Global spider_icon_w:TImage
Global spider_icon_e:TImage
Global ghost_icon_n:TImage
Global ghost_icon_s:TImage
Global ghost_icon_w:TImage
Global ghost_icon_e:TImage
Global locked_square:TImage
Global Current_time:Int
Global Game_Loaded:Byte
Const Max_Monsters:Byte = 100
Const Max_Levels:Byte = 51 '(+1 for developer mechanics)
Global All_Monsters:Byte
Global LVL:Byte
'Global Monster_Table:Byte[52, 39, 38]
Global Monster_Table:Int[52, 21, 21]
Global MTable_x:Int
Global MTable_y:Int
Type My_Monster
Field X:Byte 'position X on the map
Field Y:Byte 'position Y on the map
Field Direction:Byte 'The direction the monster goes
Field Graphic:String 'the graphic of the monster "01"=Skeleton
Field State:Byte '1=Walk 2=Attack 3=Guard 4=Patrol
Field Walking:Byte
Field Square_transition_frame:Int
Field Deadline_time:Int 'Timer Delay
Field Time_delay:Int 'animation speed
Field Not_Allow_to_move:Byte
Field square_locked:Byte
Field Choose_Direction:Byte
Field Steps:Byte
End Type
Global Monster:My_Monster[max_levels + 1, Max_Monsters + 1]
For LVL = 1 To Max_Levels
For All_Monsters = 0 To Max_Monsters
Monster[LVL, All_Monsters] = New My_Monster
Next
Next
Type My_Party
Field x:Byte
Field y:Byte
Field Level:Byte
Field Level_temp:Byte
Field Direction:Byte
Field Mana_Points:Float
Field Max_Mana_Points:Float
Field Mana_Percentage:Float
Field Collision:Byte
Field Immobilized:Byte
Field Dest_Level:Byte
EndType
Global Party:My_Party = New My_Party
'Windowed ======================
'Global graph:TGraphics = Graphics(640, 480, 0, 120)
'Full
Global graph:TGraphics = Graphics(640, 480, 32, 120, 0)
SetMaskColor(255, 0, 255)
'SetBlend(MASKBLEND)
SetBlend(ALPHABLEND | MASKBLEND)
Load_Data()
While Not AppTerminate()
Current_time = MilliSecs()
If Game_Loaded = 0 Then Load_Data()
Draw_Interface()
If KeyHit(KEY_ESCAPE) Then Ending()
Flip -1
'Windows 8 - Flip 1
Wend
Function Ending()
End
End Function
Function Draw_Interface()
Monster_Mechanics()
Draw_Game()
Keyboard_commands()
DrawText "Current Time:" + String(Current_time), 350, 10
DrawText "M1 Deadline time:" + String(Monster[1, 1].Deadline_time), 350, 20
DrawText "M1 X:" + String(Monster[1, 1].X), 350, 40
DrawText "M1 Y:" + String(Monster[1, 1].Y), 350, 50
DrawText "M1 STF:" + String(Monster[1, 1].Square_transition_frame), 350, 60
DrawText "M1 Walking:" + String(Monster[1, 1].Walking), 350, 70
End Function
Function Load_Data()
'skel_icon = LoadImage("skel_icon.png", MASKEDIMAGE)
ghost_icon_n = LoadImage("ghost_icon_n.png", MASKEDIMAGE)
ghost_icon_s = LoadImage("ghost_icon_s.png", MASKEDIMAGE)
ghost_icon_w = LoadImage("ghost_icon_w.png", MASKEDIMAGE)
ghost_icon_e = LoadImage("ghost_icon_e.png", MASKEDIMAGE)
spider_icon_n = LoadImage("spider_icon_n.png", MASKEDIMAGE)
spider_icon_s = LoadImage("spider_icon_s.png", MASKEDIMAGE)
spider_icon_w = LoadImage("spider_icon_w.png", MASKEDIMAGE)
spider_icon_e = LoadImage("spider_icon_e.png", MASKEDIMAGE)
locked_square = LoadImage("locked_square.png", MASKEDIMAGE)
map_grid = LoadImage("Map_grid.png", MASKEDIMAGE)
Inits()
'Delay(2000)
Game_Loaded = 1
End Function
Function Monster_Mechanics()
For All_Monsters = 1 To Max_Monsters
If Monster[Party.Level, All_Monsters].Direction = 1 Then
If Monster[Party.Level, All_Monsters].Square_transition_frame = 0 Then
Monster_Table[Party.Level, Monster[Party.Level, All_Monsters].X, Monster[Party.Level, All_Monsters].Y + 1] = 0
Monster_Table[Party.Level, Monster[Party.Level, All_Monsters].X, Monster[Party.Level, All_Monsters].Y] = 1
Monster[Party.Level, All_Monsters].Not_Allow_to_move = 1
'Monster[Party.Level, All_Monsters].square_locked = 0
End If
If Monster[Party.Level, All_Monsters].Square_transition_frame > 0 Then
Monster_Table[Party.Level, Monster[Party.Level, All_Monsters].X, Monster[Party.Level, All_Monsters].Y] = 2
Monster_Table[Party.Level, Monster[Party.Level, All_Monsters].X, Monster[Party.Level, All_Monsters].Y - 1] = 2
Monster[Party.Level, All_Monsters].Not_Allow_to_move = 0
End If
EndIf
If Monster[Party.Level, All_Monsters].Direction = 2 Then
If Monster[Party.Level, All_Monsters].Square_transition_frame = 0 Then
Monster_Table[Party.Level, Monster[Party.Level, All_Monsters].X, Monster[Party.Level, All_Monsters].Y - 1] = 0
Monster_Table[Party.Level, Monster[Party.Level, All_Monsters].X, Monster[Party.Level, All_Monsters].Y] = 1
Monster[Party.Level, All_Monsters].Not_Allow_to_move = 1
'Monster[Party.Level, All_Monsters].square_locked = 0
End If
If Monster[Party.Level, All_Monsters].Square_transition_frame > 0 Then
Monster_Table[Party.Level, Monster[Party.Level, All_Monsters].X, Monster[Party.Level, All_Monsters].Y] = 2
Monster_Table[Party.Level, Monster[Party.Level, All_Monsters].X, Monster[Party.Level, All_Monsters].Y + 1] = 2
Monster[Party.Level, All_Monsters].Not_Allow_to_move = 0
End If
EndIf
If Monster[Party.Level, All_Monsters].Direction = 3 Then
If Monster[Party.Level, All_Monsters].Square_transition_frame = 0 Then
Monster_Table[Party.Level, Monster[Party.Level, All_Monsters].X + 1, Monster[Party.Level, All_Monsters].Y] = 0
Monster_Table[Party.Level, Monster[Party.Level, All_Monsters].X, Monster[Party.Level, All_Monsters].Y] = 1
Monster[Party.Level, All_Monsters].Not_Allow_to_move = 1
'Monster[Party.Level, All_Monsters].square_locked = 0
End If
If Monster[Party.Level, All_Monsters].Square_transition_frame > 0 Then
Monster_Table[Party.Level, Monster[Party.Level, All_Monsters].X, Monster[Party.Level, All_Monsters].Y] = 2
Monster_Table[Party.Level, Monster[Party.Level, All_Monsters].X - 1, Monster[Party.Level, All_Monsters].Y] = 2
Monster[Party.Level, All_Monsters].Not_Allow_to_move = 0
End If
EndIf
If Monster[Party.Level, All_Monsters].Direction = 4 Then
If Monster[Party.Level, All_Monsters].Square_transition_frame = 0 Then
Monster_Table[Party.Level, Monster[Party.Level, All_Monsters].X - 1, Monster[Party.Level, All_Monsters].Y] = 0
Monster_Table[Party.Level, Monster[Party.Level, All_Monsters].X, Monster[Party.Level, All_Monsters].Y] = 1
Monster[Party.Level, All_Monsters].Not_Allow_to_move = 1
'Monster[Party.Level, All_Monsters].square_locked = 0
End If
If Monster[Party.Level, All_Monsters].Square_transition_frame > 0 Then
Monster_Table[Party.Level, Monster[Party.Level, All_Monsters].X, Monster[Party.Level, All_Monsters].Y] = 2
Monster_Table[Party.Level, Monster[Party.Level, All_Monsters].X + 1, Monster[Party.Level, All_Monsters].Y] = 2
Monster[Party.Level, All_Monsters].Not_Allow_to_move = 0
End If
EndIf
If Current_time >= Monster[Party.Level, All_Monsters].Deadline_time Then
Monster[Party.Level, All_Monsters].Time_Delay = 500
Monster[Party.Level, All_Monsters].Deadline_time = Current_time + Monster[Party.Level, All_Monsters].Time_Delay
If Monster[Party.Level, All_Monsters].X = 0 And Monster[Party.Level, All_Monsters].Y = 0 Then Continue
If Monster[Party.Level, All_Monsters].X > 0 And Monster[Party.Level, All_Monsters].Y > 0 Then
If Monster[Party.Level, All_Monsters].Square_transition_frame = 0 Then
Monster[Party.Level, All_Monsters].Steps:+1
If Monster[Party.Level, All_Monsters].Steps > Rand(5, 9) Then
Monster[Party.Level, All_Monsters].Steps = 0
If Monster[Party.Level, All_Monsters].Walking = 0 Then Monster[Party.Level, All_Monsters].Walking = 1
If Monster[Party.Level, All_Monsters].Direction = 1
Monster[Party.Level, All_Monsters].choose_direction = Rand(1, 2)
If Monster[Party.Level, All_Monsters].choose_direction = 1 Then Monster[Party.Level, All_Monsters].Direction = 3 Return
If Monster[Party.Level, All_Monsters].choose_direction = 2 Then Monster[Party.Level, All_Monsters].Direction = 4 Return
EndIf
If Monster[Party.Level, All_Monsters].Direction = 2
Monster[Party.Level, All_Monsters].choose_direction = Rand(1, 2)
If Monster[Party.Level, All_Monsters].choose_direction = 1 Then Monster[Party.Level, All_Monsters].Direction = 4 Return
If Monster[Party.Level, All_Monsters].choose_direction = 2 Then Monster[Party.Level, All_Monsters].Direction = 3 Return
EndIf
If Monster[Party.Level, All_Monsters].Direction = 3
Monster[Party.Level, All_Monsters].choose_direction = Rand(1, 2)
If Monster[Party.Level, All_Monsters].choose_direction = 1 Then Monster[Party.Level, All_Monsters].Direction = 1 Return
If Monster[Party.Level, All_Monsters].choose_direction = 2 Then Monster[Party.Level, All_Monsters].Direction = 2 Return
EndIf
If Monster[Party.Level, All_Monsters].Direction = 4
Monster[Party.Level, All_Monsters].choose_direction = Rand(1, 2)
If Monster[Party.Level, All_Monsters].choose_direction = 1 Then Monster[Party.Level, All_Monsters].Direction = 2 Return
If Monster[Party.Level, All_Monsters].choose_direction = 2 Then Monster[Party.Level, All_Monsters].Direction = 1 Return
EndIf
EndIf
EndIf
If Monster[Party.Level, All_Monsters].Walking = 1 Then
'Monster goes NORTH
If Monster[Party.Level, All_Monsters].Direction = 1
'The monster is on the first row
If Monster[Party.Level, All_Monsters].Y = 1 Then
Monster[Party.Level, All_Monsters].choose_direction = Rand(1, 2)
If Monster[Party.Level, All_Monsters].choose_direction = 1 Then Monster[Party.Level, All_Monsters].Direction = 3 Return
If Monster[Party.Level, All_Monsters].choose_direction = 2 Then Monster[Party.Level, All_Monsters].Direction = 4 Return
EndIf
'If the monster found other monster in front
If Monster_Table[Party.Level, Monster[Party.Level, All_Monsters].X, Monster[Party.Level, All_Monsters].Y - 1] <> 0 And Monster[Party.Level, All_Monsters].Not_Allow_to_move = 1 Then
Monster[Party.Level, All_Monsters].choose_direction = Rand(1, 2)
If Monster[Party.Level, All_Monsters].choose_direction = 1 Then Monster[Party.Level, All_Monsters].Direction = 3 Return
If Monster[Party.Level, All_Monsters].choose_direction = 2 Then Monster[Party.Level, All_Monsters].Direction = 4 Return
EndIf
Monster[Party.Level, All_Monsters].Square_transition_frame:+1
If Monster[Party.Level, All_Monsters].Square_transition_frame > 3 Then
Monster[Party.Level, All_Monsters].Square_transition_frame = 0
Monster[Party.Level, All_Monsters].Y:-1
EndIf
EndIf
'Monster goes SOUTH
If Monster[Party.Level, All_Monsters].Direction = 2
'The monster is on the last row
If Monster[Party.Level, All_Monsters].Y = 20 Then
Monster[Party.Level, All_Monsters].choose_direction = Rand(1, 2)
If Monster[Party.Level, All_Monsters].choose_direction = 1 Then Monster[Party.Level, All_Monsters].Direction = 4 Return
If Monster[Party.Level, All_Monsters].choose_direction = 2 Then Monster[Party.Level, All_Monsters].Direction = 3 Return
EndIf
'If the monster found other monster in front
If Monster_Table[Party.Level, Monster[Party.Level, All_Monsters].X, Monster[Party.Level, All_Monsters].Y + 1] <> 0 And Monster[Party.Level, All_Monsters].Not_Allow_to_move = 1 Then
Monster[Party.Level, All_Monsters].choose_direction = Rand(1, 2)
If Monster[Party.Level, All_Monsters].choose_direction = 1 Then Monster[Party.Level, All_Monsters].Direction = 4 Return
If Monster[Party.Level, All_Monsters].choose_direction = 2 Then Monster[Party.Level, All_Monsters].Direction = 3 Return
EndIf
Monster[Party.Level, All_Monsters].Square_transition_frame:+1
If Monster[Party.Level, All_Monsters].Square_transition_frame > 3 Then
Monster[Party.Level, All_Monsters].Square_transition_frame = 0
Monster[Party.Level, All_Monsters].Y:+1
EndIf
EndIf
'Monster goes WEST
If Monster[Party.Level, All_Monsters].Direction = 3
'The monster is on the first column
If Monster[Party.Level, All_Monsters].X = 1 Then
Monster[Party.Level, All_Monsters].choose_direction = Rand(1, 2)
If Monster[Party.Level, All_Monsters].choose_direction = 1 Then Monster[Party.Level, All_Monsters].Direction = 1 Return
If Monster[Party.Level, All_Monsters].choose_direction = 2 Then Monster[Party.Level, All_Monsters].Direction = 2 Return
EndIf
'If the monster found other monster in front
If Monster_Table[Party.Level, Monster[Party.Level, All_Monsters].X - 1, Monster[Party.Level, All_Monsters].Y] <> 0 And Monster[Party.Level, All_Monsters].Not_Allow_to_move = 1 Then
Monster[Party.Level, All_Monsters].choose_direction = Rand(1, 2)
If Monster[Party.Level, All_Monsters].choose_direction = 1 Then Monster[Party.Level, All_Monsters].Direction = 1 Return
If Monster[Party.Level, All_Monsters].choose_direction = 2 Then Monster[Party.Level, All_Monsters].Direction = 2 Return
EndIf
Monster[Party.Level, All_Monsters].Square_transition_frame:+1
If Monster[Party.Level, All_Monsters].Square_transition_frame > 3 Then
Monster[Party.Level, All_Monsters].Square_transition_frame = 0
Monster[Party.Level, All_Monsters].X:-1
EndIf
EndIf
'Monster goes EAST
If Monster[Party.Level, All_Monsters].Direction = 4
'The monster is on the last column
If Monster[Party.Level, All_Monsters].X = 20 Then
Monster[Party.Level, All_Monsters].choose_direction = Rand(1, 2)
If Monster[Party.Level, All_Monsters].choose_direction = 1 Then Monster[Party.Level, All_Monsters].Direction = 2 Return
If Monster[Party.Level, All_Monsters].choose_direction = 2 Then Monster[Party.Level, All_Monsters].Direction = 1 Return
EndIf
'If the monster found other monster in front
If Monster_Table[Party.Level, Monster[Party.Level, All_Monsters].X + 1, Monster[Party.Level, All_Monsters].Y] <> 0 And Monster[Party.Level, All_Monsters].Not_Allow_to_move = 1 Then
Monster[Party.Level, All_Monsters].choose_direction = Rand(1, 2)
If Monster[Party.Level, All_Monsters].choose_direction = 1 Then Monster[Party.Level, All_Monsters].Direction = 2 Return
If Monster[Party.Level, All_Monsters].choose_direction = 2 Then Monster[Party.Level, All_Monsters].Direction = 1 Return
EndIf
Monster[Party.Level, All_Monsters].Square_transition_frame:+1
If Monster[Party.Level, All_Monsters].Square_transition_frame > 3 Then
Monster[Party.Level, All_Monsters].Square_transition_frame = 0
Monster[Party.Level, All_Monsters].X:+1
EndIf
EndIf
EndIf
'If the monster is walking
If Monster[Party.Level, All_Monsters].Walking = 0 Then
'Monster[Party.Level, All_Monsters].Walking = 1
EndIf
EndIf
'end of monsters XY > 0
EndIf
'End of monster deadline time
If Monster[Party.Level, All_Monsters].X <= 1 Then Monster[Party.Level, All_Monsters].X = 1
If Monster[Party.Level, All_Monsters].X >= 20 Then Monster[Party.Level, All_Monsters].X = 20
If Monster[Party.Level, All_Monsters].Y <= 1 Then Monster[Party.Level, All_Monsters].Y = 1
If Monster[Party.Level, All_Monsters].Y >= 20 Then Monster[Party.Level, All_Monsters].Y = 20
Next
End Function
Function Draw_Game()
SetColor(0, 0, 0)
DrawRect(0, 0, 640, 480)
SetColor(255, 255, 255)
For MTable_y = 1 To 20
For MTable_x = 1 To 20
If Monster_Table[Party.Level, MTable_x, MTable_y] = 2 Then DrawImage(locked_square, -16 + (MTable_x * 16), -16 + (MTable_y * 16), 0)
Next
Next
For All_Monsters = 1 To Max_Monsters
If Monster[Party.Level, All_Monsters].X <= 0 And Monster[Party.Level, All_Monsters].Y <= 0 Then Continue
If Monster[Party.Level, All_Monsters].X > 0 And Monster[Party.Level, All_Monsters].Y > 0 Then
If Monster[Party.Level, All_Monsters].Direction = 1 Then
If Monster[Party.Level, All_Monsters].Graphic = "01" Then
If Monster[Party.Level, All_Monsters].Square_transition_frame = 3 Then DrawImage(spider_icon_n, -16 + (Monster[Party.Level, All_Monsters].X * 16), -16 + (Monster[Party.Level, All_Monsters].Y * 16) - 12, 0)
If Monster[Party.Level, All_Monsters].Square_transition_frame = 2 Then DrawImage(spider_icon_n, -16 + (Monster[Party.Level, All_Monsters].X * 16), -16 + (Monster[Party.Level, All_Monsters].Y * 16) - 8, 0)
If Monster[Party.Level, All_Monsters].Square_transition_frame = 1 Then DrawImage(spider_icon_n, -16 + (Monster[Party.Level, All_Monsters].X * 16), -16 + (Monster[Party.Level, All_Monsters].Y * 16) - 4, 0)
If Monster[Party.Level, All_Monsters].Square_transition_frame = 0 Then DrawImage(spider_icon_n, -16 + (Monster[Party.Level, All_Monsters].X * 16), -16 + (Monster[Party.Level, All_Monsters].Y * 16), 0)
EndIf
If Monster[Party.Level, All_Monsters].Graphic = "02" Then
If Monster[Party.Level, All_Monsters].Square_transition_frame = 3 Then DrawImage(ghost_icon_n, -16 + (Monster[Party.Level, All_Monsters].X * 16), -16 + (Monster[Party.Level, All_Monsters].Y * 16) - 12, 0)
If Monster[Party.Level, All_Monsters].Square_transition_frame = 2 Then DrawImage(ghost_icon_n, -16 + (Monster[Party.Level, All_Monsters].X * 16), -16 + (Monster[Party.Level, All_Monsters].Y * 16) - 8, 0)
If Monster[Party.Level, All_Monsters].Square_transition_frame = 1 Then DrawImage(ghost_icon_n, -16 + (Monster[Party.Level, All_Monsters].X * 16), -16 + (Monster[Party.Level, All_Monsters].Y * 16) - 4, 0)
If Monster[Party.Level, All_Monsters].Square_transition_frame = 0 Then DrawImage(ghost_icon_n, -16 + (Monster[Party.Level, All_Monsters].X * 16), -16 + (Monster[Party.Level, All_Monsters].Y * 16), 0)
EndIf
End If
If Monster[Party.Level, All_Monsters].Direction = 2 Then
If Monster[Party.Level, All_Monsters].Graphic = "01" Then
If Monster[Party.Level, All_Monsters].Square_transition_frame = 3 Then DrawImage(spider_icon_s, -16 + (Monster[Party.Level, All_Monsters].X * 16), -16 + (Monster[Party.Level, All_Monsters].Y * 16) + 12, 0)
If Monster[Party.Level, All_Monsters].Square_transition_frame = 2 Then DrawImage(spider_icon_s, -16 + (Monster[Party.Level, All_Monsters].X * 16), -16 + (Monster[Party.Level, All_Monsters].Y * 16) + 8, 0)
If Monster[Party.Level, All_Monsters].Square_transition_frame = 1 Then DrawImage(spider_icon_s, -16 + (Monster[Party.Level, All_Monsters].X * 16), -16 + (Monster[Party.Level, All_Monsters].Y * 16) + 4, 0)
If Monster[Party.Level, All_Monsters].Square_transition_frame = 0 Then DrawImage(spider_icon_s, -16 + (Monster[Party.Level, All_Monsters].X * 16), -16 + (Monster[Party.Level, All_Monsters].Y * 16), 0)
EndIf
If Monster[Party.Level, All_Monsters].Graphic = "02" Then
If Monster[Party.Level, All_Monsters].Square_transition_frame = 3 Then DrawImage(ghost_icon_s, -16 + (Monster[Party.Level, All_Monsters].X * 16), -16 + (Monster[Party.Level, All_Monsters].Y * 16) + 12, 0)
If Monster[Party.Level, All_Monsters].Square_transition_frame = 2 Then DrawImage(ghost_icon_s, -16 + (Monster[Party.Level, All_Monsters].X * 16), -16 + (Monster[Party.Level, All_Monsters].Y * 16) + 8, 0)
If Monster[Party.Level, All_Monsters].Square_transition_frame = 1 Then DrawImage(ghost_icon_s, -16 + (Monster[Party.Level, All_Monsters].X * 16), -16 + (Monster[Party.Level, All_Monsters].Y * 16) + 4, 0)
If Monster[Party.Level, All_Monsters].Square_transition_frame = 0 Then DrawImage(ghost_icon_s, -16 + (Monster[Party.Level, All_Monsters].X * 16), -16 + (Monster[Party.Level, All_Monsters].Y * 16), 0)
EndIf
End If
If Monster[Party.Level, All_Monsters].Direction = 3 Then
If Monster[Party.Level, All_Monsters].Graphic = "01" Then
If Monster[Party.Level, All_Monsters].Square_transition_frame = 3 Then DrawImage(spider_icon_w, -16 + (Monster[Party.Level, All_Monsters].X * 16) - 12, -16 + (Monster[Party.Level, All_Monsters].Y * 16) , 0)
If Monster[Party.Level, All_Monsters].Square_transition_frame = 2 Then DrawImage(spider_icon_w, -16 + (Monster[Party.Level, All_Monsters].X * 16) - 8, -16 + (Monster[Party.Level, All_Monsters].Y * 16) , 0)
If Monster[Party.Level, All_Monsters].Square_transition_frame = 1 Then DrawImage(spider_icon_w, -16 + (Monster[Party.Level, All_Monsters].X * 16) - 4, -16 + (Monster[Party.Level, All_Monsters].Y * 16) , 0)
If Monster[Party.Level, All_Monsters].Square_transition_frame = 0 Then DrawImage(spider_icon_w, -16 + (Monster[Party.Level, All_Monsters].X * 16), -16 + (Monster[Party.Level, All_Monsters].Y * 16), 0)
EndIf
If Monster[Party.Level, All_Monsters].Graphic = "02" Then
If Monster[Party.Level, All_Monsters].Square_transition_frame = 3 Then DrawImage(ghost_icon_w, -16 + (Monster[Party.Level, All_Monsters].X * 16) - 12, -16 + (Monster[Party.Level, All_Monsters].Y * 16) , 0)
If Monster[Party.Level, All_Monsters].Square_transition_frame = 2 Then DrawImage(ghost_icon_w, -16 + (Monster[Party.Level, All_Monsters].X * 16) - 8, -16 + (Monster[Party.Level, All_Monsters].Y * 16) , 0)
If Monster[Party.Level, All_Monsters].Square_transition_frame = 1 Then DrawImage(ghost_icon_w, -16 + (Monster[Party.Level, All_Monsters].X * 16) - 4, -16 + (Monster[Party.Level, All_Monsters].Y * 16) , 0)
If Monster[Party.Level, All_Monsters].Square_transition_frame = 0 Then DrawImage(ghost_icon_w, -16 + (Monster[Party.Level, All_Monsters].X * 16), -16 + (Monster[Party.Level, All_Monsters].Y * 16), 0)
EndIf
End If
If Monster[Party.Level, All_Monsters].Direction = 4 Then
If Monster[Party.Level, All_Monsters].Graphic = "01" Then
If Monster[Party.Level, All_Monsters].Square_transition_frame = 3 Then DrawImage(spider_icon_e, -16 + (Monster[Party.Level, All_Monsters].X * 16) + 12, -16 + (Monster[Party.Level, All_Monsters].Y * 16) , 0)
If Monster[Party.Level, All_Monsters].Square_transition_frame = 2 Then DrawImage(spider_icon_e, -16 + (Monster[Party.Level, All_Monsters].X * 16) + 8, -16 + (Monster[Party.Level, All_Monsters].Y * 16) , 0)
If Monster[Party.Level, All_Monsters].Square_transition_frame = 1 Then DrawImage(spider_icon_e, -16 + (Monster[Party.Level, All_Monsters].X * 16) + 4, -16 + (Monster[Party.Level, All_Monsters].Y * 16) , 0)
If Monster[Party.Level, All_Monsters].Square_transition_frame = 0 Then DrawImage(spider_icon_e, -16 + (Monster[Party.Level, All_Monsters].X * 16), -16 + (Monster[Party.Level, All_Monsters].Y * 16), 0)
EndIf
If Monster[Party.Level, All_Monsters].Graphic = "02" Then
If Monster[Party.Level, All_Monsters].Square_transition_frame = 3 Then DrawImage(ghost_icon_e, -16 + (Monster[Party.Level, All_Monsters].X * 16) + 12, -16 + (Monster[Party.Level, All_Monsters].Y * 16) , 0)
If Monster[Party.Level, All_Monsters].Square_transition_frame = 2 Then DrawImage(ghost_icon_e, -16 + (Monster[Party.Level, All_Monsters].X * 16) + 8, -16 + (Monster[Party.Level, All_Monsters].Y * 16) , 0)
If Monster[Party.Level, All_Monsters].Square_transition_frame = 1 Then DrawImage(ghost_icon_e, -16 + (Monster[Party.Level, All_Monsters].X * 16) + 4, -16 + (Monster[Party.Level, All_Monsters].Y * 16) , 0)
If Monster[Party.Level, All_Monsters].Square_transition_frame = 0 Then DrawImage(ghost_icon_e, -16 + (Monster[Party.Level, All_Monsters].X * 16), -16 + (Monster[Party.Level, All_Monsters].Y * 16), 0)
EndIf
End If
End If
'End of monster XY>0
Next
DrawImage(map_grid, 0, 0, 0)
End Function
Function Inits()
Local all_spiders:Byte
For all_spiders = 1 To 30
Monster[1, all_spiders].X = Rand(1, 20)
Monster[1, all_spiders].Y = Rand(1, 20)
Monster[1, all_spiders].Graphic = "01"
Monster[1, all_spiders].Direction = Rand(1, 4)
Monster[1, all_spiders].Square_transition_frame = 0
Monster[1, all_spiders].Not_Allow_to_move = 0
Monster[1, all_spiders].Walking = 1
Next
Monster[1, 1].X = 3
Monster[1, 1].Y = 7
Monster[1, 1].Graphic = "01"
Monster[1, 1].Direction = 1
Monster[1, 1].Square_transition_frame = 0
Monster[1, 1].Not_Allow_to_move = 0
Monster[1, 1].Walking = 1
Monster[1, 2].X = 3
Monster[1, 2].Y = 4
Monster[1, 2].Graphic = "02"
Monster[1, 2].Direction = 1
Monster[1, 2].Not_Allow_to_move = 0
Monster[1, 3].Walking = 0
Party.Level = 1
End Function
Function Keyboard_commands()
If KeyHit(KEY_W) Then
If Monster[1, 2].Direction = 1 Then
If Monster[1, 2].Y > 1 Then Monster[1, 2].Square_transition_frame:+1
EndIf
If Monster[1, 2].Direction = 2 Then
If Monster[1, 2].Y < 20 Then Monster[1, 2].Square_transition_frame:+1
EndIf
If Monster[1, 2].Direction = 3 Then
If Monster[1, 2].X > 1 Then Monster[1, 2].Square_transition_frame:+1
EndIf
If Monster[1, 2].Direction = 4 Then
If Monster[1, 2].X < 20 Then Monster[1, 2].Square_transition_frame:+1
EndIf
If Monster[1, 2].Direction = 1 Then
If Monster[1, 2].Square_transition_frame > 3 Then
Monster[1, 2].Square_transition_frame = 0
Monster[1, 2].Y:-1
Return
EndIf
EndIf
If Monster[1, 2].Direction = 2 Then
If Monster[1, 2].Square_transition_frame > 3 Then
Monster[1, 2].Square_transition_frame = 0
Monster[1, 2].Y:+1
Return
EndIf
EndIf
If Monster[1, 2].Direction = 3 Then
If Monster[1, 2].Square_transition_frame > 3 Then
Monster[1, 2].Square_transition_frame = 0
Monster[1, 2].X:-1
Return
EndIf
EndIf
If Monster[1, 2].Direction = 4 Then
If Monster[1, 2].Square_transition_frame > 3 Then
Monster[1, 2].Square_transition_frame = 0
Monster[1, 2].X:+1
Return
EndIf
EndIf
EndIf
If KeyHit(KEY_Q) Then
If Monster[1, 2].Direction = 1 Then
If Monster[1, 2].Square_transition_frame <> 0 Then Return
Monster[1, 2].Direction = 3
Return
EndIf
If Monster[1, 2].Direction = 2 Then
If Monster[1, 2].Square_transition_frame <> 0 Then Return
Monster[1, 2].Direction = 4
Return
EndIf
If Monster[1, 2].Direction = 3 Then
If Monster[1, 2].Square_transition_frame <> 0 Then Return
Monster[1, 2].Direction = 2
Return
EndIf
If Monster[1, 2].Direction = 4 Then
If Monster[1, 2].Square_transition_frame <> 0 Then Return
Monster[1, 2].Direction = 1
Return
EndIf
EndIf
If KeyHit(KEY_E) Then
If Monster[1, 2].Direction = 1 Then
If Monster[1, 2].Square_transition_frame <> 0 Then Return
Monster[1, 2].Direction = 4
Return
EndIf
If Monster[1, 2].Direction = 2 Then
If Monster[1, 2].Square_transition_frame <> 0 Then Return
Monster[1, 2].Direction = 3
Return
EndIf
If Monster[1, 2].Direction = 3 Then
If Monster[1, 2].Square_transition_frame <> 0 Then Return
Monster[1, 2].Direction = 1
Return
EndIf
If Monster[1, 2].Direction = 4 Then
If Monster[1, 2].Square_transition_frame <> 0 Then Return
Monster[1, 2].Direction = 2
Return
EndIf
EndIf
End Function
The files you will need are here: Click for sprites So far so good for now , I will try to adopt this in my game. I will tell you what I managed. |
| ||
| Glad youve managed to sort this out. |
| ||
| Thank you , now I will adjust this code in the main game engine with new battle system. And when the next version will be finished I will show a demo. |
| ||
| Excellent - Sometimes you need to either step away from the code, or come at it from a different view. starting a small project to deal with a single issue is a great way of clearing your mind :) |
| ||
| My monsters now are perfect and my new code was updated in my game core engine. No overlaps and smarter Artificial Intelligence , now my monsters can open doors , avoid other obstacles do attacks... Everything goes very nice and now I am programming the battle system. |
| ||
| It's great when it starts to come together :) |