I'm having some issues loading multiple tiles to my game. My game world currently has a pixel size of 770x450. I have loaded a single tile at position (0, 330), and wanted to make a loop that copies and loads the tile along the x axis until it reaches (770, 330).
I have been able to make this loop, however upon every loop, the next tile doesn't load, it just moves to the next position, here's the loop:
for (int i = 0; i < 770; i += 31)
{
position = new Vector2(i, 330);
// Some sort of draw method here!
if (i == 744)
{
i = i + 26;
// or here...
position = new Vector2(i, 330);
// or maybe here?
}
}
And if this helps, here's my current Draw() method:
spriteBatch.Begin();
spriteBatch.Draw(gameTile, position, Color.White);
spriteBatch.End();
You're only drawing the tile once. You can tell because you only have one spriteBatch.Draw() call. It doesn't do enough to just update the position inside the loop. You have to draw it at each location as well.
public void Draw()
{
spriteBatch.Begin();
for (int i = 0; i < 770; i += 31)
{
position = new Vector2(i, 330);
if (i == 744)
{
i = i + 26;
position = new Vector2(i, 330);
}
spriteBatch.Draw(gameTile, position, Color.White);
}
spriteBatch.End();
}
Of course, you want to avoid all that loopy logic in the Draw() method. The only way around that is to create a tile for every position you want it drawn at in your Update() method. Then the Draw() method could just loop through all of your gameTiles and draw them at their corresponding position.
Related
I have six or more sprites that are hidden, alpha set to 0. I move the sprites to a starting position at the top of the screen before showing them. Once in the new position I show them and the moving them back to their original positions.
My issue is that the sprites are show just for a couple of milliseconds before they are moved to the starting point. Even though the order of the code is move first then show.
I tried to find a position moved callback to detect when the position change is complete before showing but I don't this it is possible.
void Start() {
int i = 0;
foreach (Transform point in drawingPoints.transform)
{
//Record points original postion
Vector3 currentPosition = point.transform.position;
//Move to new starting position
point.transform.position = stepOne.transform.position;
//Now show point
var color = point.gameObject.GetComponent<SpriteRenderer>().color;
color.a = 1;
point.gameObject.GetComponent<SpriteRenderer>().color = color;
//Move point back to original postion
point.transform.DOMove(currentPosition, 1f).SetDelay(UnityEngine.Random.Range(0f, 0.3f));
i += 1;
}
}
Consider disabling the sprite renderer till the transform is at the start point.
void Start()
{
int i = 0;
foreach (Transform point in drawingPoints.transform)
{
SpriteRenderer spriteRenderer = point.gameObject.GetComponent<SpriteRenderer>();
if(spriteRenderer == null)
continue;
// Disable the renderer.
spriteRenderer.enabled = false;
//Record points original postion
Vector3 currentPosition = point.transform.position;
//Move to new starting position
point.transform.position = stepOne.transform.position;
// Now you're at start point, enable it back.
spriteRenderer.enabled = true;
//Move point back to original postion
point.transform.DOMove(currentPosition, 1f).SetDelay(UnityEngine.Random.Range(0f, 0.3f));
i += 1;
}
}
If for whatever reason or weird behaviour of unity you wanna get a callback when something is at a position, here's a hacky way
transformToMove.DoMove(destination, 0).OnComplete(()=>
{
// Now you're at the point.
});
Currently I try to write a 2D roulette wheel in C# using Monogame as framework.
I'm quiet experienced with Monogame but I never had to manage fast moving textures to stick together tho.
The idea is that 3 textures(black, red, green) are connected to each other in a line of 15 objects.
That's fine as long as I don't start to scroll all these objects to actually "make the wheel move".
After moving for a while, the textures are no more connected to each other. They get some space in between or start to overlap.
I made a short Video to clarify the problem: https://puu.sh/vwbyU/d396c6ad99.mp4 (It's about 10 MB, some Browsers may have download it before it shows up)
This is the most important code:
const int _roulleteOffset = 170; // X coordinate to start at
Sprite[] fieldList = new Sprite[15]; // Represents my wheel (Array of my roulette fields/textures)
Rectangle scrollArea; // Fixed Area for the complete fieldList
float scrollSpeed = 0.0f; // Scrollspeed of the wheel. 0 on start.
// First I call the Content.Load to fill fieldList.Texture then
// this is called to position the "wheel" objects
private void AdditionalInit()
{
for (int i = 0; i < fieldList.Length; i++)
{
fieldList[i].Position = new Vector2(_roulleteOffset + i * fieldList[i].Texture.Width, Statics.GAME_WINDOW_HEIGHT / 2 - fieldList[i].Texture.Height / 2);
}
scrollArea = new Rectangle((int)fieldList[0].Position.X, (int)fieldList[0].Position.Y, fieldList[0].Texture.Height * fieldList.Length + 30, fieldList[0].Texture.Height);
}
// This Method is called in Update() - And I guess the problem has to be fixed here
private void ScrollRoulette()
{
for (int i = 0; i < fieldList.Length; i++)
{
fieldList[i].position.X += scrollSpeed; // scrollSpeed is set with pressing + or - on keyboard
if (fieldList[i].Position.X >= scrollArea.Width + fieldList[i].Texture.Width)
{
// After leaving the "scrollArea" set it to the start of it (Leaving on right side and entering at the left side again)
fieldList[i].position.X = scrollArea.X - fieldList[i].Texture.Width;
}
}
}
// The part of my Draw Method. But I don't think that I made a mistake here
public override void Draw(GameTime gameTime)
{
Statics.SPRITEBATCH.Begin(SpriteSortMode.BackToFront, BlendState.AlphaBlend);
for (int i = 0; i < fieldList.Length; i++)
{
Statics.SPRITEBATCH.Draw(fieldList[i].Texture, fieldList[i].Position, null, Color.White, 0f, Vector2.Zero, 1f, SpriteEffects.None, 0f);
}
Statics.SPRITEBATCH.End();
}
Just watch the Video to understand what I'm talking about. Maybe you can help me with it. Even on slow speed the textures starts to disconnect or overlap over time.
With help from another german forum I resolved the problem! Thanks god. Took me a whole day these 1 line. I just had to adjust the positioning of the incoming tile. Not just set pos.x to the start.
private void ScrollRoulette()
{
for (int i = 0; i < fieldList.Length; i++)
{
fieldList[i].position.X += scrollSpeed;
if (fieldList[i].Position.X >= scrollArea.Width + (fieldList[i].Texture.Width * 2))
{
// This works now
fieldList[i].position.X = scrollArea.X + (fieldList[i].Position.X - (scrollArea.Width + scrollArea.X) );
}
}
}
Hello there wonderful people!
Let's just cut to the chase.
I've made a tile engine that draws my map relative to my camera (The tiles that are drawn are the ones visible in the camera window), and i've made a sprite (my character) that is centered within the camera.
Whenever i move the camera my character follows accordingly, the only problem is when i reach the borders of my map. Programing the way i did has constrained my camera from moving beyond the borders, resulting in limiting my character from moving closer to the borders(since it's always centered within the camera).
How do i free my camera from the restraints of my evil map?
p.s. I've made a picture to illustrate what i want to do.
And here is the guide i followed.
Here's my code where i draw the tiles and place the camera:
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.Black);
spriteBatch.Begin();
Vector2 firstSquare = new Vector2(Camera.Location.X / Tile.TileWidth, Camera.Location.Y / Tile.TileHeight);
int firstX = (int)firstSquare.X;
int firstY = (int)firstSquare.Y;
Vector2 squareOffset = new Vector2(Camera.Location.X % Tile.TileWidth, Camera.Location.Y % Tile.TileHeight);
int offsetX = (int)squareOffset.X;
int offsetY = (int)squareOffset.Y;
for (int y = 0; y < squaresDown; y++)
{
for (int x = 0; x < squaresAcross; x++)
{
foreach (int tileID in myMap.Rows[y + firstY].Columns[x + firstX].BaseTiles)
{
spriteBatch.Draw(
Tile.TileSetTexture,
new Rectangle(
(x * Tile.TileWidth) - offsetX, (y * Tile.TileHeight) - offsetY,
Tile.TileWidth, Tile.TileHeight),
Tile.GetSourceRectangle(tileID),
Color.White);
}
}
}
spriteBatch.End();
// TODO: Add your drawing code here
base.Draw(gameTime);
}
And here is the code where i move the camera:
protected override void Update(GameTime gameTime)
{
// Allows the game to exit
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
this.Exit();
IsMouseVisible = true;
KeyboardState ks = Keyboard.GetState();
if (ks.IsKeyDown(Keys.A))
{
Camera.Location.X = MathHelper.Clamp(Camera.Location.X - 2, 0, (myMap.MapWidth - squaresAcross) * Tile.TileWidth);
}
if (ks.IsKeyDown(Keys.D))
{
Camera.Location.X = MathHelper.Clamp(Camera.Location.X + 2, 0, (myMap.MapWidth - squaresAcross) * Tile.TileWidth);
}
if (ks.IsKeyDown(Keys.W))
{
Camera.Location.Y = MathHelper.Clamp(Camera.Location.Y - 2, 0, (myMap.MapHeight - squaresDown) * Tile.TileHeight);
}
if (ks.IsKeyDown(Keys.S))
{
Camera.Location.Y = MathHelper.Clamp(Camera.Location.Y + 2, 0, (myMap.MapHeight - squaresDown) * Tile.TileHeight);
}
// TODO: Add your update logic here
base.Update(gameTime);
}
Instead of making your player follow the camera, you need to make your camera follow the player. That way you can set restrictions on the camera, instead of attempting to hack the camera system to make the character do things.
On every update, you would have something like:
Player.Update(gametime);
Camera.Update(Player.Position);
I'm pretty new to XNA|C# and what I want to do is simply move a sprite between two points and have it move back and forth continuously.
Let's say I want the sprite to move between the y-coordinate 100 and 0.
How would I accomplish this?
Your question has nothing to do with XNA itself. You are asking how to move an object in a straight line and that is something that is usually learnt in first year geometry.
I'll assume you are drawing your texture like this:
SpriteTexture sprite;
Vector2 position;
...
protected override void Draw(GameTime gameTime)
{
graphics.GraphicsDevice.Clear(Color.CornflowerBlue);
spriteBatch.Begin();
spriteBatch.Draw(sprite, position, Color.White);
spriteBatch.End();
base.Draw(gameTime);
}
A straight line is an extremely simple path - it is easily defined by two points. Let the points be P1 and P2. The straight line is then defined as the function (1 - t) * P1 + t * P2 where 0 <= t <= 1. To move the sprite, start from t = 0 and increment t in each update cycle. Computing the function with the given t gives you the position of the sprite. When t >= 1 you've reached P2, this means you should start decrementing t back to 0 and so on and so forth. Here's how to use that fact to move the sprite:
SpriteTexture sprite;
Vector2 position;
Vector2 p1 = new Vector2(0, 100),
p2 = new Vector2(0, 0);
double currentTime = 0, timestep = 0.01;
...
protected override void Update(GameTime gameTime)
{
position = currentTime * p1 + (1 - currentTime) * p2;
currentTime += timestep;
if (currentTime >= 1 || currentTime <= 0)
{
timestep *= -1;
}
}
Here is how XNA works, every frame it calls the methods update and draw in your game's main page. We need to keep track of which direction your sprite is moving and its position so lets add to your main game file:
public Vector2 rectanglePosition = new Vector2(0,0);
public bool moveRight = true;
Now what you want to do is every frame update the position, and use it to draw an object. So in the update method you would have something like
if (moveRight)
rectanglePosition.Y += 10;
else
rectanglePosition.Y -= 10;
if(rectanglePosition.Y>100 || rectanglePosition.Y<0)
moveRight = !moveright;
Then in the draw method just draw the sprite based on the position (you can start by just drawing a rectangle), which you can look up how to do easily.
I can further help you if you don't get the code.
I am attempting to create a 2d scrolling XNA game as a learning exercise, but have run into some issues with the scrolling background. I am loading a level from a text file, parsing through to create the appropriate tiles and store them in a matrix (tiles[,]).
I then have an update method which alters the position of the tile so when it is redrawn it will move.
Currently, I loop through all tiles to draw them all before moving. This is clearly not very efficient. Ideally, I only want to draw the tiles on the screen. I can do this by taking the viewport and using the height/width of a tile to determine how many tiles will fit on the screen and only loop through those tiles, as follows:
private void DrawTiles(SpriteBatch spriteBatch)
{
float tileWidth = 40;
float tileHeight = 32;
for (int y = 0; y < (int)Math.Ceiling(mViewport.Height / tileHeight); ++y)
{
for (int x = 0; x < (int)Math.Ceiling(mViewport.Width / tileWidth); ++x)
{
tiles[x, y].Draw(spriteBatch);
}
}
}
However, this only draws the iles in the original viewport. Tiles outside will never be drawn even though their position does come into view.
I think this can be resolved by using a counter to start and end the loop, incrementing it each time the draw method is called. However, I do not think this is a great solution, but alas I cannot think of a better way to ensure only tiles in the viewport are drawn.
You need to keep track of the starting X and Y of the ViewPort, as you're always starting at 0 in your example. e.g.
var startX = 10; // Should increment as viewport scrolls
var startY = 10; // Should increment as viewport scrolls
...
for (int y = startY; y < (int)Math.Ceiling(mViewport.Height / tileHeight); ++y)
{
for (int x = startX; x < (int)Math.Ceiling(mViewport.Width / tileWidth); ++x)
{
tiles[x, y].Draw(spriteBatch);
}
}
On a side note, your ViewPort probably has a Top and Left or X and Y to keep track of this as well. In that case, replace startX and startY with the appropriate property from your ViewPort.
What I implemented in my design was an inherited interface that contained the properties IsInView and a collision property or in your case a position could be substituted. I then created a seperate thread that would loop through and determine if the object is in view. you can then in each object have the InView and OutView add and remove it from a draw list.
Run from seperate thread with a loop. -- This could be adapted to determine if the tile is visible
public void CalculateObjsInView()
{
foreach (Obj o in new List<Obj>(ObjInstanceList))
{
if (o == null)
continue;
if (Camera.CollisionMask.Intersects(o.CollisionMask))
o.IsInView = true;
else
o.IsInView = false;
}
}
In Obj class
private bool _isInView = false;
public bool IsInView
{
get { return _isInView; }
set
{
if (_isInView != value)
{
if (value)
InView();
else
OutView();
}
_isInView = value;
}
}
private void InView()
{
Game.ObjectDrawEventHandler.Add(Draw);
}
private void OutView()
{
Game.ObjectDrawEventHandler.Remove(Draw);
}