Turn Based Strategy

Started by lakotajames, Mon 29/09/2008 18:17:13

Previous topic - Next topic

lakotajames

I'm not sure if this should be in Beginners Technical Questions or here, so move it if I put it in the wrong place.

I am trying to make a turn based strategy. here is my global script:

#sectionstart game_start  // DO NOT EDIT OR REMOVE THIS LINE
function game_start() // called when the game starts, before the first room is loaded
{
GiveScore(5);

}
#sectionend game_start  // DO NOT EDIT OR REMOVE THIS LINE


#sectionstart repeatedly_execute  // DO NOT EDIT OR REMOVE THIS LINE
function repeatedly_execute() {

}
#sectionend repeatedly_execute  // DO NOT EDIT OR REMOVE THIS LINE

#sectionstart on_key_press  // DO NOT EDIT OR REMOVE THIS LINE
function on_key_press(int keycode) {// called when a key is pressed. keycode holds the key's ASCII code
if (IsGamePaused()==1) keycode=0; // game paused, so don't react to keypresses
if (keycode==17) QuitGame(1); // Ctrl-Q
if (keycode==363) SaveGameDialog(); // F5
if (keycode==365) RestoreGameDialog(); // F7
if (keycode==367) RestartGame(); // F9
if (keycode==434) SaveScreenShot("scrnshot.pcx");  // F12
if (keycode==9) InventoryScreen(); // Tab, show inventory
if (keycode==19) Debug(0,0); // Ctrl-S, give all inventory
if (keycode==22) Debug(1,0); // Ctrl-V, version
if (keycode==1) Debug(2,0); // Ctrl-A, show walkable areas
if (keycode==24) Debug(3,0); // Ctrl-X, teleport to room
while (player.Moving) Wait(1);
if (keycode==375 && Character.GetAtScreenXY(player.x-20, player.y) != cRed1){
   player.WalkStraight(player.x-20, player.y);
   GiveScore(-1);
   if (game.score == 0 && player.ID == 0) {
     while (player.Moving) Wait(1);
      player.ChangeView (1);
      cRed2.SetAsPlayer();
      player.ChangeView (2);
      GiveScore(5);
      }
   if (game.score == 0 && player.ID == 1) {      
      while (player.Moving) Wait(1);
      player.ChangeView (1);
      //Enemy's turn         
      cRed1.SetAsPlayer();
      player.ChangeView (2);
      GiveScore(5);
      }
   }
if (keycode==377) {
   player.WalkStraight(player.x+20, player.y);
   GiveScore(-1);
   if (game.score == 0 && player.ID == 0) {   
      while (player.Moving) Wait(1);
      player.ChangeView (1);
      cRed2.SetAsPlayer();
      player.ChangeView (2);
      GiveScore(5);
      }
   if (game.score == 0 && player.ID == 1) {   
      while (player.Moving) Wait(1);
      player.ChangeView (1);
      //Enemy's turn         
      cRed1.SetAsPlayer();
      player.ChangeView (2);
      GiveScore(5);
      }
   }
if (keycode==380) {
   player.WalkStraight(player.x, player.y+20);
   GiveScore(-1);
   if (game.score == 0 && player.ID == 0) {   
      while (player.Moving) Wait(1);
      player.ChangeView (1);
      cRed2.SetAsPlayer();
      player.ChangeView (2);
      GiveScore(5);
      }
   if (game.score == 0 && player.ID == 1) {      
      while (player.Moving) Wait(1);
      player.ChangeView (1);
      //Enemy's turn         
      cRed1.SetAsPlayer();
      player.ChangeView (2);
      GiveScore(5);
      }
   }
if (keycode==372) {
   player.WalkStraight(player.x, player.y-20);
   GiveScore(-1);
   if (game.score == 0 && player.ID == 0) {   
      while (player.Moving) Wait(1);
      player.ChangeView (1);
      cRed2.SetAsPlayer();
      player.ChangeView (2);
      GiveScore(5);
      }
   if (game.score == 0 && player.ID == 1) {      
      while (player.Moving) Wait(1);
      player.ChangeView (1);
      //Enemy's turn         
      cRed1.SetAsPlayer();
      player.ChangeView (2);
      GiveScore(5);
      }
   }
}
#sectionend on_key_press  // DO NOT EDIT OR REMOVE THIS LINE


#sectionstart on_mouse_click  // DO NOT EDIT OR REMOVE THIS LINE
function on_mouse_click(MouseButton button) // called when a mouse button is clicked. button is either LEFT or RIGHT
  {
  if (IsGamePaused() == 1) // Game is paused, so do nothing (ie. don't allow mouse click)
    {
    }
  else if (button == eMouseLeft)
    {
    ProcessClick(mouse.x,mouse.y, mouse.Mode);
    }
  else // right-click, so cycle cursor
    {   
    gPopup.Visible = true;
    }
  }
#sectionend on_mouse_click  // DO NOT EDIT OR REMOVE THIS LINE


#sectionstart interface_click  // DO NOT EDIT OR REMOVE THIS LINE
function interface_click(int interface, int button) {
  }
#sectionend interface_click  // DO NOT EDIT OR REMOVE THIS LINE

#sectionstart Quit_Click
function Quit_Click(GUIControl *control, MouseButton button) {
 
  QuitGame(1);
}
#sectionend Quit_Click
#sectionstart popupclose_Click
function popupclose_Click(GUIControl *control,  MouseButton button) {
  gPopup.Visible = false;
}
#sectionend popupclose_Click
#sectionstart Help_Click
function Help_Click(GUIControl *control, MouseButton button) {
Display("Arrow keys: Move");


}
#sectionend Help_Click
#sectionstart character1_a  // DO NOT EDIT OR REMOVE THIS LINE
function character1_a() {
  // script for Character 1 (RED2): Any click on character

}
#sectionend character1_a  // DO NOT EDIT OR REMOVE THIS LINE

#sectionstart unhandled_event  // DO NOT EDIT OR REMOVE THIS LINE
function unhandled_event(int what, int type) {
 
}
#sectionend unhandled_event  // DO NOT EDIT OR REMOVE THIS LINE


As you may have gathered, I have very little idea what I am doing. 

I have the character switching code in each of the sections to move the character.  Now I realized that the enemy code will have to be duplicated four times, once for each direction of movement.  There is no way that this is the best way to do this, so I thought I would let one of you tell me a better way.

I also am having problems with collision detection of the characters.  How can I make them not walk over each other?  If I make the characters solid, they move right next to each other then stop, and then they are no longer lined up with the grid that I am using for the map.

Help???

Pumaman

You've got a lot of copy & pasted scripting there, so the first thing you need to do is extract it into a custom function. In particular, this code:

Quote
   GiveScore(-1);
   if (game.score == 0 && player.ID == 0) {   
      while (player.Moving) Wait(1);
      player.ChangeView (1);
      cRed2.SetAsPlayer();
      player.ChangeView (2);
      GiveScore(5);
      }
   if (game.score == 0 && player.ID == 1) {     
      while (player.Moving) Wait(1);
      player.ChangeView (1);
      //Enemy's turn         
      cRed1.SetAsPlayer();
      player.ChangeView (2);
      GiveScore(5);
      }

seems to be there four times. What you can do is  go to the top of the script file and add your own function, like this:

function ChangeTurn()
{
/// PASTE THE COMMON CODE HERE
}

Then, in the 4 places where you've currently got that code, just replace it with one line:
ChangeTurn();

And even within that function, there's some unnecessary duplication. Instead of having two "if" statements and having nearly identical code in both, why not do:

   if (game.score == 0) {   
      while (player.Moving) Wait(1);
      player.ChangeView (1);
      if (player == cRed1)
      {
        cRed2.SetAsPlayer();
      }
      else
      {
        cRed1.SetAsPlayer();
      }
      player.ChangeView (2);
      GiveScore(5);
      }

lakotajames

Thanks Pumaman.  That will help a lot.  Now, does anyone know how to make the characters so they will not run over each other?  I tried to do this here:
Code: ags
if (keycode==375 && Character.GetAtScreenXY(player.x-20, player.y) != cRed1){

It doesn't work, though.

Pumaman

Just make them solid. I notice you said:

QuoteIf I make the characters solid, they move right next to each other then stop, and then they are no longer lined up with the grid that I am using for the map.

Not quite sure what this means, maybe you could elaborate on how this grid works?

lakotajames

Like on a chess board, where you are always in a square.  The pieces will never be setting on the lines, they go directly to the next square.  if i make the characters solid, then the character moves on to the next square but stops just before reaching the center, and from then on when he moves he is no longer on the squares.

Pumaman

Perhaps the best thing to do would be manually check all the character X/Y co-ordinates, work out which grid square they are in, and then use that to decide how far the main character can move?

monkey0506

#6
It would be easy to set up some functions like:

Code: ags
// global script
int GridUnitWidth = 20; // set this to the width of each section of the grid
int GridUnitHeight = 20; // the height of each section

int GetGridX(int roomX) {
  return ((roomX / GridUnitWidth) * GridUnitWidth) + (GridUnitWidth / 2);
}

int GetGridY(int roomY) {
  return ((roomY / GridUnitWidth) * GridUnitWidth) + (GridUnitWidth / 2);
}


Then in on_mouse_click you could do:

Code: ags
if (mouse.Mode == eModeWalkto) ProcessClick(GetGridX(mouse.x), GetGridY(mouse.y), mouse.Mode);


This doesn't restrict movement to the grid, but you could do that with your walkable areas. Instead of filling the areas, just make a 3-4 pixel wide path through the grid. ;)

Edit: I see you're using the keyboard for movement...oh and also my code didn't really help with the collision prevention... :-[ This should.

Code: ags
void WalkToXYOnGrid(Character *theChar, int roomX, int roomY) {
  if (theChar == null) return;
  roomX = GetGridX(roomX);
  roomY = GetGridY(roomY);
  Character *charAtXY = Character.GetAtScreenXY(roomX - GetViewportX(), roomY - GetViewportY());
  if (charAtXY != null) {
    int xdiff = theChar.x - roomX;
    int ydiff = theChar.y - roomY;
    if (xdiff < 0) xdiff = -xdiff;
    if (ydiff < 0) ydiff = -ydiff;
    if (xdiff > ydiff) {
      if (theChar.x < charAtXY.x) {
        if (roomX > (GridUnitWidth / 2)) roomX -= GridUnitWidth;
        else roomX += GridUnitWidth;
      }
      else {
        if (roomX < (Room.Width - (GridUnitWidth / 2))) roomX += GridUnitWidth;
        else roomX -= GridUnitWidth;
      }
    }
    else {
      if (theChar.y < charAtXY.y) {
        if (roomY > (GridUnitHeight / 2)) roomY -= GridUnitHeight;
        else roomY += GridUnitHeight;
      }
      else {
        if (roomY < (Room.Height - (GridUnitHeight / 2))) roomY += GridUnitHeight;
        else roomY -= GridUnitHeight;
      }
    }
  }
  theChar.Walk(roomX, roomY);
}

// ...
if (keycode==375) {
  WalkToXYOnGrid(player, player.x - 20, player.y);
// ...
if (keycode==377) {
  WalkToXYOnGrid(player, player.x + 20, player.y);
// ...
if (keycode==380) {
  WalkToXYOnGrid(player, player.x, player.y + 20);
// ...
if (keycode==372) {
  WalkToXYOnGrid(player, player.x, player.y - 20);
// ...

Khris

You need some sort of framework to handle the characters' positions and other data.
There are several threads about multidimensional arrays and structs in general.
So, if the character's supposed to go right from position (x,y) you simply check what's on (x+1,y), then go from there.

Creating turn-based strategy using AGS' built in collision detection is bound to fail.

lakotajames

my code now:
Code: ags

// global script
int GridUnitWidth = 20; // set this to the width of each section of the grid
int GridUnitHeight = 20; // the height of each section

int GetGridX(int roomX) {
  return ((roomX / GridUnitWidth) * GridUnitWidth) + (GridUnitWidth / 2);
}

int GetGridY(int roomY) {
  return ((roomY / GridUnitWidth) * GridUnitWidth) + (GridUnitWidth / 2);
}


function ChangeTurn() {
	if (game.score == 0) {   
		player.ChangeView (player.View-1);
		if ((player == cRed2) || (player == cBlue2)) {
			//Switch Sides
			if (player == cRed2) cBlue.SetAsPlayer();
			if (player == cBlue2) cRed1.SetAsPlayer();
			}
			else {
			//Switch Players
			if (player == cBlue) cBlue2.SetAsPlayer();
			if (player == cRed1) cRed2.SetAsPlayer();
			}
		player.ChangeView (player.View+1);
		GiveScore(5);			
		}    
	}



void WalkToXYOnGrid(Character *theChar, int roomX, int roomY) {
  if (theChar == null) return;
  roomX = GetGridX(roomX);
  roomY = GetGridY(roomY);
  Character *charAtXY = Character.GetAtScreenXY(roomX - GetViewportX(), roomY - GetViewportY());
  if (charAtXY != null) {
    int xdiff = theChar.x - roomX;
    int ydiff = theChar.y - roomY;
    if (xdiff < 0) xdiff = -xdiff;
    if (ydiff < 0) ydiff = -ydiff;
    if (xdiff > ydiff) {
      if (theChar.x < charAtXY.x) {
        if (roomX > (GridUnitWidth / 2)) roomX -= GridUnitWidth;
        else roomX += GridUnitWidth;
      }
      else {
        if (roomX < (Room.Width - (GridUnitWidth / 2))) roomX += GridUnitWidth;
        else roomX -= GridUnitWidth;
      }
    }
    else {
      if (theChar.y < charAtXY.y) {
        if (roomY > (GridUnitHeight / 2)) roomY -= GridUnitHeight;
        else roomY += GridUnitHeight;
      }
      else {
        if (roomY < (Room.Height - (GridUnitHeight / 2))) roomY += GridUnitHeight;
        else roomY -= GridUnitHeight;
      }
    }
  }
  theChar.Walk(roomX, roomY);
}
#sectionstart game_start  // DO NOT EDIT OR REMOVE THIS LINE
function game_start() // called when the game starts, before the first room is loaded
{
GiveScore(5);

}
#sectionend game_start  // DO NOT EDIT OR REMOVE THIS LINE


#sectionstart repeatedly_execute  // DO NOT EDIT OR REMOVE THIS LINE
function repeatedly_execute() {

}
#sectionend repeatedly_execute  // DO NOT EDIT OR REMOVE THIS LINE

#sectionstart on_key_press  // DO NOT EDIT OR REMOVE THIS LINE
function on_key_press(int keycode) {// called when a key is pressed. keycode holds the key's ASCII code
if (IsGamePaused()==1) keycode=0; // game paused, so don't react to keypresses
if (keycode==17) QuitGame(1); // Ctrl-Q
if (keycode==363) SaveGameDialog(); // F5
if (keycode==365) RestoreGameDialog(); // F7
if (keycode==367) RestartGame(); // F9
if (keycode==434) SaveScreenShot("scrnshot.pcx");  // F12
if (keycode==9) InventoryScreen(); // Tab, show inventory
if (keycode==19) Debug(0,0); // Ctrl-S, give all inventory
if (keycode==22) Debug(1,0); // Ctrl-V, version
if (keycode==1) Debug(2,0); // Ctrl-A, show walkable areas
if (keycode==24) Debug(3,0); // Ctrl-X, teleport to room
while (player.Moving) Wait(1);
if (keycode==375) {
	WalkToXYOnGrid(player, player.x - 20, player.y);
	GiveScore(-1);
	ChangeTurn();
	}
if (keycode==377) {
	WalkToXYOnGrid(player, player.x+20, player.y);
	GiveScore(-1);
	ChangeTurn();
	}
if (keycode==380) {
	WalkToXYOnGrid(player, player.x, player.y+20);
	GiveScore(-1);
	ChangeTurn();
	}
if (keycode==372) {
	WalkToXYOnGrid(player, player.x, player.y-20);
	GiveScore(-1);
	ChangeTurn();
	}
}
#sectionend on_key_press  // DO NOT EDIT OR REMOVE THIS LINE
 

#sectionstart on_mouse_click  // DO NOT EDIT OR REMOVE THIS LINE
function on_mouse_click(MouseButton button) // called when a mouse button is clicked. button is either LEFT or RIGHT
  {
  if (IsGamePaused() == 1) // Game is paused, so do nothing (ie. don't allow mouse click)
    {
    }
  else if (button == eMouseLeft) 
    {
    ProcessClick(mouse.x,mouse.y, mouse.Mode);
    }
  else // right-click, so show menu
    {   
    gPopup.Visible = true;
    }
  }
#sectionend on_mouse_click  // DO NOT EDIT OR REMOVE THIS LINE


#sectionstart interface_click  // DO NOT EDIT OR REMOVE THIS LINE
function interface_click(int interface, int button) {
  }
#sectionend interface_click  // DO NOT EDIT OR REMOVE THIS LINE

#sectionstart Quit_Click
function Quit_Click(GUIControl *control, MouseButton button) {
  
  QuitGame(1);
}
#sectionend Quit_Click
#sectionstart popupclose_Click
function popupclose_Click(GUIControl *control,  MouseButton button) {
  gPopup.Visible = false;
}
#sectionend popupclose_Click
#sectionstart Help_Click
function Help_Click(GUIControl *control, MouseButton button) {
Display("Arrow keys: Move");


}
#sectionend Help_Click
#sectionstart character1_a  // DO NOT EDIT OR REMOVE THIS LINE
function character1_a() {
  // script for Character 1 (RED2): Any click on character

}
#sectionend character1_a  // DO NOT EDIT OR REMOVE THIS LINE

#sectionstart unhandled_event  // DO NOT EDIT OR REMOVE THIS LINE
function unhandled_event(int what, int type) {
  
}
#sectionend unhandled_event  // DO NOT EDIT OR REMOVE THIS LINE



Now they will no longer move upwards, and there still isn't any collision detection.  Also, they are no longer lined up with my grid, but that isn't as important as the ability to move upwards.

SMF spam blocked by CleanTalk