Check the border of a sprite in XNA? - c#

I'm trying to use Window.ClientBounds.Width to check if the sprite is within the windows border. I want to use this in the another class than the Game1.cs. Let's say I have a Car.cs class and inside that class I want to have an own Update method that check if it's inside the borders of the window, but I cant use Window.ClientBounds.Width this!? I have also tested to create a static int gameBorder = Window.ClientBounds.Width; inside Game1.cs and reach the value that way, but this doesn't work either?! Help is preciated! Thanks!
Is there a better way than stackowerflow for XNA questions that is free?

When constructing the Car class I would pass a reference to the Game that the car is supposed to be part of or the GraphicsDevice that it's supposed to be displayed on.
class Car
{
// Keep a reference to the game inside the car class.
Game game;
public Car (Game game)
{
this.game = game;
}
public void Update(.....
{
// You can access the client bounds here.
// the best thing about this method is that
// if the bounds ever changes, you don't have
// to notify the car, it always has the correct
// values.
}
}

There's no need to go to all that work, and waste all that memory.
XNA has a very exact and specific means of testing positions of objects.
You can simply pass in the GraphicsDeviceManager graphics.PreferredBackBufferWidth and Height methods to get the width and height of your window.
From there, you know whether an object is visible in the game window based on whether it is within the rectangle of those positions.
So lets say you set your back buffer width and height to be 640x480.
Then you would simply check to see if the bounds of your texture are within that rectangle.
So, here's your function:
public void CheckIfWithinWindow(int width, int height)
{
Rectangle wndRect = new Rectangle(0, 0, width, height);
Rectangle carRect = new Rectangle(carPos.X, carPos.Y, carTexture.Width, carTexture.Height);
if (wndRect.Intersects(carRect))
{
//carTexture is within currently visible window bounds!
}
else
{
//carTexture is NOT within currently visible window bounds!
}
}
Then you can call this function from your Update Method in your starting XNA class like so.
public void Update(GameTime gameTime)
{
myCar.CheckIfWithinWindow(graphics.PreferredBackBufferWidth, graphics.PreferredBackBufferHeight);
}
Hope that helps. Have fun.

Related

My snake program won't show the objects I drew. How can I fix it?

I'm following a snake tutorial right now and I wrote the exact thing as said, but it won't even show the rectangles of the snake and food.enter code here
I'm using Windows Form Application.
I made separate classes - Food; Snake; And the one for the form.
//Snake class
public Rectangle[] Body;
private int x = 0, y = 0, width = 20, height = 20;
public Snake()
{
Body = new Rectangle[1];
Body[0] = new Rectangle(x, y, width, height);
}
public void Draw()
{
for (int i = Body.Length - 1; i < 0; i--)
Body[i] = Body[i - 1];
}
public void Draw (Graphics graphics)
{
graphics.FillRectangles(Brushes.AliceBlue, Body);
}
public void Move (int direction)
{
Draw();
//Food Class
public class Food
{
public Rectangle Piece;
private int x, y, width = 20, height = 20;
public Food(Random rand)
{
Generate(rand);
Piece = new Rectangle(x, y, width, height);
}
public void Draw(Graphics graphics)
{
Piece.X = x;
Piece.Y = y;
graphics.FillRectangle(Brushes.Red, Piece);
You are not inheriting your body and food classes from any form of drawable context objects. So the "draw" routine would need to be explicitly called any time a change happens. You appear to be trying to mimic the structure of a WinForms UI component, where it has its own built-in Draw() method that is implicitly called any time the UI needs to update.
Also, since you are calling "Draw" without any parameters, that should be throwing an error unless you have an overload somewhere that doesn't require parameters. In which case, there would be no graphics context to draw to.
I'm no expert in doing game graphics, but I do know that constantly calling the redraw method of a UI component is exceptionally inefficient. There are overrides for the Invalidate() method where you can provide rectangles to invalidate only small portions of the entire component. That can help with improving redraw rate.
I would suggest having a single renderable UI component on screen that links to your data objects. And override the draw() method of that component so that it draws the entire game board (or portions of it based on the invalidated regions), based on the data stored in your game objects.

XNA Adding a Texture2D to Main Constructor

I have a class named Ball (for pong project) and I need to pass the Texture2D through the Main Constructor as so:
Ball.cs
public class Ball
{
Texture2D _ballSprite;
private float _ballSpeed;
private Vector2 _ballMovement;
private Vector2 _ballPosition;
private const int WINDOW_WIDTH = 800;
private const int WINDOW_HEIGHT = 600;
public Ball(Texture2D sprite)
{
_ballSprite = sprite;
}
and then in the Main
Game1.cs
Ball ball = new Ball();
What should I pass though the parameters in Main to have the Texture2D appear?
You shouldn't pass Texture2D in constructor. Graphic resources like Texture2D can become disposed while game is running in event of graphic device being reset. And you will need a new instances of all Texture2D objects each time that happens.
Therefore in XNA all content loading of graphical resources should be done inside LoadContent() method. Your Game class overrides LoadContent() method. There you can load your texture like this: byBall.BallSprite = Content.Load<Texture2D>("balltexture"); (you need to make BallSprite property public in that case)
Or you could create a method for loading inside Ball class
public void LoadContent(Content content)
{
_ballSprite = content.Load<Texture2D>("balltexture");
}
and then call myBall.LoadContent(Content) from overriden Game class LoadContent() method.
Note that that Content object is ContentManager and will in case you load same texture multiple times, load that texture in memory only once (first time load is called). For all subsequent calls same Texture2D instance will be returned.
Game.LoadContent() method is called by XNA before first update and each time graphic device is reset (that can happen for number of reasons at any time). So you need to be careful what you do inside LoadContent() method. If you would for instance try to create Ball class instance inside LoadContent(), that ball instance could be replaced by new ball instance at any time mid game and _ballSpeed, _ballMovement, _ballPosition values would be lost.

Getting a line that has the coordinates defined by the mouse location

I'm trying to make a little graphics program that has a circle of diameter 100 on the screen and from the center of it, a line is coming out of it that is always attached to the mouse pointer until such time that the user does a click, and then the line is permanently drawn. It's exactly like MSPaint's line, except that starting point is always the center of the circle.
I tried a few things that DON'T work.
I can get the line to appear only after a mouse-click. That's not what I want. I want the line to always be present and pivoting from the circle-center until the mouse is clicked and then it's then permanently on the screen.
I can get a smeary thing where the line is always being drawn. It makes a sort of star shape, but that's not what I want either.
Basically, I want the same functionality that you have in MSPaint when you draw a line. What am I supposed to do? Draw the line and then erase it a second later, and then draw it again when the mouse is in a new position? I tried something like that, but it does a thing where it erases the background a little bit, and then the line is only drawn when the mouse is in motion, but not when the mouse is stationary.
If anyone can provide a code snippet, that'd be great. Or just some pseudo-code.
Is this the right pseudo code?
Start:
Left click and a line appears from center of circle to mouse tip
Line stays there until a new mouse coordinate is made (how do I keep track)?
Line from center of circle to original location gets erased
New line is made to new location of mouse coordinates.
I think this something of a state-machine to use what I learned in digital class. How are states implemented in C#?
Any help would be appreciated, and thanks to everyone that can understand my question even though I'm probably not using the proper terminology.
So short answer is you will need some custom painting. The longer answer involves custom drawing, and event handling.
The other piece of code you need is a list of some sort to hold all of the lines. The code below creates a user control and does the custom painting without relying on a state machine. To test it, create a new project add a user control called UserControl1, and add it to a form. Make sure you tie into the listed events.
I tried to comment the relevant sections and this shows a quick and dirty way to do what you appear to be trying to do.
using System.Collections.Generic;
using System.Drawing;
using System.Windows.Forms;
namespace CustomDrawingAndEvents
{
public partial class UserControl1 : UserControl
{
private struct MyLine
{
public Point mStart;
public Point mEnd;
public MyLine(Point xStart, Point xEnd)
{
mStart = xStart;
mEnd = xEnd;
}
}
private List<MyLine> mLines;
private Point mCircleCenter;
private Point mMousePosition;
public UserControl1()
{
InitializeComponent();
mLines = new List<MyLine>();
//Double Buffer to prevent flicker
DoubleBuffered = true;
//Create the center for our circle. For this just put it in the center of
//the control.
mCircleCenter = new Point(this.Width / 2, this.Height / 2);
}
private void UserControl1_MouseClick(object sender, MouseEventArgs e)
{
//User clicked create a new line to add to the list.
mLines.Add(new MyLine(mCircleCenter, e.Location));
}
private void UserControl1_MouseMove(object sender, MouseEventArgs e)
{
//Update mouse position
mMousePosition = e.Location;
//Make the control redraw itself
Invalidate();
}
private void UserControl1_Paint(object sender, PaintEventArgs e)
{
//Create the rect with 100 width/height (subtract half the diameter to center the rect over the circle)
Rectangle lCenterRect = new Rectangle(mCircleCenter.X - 50, mCircleCenter.Y - 50, 100, 100);
//Draw our circle in the center of the control with a diameter of 100
e.Graphics.DrawEllipse(new Pen(Brushes.Black), lCenterRect);
//Draw all of our saved lines
foreach (MyLine lLine in mLines)
e.Graphics.DrawLine(new Pen(Brushes.Red), lLine.mStart, lLine.mEnd);
//Draw our active line from the center of the circle to
//our mouse location
e.Graphics.DrawLine(new Pen(Brushes.Blue), mCircleCenter, mMousePosition);
}
}
}

Creating a transparent portion of a control to see controls underneath it

I've modified the SuperContextMenuStrip found at CodeProject to meet some of my projects needs. I'm using it as a tooltip for map markers on a GMap.NET Map Control. Here is a sample of what it looks like:
What I would like to do is pretty this up a little by making it look more like a bubble. Similar to an old Google Maps stytle tooltip:
I've spent some time searching on control transparency and I know this isn't an easy thing. This SO question in particular illustrates that.
I have considered overriding the OnPaint method of the SuperContextMenuStrip to draw a background of the GMap.NET control that is underneath the SuperContextMenuStrip, but even that would fail in cases where the marker is hanging off the GMap.NET control:
What is the correct way to create the type of transparency I am looking for?
In Windows Forms, you achieve transparency (or draw irregularly shaped windows) by defining a region. To quote MSDN
The window region is a collection of pixels within the window where
the operating system permits drawing.
In your case, you should have a bitmap that you will use as a mask. The bitmap should have at least two distinct colors. One of these colors should represent the part of the control that you want to be transparent.
You would then create a region like this:
// this code assumes that the pixel 0, 0 (the pixel at the top, left corner)
// of the bitmap passed contains the color you wish to make transparent.
private static Region CreateRegion(Bitmap maskImage) {
Color mask = maskImage.GetPixel(0, 0);
GraphicsPath grapicsPath = new GraphicsPath();
for (int x = 0; x < maskImage.Width; x++) {
for (int y = 0; y < maskImage.Height; y++) {
if (!maskImage.GetPixel(x, y).Equals(mask)) {
grapicsPath.AddRectangle(new Rectangle(x, y, 1, 1));
}
}
}
return new Region(grapicsPath);
}
You would then set the control’s Region to the Region returned by the CreateRegion method.
this.Region = CreateRegion(YourMaskBitmap);
to remove the transparency:
this.Region = new Region();
As you can probably tell from the code above, creating regions is expensive resource-wise. I'd advice saving regions in variables should you need to use them multiple times. If you use cached regions this way, you'd soon experience another problem. The assignment would work the first time but you would get an ObjectDisposedException on subsequent calls.
A little investigation with refrector would reveal the following code within the set accessor of the Region Property:
this.Properties.SetObject(PropRegion, value);
if (region != null)
{
region.Dispose();
}
The Region object is disposed after use!
Luckily, the Region is clonable and all you need to do to preserve your Region object is to assign a clone:
private Region _myRegion = null;
private void SomeMethod() {
_myRegion = CreateRegion(YourMaskBitmap);
}
private void SomeOtherMethod() {
this.Region = _myRegion.Clone();
}

Drawing a "floor" texture

Alright, let's say that I have a tile texture of some floor or something. And I'd like that my player will walk on that.
How can I set this tile to make it a as a floor?
I need this tile texture to be all over the screen width right?
How am I doing it?
Thanks
If you want a really easy way, here it is:
First you create a new Class and name it Tile:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework; // Don't forget those, they will let you
using Microsoft.Xna.Framework.Content; // access some class like:
using Microsoft.Xna.Framework.Graphics; // Texture2D or Vector2
namespace Your_Project _Name
{
class Tile
{
}
{
So far so good, now create the Texture and Position in your class just like this:
namespace Your_Project _Name
{
class Tile
{
Texture2D texture;
Vector2 position;
public void Initialize()
{
}
public void Draw()
{
}
}
{
As you can see I also created two Methods, Initialize and Draw, now we will Initialize our
texture and position for the tile texture in the public void Initialize(),
I don't know how you use your ContentManager but here is a easy way:
public void Initialize(ContentManager Content)
{
texture = Content.Load<Texture2D>("YourfloorTexture"); //it will load your texture.
position = new Vector2(); //the position will be (0,0)
}
Now we need to draw our texture a number of time how will we do that? The way thasc said, the code can be more complex but here is one that you will understand, I will add a SpriteBatch so I can Draw. All this is done in the public void Draw():
public void Draw(SpriteBatch spriteBatch)
{
for (int i=0; i<30;i++) //will do a loop 30 times. Each Time i will =
//a valor from 0 to 30.
{
spriteBatch.Draw(texture, position, Color.White);
//Will draw the texture once, at the position Vector2
//right now position = (0,0)
spriteBatch.Draw(texture, new Vector2((int)i,(int)i), Color.White);
//Will Draw the texture 30 times, the first time on the position (0,0)
//Second Time on (1,1) .. third (2,2) etc...
spriteBatch.Draw(texture, new Vector2((int)position.X + (i * texture.Width), (int)position.Y + (i * texture.Height), Color.White));
//Will Draw the Texture 30 times Spaced by the Width and height
//of the texture (this is the code you need)
}
}
I didn't tried it but it should work, now its just a sample, you can figure out the rest. There is a lot of other methods to do it but this one is really easy. Ok, now the final step is to implement this class so go in your principal class where you have all your code and before this:
public Game1()
Create a new instance of your tile class
Tile tile;
and Initialize it in the protected override void Initialize():
tile = new Tile();
tile.Initialize(Content);
Now you have to draw it on the screen go at the end of the class and find protected override void Draw(GameTime gameTime) and call the draw method of our class:
spriteBatch.Begin();
tile.Draw(spriteBatch);
spriteBatch.End();
This is all the steps to complete a plain simple tile system. As I said there is a lot of others methods you just have to read tutorials about them or create them on your own.
If you don't plan on doing anything extra with the tiled background, I'd recommend thasc's solution and tile the sprite in a single call.
To do that, you create a rectangle as large as your background, and pass SamplerState.LinearWrap to SpriteBatch.Begin, then call Draw on the background rectangle.
Rectangle backgroundRect = new Rectangle(0, 0, backWidth, backHeight);
spriteBatch.Begin(..., ..., SamplerState.LinearWrap, ..., ...);
spriteBatch.Draw(backgroundTexture, backgroundRect, Color.White);
spriteBatch.End();
In case you're curious, what this does is create a single polygon that covers the background area, which will grab coordinates off your texture from 0.0f to backWidth. Textures are usually mapped between (0.0f, 0.0f) and (1.0f, 1.0f), which represent the corners of the given texture. If you go beyond these boundaries, TextureAddressMode defines how these coordinates will be treated:
Clamp will cut down the coordinates back into the 0-1 range.
Wrap will wrap the coordinates back to 0, so 0.0 = 2.0 = 4.0 = etc. and 1.0 = 3.0 = 5.0 = etc.
Mirror will also wrap, but mirroring the texture every other pass, basically going left-to-right-to-left-etc. as the polygon is rendered.

Categories

Resources