Background; I'm trying to create a dice game for multi-players where you can choose how many players, sides on the die and dice's themselves you want in the game. And players each take a turn rolling n amount of dices and per each roll the score gets appended to the player classes playerScore property. Once a player reaches X amount of points, player is declared a winner.
Problem; The below code is part of the "Game" class. When I compile the code, the game does what I expect for the most part; it rolls 5 dices each turn per player and appends the points to said player, but once the player reaches 100 points, the player is declared a winner, but the die's are rolled again for another player, despite the fact that the while loop is invalidated. The way i see it, the problem is with the for loop, but I have no idea how to fix this, i tried "break" but it only breaks from the if statement.
My program has 3 classes; Die, Player, Game. If you need more information or screen shots. I can provide them.
P.S. If you think this code could be improved, please comment, I'd be glad to hear it out.
The if statements are messing with your flow. Why?
if (gameEnded || playerArray[i].PlayerScore >= maxPoints)
{
Console.WriteLine("Congratulations, Player '{0}' has won by reaching {1} points.",playerArray[i].PlayerName, playerArray[i].PlayerScore);
gameEnded = true;
break;
}
else if (!gameEnded )
{
playerArray[i].PlayerScore += rollAllDice();
Console.WriteLine("'{0}': {1}", playerArray[i].PlayerName, playerArray[i].PlayerScore);
}
Here, you're checking if the current player has reached the final score. If so, you break you for loop and set gameEnded = true, breaking the while loop as well. But this checks the score of the current player; it doesn't check if the current player has reached the score. This way, you will only discover if Player A won the game on the next round, not the current.
This way, as soon as a player reaches the score, the game ends:
public void StartGame(int maxPoints)
{
playerArray[0].PlayerTurn = true; // Not sure why you're doing this, so I'm gonna leave this here
Player winner = null;
while (!gameEnded)
{
for (int i = 0; i < playerArray.Length; i++)
{
Player currentPlayer = playerArray[i];
currentPlayer.PlayerScore += rollAllDice();
Console.WriteLine("'{0}': {1}", currentPlayer.PlayerName, currentPlayer.PlayerScore);
if (currentPlayer.PlayerScore >= maxPoints)
{
winner = currentPlayer;
gameEnded = true;
break;
}
}
}
Console.WriteLine("Congratulations, Player '{0}' has won by reaching {1} points.", winner.PlayerName, winner.PlayerScore);
}
There is only one "problem" within this code: as soon as a player reaches the number of points, it ends the game. It doesn't wait for the round to end..
You could do like this:
public void StartGame(int maxPoints)
{
//playerArray[0].PlayerTurn = true; // Is it necessary?
while (true)
{
for (int i = 0; i < playerArray.Length; i++)
{
Player currentPlayer = playerArray[i];
currentPlayer.PlayerScore += rollAllDice();
Console.WriteLine("'{0}': {1}", currentPlayer.PlayerName, currentPlayer.PlayerScore);
if (currentPlayer.PlayerScore >= maxPoints)
{
Console.WriteLine("Congratulations, Player '{0}' has won by reaching {1} points.", currentPlayer.PlayerName, currentPlayer.PlayerScore);
return;
}
}
}
}
I think your flow was just a little off, this may work better. To me the real issue was you should have rolled the dice first, then checked if it was a win. This would make your WHILE work properly.
public void StartGame(int maxPoints)
{
while (!gameEnded)
{
for (int i = 0; i < playerArray.Length; i++)
{
playerArray[i].PlayerScore += rollAllDice();
Console.WriteLine("'{0}': {1}", playerArray[i].PlayerName, playerArray[i].PlayerScore);
if(playerArray[i].PlayerScore >= maxPoints){
Console.WriteLine("Congratulations, Player '{0}' has won by reaching {1} points.",playerArray[i].PlayerName, playerArray[i].PlayerScore);
gameEnded = true;
break;
}
}
}
}
Related
Using yield return new WaitForSeconds(waitTime);
within an IEnumerator, what is the shortest wait time other than 0? I have tried using a float number and have tried as low as 0.00001f for the waitTime, however i'm not sure if there is a limit or not?
The purpose is that I am having a player's coins added one unit at a time, so the meter is 'filling up' rather than instant. I have tried searching but I cannot seem to find the answer to what the shortest limit is for WaitForSeconds, so if anyone knows I'd greatly appreciate the answer.
Additionally, my code is as follows if anyone has any input on how I can speed up the process without making it instant, as it's just not quite quick enough and the player is having to sit for a while waiting for the coins to be added to the meter at the end of the game.
IEnumerator AddCoins()
{
yield return new WaitForSeconds(1);
while (userGainedCoins > 0)
{
if (addingSoundPlaying == false)
{
addingSound.Play();
addingSoundPlaying = true;
}
if (userGainedCoins == 1)
{
addingSound.Stop();
}
userCoins += 1;
userGainedCoins -= 1;
PlayerPrefs.SetInt("User Coins", userCoins);
yield return new WaitForSeconds(waitTime);
}
addingSoundPlaying = false;
}
I think it doesn't have a minimum time, it just waits until it reaches a certain amount before waiting. If you want, you can just add multiple coins at a time. I usually try not to mess with these kinds of things, and instead of messing with the coins, I would just mess with the value it displays. You could have a script that holds the number of coins and increases/decreases it based on the timestep. Something like this:
public int coins = 100;
public int displayedCoins = 0;
private void Update() {
int change = Mathf.CeilToInt(300 * Time.deltaTime);
if (displayedCoins < coins)
displayedCoins = Math.Min(displayedCoins + change, coins);
else
displayedCoins = Math.Max(displayedCoins - change, coins);
}
and with this you can just set the amount and forget about it, and it works with gaining and losing coins. You can also change the change value to something like int change = Mathf.CeilToInt(Mathf.Abs(coins - displayCoins) * Time.deltaTime) to make it have an ease-out effect, or whatever you want. (I didn't test this code.)
I would like to make a bowling game in unity and I want to change the players after they threw the ball two times and the whole game to continue for 4 turns.
so I have two balls and each one has a script with a playerController that moves around the balls and after collision they respawn in the original position.
so for the turns I made a gameController that enables player1 (ball) input and disables player2 input then it enables player2 and disables player1.
How can I make player 1 to play twice and then change to player 2.
the script is:
public IEnumerator gamePlay()
{
if (pl1.hasPlay == false)
{
pl1.gameObject.SendMessage("Activate");
pl2.gameObject.SendMessage("Deactivate");
}
if (pl1.hasPlay == true)
{
pl2.gameObject.SendMessage("Activate");
pl1.gameObject.SendMessage("Deactivate");
}
yield return 0;
}
I'd recommend using two integers: one to store the number of plays and another to store the number of rounds.
It would look like this:
private int plays;
private int rounds;
private void Start()
{
plays = 0;
rounds = 0;
StartCoroutine(gamePlay());
}
public void NextBall()
{
plays++;
// Here you can change the logic behind the 2 balls
// (I remember it changes depending on whether you did a strike or not, if it's your last play or not, ...)
if (plays >= 2)
{
plays = 0;
rounds++;
StartCoroutine(gamePlay());
}
}
public IEnumerator gamePlay()
{
// This is based on player 1 being the first player
pl1.hasPlay = (rounds % 2 == 0);
pl2.hasPlay = !pl1.hasPlay;
pl1.gameObject.SendMessage(pl1.hasPlay ? "Activate" : "Deactivate");
pl2.gameObject.SendMessage(pl2.hasPlay ? "Activate" : "Deactivate");
yield return 0;
}
Also i'm not sure why you declared gamePlay() as an IEnumerator and not as a method but I guess you needed it this way :)
I changed the if/else condition by a ternary operator since the content on both part was similar, I find it easier to read like this.
Hope this helps,
So I created a game where player one and player two can play a game where they answer math questions, basically they go one after another for 5 rounds, so if one player answers the question right first they "Win" and if they both answer it right it is a "tie". Kind of a weird way to explain a weird game, but that's not my issue. I already finished the game inside of a class and it is functional and fine, my problem is that I need the players to play 5 games, and for it to tell who won the game the most, ex: "Player 1( or player 2, or draw) has won {0} times!" I have tried a lot of different things, but its all not working. Here is my code:
static void Main(string[] args)
{
string ID = "";
bool gOver = false;
Console.WriteLine("ID 1 ");
ID = Console.ReadLine();
MathGame p1 = new MathGame(1, ID);
Console.WriteLine();
Console.WriteLine("ID 2");
ID = Console.ReadLine();
MathGame p2 = new MathGame(2, ID);
Console.WriteLine();
while (!gOver)
{
MathGame.prblm();
while (!p1.Game() && !p2.Game())
gOver = true;
}
}
To reiterate; I'd like to make the game loop 5 times and tell me who won the most. I feel like my mistake is simple, make its just where I'm tired. Thanks for any and all help, this website is very helpful.
You need to wrap your game in a for loop, not a while. Then when the while loop (of your game) ends you should check who won and tally it. After the for loop you should have counters to display then.
There are many ways to "tally" but the easiest would be to add a variable for each player and increment when they win.
const in GAME_COUNT_TO_PLAY = 5;
for(int i = 0; i < GAME_COUNT_TO_PLAY; i++)
{
MathGame.prblm();
while (!p1.Game() && !p2.Game())
{
//Keep track of score here, incriment some counter for winner
//e.g. if(p1.Win) p1Count++;
}
}
After the for loop you can check for who won.
if(p1Count > p2Count)
Display("Player 1 Wins!");
else if(p1Count < p2Count)
Display("Player 2 Wins!")
else
Display("Draw!");
This is a follow up question to a question that I posted last night. I have to write a game in a Windows Form for school, and I am creating a maze game in which a player must navigate through a maze before they are killed. As a maze game, some collision detection must be used to make sure that the player doesn't simply run through the walls (this would be quite a boring game). I've implemented a feature which prevents this based on the question that I asked last night, but I'm getting some weird results.
When the player touches a wall, the game stops them, and the player ends up getting stuck. The player CANNOT move unless they press a combination of keys to move through the wall (my game uses WASD, so if I touch a wall, I can press W + A and go through the wall to the other side where my player gets unstuck).
This is my collision code:
// This goes in the main class
foreach (Rectangle wall in mazeWalls)
{
if (playerRectangle.IntersectsWith(wall))
{
player.Stop();
}
}
This is the player's movement code:
public void Move(Direction dir)
{
// First, check & save the current position.
this.lastX = this.x;
this.lastY = this.y;
if (dir == Direction.NORTH)
{
if (!CheckCollision())
{
this.y -= moveSpeed;
}
else
{
this.y += 1;
}
}
else if (dir == Direction.SOUTH)
{
if (!CheckCollision())
{
this.y += moveSpeed;
}
else
{
this.y -= 1;
}
}
else if (dir == Direction.EAST)
{
if (!CheckCollision())
{
this.x += moveSpeed;
}
else
{
this.x -= 1;
}
}
else if (dir == Direction.WEST)
{
if (!CheckCollision())
{
this.x -= moveSpeed;
}
else
{
this.x += 1;
}
}
}
My CheckCollision() method:
private bool CheckCollision()
{
// First, check to see if the player is hitting any of the boundaries of the game.
if (this.x <= 0)
{
isColliding = true;
}
else if (this.x >= 748)
{
isColliding = true;
}
else if (this.y <= 0)
{
isColliding = true;
}
else if (this.y >= 405)
{
isColliding = true;
}
else if (isColliding)
{
isColliding = false;
}
// Second, check for wall collision.
return isColliding;
}
The Stop() method:
public void Stop()
{
this.x = lastX;
this.y = lastY;
}
Here is a gif that I have uploaded so that you can see the behavior of the player with the maze walls. Notice how he slides through the walls and repeatedly gets stuck.
My question is how do I get this player to stop sticking and actually be able to slide and move with the walls? I've tried multiple collision patterns, and used last night's (very helpful) answer, but he won't stop sticking to the walls! Let me know if you need any other details/information.
EDIT: The Input code, as requested by Dan-o: http://pastebin.com/bFpPrq7g
Game design is a complicated subject. There are some pretty well documented strategies for implementing 2D maze games. The most anyone can do here is to make general suggestions based on what you've done knowing that a commercial game is not what trying to make here. So anyhow, I'll throw in my two cents. I've only done anything like this in OpenGL, not with Windows Forms.
The first thing I see is that your sprite doesn't stay centered in it's lanes. Calculating that will ultimately make things easier because there are always only 4 possible directions that the player can be moving. North, South, East, and West don't mean as much when diagonal is also possible.
Design your gameboard so that your walls and your lanes are the same width. Use evenly spaces rows and columns. Since you're using a fixed board size, this should be as simple as dividing your width and height by the number of rows and columns you want.
Once you've done this, you will always know what lane you're in based on your x and y coordinates. If your columns are 80 pixels wide, for instance, and you're at x = 160 then you know you're in column 2 (1 in a 0-based array). This is the only way you are going to be able to put enemies on the board and be able to programmatically track where they are going. Also, you'll be able to size your players and enemies appropriately for the lanes.
Let's say your rows and columns are 80Wx60H pixels (they can be whatever you like best). Now let's say that your player is moving East starting from 0, 160. And, he can move North and South when he gets to column 3 (2 in a zero-based model), according to your map. Meaning, when he gets to 160, 160. Remember, if x = 0 starts column 1, then 80 starts column 2, and so on.
Forgetting collisions for a moment, you could use logic like this.
RectangleF playerRectangle = new RectangleF();
int COLUMN_WIDTH = 80;
int ROW_HEIGHT = 60;
if (playerRectangle.IntersectsWith(wall)){
int column = playerRectangle.X / COLUMN_WIDTH;
//----------------------------------------------
// This will return false if the player
// is not positioned right at the column. The
// result of % will contain decimal digits.
// playerRectangle.X has to be a float though.
//----------------------------------------------
if(column % 1 == 0){
//--------------------------------------------
// do this based on your keyboard logic. this
// is pseudo-code
//--------------------------------------------
if(keys == keys.UP){
// Move up
}
else if(keys == keys.DOWN){
// Move down
}
}
}
Another thing you'll want to do is to store an orientation property with your walls. That way when you collide with one, you'll know what your options are for movement. If the wall you collide with is WallOrientation.NorthSouth, you can only move North or South once you hit it. Or, you can go in reverse to the direction you hit it from. If no keys are pressed you sit still. Some thing like this will do.
public enum WallOrientation{
NorthSouth,
EastWest
}
None of this code is tested. I just wrote it on the fly so there could be mistakes. I'm just trying to give you some ideas. I hope this advice helps you out some.
I'll get to the point. Having an issue with a beginner level game im coding at the moment. I have 2 lists to store "Objects" that are in the game. One is for "diamonds" pushable blocks that are to be moved onto the "Goals". Once all diamonds are on the goals, the level should change. I'm currently using "GameStates" to load each level. Here is the snippet of my code I'm having issues with. What happens currently is the game will allow me to push the "diamonds" onto the "goals", but the gamestate will not change once I do this. Not sure what I am missing - any help is appreciated. Thankyou for your time!
void Level1Update(KeyboardState cKB, KeyboardState oKB)
{
for (int i = 2; i < diamondlist.Count; i++)
{
if ((Goallist[i].Position == diamondlist[i].Position))
{
CurrentGameState = GameState.Level2;
}
}
}
If I understood correctly, you want to set current game state to the next level only if all the diamonds and goals are on the same tiles. The following code ensures that.
void Level1Update(KeyboardState cKB, KeyboardState oKB)
{
int i;
for (i = 0; i < diamondlist.Count; ++i)
{
if (Goallist[i].Position != diamondlist[i].Position)
break;
}
// When breaked off the loop, i is never equal to list count
if (i == diamondList.Count)
CurrentGameState = GameState.Level2;
}