I have VS2012 and try to make a simple xna app for Windows Phone 7/8.
I have something like this:
public partial class GamePage : PhoneApplicationPage
{
ContentManager contentManager;
GameTimer timer;
SpriteBatch spriteBatch;
public Texture2D firstSprite { get; set; }
public Vector2 transition = new Vector2(0, 0);
public GamePage()
{
InitializeComponent();
contentManager = (Application.Current as App).Content;
timer = new GameTimer();
timer.UpdateInterval = TimeSpan.FromTicks(333333);
timer.Update += OnUpdate;
timer.Draw += OnDraw;
}
protected override void OnNavigatedTo(NavigationEventArgs e)
{
SharedGraphicsDeviceManager.Current.GraphicsDevice.SetSharingMode(true);
spriteBatch = new SpriteBatch(SharedGraphicsDeviceManager.Current.GraphicsDevice);
firstSprite = this.contentManager.Load<Texture2D>("ikona");
timer.Start();
base.OnNavigatedTo(e);
}
protected override void OnNavigatedFrom(NavigationEventArgs e)
{
timer.Stop();
SharedGraphicsDeviceManager.Current.GraphicsDevice.SetSharingMode(false);
base.OnNavigatedFrom(e);
}
float d = 0;
private void OnUpdate(object sender, GameTimerEventArgs e)
{
TouchCollection touchCollection = TouchPanel.GetState();
foreach (TouchLocation tl in touchCollection)
{
if (tl.State == TouchLocationState.Pressed && tl.Position.X < 240)
{
d = -10;
}
if (tl.State == TouchLocationState.Pressed && tl.Position.X > 240)
{
d = 10;
}
if (tl.State == TouchLocationState.Released)
d = 0;
}
transition += new Vector2(d, 0);
}
private void OnDraw(object sender, GameTimerEventArgs e)
{
SharedGraphicsDeviceManager.Current.GraphicsDevice.Clear(Color.CornflowerBlue);
spriteBatch.Begin();
spriteBatch.Draw(firstSprite, transition, null, Color.White, 0, new Vector2(0, 0), 1f, SpriteEffects.None, 0);
spriteBatch.End();
}
}
Is it a good way do animate sprite? Will it be animated same way on every device? When I was testing it on lumia920 it wasn't very smooth, so I think I do it badly.
And second thing. I want to move picture left when I press left half of the screen and move right when I press right side. It partly works but when I press left (it moves left), then at the same time press right (it moves right), and then release right, picture stops. I thought it would move again left. How can I achieve this?
/edit/
And what about touch handling?
I'm not sure how it's animated as I'm not familiar with TouchCollection.
But using XNA to animate works like this for most of the solutions out there:
You have your texture which is a spritesheet I assume containing all the frames for your animated sprite.
You use a Rectangle which will hold Position and size on the screen.
You also use something called a source rectangle, which is a rectangle that represents an area inside your sprite, which will stretch in your position rectangle. Here is an image:
Rectangle A is your position + size rectangle, and rectangle B is your source rectangle.
To create an animation you say the following ( pseudo code ):
int timer = 0;
Rectangle position = new Rectangle(100, 100, 80, 80); // position 100x, 100y, and size is 80 width and height.
Rectangle source = new Rectangle(0, 0, 80, 80); // Position on the spritesheet is 0, 0 which should be first frame, and the frames are all 80*80 pixels in size.
private void OnUpdate(object sender, GameTimerEventArgs e)
{
timer += e.ElapsedTime.TotalMilliseconds;
if(timer > 30) // If it has been 0.03 seconds = 33 frames per second
{
timer = 0; // reset timer
source.X += 80; // Move x value to next frame
if(source.X > widthOfYourSpriteSheet) source.X = 0; // Reset the animation to the beginning when we are at the end
}
}
Your draw function will look pretty much the same, except for the sourcerectangle argument you will put in it.
Related
I have this code in SharpGL where zoom and pan were implemented. This is de draw method:
private void OpenGLDraw(object sender, SharpGL.WPF.OpenGLRoutedEventArgs args)
{
// Enable finish button
if (openFileOk && dispCBOk) { finish_btn.IsEnabled = true; }
else { finish_btn.IsEnabled = false; }
// Get the OpenGL object
OpenGL gl = GLControl.OpenGL;
// Set The Material Color
float[] glfMaterialColor = new float[] { 0.4f, 0.2f, 0.8f, 1.0f };
float w = (float)GLControl.ActualWidth;
float h = (float)GLControl.ActualHeight;
// Perspective projection
gl.Viewport(0, 0, (int)w, (int)h);
gl.Ortho(0, w, 0, h, -100, 100);
// Clear The Screen And The Depth Buffer
gl.Clear(OpenGL.GL_COLOR_BUFFER_BIT | OpenGL.GL_DEPTH_BUFFER_BIT);
gl.Material(OpenGL.GL_FRONT_AND_BACK, OpenGL.GL_AMBIENT_AND_DIFFUSE, glfMaterialColor);
gl.MatrixMode(MatrixMode.Modelview);
gl.LoadIdentity();
gl.Scale(scale,scale,1);
// Camera Position
gl.LookAt(_position[0], _position[1], _position[2],
_viewPoint[0], _viewPoint[1], _viewPoint[2],
_upVector[0], _upVector[1], _upVector[2]);
// Draw the helix
float[][] points = vertexes.ToArray();
Helix(points.Length, points);
}
What I have here is a perspective projection using Viewport (the ortho projection and scale are used for zooming).
This is the code for panning whatever is drawn on the screen:
// pan
// y axis
// Up
if (keyCode == 1)
{
_viewPoint[1] += _moveDistance;
_position[1] += _moveDistance;
}
// Down
else if (keyCode == 2)
{
_viewPoint[1] += -_moveDistance;
_position[1] += -_moveDistance;
}
// x axis
// Left
else if (keyCode == 3)
{
_viewPoint[2] += _moveDistance;
_position[2] += _moveDistance;
}
// Right
else if (keyCode == 4)
{
_viewPoint[2] += -_moveDistance;
_position[2] += -_moveDistance;
}
The thing is that when I move too much to any one of the sides (up, down, left, right), the drawing gets really distorted. I didn't notice it at first because I was working with the image very zoomed in and couldn't see the difference, but now I see that the distortion always happens, it's just more intense the more you move away from the image.
All I want to know is why this happens, and if possible, a solution for it, thank you.
Here is an example of what happens:
Normal view
Distorted view
I am developing Cad application and want to implement snap - when user moves mouse near some object, I set Cursor.Position to the center point of that object. If user moves mouse say 7 pixels in any direction, then Cursor is set free.The way I do it is - I store snaped Cursor position and then under MouseMoveEvent I calculate the distance from stored position to current position. If this position is smaller than defined threshold then I set current cursor position back to stored value. Every time MouseMoveEvent is called that small difference between two cursor positions is added to previously calclated difference, so sooner or later my threshold is reached and Cursor jumps out of snaped position. Code sample:
var x = Cursor.Position.X - storedPosition.X;
pixelsX += x;
int threshold = 7;
if (pixelsX > threshold)
{
Cursor.Position = new System.Drawing.Point(storedPosition.X + 10, storedPosition.Y);
snapReleased = true;
}
The problem with this is that in every MouseMoveEvent mouse is moved very small amount and if threshold is not reached it is set back to stored position which makes Cursor blink(which is very annoying) So my question is - is there a way to detect mouse movement if Cursor is locked in one position?
I would not "snap" the mouse pointer. Do you know the feeling when your mouse is stuck? Depending on your age you may remember roller mice, those with a rubber ball inside. It is horrible.
Instead, I think that the objects you are about to select or are currently moving should react with a snap. For example, when you are about to select an object, when the mouse pointer is closer than the threshold the object gets highlighted. The user can the click the mouse and grab the object.
When moving an object, the object can snap into place when closer than the threshold to another object, guide lines, etc.
The following is a custom panel control that demonstrates an owner drawn cursor that snaps to a grid (snapPoints). The system cursor is hidden/shown on mouse entry/leave. The snap to point distance is controlled by the constant snapLimit.
using System;
using System.Collections.Generic;
using System.Windows.Forms;
using System.Drawing;
namespace WindowsFormsApplication1
{
public class DrawingSurface : Panel
{
private const double snapLimit = 7.0D;
private List<Point> snapPoints = new List<Point>();
private Point cursorPos;
private Point lastDrawnPos;
private bool drawCursor;
public DrawingSurface() : base()
{
this.BorderStyle = BorderStyle.Fixed3D;
this.BackColor = Color.AliceBlue;
this.DoubleBuffered = true;
this.Cursor = Cursors.Cross;
}
protected override void OnMouseEnter(EventArgs e)
{
base.OnMouseEnter(e);
System.Windows.Forms.Cursor.Hide();
}
protected override void OnMouseLeave(EventArgs e)
{
base.OnMouseLeave(e);
System.Windows.Forms.Cursor.Show();
this.drawCursor = false;
this.Invalidate();
}
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
foreach (Point dot in this.snapPoints)
{
e.Graphics.FillEllipse(Brushes.Red, dot.X - 1, dot.Y - 1, 2, 2);
}
if (drawCursor)
{
Cursor cur = System.Windows.Forms.Cursor.Current;
Point pt = this.cursorPos;
pt.Offset(-cur.HotSpot.X, -cur.HotSpot.Y);
Rectangle target = new Rectangle(pt, cur.Size);
cur.Draw(e.Graphics, target);
this.lastDrawnPos = this.cursorPos;
}
}
protected override void OnMouseMove(MouseEventArgs e)
{
base.OnMouseMove(e);
SetCursor(e.Location);
}
private void SetCursor(Point loc)
{
this.cursorPos = loc;
foreach (Point pt in this.snapPoints)
{
double deltaX = loc.X - pt.X;
double deltaY = loc.Y - pt.Y;
double radius = Math.Sqrt((deltaX * deltaX) + (deltaY * deltaY));
if (radius < snapLimit)
{
this.cursorPos = pt;
break;
}
}
if (lastDrawnPos != this.cursorPos)
{
this.drawCursor = true;
this.Invalidate();
}
}
protected override void OnSizeChanged(EventArgs e)
{
base.OnSizeChanged(e);
this.snapPoints.Clear();
for (int y = 0; y <= this.ClientRectangle.Height; y += 50)
{
for (int x = 0; x <= this.ClientRectangle.Width; x += 50)
{
this.snapPoints.Add(new Point(x, y));
}
}
}
}
}
I found this small application that i've been playing around with for the past little while. I was wondering, if i wanted to simply rotate the image in a circle? or make the entire image just bounce up and down, how would i modify this program to do so? Everything i've tried will just stretch the image - even if i do get it to move to the left or to the right. Any ideas on what i can do? Code is below
public partial class Form1 : Form
{
private int width = 15;
private int height = 15;
Image pic = Image.FromFile("402.png");
private Button abort = new Button();
Thread t;
public Form1()
{
abort.Text = "Abort";
abort.Location = new Point(190, 230);
abort.Click += new EventHandler(Abort_Click);
Controls.Add(abort);
SetStyle(ControlStyles.DoubleBuffer| ControlStyles.AllPaintingInWmPaint| ControlStyles.UserPaint, true);
t = new Thread(new ThreadStart(Run));
t.Start();
}
protected void Abort_Click(object sender, EventArgs e)
{
t.Abort();
}
protected override void OnPaint( PaintEventArgs e )
{
Graphics g = e.Graphics;
g.DrawImage(pic, 10, 10, width, height);
base.OnPaint(e);
}
public void Run()
{
while (true)
{
for(int i = 0; i < 200; i++)
{
width += 5;
Invalidate();
Thread.Sleep(30);
}
}
}
}
So I don't know what you're trying to achieve, but to get the fundies out of the way, WinForms is a GDI+ library and its meant more for GUI stuff, so something like animation will probably be handled better by a graphics library like SFML.
Anyways, there's a million ways to achieve what you want. In terms of moving something around in a circle, you're gonna need a little simple trig. For a bouncing motion, I would say following a sine curve would be the easiest way.
Here's some pseudo-code (not sure if this is syntax-perfect) for bouncing:
Field Definitions:
private double frame = 0;
OnPaint:
Graphics g = e.Graphics;
g.DrawImage(pic, 10, 10 + Math.sin(frame)*10, width, height);
frame+=.01;
base.OnPaint(e);
This way, every time the paint event is triggered, t will increase by .01 radians. The sin has a domain that will oscillate between -1 and 1, and you can multiply that by a factor of 10 to get that bouncing effect.
Frame represents your "keyframe". If you want to speed it up, increase the frame+=__ to a higher value. If you want to increase the range, change the offset Math.sin(frame)*__
I want to create a low resolution game on a larger window. (96x54 res on 960x540 size window for example).
How would I go about this? Is there a way to resize a window independently of the preferred back buffer width and height? Or should I just keep a low resolution render target I draw on, and just draw it as a full screen quad on my window when I'm done adjusting for nearest texture sampling?
Thanks in advance,
xoorath
I tend to opt for the "render to texture" solution so that I can allow for things like full screen without distortions.
The class I use to achieve this usually looks something like:
class VirtualScreen
{
public readonly int VirtualWidth;
public readonly int VirtualHeight;
public readonly float VirtualAspectRatio;
private GraphicsDevice graphicsDevice;
private RenderTarget2D screen;
public VirtualScreen(int virtualWidth, int virtualHeight, GraphicsDevice graphicsDevice)
{
VirtualWidth = virtualWidth;
VirtualHeight = virtualHeight;
VirtualAspectRatio = (float)(virtualWidth) / (float)(virtualHeight);
this.graphicsDevice = graphicsDevice;
screen = new RenderTarget2D(graphicsDevice, virtualWidth, virtualHeight, false, graphicsDevice.PresentationParameters.BackBufferFormat, graphicsDevice.PresentationParameters.DepthStencilFormat, graphicsDevice.PresentationParameters.MultiSampleCount, RenderTargetUsage.DiscardContents);
}
private bool areaIsDirty = true;
public void PhysicalResolutionChanged()
{
areaIsDirty = true;
}
private Rectangle area;
public void Update()
{
if (!areaIsDirty)
{
return;
}
areaIsDirty = false;
var physicalWidth = graphicsDevice.Viewport.Width;
var physicalHeight = graphicsDevice.Viewport.Height;
var physicalAspectRatio = graphicsDevice.Viewport.AspectRatio;
if ((int)(physicalAspectRatio * 10) == (int)(VirtualAspectRatio * 10))
{
area = new Rectangle(0, 0, physicalWidth, physicalHeight);
return;
}
if (VirtualAspectRatio > physicalAspectRatio)
{
var scaling = (float)physicalWidth / (float)VirtualWidth;
var width = (float)(VirtualWidth) * scaling;
var height = (float)(VirtualHeight) * scaling;
var borderSize = (int)((physicalHeight - height) / 2);
area = new Rectangle(0, borderSize, (int)width, (int)height);
}
else
{
var scaling = (float)physicalHeight / (float)VirtualHeight;
var width = (float)(VirtualWidth) * scaling;
var height = (float)(VirtualHeight) * scaling;
var borderSize = (int)((physicalWidth - width) / 2);
area = new Rectangle(borderSize, 0, (int)width, (int)height);
}
}
public void BeginCapture()
{
graphicsDevice.SetRenderTarget(screen);
}
public void EndCapture()
{
graphicsDevice.SetRenderTarget(null);
}
public void Draw(SpriteBatch spriteBatch)
{
spriteBatch.Draw(screen, area, Color.White);
}
}
And then in my game, the initialisation tends look something like:
VirtualScreen virtualScreen;
protected override void Initialize()
{
virtualScreen = new VirtualScreen(96, 54, GraphicsDevice);
Window.ClientSizeChanged += new EventHandler<EventArgs>(Window_ClientSizeChanged);
Window.AllowUserResizing = true;
base.Initialize();
}
void Window_ClientSizeChanged(object sender, EventArgs e)
{
virtualScreen.PhysicalResolutionChanged();
}
With the all important call to Update:
protected override void Update(GameTime gameTime)
{
virtualScreen.Update();
base.Update(gameTime);
}
And then the act of drawing itself:
protected override void Draw(GameTime gameTime)
{
virtualScreen.BeginCapture();
GraphicsDevice.Clear(Color.CornflowerBlue);
// game rendering happens here...
virtualScreen.EndCapture();
GraphicsDevice.Clear(Color.Black);
spriteBatch.Begin();
virtualScreen.Draw(spriteBatch);
spriteBatch.End();
base.Draw(gameTime);
}
With this in place, I can basically stop caring about resolution at all and just focus on the game.
Using the RenderToTexture method you're talking about might be a good idea (plus it will be easier for you if you want to do post-process shaders).
Alternatively, you can set the Window's size, but your code will only work on a desktop.
You must add those 2 references in your project:
using System.Drawing;
using System.Windows.Forms;
And then in your Game class (i.e. in the Initialize method)
GraphicsDeviceManager.PreferredBackBufferWidth = 96;
GraphicsDeviceManager.PreferredBackBufferHeight = 54;
IntPtr ptr = this.Window.Handle;
Form form = (Form) Control.FromHandle(ptr);
form.Size = new Size(960, 540);
I've managed to get the cursor to change to an IBeam in a trivial XNA 'Game' with Update as:
protected override void Update(GameTime gameTime)
{
// Allows the game to exit
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
this.Exit();
// TODO: Add your update logic here
if (Keyboard.GetState().IsKeyDown(Keys.A))
{
System.Windows.Forms.Cursor.Current = System.Windows.Forms.Cursors.Arrow;
}
if (Keyboard.GetState().IsKeyDown(Keys.I))
{
System.Windows.Forms.Cursor.Current = System.Windows.Forms.Cursors.IBeam;
}
base.Update(gameTime);
}
The mouse changes to the IBeam cursor when 'I' is pressed, but immediately changes back to an arrow when you move the mouse. Is there a way to get it to stay as the default Windows IBeam, or will I need to create and track a custom cursor?
[EDIT] I should also point out that setting the cursor every single frame causes it to flicker when the mouse is moved. It seems the XNA (or Windows) is internally resetting the cursor to an arrow every frame?
Before resorting to drawing it manually, I'd try to set the Cursor property of the underlying System.Windows.Forms.Form:
Form f = (Form)Control.FromHandle(Game.Window.Handle);
f.Cursor = System.Windows.Forms.Cursors.IBeam;
As I don't have XNA installed right now, I don't know if this will work, or if it will be permenant, but I don't see why it wouldn't.
Sounds like your going to have to draw it manually. It shouldn't be too hard - just draw a sprite via SpriteBatch at the location of the cursor.
// ex.
protected override void Draw(GameTime gameTime)
{
// Other stuff...
base.Draw(gameTime);
// Retrieve mouse position
MouseState mState = Mouse.GetState();
Vector2 mousePos = new Vector2(mState.X, mState.Y);
// Use this instead to optionally center the texture:
// Vector2 mousePos = new Vector2(mState.X - cursorTexture.Width / 2, mState.Y - cursorTexture.Height / 2);
// Draw cursor after base.Draw in order to draw it after any DrawableGameComponents.
this.spriteBatch.Begin(); // Optionally save state
this.spriteBatch.Draw(cursorTexture, mousePos, Color.White);
this.spriteBatch.End();
}
And here's some code to extract the cursor image. Keep in mind you'll need an extra reference to System.Drawing.
protected override void LoadContent()
{
// Other stuff...
// The size of the cursor in pixels.
int cursorSize = 32;
// Draw the cursor to a Bitmap
Cursor cursor = Cursors.IBeam;
Bitmap image = new Bitmap(cursorSize, cursorSize);
Graphics graphics = Graphics.FromImage(image);
cursor.Draw(graphics, new Rectangle(0, 0, cursorSize, cursorSize));
// Extract pixels from the bitmap, and copy into the texture.
cursorTexture = new Texture2D(GraphicsDevice, cursorSize, cursorSize);
Microsoft.Xna.Framework.Graphics.Color[] data = new Microsoft.Xna.Framework.Graphics.Color[cursorSize * cursorSize];
for (int y = 0; y < cursorSize; y++)
{
for (int x = 0; x < cursorSize; x++)
{
System.Drawing.Color color = image.GetPixel(x, y);
data[x + y * cursorSize] = new Microsoft.Xna.Framework.Graphics.Color(color.R, color.G, color.B, color.A);
}
}
cursorTexture.SetData<Microsoft.Xna.Framework.Graphics.Color>(data);
}
Keep in mind this is off the top of my head - not guaranteed to work. The basic idea is there, though.