How to make monster move left then right continuously C# XNA - c#

i'm making my first game on XNA for my class. I'm trying to make the monsters move left and right automatically. I have total 4 monsters for now. I'm trying to get them move left then right within the screen.
//Monster movements
for (int i = 0; i < numOfMonster; i++)
{
if (destinationMonster[i].X >= screenWidth - 60)
{
while(destinationMonster[i].X != -10)
moveLeft = true;
}
else
{
moveRight = true;
}
if (moveLeft)
{
int temp = destinationMonster[i].X;
temp = destinationMonster[i].X - monsterSpeed;
//This prevents the object passing the screen boundary
if (!(temp < -10))
{
destinationMonster[i].X = temp;
}
moveLeft = false;
}
if (moveRight)
{
int temp = destinationMonster[i].X;
temp = destinationMonster[i].X + monsterSpeed;
//This prevents the object passing the screen boundary
if (!(temp > screenWidth - 50))
{
destinationMonster[i].X = temp;
}
moveRight = false;
}
}

Your first problem is your while statement, once you enter it you are not going to exit because you are not changing your X value. If it were me I would have a bool array variable corresponding to each of your monsters. I would also change your conditional to trigger the change of the boolean value once the monster has reached the extents at either end. Something like this.
if (destinationMonster[i].X >= screenWidth - 60)
{
moveRight[i] = false ;
}
else if (destinationMonster[i].X <= -10)
{
moveRight[i] = true ;
}

Related

How to debug a recursive function in unity C#

Im trying to make a maze generator using recursion. Its not working how its supposed to work, and Im trying to figure out where the error is. So I want to step through the recursion 1 iteration at the time. How do I do this?
private void DevideRecursive(int pMinX, int pMaxX, int pMinY, int pMaxY)
{
int randomX = Random.Range(pMinX +1, pMaxX);
int randomY = Random.Range(pMinY +1, pMaxY);
int randomWall = Random.Range(0, 4);
List<GameObject> WalllistX1 = new List<GameObject>();
List<GameObject> WalllistX2 = new List<GameObject>();
List<GameObject> WalllistY1 = new List<GameObject>();
List<GameObject> WalllistY2 = new List<GameObject>();
List<List<GameObject>> MainWallList = new List<List<GameObject>>();
MainWallList.Add(WalllistX1);
MainWallList.Add(WalllistX2);
MainWallList.Add(WalllistY1);
MainWallList.Add(WalllistY2);
//// add a wall on a random x coordinate
for (int x = pMinX; x < pMaxX; x++)
{
GameObject wall = Instantiate(WallHor);
wall.transform.position = new Vector2(tilesize * x + tilesize / 2, tilesize * randomY);
if (x < randomX)
{
WalllistX1.Add(wall);
}
else
{
WalllistX2.Add(wall);
}
}
//// add a wall on a random y coordinate
for (int y = pMinY; y < pMaxY ; y++)
{
GameObject wall = Instantiate(WallVer);
wall.transform.position = new Vector2(tilesize * randomX, tilesize * y + tilesize / 2);
if (y < randomY)
{
WalllistY1.Add(wall);
}
else
{
WalllistY2.Add(wall);
}
}
//make a hole in 3 out of tht 4 walls randomly
for (int i = 0; i < MainWallList.Count; i++)
{
if (randomWall != i)
{
RemoveWall(MainWallList[i]);
}
}
////
////
//// If either of the walls have a cell with only 1 grid stop the recursion
Debug.Log("randomX - pMinX:" + (randomX - pMinX));
Debug.Log("pMaxY - randomY:" + (pMaxY - randomY));
Debug.Log("pMaxX - randomX:" + (pMaxX - randomX));
Debug.Log("randomY - pMinY:" + (randomY - pMinY));
if (!(randomX - pMinX <= 1) || !(pMaxY - randomY <= 1))
{
Debug.Log("a");
DevideRecursive(pMinX, randomX, randomY, pMaxY);
}
else
{
return;
}
if (!(pMaxX - randomX <= 1) || !(pMaxY - randomY <= 1))
{
Debug.Log("b");
DevideRecursive(randomX, pMaxX, randomY, pMaxY);
}
else
{
return;
}
if (!(randomX - pMinX <= 1 )|| !(randomY - pMinY <= 1))
{
Debug.Log("c");
DevideRecursive(pMinX, randomX, pMinY, randomY);
}
else
{
return;
}
if (!(pMaxX - randomX <= 1) || !(randomY - pMinY <= 1))
{
Debug.Log("d");
DevideRecursive(randomX, pMaxX, pMinY, randomY);
}
else
{
return;
}
}
This is my Recursive method. It get called in the Start function.
The method creates 2 random walls(1 vertical, 1 horizontal). Which devides the room in 4 smaller rooms. Then it does the same thing for those rooms.
Any help is appriciated
You could modify the function to use async.
using System.Threading.Tasks;
void Start () {
DevideRecursive( ..params.. );
}
private async void DevideRecursive(int pMinX, int pMaxX, int pMinY, int pMaxY) {
// code
while (!Input.GetKeyDown(KeyCode.Space))
await Task.Yield ();
// code
DevideRecursive( .. params .. );
return
}
More infomation on aysnc in Unity here.
An IEnumerator could also be used, which gives you the option to control the function externally.

When calculating the space for each direction when the grid size is multiply by 1.5 the directions are wrong why?

If the grid is 10x10 or 23x7 it's working fine but when the grid have 1.5 spaces between the cubes the directions sometimes are wrong.
This is the grid script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class GridGenerator : MonoBehaviour
{
public GameObject gridBlock;
public int gridWidth = 10;
public int gridHeight = 10;
public GameObject[] allBlocks;
private GameObject[] wallsParents = new GameObject[4];
void Start()
{
wallsParents[0] = GameObject.Find("Top Wall");
wallsParents[1] = GameObject.Find("Left Wall");
wallsParents[2] = GameObject.Find("Right Wall");
wallsParents[3] = GameObject.Find("Bottom Wall");
GenerateGrid();
allBlocks = GameObject.FindGameObjectsWithTag("Blocks");
var findpath = GetComponent<PathFinder>();
findpath.FindPath();
}
public void AutoGenerateGrid()
{
allBlocks = GameObject.FindGameObjectsWithTag("Blocks");
for (int i = 0; i < allBlocks.Length; i++)
{
DestroyImmediate(allBlocks[i]);
}
var end = GameObject.FindGameObjectWithTag("End");
DestroyImmediate(end);
GenerateGrid();
allBlocks = GameObject.FindGameObjectsWithTag("Blocks");
var findpath = GetComponent<PathFinder>();
findpath.FindPath();
}
public void GenerateGrid()
{
for (int x = 0; x < gridWidth; x++)
{
for (int z = 0; z < gridHeight; z++)
{
GameObject block = Instantiate(gridBlock, Vector3.zero, gridBlock.transform.rotation) as GameObject;
block.transform.parent = transform;
block.transform.name = "Block";
block.transform.tag = "Blocks";
block.transform.localPosition = new Vector3(x * 1.5f, 0, z * 1.5f);
block.GetComponent<Renderer>().material.color = new Color(241, 255, 0, 255);
if (x == 0)//TOP
{
block.transform.parent = wallsParents[0].transform;
block.transform.name = "TopWall";
block.transform.tag = "Blocks";
}
else if (z == 0)//LEFT
{
block.transform.parent = wallsParents[1].transform;
block.transform.name = "LeftWall";
block.transform.tag = "Blocks";
}
else if (z == gridHeight - 1)//RIGHT
{
block.transform.parent = wallsParents[2].transform;
block.transform.name = "RightWall";
block.transform.tag = "Blocks";
}
else if (x == gridWidth - 1)//BOTTOM
{
block.transform.parent = wallsParents[3].transform;
block.transform.name = "BottomWall";
block.transform.tag = "Blocks";
}
}
}
}
}
On this line i'm adding the spaces between the cubes:
block.transform.localPosition = new Vector3(x * 1.5f, 0, z * 1.5f);
Then in another script i'm trying to find what directions next are possible to move to.
private void Directions()
{
GridGenerator gridgenerator = GetComponent<GridGenerator>();
Vector3 playerPosition;
playerPosition = player.localPosition;
if (playerPosition.x > 0)
{
// can go left
possibleDirections[0] = "Can go left";
}
else
{
possibleDirections[0] = "Can't go left";
}
if (playerPosition.x + 1 < gridgenerator.gridWidth * 1.5f)
{
// can go right
possibleDirections[1] = "Can go right";
}
else
{
possibleDirections[1] = "Can't go right";
}
if (playerPosition.z > 0)
{
// can go backward
possibleDirections[2] = "Can go backward";
}
else
{
possibleDirections[2] = "Can't go backward";
}
if (playerPosition.z + 1 < gridgenerator.gridHeight * 1.5f)
{
// can go backward
possibleDirections[3] = "Can go forward";
}
else
{
possibleDirections[3] = "Can't go forward";
}
}
possibleDirections is array string type
When the grid size is 10x10 without spaces between cubes this two lines:
if (playerPosition.x + 1 < gridgenerator.gridWidth * 1.5f)
if (playerPosition.z + 1 < gridgenerator.gridHeight * 1.5f)
Was:
if (playerPosition.x + 1 < gridgenerator.gridWidth)
if (playerPosition.z + 1 < gridgenerator.gridHeight)
But when i added the spaces between the cubes i tried to add to the gridgenerator.gridWidth and gridgenerator.gridHeight the * 1.5
But it didn't work so i tried also:
if (playerPosition.x + 1 < gridgenerator.gridWidth * (1 + 1.5))
if (playerPosition.z + 1 < gridgenerator.gridHeight * (1 + 1.5))
1 is the cube width and 1.5 is the space. But this is not working good either.
In the screenshot the player is in the top left corner facing up(forward)
He can't move forward but in the inspector it says "Can go forward" And should be "Can't go forward"
It only happens when there are spaces between the cubes.
This line is wrong:
if (playerPosition.x + 1 < gridgenerator.gridWidth * 1.5f)
Your gridWidth variable stores the number of cubes, not their collective spacing. You have 10 cubes representing move spaces, determining the out-of-bounds this value should remain constant (it's still only 10 cubes, even if they're spaced with a half-block worth of space between them).
You need to convert from the player's scene location (transform.position.x) to a board space location (likely dividing by the same multiplier used to space the cubes out).
Alternatively, the "this makes my soul cry" solution of doing this:
if (playerPosition.x + 1.5f < gridgenerator.gridWidth * 1.5f)
Because the next cube is 1.5 scene units away, not 1. And this makes my soul cry because it makes your code full of hard-coded 1.5f multipliers and offsets rather than keeping such things to a single, fixed, constant value stored Elsewhere and used sparingly.
Related:
possibleDirections[0] = "Can go left";
Why are you using stringly typed things? There are values called booleans for a reason...

XNA - Mouse.Left Button gets executed more than once in Update

I am making a Tic-Tac-Toe game. I need to check if a player is clicking on a square they have already clicked.
Problem is error is shown in the first click itself.
My update code is:
MouseState mouse = Mouse.GetState();
int x, y;
int go = 0;
if (mouse.LeftButton == ButtonState.Pressed)
{
showerror = 0;
gamestate = 1;
x = mouse.X;
y = mouse.Y;
int getx = x / squaresize;
int gety = y / squaresize;
for (int i = 0; i < 3; i++)
{
if (go == 1)
{
break;
}
for (int j = 0; j < 3; j++)
{
if (getx == i && gety == j)
{
if (storex[i, j] == 0)
{
showerror = 1;
}
go = 1;
if (showerror != 1)
{
loc = i;
loc2 = j;
storex[i, j] = 0;
break;
}
}
}
}
}
showerror is set to 0 whenever left button is clicked. My matrix is a 3x3 matrix for storing information. If it is 0 that means it has been already clicked.So in the loop I check if store[i,j] == 0 then set showerror to 1.
Now in the draw function I made this call for showerror
spriteBatch.Begin();
if (showerror == 1)
{
spriteBatch.Draw(invalid, new Rectangle(25, 280, 105, 19), Color.White);
}
spriteBatch.End();
Problem is whenever i click on empty square it turns into cross but error gets shown.Please help me out
How to Fix:
Add a new global variable to store the mouse state from the previous frame:
MouseState oldMouseState;
At the very beginning (or end) of your update method, add this,
oldMouseState = mouse;
And replace
if (mouse.LeftButton == ButtonState.Pressed)
with
if (mouse.LeftButton == ButtonState.Pressed && oldMouseState.LeftButton == ButtonState.Released)
What this does is check if you made one click, having the key released then pressing, because sometimes you may hold the key for multiple frames.
To Recap:
By setting oldMouseState before you update the currentMouseState (Or after you are done with it), you garantee that oldMouseState will be one frame behind currentMouseState. Using this you can check if a button was down the previous frame, but not anymore, and handle input accordingly. A good idea to extend this is write some extension methods like IsHolding(), IsClicking(), etc.
In simple code:
private MouseState oldMouseState, currentMouseState;
protected override void Update(GameTime gameTime)
{
oldMouseState = currentMouseState;
currentMouseState = Mouse.GetState();
//TODO: Update your code here
}

XNA - 2D collision failure without any obvious pattern

Alright, so I am pretty new to XNA programming and I am trying to code a platformer. I have implemented pixel-perfect collision but it seems to fail for no apparent reason sometimes (I couldn't figure out a pattern) and the hero sprite goes through platforms.
static bool IntersectsPixel(Rectangle rect1, Color[] data1, Rectangle rect2, Color[] data2)
{
int top = Math.Max (rect1.Top, rect2.Top);
int bottom = Math.Min(rect1.Bottom, rect2.Bottom);
int left = Math.Max (rect1.Left,rect2.Left);
int right = Math.Min(rect1.Right,rect2.Right);
//Top
for(int y = top; y<bottom;y++)
for (int x = left; x < right; x++)
{
Color color1 = data1[x-rect1.Left + (y-rect1.Top) * rect1.Width];
Color color2 = data2[x - rect2.Left + (y - rect2.Top) * rect2.Width];
if (color1.A != 0 && color2.A != 0)
return true;
}
return false;
}
And here's the Update Method
protected override void Update(GameTime gameTime)
{
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
this.Exit();
foreach(Platform platform in platformList)
{
Rectangle check = new Rectangle(hero.GetRectangle().X - 300, hero.GetRectangle().Y - 300, 600, 600);
if(check.Intersects(platform.rectangle))
if (IntersectsPixel(hero.GetRectangle(), hero.textureData, platform.rectangle, platform.platformTextureData))
{
int direction = CheckDirection(platform,hero);
if (hero.hasJumped == true && direction == 3 && hero.velocity.Y <= 0 )
{
hero.velocity.Y = 0f;
hero.SetPosition(new Vector2((float)hero.GetPosition().X, (float)platform.rectangle.Bottom));
break;
}
else
if (direction == 4 && hero.velocity.X >= 0)
{
hero.velocity.X = 1;
hero.SetPosition(new Vector2((float)platform.rectangle.Left - (float)hero.GetRectangle().Width, (float)hero.GetPosition().Y));
break;
}
else
if (direction == 2 && hero.velocity.X <= 0)
{
hero.velocity.X = -1;
hero.SetPosition(new Vector2((float)platform.rectangle.Right - 1, (float)hero.GetPosition().Y));
break;
}
else
if (direction == 1 && hero.velocity.Y >= 0)
{
hero.velocity.Y = 0;
hero.hasJumped = false;
hero.SetPosition(new Vector2((float)hero.GetRectangle().X, (float)platform.rectangle.Y - (float)hero.GetRectangle().Height + 1));
hero.SetRectangle(new Rectangle((int)hero.GetPosition().X, (int)hero.GetPosition().Y, (int)hero.GetSize().X, (int)hero.GetSize().Y));
break;
}
}
}
hero.Update(gameTime);
camera.Update(gameTime, hero, screenBounds);
base.Update(gameTime);
}
And here's the direction check:
private int CheckDirection(Platform platform,Hero hero)
{
int distance = Math.Abs(platform.rectangle.Top - hero.GetRectangle().Bottom);
int direction = 1; //Top
if (distance > Math.Abs(platform.rectangle.Right - hero.GetRectangle().Left))
{
distance = Math.Abs(platform.rectangle.Right - hero.GetRectangle().Left);
direction = 2;
}
if (distance > Math.Abs(platform.rectangle.Bottom - hero.GetRectangle().Top))
{
distance = Math.Abs(platform.rectangle.Bottom - hero.GetRectangle().Top);
direction = 3;
}
if (distance > Math.Abs(platform.rectangle.Left - hero.GetRectangle().Right))
{
direction = 4;
distance = Math.Abs(platform.rectangle.Left - hero.GetRectangle().Right);
}
return direction;
}
Those are all my functions related to collision detection. If you happen to have any ideea of what might cause this, please let me know.
Thank you very much !
One thing I see that might be a possible reason is that right in the beginning where you build a box around both objects:
int top = Math.Max (rect1.Top, rect2.Top);
int bottom = Math.Min(rect1.Bottom, rect2.Bottom);
int left = Math.Max (rect1.Left,rect2.Left);
int right = Math.Min(rect1.Right,rect2.Right);
Unless you flipped it, typically XNA's Y grows positive as you go down (not up). This means you would actually want to take the Max of Bottom, and the Min of Top, since Top will always be less than Bottom. It looks like you already knew that though by the look of this line:
for(int y = top; y<bottom;y++)
I'll keep looking (it's difficult to test without the actual project). Another recommendation I'd give you is to do some debug drawing. Draw where the intersection functions thinks that pixels are touching or not touching.
Because of lag, Your character could be moving more than the blocks height per frame, so the collision may think it is in between blocks, and cause it to fly through.
https://gamedev.stackexchange.com/questions/30458/platformer-starter-kit-collision-issues
Check that out, It solved the problem for me.
Either slowing down movement, or clamping the change in position to the size of a block should solve this.

SpriteSheet Animation with XNA

I'm working on my First 2D Game with XNA and I have a little problem.
To give a running effect to my Sprite, I scroll through a SpriteSheet with this code(running right):
if (AnimationDelay == 6)
{
if (CurrentFrameR.X < SheetSizeR.X)
{
++CurrentFrameR.X;
}
else
{
CurrentFrameR.Y++;
CurrentFrameR.X = 1;
}
if (CurrentFrameR.Y >= SheetSizeR.Y)
{
CurrentFrameR.X = 0;
CurrentFrameR.Y = 0;
}
AnimationDelay = 0;
}
else
{
AnimationDelay += 1;
}
xPosition += xDeplacement;
}
And these are the objects used :
Point FrameSizeR = new Point(29, 33);
Point SheetSizeR = new Point(5, 1);
Point CurrentFrameR = new Point(0, 0);
int AnimationDelay = 0;
I have the same Code with different SpriteSheet when the sprite is running Left.
Everything is working fine I'd say 90% of the time but the other 10% the sprite animation stays on one Frame of the SpriteSheet, on both directions(left and right) and it stays stuck until I close the program.
The thing is I can't quite figure out why since it never happens at the same moment..Sometimes after 10,15,30 seconds and sometimes even on boot!
Any idea why?
Thanks in advance and let me know if you need any other parts of the code
Your code can be rewrited this way:
ElapsedTimeFrame += (float) GameTime.ElapsedTime.TotalSeconds;
if (ElapsedTimeFrame >= TimePerFrame)
{
CurrentFrameR.X = (CurrentFrameR.X + 1) % SheetSizeR.X;
if (CurrentFrameR.X == 0)
{
CurrentFrameR.Y = (CurrentFrameR.Y + 1) % SheetSizeR.Y;
}
ElapsedTimeFrame-= TimePerFrame;
}
But you have to show more code to guess what happens...

Categories