Am I the only one experiencing this? I have nothing but a little, tiny, game, but it's close to unplayable now because of FPS drops.
Here's my code, if anyone is wondering:
Game1.cs
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using System.IO;
namespace Innovationally
{
enum GameState
{
TITLESCREEN,
HELPSCREEN,
PLAYING,
WON,
LOST
}
public class Game1 : Microsoft.Xna.Framework.Game
{
GraphicsDeviceManager graphics;
SpriteBatch spriteBatch;
GameState gameState = GameState.PLAYING;
//PLAYER STATS
public static Player player;
KeyboardState currentKeyboardState;
KeyboardState previousKeyboardState;
float playerMoveSpeed;
//COLLISION STATS
Rectangle kollision;
int bHit;
//LEVEL STATS
int level_number = 0;
int loadlevel = 0;
Texture2D hud, level0, level1, level2, level3, level4, level5;
Vector2 levelPos;
//ROOM STATS
List<int> tile_life = new List<int>();
Texture2D tile_gfx, stairsUp, stairsDown;
List<Vector2> tile_position = new List<Vector2>();
List<int> tile_type = new List<int>();
List<int> tile_elev = new List<int>();
int antlabb = 0;
int antvapen = 0;
int antpolis = 0;
int antwavers = 0;
int researchSpan;
//MISC
SpriteFont font;
Loot loot;
//GAMEPLAY STATS
TimeSpan timeElapsed;
public Game1()
{
graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
graphics.PreferredBackBufferHeight = 800;
graphics.PreferredBackBufferWidth = 900;
}
protected override void Initialize()
{
player = new Player();
playerMoveSpeed = 4.0f;
levelPos.X = 0;
levelPos.Y = 0;
loot = new Loot();
researchSpan = 120;
base.Initialize();
}
protected override void LoadContent()
{
spriteBatch = new SpriteBatch(GraphicsDevice);
Vector2 playerPosition = new Vector2(430, 450);
//LEVEL STATS
LaddaLevel(level_number);
level0 = Content.Load<Texture2D>("level0");
level1 = Content.Load<Texture2D>("level1");
level2 = Content.Load<Texture2D>("level2");
level3 = Content.Load<Texture2D>("level3");
level4 = Content.Load<Texture2D>("level4");
level5 = Content.Load<Texture2D>("level5");
hud = Content.Load<Texture2D>("hud");
//ROOM STATS
tile_gfx = Content.Load<Texture2D>("tile");
stairsUp = Content.Load<Texture2D>("stairsUp");
stairsDown = Content.Load<Texture2D>("stairsDown");
font = Content.Load<SpriteFont>("SpriteFont1");
player.Initialize(Content.Load<Texture2D>("Leftplayer"), playerPosition);
//SOMEONE STOP THE MUSIC, MUSIC.
MediaPlayer.Volume = 0.5f;
MediaPlayer.IsRepeating = true;
MediaPlayer.Play(Content.Load<Song>("barn-beat"));
}
public void LaddaLevel(int nummer)
{
StreamReader SR = new StreamReader(nummer.ToString());
string bana = SR.ReadToEnd();
SR.Close();
int temp_positionY = 0;
int temp_positionX = 0;
tile_position.Clear();
tile_type.Clear();
tile_life.Clear();
for (int i = 0; i < bana.Length; i++)
{
switch (bana[i])
{
case ' ':
temp_positionX++;
break;
case '0':
tile_life.Add(loot.myRnd.Next(8));
tile_position.Add(new Vector2((temp_positionX * 100), (temp_positionY * 100)));
temp_positionX++;
tile_type.Add(int.Parse(bana[i].ToString()));
break;
case '8':
tile_position.Add(new Vector2((temp_positionX * 100), (temp_positionY * 100)));
temp_positionX++;
tile_type.Add(int.Parse(bana[i].ToString()));
tile_life.Add(8);
break;
case '9':
tile_position.Add(new Vector2((temp_positionX * 100), (temp_positionY * 100)));
temp_positionX++;
tile_type.Add(int.Parse(bana[i].ToString()));
tile_life.Add(9);
break;
case '\n':
temp_positionY++;
temp_positionX = 0;
break;
}
}
}
protected override void UnloadContent()
{
}
protected override void Update(GameTime gameTime)
{
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
this.Exit();
previousKeyboardState = currentKeyboardState;
currentKeyboardState = Keyboard.GetState();
if (currentKeyboardState.IsKeyDown(Keys.Escape) && previousKeyboardState.IsKeyUp(Keys.Escape))
this.Exit();
switch (gameState)
{
case GameState.TITLESCREEN:
if (currentKeyboardState.IsKeyDown(Keys.S) && previousKeyboardState.IsKeyUp(Keys.S))
gameState = GameState.PLAYING;
if (currentKeyboardState.IsKeyDown(Keys.H) && previousKeyboardState.IsKeyUp(Keys.H))
gameState = GameState.HELPSCREEN;
break;
case GameState.HELPSCREEN:
if (currentKeyboardState.IsKeyDown(Keys.B) && previousKeyboardState.IsKeyUp(Keys.B))
gameState = GameState.TITLESCREEN;
break;
case GameState.PLAYING:
timeElapsed += gameTime.ElapsedGameTime;
UpdatePlayer(gameTime);
UpdateResearchCenters(gameTime);
UpdateCollisions(gameTime);
break;
case GameState.LOST:
if (currentKeyboardState.IsKeyDown(Keys.S) && previousKeyboardState.IsKeyUp(Keys.S))
{
loadlevel = 0;
gameState = GameState.PLAYING;
}
break;
}
base.Update(gameTime);
}
private void UpdatePlayer(GameTime gameTime)
{
if (currentKeyboardState.IsKeyDown(Keys.Left))
{
player.angle = (float)Math.PI * 1.5f;
player.Position.X -= playerMoveSpeed;
}
if (currentKeyboardState.IsKeyDown(Keys.Right))
{
player.angle = (float)Math.PI / 2;
player.Position.X += playerMoveSpeed;
}
if (currentKeyboardState.IsKeyDown(Keys.Up))
{
player.angle = (float)Math.PI * 2;
player.Position.Y -= playerMoveSpeed;
}
if (currentKeyboardState.IsKeyDown(Keys.Down))
{
player.angle = (float)Math.PI;
player.Position.Y += playerMoveSpeed;
}
if (player.health <= 0)
gameState = GameState.LOST;
}
public void UpdateResearchCenters(GameTime gameTime)
{
researchSpan -= gameTime.ElapsedGameTime.Seconds;
if (researchSpan <= 0)
{
loot.RandomResearch();
researchSpan = 120;
}
}
public void UpdateCollisions(GameTime gameTime)
{
Rectangle playerBox = new Rectangle((int)player.Position.X - 20, (int)player.Position.Y - 20, 40, 37);
Rectangle levelBox = new Rectangle(0, 0, 900, 800);
for (int i = 0; i < tile_position.Count; i++)
{
Rectangle tileBox = new Rectangle((int)tile_position[i].X, (int)tile_position[i].Y, 100, 100);
if (playerBox.Intersects(tileBox))
{
if (tile_life[i] <= 9)
{
if (tile_life[i] == 9 && currentKeyboardState.IsKeyDown(Keys.Space))
{
loadlevel += 1;
LaddaLevel(loadlevel);
}
else if (tile_life[i] == 8 && currentKeyboardState.IsKeyDown(Keys.Space))
{
loadlevel -= 1;
LaddaLevel(loadlevel);
}
else if (tile_life[i] == 7 && currentKeyboardState.IsKeyDown(Keys.Space))
{
loot.RandomLoot();
tile_life[i] = 70;
}
else if ((tile_life[i] == 6 || tile_life[i] == 60) && currentKeyboardState.IsKeyDown(Keys.Space) && (player.mvgelever >= 1 || player.problemelever >= 1 || player.normalaelever >= 1))
{
if (player.mvgelever >= 1)
{
player.mvgelever -= 1;
tile_elev.Add(1);
}
else if (player.normalaelever >= 1)
{
player.normalaelever -= 1;
tile_elev.Add(2);
}
else if (player.problemelever >= 1)
{
player.problemelever -= 1;
tile_elev.Add(3);
}
tile_life[i] = 60;
antlabb += 1;
}
if (tile_life[i] == 60 && currentKeyboardState.IsKeyDown(Keys.Space))
{
antlabb -= 1;
if (tile_elev.Contains(1))
player.mvgelever += 1;
if (tile_elev.Contains(2))
player.normalaelever += 1;
if (tile_elev.Contains(3))
player.problemelever += 1;
tile_life[i] = 6;
}
}
}
}
//Överlappar vi?
kollision = Intersection(playerBox, levelBox);
if (kollision.Width > 0 && kollision.Height > 0)
{
Rectangle r1 = Normalize(playerBox, kollision);
Rectangle r2 = Normalize(levelBox, kollision);
if (loadlevel == 0)
bHit = TestCollision(player.PlayerTexture, r1, level0, r2);
if (loadlevel == 1)
bHit = TestCollision(player.PlayerTexture, r1, level1, r2);
if (loadlevel == 2)
bHit = TestCollision(player.PlayerTexture, r1, level2, r2);
if (loadlevel == 3)
bHit = TestCollision(player.PlayerTexture, r1, level3, r2);
if (loadlevel == 4)
bHit = TestCollision(player.PlayerTexture, r1, level4, r2);
if (loadlevel == 5)
bHit = TestCollision(player.PlayerTexture, r1, level5, r2);
}
else
{
bHit = 0;
}
if (bHit == 1 || bHit == 2)
{
if (player.angle == (float)Math.PI)
player.Position.Y -= playerMoveSpeed;
if (player.angle == (float)Math.PI * 2)
player.Position.Y += playerMoveSpeed;
if (player.angle == (float)Math.PI / 2)
player.Position.X -= playerMoveSpeed;
if (player.angle == (float)Math.PI * 1.5f)
player.Position.X += playerMoveSpeed;
}
}
public static Rectangle Intersection(Rectangle r1, Rectangle r2)
{
int x1 = Math.Max(r1.Left, r2.Left);
int y1 = Math.Max(r1.Top, r2.Top);
int x2 = Math.Min(r1.Right, r2.Right);
int y2 = Math.Min(r1.Bottom, r2.Bottom);
if ((x2 >= x1) && (y2 >= y1))
{
return new Rectangle(x1, y1, x2 - x1, y2 - y1);
}
return Rectangle.Empty;
}
public static Rectangle Normalize(Rectangle reference, Rectangle overlap)
{
//Räkna ut en rektangel som kan användas relativt till referensrektangeln
return new Rectangle(
overlap.X - reference.X,
overlap.Y - reference.Y,
overlap.Width,
overlap.Height);
}
public static int TestCollision(Texture2D t1, Rectangle r1, Texture2D t2, Rectangle r2)
{
//Beräkna hur många pixlar som finns i området som ska undersökas
int pixelCount = r1.Width * r1.Height;
uint[] texture1Pixels = new uint[pixelCount];
uint[] texture2Pixels = new uint[pixelCount];
//Kopiera ut pixlarna från båda områdena
t1.GetData(0, r1, texture1Pixels, 0, pixelCount);
t2.GetData(0, r2, texture2Pixels, 0, pixelCount);
//Jämför om vi har några pixlar som överlappar varandra i områdena
for (int i = 0; i < pixelCount; ++i)
{
if (((texture1Pixels[i] & 0xff000000) > 0) && (texture2Pixels[i] == 0xffC3C3C3))
{
return 1;
}
if (((texture1Pixels[i] & 0xff000000) > 0) && (texture2Pixels[i] == 0xff000000))
{
return 2;
}
if (((texture1Pixels[i] & 0xff000000) > 0) && (texture2Pixels[i] == 0xff000000))
{
return 1;
}
}
return 0;
}
private void DrawHud()
{
string timeString = "TIME: " + timeElapsed.Minutes.ToString("00") + ":" + timeElapsed.Seconds.ToString("00");
spriteBatch.Draw(hud, new Vector2(0, 0), Color.White);
spriteBatch.DrawString(font, timeString, new Vector2(15, 35), Color.White);
spriteBatch.DrawString(font, "Level " + (loadlevel + 1), new Vector2(15, 10), Color.White);
spriteBatch.DrawString(font, "" + player.mvgelever, new Vector2(739, 55), Color.White);
spriteBatch.DrawString(font, "" + player.problemelever, new Vector2(799, 55), Color.White);
spriteBatch.DrawString(font, "" + player.normalaelever, new Vector2(859, 55), Color.White);
spriteBatch.DrawString(font, "" + antwavers, new Vector2(454, 55), Color.White);
spriteBatch.DrawString(font, "" + antpolis, new Vector2(514, 55), Color.White);
spriteBatch.DrawString(font, "" + antvapen, new Vector2(574, 55), Color.White);
spriteBatch.DrawString(font, "" + antlabb, new Vector2(633, 55), Color.White);
spriteBatch.DrawString(font, "" + player.coins, new Vector2(359, 55), Color.White);
spriteBatch.DrawString(font, "" + player.nyckel, new Vector2(328, 55), Color.White);
spriteBatch.DrawString(font, "" + player.bombs, new Vector2(296, 55), Color.White);
spriteBatch.DrawString(font, "RESEARCH IN: " + researchSpan, new Vector2(15, 55), Color.White);
}
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);
spriteBatch.Begin();
switch (gameState)
{
case GameState.TITLESCREEN:
break;
case GameState.PLAYING:
if (loadlevel == 0)
spriteBatch.Draw(level0, new Vector2(0, 0), Color.White);
if (loadlevel == 1)
spriteBatch.Draw(level1, new Vector2(0, 0), Color.White);
if (loadlevel == 2)
spriteBatch.Draw(level2, new Vector2(0, 0), Color.White);
if (loadlevel == 3)
spriteBatch.Draw(level3, new Vector2(0, 0), Color.White);
if (loadlevel == 4)
spriteBatch.Draw(level4, new Vector2(0, 0), Color.White);
if (loadlevel == 5)
spriteBatch.Draw(level5, new Vector2(0, 0), Color.White);
for (int i = 0; i < tile_position.Count; i++)
{
switch (tile_life[i])
{
case 0: spriteBatch.Draw(tile_gfx, tile_position[i], Color.White);
break;
case 1: spriteBatch.Draw(tile_gfx, tile_position[i], Color.HotPink);
break;
case 2: spriteBatch.Draw(tile_gfx, tile_position[i], Color.YellowGreen);
break;
case 3: spriteBatch.Draw(tile_gfx, tile_position[i], Color.Purple);
break;
case 4: spriteBatch.Draw(tile_gfx, tile_position[i], Color.Yellow);
break;
case 5: spriteBatch.Draw(tile_gfx, tile_position[i], Color.Silver);
break;
case 6: spriteBatch.Draw(tile_gfx, tile_position[i], Color.Gold);
break;
case 60: spriteBatch.Draw(tile_gfx, tile_position[i], Color.Gold);
spriteBatch.Draw(player.PlayerTexture, new Vector2(tile_position[i].X + 40, tile_position[i].Y + 40), Color.White);
break;
case 7: spriteBatch.Draw(tile_gfx, tile_position[i], Color.Orange);
break;
case 70: spriteBatch.Draw(tile_gfx, tile_position[i], Color.DarkOrange);
break;
case 8: spriteBatch.Draw(stairsDown, tile_position[i], Color.White);
break;
case 9: spriteBatch.Draw(stairsUp, tile_position[i], Color.White);
break;
}
}
DrawHud();
player.Draw(spriteBatch);
break;
}
spriteBatch.End();
base.Draw(gameTime);
}
}
}
Player class (Player.cs):
using System;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
namespace Innovationally
{
public class Player
{
public Texture2D PlayerTexture;
public Vector2 Position;
public bool Active;
public float angle;
public int coins { get; set; }
public int bombs { get; set; }
public int normalaelever { get; set; }
public int health { get; set; }
public int damage { get; set; }
public int maximumhealth { get; set; }
public int problemelever { get; set; }
public int mvgelever { get; set; }
public int elever { get; set; }
public int nyckel { get; set; }
public int Width
{
get { return PlayerTexture.Width; }
}
public int Height
{
get { return PlayerTexture.Height; }
}
public void Initialize(Texture2D texture, Vector2 position)
{
PlayerTexture = texture;
Position = position;
Active = true;
elever = 0;
mvgelever = 0;
normalaelever = 0;
coins = 0;
bombs = 0;
health = 100;
maximumhealth = 100;
damage = 20;
nyckel = 1;
angle = (float)Math.PI * 2;
}
public void Draw(SpriteBatch spriteBatch)
{
spriteBatch.Draw(PlayerTexture, Position, null, Color.White, angle, new Vector2(PlayerTexture.Width / 2, PlayerTexture.Height / 2), 1f, SpriteEffects.None, 0f);
}
}
}
And finally, Loot.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Innovationally
{
class Loot
{
Player player = Game1.player;
public Random myRnd = new Random();
public int primarylootnumber;
public int secondarylootnumber;
public int tertiarylootnumber;
public void RandomLoot()
{
primarylootnumber = myRnd.Next(1, 11);
switch (primarylootnumber)
{
case 1:player.coins++;
break;
case 2:player.coins += 3;
break;
case 3:player.coins += 5;
break;
case 4:player.normalaelever += 1;
break;
case 5:player.normalaelever += 2;
break;
case 6:player.health += 10;
break;
case 7:player.health += 30;
break;
case 8:player.health += 50;
break;
case 9:player.damage += 5;
break;
case 10:player.damage += 10;
break;
}
secondarylootnumber = myRnd.Next(1, 11);
switch (primarylootnumber)
{
case 1:player.maximumhealth += 10;
break;
case 2:player.coins += 10;
break;
case 3:player.damage += 15;
break;
case 4:player.mvgelever += 1;
break;
case 5:player.problemelever += 1;
break;
}
tertiarylootnumber = myRnd.Next(1, 31);
switch (primarylootnumber)
{
case 10:
player.mvgelever += 1;
player.problemelever += 1;
break;
case 20:player.coins += 50;
break;
case 30:player.maximumhealth += 30;
break;
}
}
public void RandomResearch()
{
primarylootnumber = myRnd.Next(1, 6);
switch (primarylootnumber)
{
case 1:player.maximumhealth += 30;
break;
case 2: player.damage += 20;
break;
case 3:
break;
case 4:
break;
case 5:
break;
}
}
}
}
The only red flag I can see at the moment is:
t1.GetData(0, r1, texture1Pixels, 0, pixelCount);
t2.GetData(0, r2, texture2Pixels, 0, pixelCount);
These calls have a high overhead. I would recommend, if you are doing per-pixel collision detection, caching or pre-computing the pixel data rather than retrieving the data from the texture every frame.
EDIT:
here is a toy implementation (NOT TESTED!) of how you may want to retrieve the pixel data. Hopefully this will be enough to get you started.
Here are two mini functions for getting the texture data. When initializing your game, use 'PixelMaps' passing in all of your textures (e.g in an array). You will then have a dictionary you can use to perform lookups of the pixel data. You will want to use the information gleamed from the Texture and the rectangle you are testing to pick the right pixels.
public static uint[] Pixels(Texture2D texture)
{
uint[] data = new uint[texture.Width * texture.Height];
texture.GetData(data);
return data;
}
public static Dictionary<Texture2D, uint[]> PixelMaps(IEnumerable<Texture2D> textures)
{
return textures.ToDictionary(t => t, Pixels);
}
The TestCollision function may now look something like this (I have tried to keep the code as close as possible to the original).
public static int TestCollision(uint[] t1,
int t1Width,
Rectangle r,
uint[] t2)
{
for(var x = r.X; x < r.X + r.Width; x++)
for (var y = r.Y; y < r.Y + r.Height; y++)
{
var i = x + (y * t1Width);
if (((t1[i] & 0xff000000) > 0) && (t2[i] == 0xffC3C3C3))
{
return 1;
}
if (((t1[i] & 0xff000000) > 0) && (t2[i] == 0xff000000))
{
return 2;
}
if (((t1[i] & 0xff000000) > 0) && (t2[i] == 0xff000000))
{
return 1;
}
}
return 0;
}
Hopefully that is enough to get you started! Have fun :)
EDIT2:
Ok more information, again, trying to not change your code too much here we go:
introduce a new private member for the pixel maps. e.g:
Dictionary<Texture2D, uint[]> pixelMaps;
In your init function try this (btw I would also put the levels in a dictionary using an enum as a key, look it up. You should never have fields/properties like 0,1,2,3 that just screams I need some kind of list/array/assoc data structure.):
//LEVEL STATS
level0 = Content.Load<Texture2D>("level0");
level1 = Content.Load<Texture2D>("level1");
level2 = Content.Load<Texture2D>("level2");
level3 = Content.Load<Texture2D>("level3");
level4 = Content.Load<Texture2D>("level4");
level5 = Content.Load<Texture2D>("level5");
//As you can see I'm using the new PixelMaps function here...
pixelMaps = PixelMaps(new[] { level0, level1, level2, level3, level4, level5 });
When you come to test collisions you can do this:
var playerMap = pixelMaps[player.PlayerTexture];
var level0Map = pixelMaps[level0];
if (loadlevel == 0)
bHit = TestCollision(playerMap, r1, level0Map);
The best and quickest way to solve this problem (and many others while your at it) is to use a profiler. It will be able to show you what methods (and possibly lines, ANTS supports this) are taking the longest to complete. Once you narrow it down you can figure out how to fix these individual problems.
As for the code you posted, I'd have to agree with thedajaw that the collision code has alot of room for optimization. Getting the texture data everyframe is never a good idea, and should be done once at the begining of the game and stored in a variable for later use.
Overall I think the rest is fine, but see what the profiler shows up. Some minor structure issues (Could use some else ifs instead of ifs, things could be handled better,etc)
I'd recommend to read this question I asked a while back on a simlar subject.
Related
I have 5 different sprites having same Rect.
I create canvas Image and pass sprite to it. I want to get the pixel of that image according to texture size not to the canvas size or screen size through mouse position.
After accessing that position I can change that pixel to another sprite pixel having same rect.
I am working on it. But issue is that I have 2 sprites having resolution of 1080 x 1920. It works only that resolution but when I change the resolution it does not work correctly because resolution of sprite and canvas are different and mouse position values changes according to canvas resolution and sprite resolution is fixed. How I can do this. Anyone know the solution please tell me.
I give you the working script.
public class MaskControl : MonoBehaviour, IPointerDownHandler {
private void Awake()
{
if (instance == null)
instance = this;
DifferenceMultiplyer = this.ScreenReferance.y / (float)Screen.height;
}
private void Start()
{
//this.PlaceTexture(this.TargetTexture);
}
public void OnPointerDown(PointerEventData eventData)
{
Drawn = false;
canDraw = true;
}
private void Update()
{
if (!this.canDraw)
{
return;
}
if (Input.GetMouseButton(0))
{
/*if (Varf != this.Varf)
{
init(this.Varf);
}*/
//Vector2 pos = Camera.main.WorldToScreenPoint(this.Varf.position);
//Vector2 val = Input.mousePosition / canvas.scaleFactor;
//this.VarfPos = this.Varf.position;
//this.VarfPos = new Vector2(Camera.main.ScreenToWorldPoint(Input.mousePosition).x, Camera.main.ScreenToWorldPoint(Input.mousePosition).y);
this.PixelAdress = Input.mousePosition;
//this.PixelAdress = new Vector2(this.VarfPos.x * this.DifferenceMultiplyer + (this.ScreenReferance.x - (float)Screen.width * this.DifferenceMultiplyer) / 2f, this.VarfPos.y * this.DifferenceMultiplyer);
//this.PixelAdress = new Vector2(this.VarfPos.x * this.DifferenceMultiplyer , this.VarfPos.y * this.DifferenceMultiplyer);
/*if (SceneManager.GetActiveScene().name == "Nails" && NailManager.instance.RightHand.activeSelf)
{
this.PixelAdress = new Vector2(-this.PixelAdress.x, this.PixelAdress.y);
}*/
Debug.Log(DifferenceMultiplyer + " "+this.PixelAdress + " "+ Input.mousePosition);
if (!this.drawAlpha)
{
this.Circle(this.TargetTexture, (int)this.PixelAdress.x, (int)this.PixelAdress.y, this.BrushSize, true);
}
else
{
this.Circle(this.TargetTexture, (int)this.PixelAdress.x, (int)this.PixelAdress.y, this.BrushSize, false);
}
}
if (Input.GetMouseButtonUp(0))
{
this.canDraw = false;
this.drawAlpha = false;
}
}
public void ResetDraw()
{
this.SourceTexture = null;
SourceTextureColors = null;
DrawTexture = null;
TargetTextureColors = null;
}
public void init(Transform varf)
{
this.Varf = varf;
this.canDraw = true;
this.InitializeDraw(Change_sp.texture, TargetImage, this.Varf, 40, false);
}
public void InitializeDraw(Texture2D sourceTexture, Image targetImage, Transform varf, int brushSize, bool forced = false)
{
UnityEngine.Debug.Log("start to initialize draw");
this.BrushSize = brushSize;
this.Varf = varf;
if (this.SourceTexture != null && !forced && sourceTexture.name == this.SourceTexture.name)
{
if (targetImage.name == this.TargetImage.name)
{
return;
}
}
this.SourceTexture = sourceTexture;
this.TargetImage = targetImage;
this.TargetTexture = new Texture2D(sourceTexture.width, sourceTexture.height, TextureFormat.ARGB32, false);
if (DrawTexture == null)
{
this.TargetImage.gameObject.SetActive(true);
if (targetImage.sprite == null)
{
Color32[] pixels = this.TargetTexture.GetPixels32();
for (int i = 0; i < pixels.Length; i++)
{
pixels[i] = new Color32(byte.MaxValue, byte.MaxValue, byte.MaxValue, 1);
}
this.TargetTexture.SetPixels32(pixels);
this.TargetTexture.Apply();
this.TargetImage.sprite = Sprite.Create(this.TargetTexture, new Rect(0f, 0f, (float)sourceTexture.width, (float)sourceTexture.height), Vector2.zero);
}
else
{
Color32[] pixels2 = targetImage.sprite.texture.GetPixels32();
for (int j = 0; j < pixels2.Length; j++)
{
if (pixels2[j].a == 0)
{
pixels2[j] = new Color32(byte.MaxValue, byte.MaxValue, byte.MaxValue, 1);
}
}
this.TargetTexture.SetPixels32(pixels2);
this.TargetTexture.Apply();
this.TargetImage.sprite = Sprite.Create(this.TargetTexture, new Rect(0f, 0f, (float)sourceTexture.width, (float)sourceTexture.height), Vector2.zero);
targetImage.sprite.texture.Apply();
}
DrawTexture = this.TargetTexture;
}
else
{
Color32[] pixels3 = DrawTexture.GetPixels32();
for (int k = 0; k < pixels3.Length; k++)
{
if (pixels3[k].a == 0)
{
pixels3[k] = new Color32(byte.MaxValue, byte.MaxValue, byte.MaxValue, 1);
}
}
this.TargetTexture.SetPixels32(pixels3);
this.TargetTexture.Apply();
this.TargetImage.sprite = Sprite.Create(this.TargetTexture, new Rect(0f, 0f, (float)sourceTexture.width, (float)sourceTexture.height), Vector2.zero);
}
this.TargetTextureColors = this.TargetTexture.GetPixels32();
this.SourceTextureColors = sourceTexture.GetPixels32();
}
public void Circle(Texture2D tex, int cx, int cy, int r, bool draw)
{
for (int i = 0; i <= r; i++)
{
int num = (int)Mathf.Ceil(Mathf.Sqrt((float)(r * r - i * i)));
for (int j = 0; j <= num; j++)
{
int num2 = cx + i;
int num3 = cx - i;
int num4 = cy + j;
int num5 = cy - j;
Debug.Log(num2 + " " + tex.width + " " + num4 + " "+ byte.MaxValue);
if (draw)
{
if (num4 * tex.width + num2 < this.SourceTextureColors.Length)
{
this.TargetTextureColors[num4 * tex.width + num2] = this.SourceTextureColors[num4 * tex.width + num2];
}
}
else
{
this.TargetTextureColors[num4 * tex.width + num2] = new Color32(byte.MaxValue, byte.MaxValue, byte.MaxValue, 1);
}
if (draw)
{
if (num4 * tex.width + num3 < this.SourceTextureColors.Length)
{
this.TargetTextureColors[num4 * tex.width + num3] = this.SourceTextureColors[num4 * tex.width + num3];
}
}
else
{
this.TargetTextureColors[num4 * tex.width + num3] = new Color32(byte.MaxValue, byte.MaxValue, byte.MaxValue, 1);
}
if (draw)
{
if (num5 * tex.width + num2 < this.SourceTextureColors.Length)
{
this.TargetTextureColors[num5 * tex.width + num2] = this.SourceTextureColors[num5 * tex.width + num2];
}
}
else
{
this.TargetTextureColors[num5 * tex.width + num2] = new Color32(byte.MaxValue, byte.MaxValue, byte.MaxValue, 1);
}
if (draw)
{
if (num5 * tex.width + num3 < this.SourceTextureColors.Length)
{
this.TargetTextureColors[num5 * tex.width + num3] = this.SourceTextureColors[num5 * tex.width + num3];
}
}
else
{
this.TargetTextureColors[num5 * tex.width + num3] = new Color32(byte.MaxValue, byte.MaxValue, byte.MaxValue, 1);
}
if (!this.Drawn && draw)
{
if (this.SourceTextureColors[num4 * tex.width + num2].a != 0)
{
this.Drawn = true;
}
else if (this.SourceTextureColors[num4 * tex.width + num3].a != 0)
{
this.Drawn = true;
}
else if (this.SourceTextureColors[num5 * tex.width + num2].a != 0)
{
this.Drawn = true;
}
else if (this.SourceTextureColors[num5 * tex.width + num3].a != 0)
{
this.Drawn = true;
}
}
}
}
tex.SetPixels32(this.TargetTextureColors);
tex.Apply();
}
public static MaskControl instance;
public Sprite Change_sp;
public Image TargetImage;
public Texture2D SourceTexture;
public Texture2D TargetTexture;
[Header("```````````````````````")]
public Transform Varf;
private Color32[] SourceTextureColors;
private Color32[] TargetTextureColors;
private float DifferenceMultiplyer;
public Vector2 ScreenReferance;
private Vector2 PixelAdress;
public Texture2D DrawTexture;
public int BrushSize;
public bool canDraw;
public bool drawAlpha;
public bool Drawn;
public Vector2 VarfPos;
}
I am recreating a simple tile based game (ref: Javidx9 cpp tile game) on c# winforms and the screen flickers as i move, I have DoubleBuffered = true. i will show an example with textures and one without.
TEXTURES > e.Graphics.DrawImage()
NO TEXTURES > e.Graphics.FillRectangle()
in the code I made a GameManager, CameraManager, PlayerModel, lastly the form OnPaint that draws the game information. the way it works is the GameManager tells the Player to update itself depending on user input (move, jump, ect...), then tells the Camera to update depending on the players position. at first i called the GameManager.Update() from the Paint event but then i separated the Paint event from the GameManager and made the GameManager update asynchronous because the Paint event updates too slow. thats when the problem started.
//GameManager
public void CreateSoloGame(MapModel map)
{
CurrentMap = map;
ResetPlayer();
_inGame = true;
new Task(() =>
{
while (_inGame)
{
Elapsed = _stopwatch.ElapsedMilliseconds;
_stopwatch.Restart();
int i = 0;
Step(Elapsed);
while (i < _gameTime) //_gameTime controls the speed of the game
{
i++;
}
}
}).Start();
}
public void Step(double elapsed)
{
Player.Update(CurrentMap, elapsed);
Camera.SetCamera(Player.Position, CurrentMap);
}
//PlayerModel
public void DetectCollision(MapModel CurrentMap, double Elapsed)
{
//adds velocity to players position
float NextPlayerX = Position.X + (VelX * (float)Elapsed);
float NextPlayerY = Position.Y + (VelY * (float)Elapsed);
//collision detection
OnFloor = false;
if (VelY > 0)
{
//bottom
if (CurrentMap.GetTile((int)(Position.X + .1), (int)(NextPlayerY + 1)) == '#' || CurrentMap.GetTile((int)(Position.X + .9), (int)(NextPlayerY + 1)) == '#')
{
NextPlayerY = (int)NextPlayerY;
VelY = 0;
OnFloor = true;
_jumps = 2;
}
}
else
{
//top
if (CurrentMap.GetTile((int)(Position.X + .1), (int)NextPlayerY) == '#' || CurrentMap.GetTile((int)(Position.X + .9), (int)NextPlayerY) == '#')
{
NextPlayerY = (int)NextPlayerY + 1;
VelY = 0;
}
}
if (VelX < 0)
{
//left
if (CurrentMap.GetTile((int)NextPlayerX, (int)Position.Y) == '#' || CurrentMap.GetTile((int)NextPlayerX, (int)(Position.Y + .9)) == '#')
{
NextPlayerX = (int)NextPlayerX + 1;
VelX = 0;
}
}
else
{
//right
if (CurrentMap.GetTile((int)(NextPlayerX + 1), (int)Position.Y) == '#' || CurrentMap.GetTile((int)(NextPlayerX + 1), (int)(Position.Y + .9)) == '#')
{
NextPlayerX = (int)NextPlayerX;
VelX = 0;
}
}
//updates player position
Position = new PointF(NextPlayerX, NextPlayerY);
}
public void Jump()
{
if (_jumps > 0)
{
VelY = -.06f;
_jumps--;
}
}
public void ReadInput(double elapsed)
{
//resets velocity back to 0 if player isnt moving
if (Math.Abs(VelY) < 0.001f) VelY = 0;
if (Math.Abs(VelX) < 0.001f) VelX = 0;
//sets velocity according to player input - S and W are used for no clip free mode
//if (UserInput.KeyInput[Keys.W]) _playerVelY -= .001f;
//if (UserInput.KeyInput[Keys.S]) _playerVelY += .001f;
if (Input.KEYINPUT[Keys.A]) VelX -= .001f * (float)elapsed;
else if (Input.KEYINPUT[Keys.D]) VelX += .001f * (float)elapsed;
else if (Math.Abs(VelX) > 0.001f && OnFloor) VelX += -0.06f * VelX * (float)elapsed;
//resets jumping
if (!OnFloor)
VelY += .0004f * (float)elapsed;
//limits velocity
//if (_playerVelY <= -.014) _playerVelY = -.014f; //disabled to allow jumps
if (VelY >= .05) VelY = .05f;
if (VelX >= .02 && !Input.KEYINPUT[Keys.ShiftKey]) VelX = .02f;
else if (VelX >= .005 && Input.KEYINPUT[Keys.ShiftKey]) VelX = .005f;
if (VelX <= -.02 && !Input.KEYINPUT[Keys.ShiftKey]) VelX = -.02f;
else if (VelX <= -.005 && Input.KEYINPUT[Keys.ShiftKey]) VelX = -.005f;
}
public void Update(MapModel map, double elapsed)
{
ReadInput(elapsed);
DetectCollision(map, elapsed);
}
//CameraManager
public void SetCamera(PointF center, MapModel map, bool clamp = true)
{
//changes the tile size according to the screen size
TileSize = Input.ClientScreen.Width / Tiles;
//amount of tiles along thier axis
TilesX = Input.ClientScreen.Width / TileSize;
TilesY = Input.ClientScreen.Height / TileSize;
//camera offset
OffsetX = center.X - TilesX / 2.0f;
OffsetY = center.Y - TilesY / 2.0f;
//make sure the offset does not go beyond bounds
if (OffsetX < 0 && clamp) OffsetX = 0;
if (OffsetY < 0 && clamp) OffsetY = 0;
if (OffsetX > map.MapWidth - TilesX && clamp) OffsetX = map.MapWidth - TilesX;
if (OffsetY > map.MapHeight - TilesY && clamp) OffsetY = map.MapHeight - TilesY;
//smooths out movement for tiles
TileOffsetX = (OffsetX - (int)OffsetX) * TileSize;
TileOffsetY = (OffsetY - (int)OffsetY) * TileSize;
}
//Form Paint event
private void Draw(object sender, PaintEventArgs e)
{
Brush b;
Input.ClientScreen = ClientRectangle;
for (int x = -1; x < _camera.TilesX + 1; x++)
{
for (int y = -1; y < _camera.TilesY + 1; y++)
{
switch (_map.GetTile(x + (int)_camera.OffsetX, y + (int)_camera.OffsetY))
{
case '.':
//e.Graphics.DrawImage(sky, x * _camera.TileSize - _camera.TileOffsetX, y * _camera.TileSize - _camera.TileOffsetY, _camera.TileSize, _camera.TileSize);
//continue;
b = Brushes.MediumSlateBlue;
break;
case '#':
//e.Graphics.DrawImage(block, x * _camera.TileSize - _camera.TileOffsetX, y * _camera.TileSize - _camera.TileOffsetY, _camera.TileSize, _camera.TileSize);
//continue;
b = Brushes.DarkGray;
break;
case 'o':
b = Brushes.Yellow;
break;
case '%':
b = Brushes.Green;
break;
default:
b = Brushes.MediumSlateBlue;
break;
}
e.Graphics.FillRectangle(b, x * _camera.TileSize - _camera.TileOffsetX, y * _camera.TileSize - _camera.TileOffsetY, (x + 1) * _camera.TileSize, (y + 1) * _camera.TileSize);
}
}
e.Graphics.FillRectangle(Brushes.Purple, (_manager.Player.Position.X - _camera.OffsetX) * _camera.TileSize, (_manager.Player.Position.Y - _camera.OffsetY) * _camera.TileSize, _camera.TileSize, _camera.TileSize);
//e.Graphics.DrawImage(chef, (_manager.Player.Position.X - _camera.OffsetX) * _camera.TileSize, (_manager.Player.Position.Y - _camera.OffsetY) * _camera.TileSize, _camera.TileSize, _camera.TileSize);
Invalidate();
}
P.S. i use winforms because i dont work with GUIs much and its the one im most familiar with and this is just something quick i wanted to try out but i've never had this issue. i tried a couple of things but nothing worked so this is my last resort. if you think i should use another GUI let me know and ill look into it. also if you think my code is ugly lmk why.
Fill the form with a PictureBox and hook into the .Paint() event. For some reason, there is no flicker drawing on a PictureBox compared to drawing on a form.
Also having a game loop improves things a lot. I am getting 600+ fps with my example code.
full code below:
public partial class RunningForm1 : Form
{
static readonly Random rng = new Random();
float offset;
int index;
Queue<int> town;
const int grid = 12;
Color[] pallete;
FpsCounter clock;
#region Windows API - User32.dll
[StructLayout(LayoutKind.Sequential)]
public struct WinMessage
{
public IntPtr hWnd;
public Message msg;
public IntPtr wParam;
public IntPtr lParam;
public uint time;
public System.Drawing.Point p;
}
[System.Security.SuppressUnmanagedCodeSecurity] // We won't use this maliciously
[DllImport("User32.dll", CharSet = CharSet.Auto)]
public static extern bool PeekMessage(out WinMessage msg, IntPtr hWnd, uint messageFilterMin, uint messageFilterMax, uint flags);
#endregion
public RunningForm1()
{
InitializeComponent();
this.pic.Paint += new PaintEventHandler(this.pic_Paint);
this.pic.SizeChanged += new EventHandler(this.pic_SizeChanged);
//Initialize the machine
this.clock = new FpsCounter();
}
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
Setup();
System.Windows.Forms.Application.Idle += new EventHandler(OnApplicationIdle);
}
void UpdateMachine()
{
pic.Refresh();
}
#region Main Loop
private void OnApplicationIdle(object sender, EventArgs e)
{
while (AppStillIdle)
{
// Render a frame during idle time (no messages are waiting)
UpdateMachine();
}
}
private bool AppStillIdle
{
get
{
WinMessage msg;
return !PeekMessage(out msg, IntPtr.Zero, 0, 0, 0);
}
}
#endregion
private void pic_SizeChanged(object sender, EventArgs e)
{
pic.Refresh();
}
private void pic_Paint(object sender, PaintEventArgs e)
{
// Show FPS counter
var fps = clock.Measure();
var text = $"{fps:F2} fps";
var sz = e.Graphics.MeasureString(text, SystemFonts.DialogFont);
var pt = new PointF(pic.Width - 1 - sz.Width - 4, 4);
e.Graphics.DrawString(text, SystemFonts.DialogFont, Brushes.Black, pt);
// draw on e.Graphics
e.Graphics.SmoothingMode = SmoothingMode.HighQuality;
e.Graphics.TranslateTransform(0, pic.ClientSize.Height - 1);
e.Graphics.ScaleTransform(1, -1);
int wt = pic.ClientSize.Width / (grid - 1);
int ht = pic.ClientSize.Height / (grid + 1);
SolidBrush fill = new SolidBrush(Color.Black);
for (int i = 0; i < town.Count; i++)
{
float x = offset + i * wt;
var building = new RectangleF(
x, 0,
wt, ht * town.ElementAt(i));
fill.Color = pallete[(index + i) % pallete.Length];
e.Graphics.FillRectangle(fill, building);
}
offset -= 0.4f;
if (offset <= -grid - wt)
{
UpdateTown();
offset += wt;
}
}
private void Setup()
{
offset = 0;
index = 0;
town = new Queue<int>();
pallete = new Color[]
{
Color.FromKnownColor(KnownColor.Purple),
Color.FromKnownColor(KnownColor.Green),
Color.FromKnownColor(KnownColor.Yellow),
Color.FromKnownColor(KnownColor.SlateBlue),
Color.FromKnownColor(KnownColor.LightCoral),
Color.FromKnownColor(KnownColor.Red),
Color.FromKnownColor(KnownColor.Blue),
Color.FromKnownColor(KnownColor.LightCyan),
Color.FromKnownColor(KnownColor.Crimson),
Color.FromKnownColor(KnownColor.GreenYellow),
Color.FromKnownColor(KnownColor.Orange),
Color.FromKnownColor(KnownColor.LightGreen),
Color.FromKnownColor(KnownColor.Gold),
};
for (int i = 0; i <= grid; i++)
{
town.Enqueue(rng.Next(grid) + 1);
}
}
private void UpdateTown()
{
town.Dequeue();
town.Enqueue(rng.Next(grid) + 1);
index = (index + 1) % pallete.Length;
}
}
public class FpsCounter
{
public FpsCounter()
{
this.PrevFrame = 0;
this.Frames = 0;
this.PollOverFrames = 100;
this.Clock = Stopwatch.StartNew();
}
/// <summary>
/// Use this method to poll the FPS counter
/// </summary>
/// <returns>The last measured FPS</returns>
public float Measure()
{
Frames++;
PrevFrame++;
var dt = Clock.Elapsed.TotalSeconds;
if (PrevFrame > PollOverFrames || dt > PollOverFrames / 50)
{
LastFps = (float)(PrevFrame / dt);
PrevFrame = 0;
Clock.Restart();
}
return LastFps;
}
public float LastFps { get; private set; }
public long Frames { get; private set; }
private Stopwatch Clock { get; }
private int PrevFrame { get; set; }
/// <summary>
/// The number of frames to average to get a more accurate frame count.
/// The higher this is the more stable the result, but it will update
/// slower. The lower this is, the more chaotic the result of <see cref="Measure()"/>
/// but it will get a new result sooner. Default is 100 frames.
/// </summary>
public int PollOverFrames { get; set; }
}
When I get my points(poang) to highscore when I hit the blocks with 5 points. They will not update the same, sometimes points(poang) will be 18 and highscore will be 20.
(Sorry about my bad english)
poang = points
linje = line
liv = lives
boll = ball
poang = points
blockröd = blockred
blockgrön = blockgreen
public class Game1 : Game
{
GraphicsDeviceManager graphics;
SpriteBatch spriteBatch;
SpriteFont spritefont;
Texture2D linje_texture;
Texture2D linjeliten_texture;
Texture2D boll_texture;
Texture2D blockröd_texture;
Texture2D blockgrön_texture;
Texture2D gameover_texture;
Rectangle linje_rect;
Rectangle linjeliten_rect;
Rectangle boll_rect;
Rectangle blockröd_rect;
Rectangle blockgrön_rect;
Rectangle gameover_rect;
Vector2 linje_speed;
Vector2 linjeliten_speed;
Vector2 boll_speed;
Random random;
StreamReader sr;
StreamWriter sw;
int liv = 3;
int poang = 0;
int highscore;
List<Rectangle> block = new List<Rectangle>();
List<Rectangle> block2 = new List<Rectangle>();
bool Start = false;
bool holdingleft = false;
bool holdingright = false;
bool resetballspeed = false;
public Game1()
{
graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
graphics.PreferredBackBufferWidth = 760;
graphics.PreferredBackBufferHeight = 620;
}
protected override void Initialize()
{
random = new Random();
linje_speed.X = 6f;
linjeliten_speed.X = 6f;
boll_speed.X = random.Next(-1, 1);
boll_speed.Y = 7f;
sr = new StreamReader("highscore.txt");
highscore = int.Parse(sr.ReadLine());
sr.Close();
base.Initialize();
}
protected override void LoadContent()
{
spriteBatch = new SpriteBatch(GraphicsDevice);
spritefont = Content.Load<SpriteFont>("Fonts/Myfont");
linje_texture = Content.Load<Texture2D>("Pics/linje-lång");
linjeliten_texture = Content.Load<Texture2D>("Pics/linje");
boll_texture = Content.Load<Texture2D>("Pics/boll");
blockgrön_texture = Content.Load<Texture2D>("Pics/block-grön");
blockröd_texture = Content.Load<Texture2D>("Pics/block-röd");
gameover_texture = Content.Load<Texture2D>("Pics/GameOver");
linje_rect = new Rectangle((Window.ClientBounds.Width - linje_texture.Width) / 2, 580, linje_texture.Width, linje_texture.Height);
linjeliten_rect = new Rectangle((Window.ClientBounds.Width - linjeliten_texture.Width) / 2, 580, linjeliten_texture.Width, linjeliten_texture.Height);
boll_rect = new Rectangle((Window.ClientBounds.Width - boll_texture.Width) / 2, 556, boll_texture.Width, boll_texture.Height);
gameover_rect = new Rectangle((Window.ClientBounds.Width / 2) - (gameover_texture.Width / 2), (Window.ClientBounds.Height / 2) - gameover_texture.Height / 2, gameover_texture.Width, gameover_texture.Height);
block.Add(blockgrön_rect);
block2.Add(blockröd_rect);
for (int i = 1; i < 2; i++)
{
for (int g = 1; g < 13; g++)
{
block2.Add(new Rectangle((g * 63) - 60, (i * 20), blockröd_texture.Width, blockröd_texture.Height));
}
}
for (int i = 1; i < 4; i++)
{
for (int g = 1; g < 13; g++)
{
block.Add(new Rectangle((g * 63) - 60, (i * 20) + 20, blockgrön_texture.Width, blockgrön_texture.Height));
}
}
}
protected override void UnloadContent()
{
// TODO: Unload any non ContentManager content here
}
protected override void Update(GameTime gameTime)
{
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed || Keyboard.GetState().IsKeyDown(Keys.Escape))
{
if (poang == highscore)
{
sw = new StreamWriter("highscore.txt");
sw.WriteLine(poang);
sw.Close();
}
Exit();
}
if (Start == true)
{
boll_rect.X += (int)boll_speed.X;
boll_rect.Y += (int)boll_speed.Y;
}
if (Start == false)
{
boll_rect.X = linje_rect.X + ((linje_texture.Width / 2) - (boll_texture.Width / 2)); //how the ball condition is to the long line
boll_rect.X = linjeliten_rect.X + ((linjeliten_texture.Width / 2) - (boll_texture.Width / 2)); //the same but ball condition to small line
}
if (boll_rect.X > Window.ClientBounds.Width - boll_texture.Width || boll_rect.X < 0)
boll_speed.X *= -1;
if (boll_rect.Y > Window.ClientBounds.Height - boll_texture.Height || boll_rect.Y < 0)
boll_speed.Y *= -1;
if (boll_rect.Y > Window.ClientBounds.Height - boll_texture.Height)
{
liv -= 1;
Start = false;
boll_rect.X = (Window.ClientBounds.Width - boll_texture.Width) / 2;
boll_rect.Y = 556;
linje_rect.X = (Window.ClientBounds.Width - linje_texture.Width) / 2;
linje_rect.Y = 580;
linjeliten_rect.X = (Window.ClientBounds.Width - linjeliten_texture.Width) / 2;
linjeliten_rect.Y = 580;
}
KeyboardState ks = Keyboard.GetState();
if (ks.IsKeyDown(Keys.Left))
{
linje_rect.X -= (int)linje_speed.X;
linjeliten_rect.X -= (int)linjeliten_speed.X;
holdingleft = true;
}
else if (ks.IsKeyDown(Keys.Right))
{
linje_rect.X += (int)linje_speed.X;
linjeliten_rect.X += (int)linjeliten_speed.X;
holdingright = true;
}
else if (ks.IsKeyDown(Keys.Space))
{
Start = true;
}
if (ks.Equals(new KeyboardState()))
{
resetballspeed = true;
}
if (linje_rect.X > Window.ClientBounds.Width - linje_texture.Width)
linje_rect.X = (Window.ClientBounds.Width - linje_texture.Width);
if (linjeliten_rect.X > Window.ClientBounds.Width - linjeliten_texture.Width)
linjeliten_rect.X = (Window.ClientBounds.Width - linjeliten_texture.Width);
if (linje_rect.X < 0)
linje_rect.X = 0;
if (linjeliten_rect.X < 0)
linjeliten_rect.X = 0;
if (linje_rect.Intersects(boll_rect))
{
boll_speed.Y *= -1;
boll_rect.Y += (int)boll_speed.Y;
if (holdingleft == true)
{
boll_speed.X -= 2;
}
else if (holdingright == true)
{
boll_speed.X += 2;
}
else if (resetballspeed == true)
{
boll_speed.X = 1;
}
}
if (linjeliten_rect.Intersects(boll_rect))
{
boll_speed.Y *= -1;
boll_rect.Y += (int)boll_speed.Y;
if (holdingleft == true)
{
boll_speed.X -= 1;
}
else if (holdingright == true)
{
boll_speed.X += 1;
}
else if (resetballspeed == true)
{
boll_speed.X = 1;
}
}
for (int j = 1; j < block.Count; j++)
{
if (boll_rect.Intersects(block[j]))
{
boll_speed.Y *= -1;
poang += 1;
block.RemoveAt(j);
if (poang > highscore)
{
highscore++;
}
}
}
for (int k = 1; k < block2.Count; k++)
{
if (boll_rect.Intersects(block2[k]))
{
boll_speed.Y *= -1;
poang += 5;
block2.RemoveAt(k);
if (poang > highscore)
{
highscore += 5;
}
}
}
holdingleft = false;
holdingright = false;
base.Update(gameTime);
}
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.Black);
spriteBatch.Begin();
if (liv > 0)
{
if (poang < 10)
{
spriteBatch.Draw(linje_texture, linje_rect, Color.White);
}
else if (poang > 9)
{
spriteBatch.Draw(linjeliten_texture, linjeliten_rect, Color.White);
}
spriteBatch.Draw(boll_texture, boll_rect, Color.White);
spriteBatch.DrawString(spritefont, "Lives left: " + liv, Vector2.Zero, Color.White);
spriteBatch.DrawString(spritefont, "Points: " + poang, new Vector2(350, 0), Color.White);
spriteBatch.DrawString(spritefont, "Highscore: " + highscore, new Vector2(660, 0), Color.White);
foreach (Rectangle g in block)
{
spriteBatch.Draw(blockgrön_texture, g, Color.White);
}
foreach (Rectangle t in block2)
{
spriteBatch.Draw(blockröd_texture, t, Color.White);
}
}
else if (liv == 0)
{
spriteBatch.Draw(gameover_texture, gameover_rect, Color.White);
if (poang == highscore)
{
sw = new StreamWriter("highscore.txt");
sw.WriteLine(poang);
sw.Close();
}
}
spriteBatch.End();
base.Draw(gameTime);
}
}
Having trouble with these parts:
for (int j = 1; j < block.Count; j++) //loopar igenom alla block
{
if (boll_rect.Intersects(block[j])) //om bollen träffar rutorna
{
boll_speed.Y *= -1;
poang += 1;
block.RemoveAt(j); //tar bort gröna blocket man träffar
if (poang > 9)
{
linje_rect.Width = 60;
}
if (poang > highscore)
{
highscore++;
}
}
}
for (int k = 1; k < block2.Count; k++)
{
if (boll_rect.Intersects(block2[k]))
{
boll_speed.Y *= -1;
poang += 5;
block2.RemoveAt(k);
if (poang > highscore)
{
highscore += 5;
}
block2.RemoveAt(k);
}
}
Replace highscore++; with highscore = poang;
and highscore += 5; with highscore = poang;
to avoid mismatches between highscore and current score.
I have a problem with my code, check the code down below, so you understand which section i'm talking about!
I'm trying to add new block levels when "block.Count == 1", you know when all my blocks are destroyed by the ball. I want it to start a new level with a different block path. When I have:
else if (block.Count == 1 && block2.Count == 1)
{
spriteBatch.Draw(gameover_texture, gameover_rect, Color.White);
}
It doesn't draw out my gameover_texture, when are blocks are gone?
(Sorry about my bad english)
public class Game1 : Game
{
GraphicsDeviceManager graphics;
SpriteBatch spriteBatch;
SpriteFont spritefont;
Texture2D paddle_texture;
Texture2D ball_texture;
Texture2D blockred_texture;
Texture2D blockgreen_texture;
Texture2D gameover_texture;
Rectangle paddle_rect;
Rectangle ball_rect;
Rectangle blockred_rect;
Rectangle blockgreen_rect;
Rectangle gameover_rect;
Vector2 paddle_speed;
Vector2 ball_speed;
Random random;
StreamReader sr;
StreamWriter sw;
int lives = 3;
int points = 0;
int highscore;
int counter = 0;
int seconds = 0;
List<Rectangle> block = new List<Rectangle>();
List<Rectangle> block2 = new List<Rectangle>();
bool Start = false;
bool holdingleft = false;
bool holdingright = false;
bool resetballspeed = false;
public Game1()
{
graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
graphics.PreferredBackBufferWidth = 760;
graphics.PreferredBackBufferHeight = 620;
}
protected override void Initialize()
{
random = new Random();
paddle_speed.X = 6f;
ball_speed.X = random.Next(-1, 1);
ball_speed.Y = 7f;
sr = new StreamReader("highscore.txt");
highscore = int.Parse(sr.ReadLine());
sr.Close();
base.Initialize();
}
protected override void LoadContent()
{
spriteBatch = new SpriteBatch(GraphicsDevice);
spritefont = Content.Load<SpriteFont>("Fonts/Myfont");
paddle_texture = Content.Load<Texture2D>("Pics/linje");
ball_texture = Content.Load<Texture2D>("Pics/boll");
blockgreen_texture = Content.Load<Texture2D>("Pics/block-grön");
blockred_texture = Content.Load<Texture2D>("Pics/block-röd");
gameover_texture = Content.Load<Texture2D>("Pics/GameOver");
paddle_rect = new Rectangle((Window.ClientBounds.Width - paddle_texture.Width) / 2, 580, paddle_texture.Width, paddle_texture.Height);
ball_rect = new Rectangle((Window.ClientBounds.Width - ball_texture.Width) / 2, 556, ball_texture.Width, ball_texture.Height);
gameover_rect = new Rectangle((Window.ClientBounds.Width / 2) - (gameover_texture.Width / 2), (Window.ClientBounds.Height / 2) - gameover_texture.Height / 2, gameover_texture.Width, gameover_texture.Height);
block.Add(blockgreen_rect);
block2.Add(blockred_rect);
for (int i = 1; i < 2; i++)
{
for (int g = 1; g < 3; g++)
{
block2.Add(new Rectangle((g * 63) - 60, (i * 40), blockred_texture.Width, blockred_texture.Height));
}
}
for (int i = 1; i < 2; i++)
{
for (int g = 1; g < 3; g++)
{
block.Add(new Rectangle((g * 63) - 60, (i * 20) + 40, blockgreen_texture.Width, blockgreen_texture.Height));
}
}
}
protected override void UnloadContent()
{
// TODO: Unload any non ContentManager content here
}
protected override void Update(GameTime gameTime)
{
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed || Keyboard.GetState().IsKeyDown(Keys.Escape))
Exit();
if (Start == true) //kolla om "Start == true",
{
ball_rect.X += (int)ball_speed.X;
ball_rect.Y += (int)ball_speed.Y;
}
if (Start == false)
{
ball_rect.X = paddle_rect.X + ((paddle_rect.Width / 2) - (ball_texture.Width / 2));
}
if (ball_rect.X > Window.ClientBounds.Width - ball_texture.Width || ball_rect.X < 0)
ball_speed.X *= -1;
if (ball_rect.Y > Window.ClientBounds.Height - ball_texture.Height || ball_rect.Y < 0)
ball_speed.Y *= -1;
if (ball_rect.Y > Window.ClientBounds.Height - ball_texture.Height)
{
lives -= 1;
Start = false;
ball_rect.X = (Window.ClientBounds.Width - ball_texture.Width) / 2;
ball_rect.Y = 556;
paddle_rect.X = (Window.ClientBounds.Width - paddle_texture.Width) / 2;
paddle_rect.Y = 580;
}
KeyboardState ks = Keyboard.GetState();
if (ks.IsKeyDown(Keys.Left))
{
paddle_rect.X -= (int)paddle_speed.X;
holdingleft = true;
}
else if (ks.IsKeyDown(Keys.Right))
{
paddle_rect.X += (int)paddle_speed.X;
holdingright = true;
}
else if (ks.IsKeyDown(Keys.Space))
{
Start = true;
}
else if (ks.Equals(new KeyboardState()))
{
resetballspeed = true;
}
if (paddle_rect.X > Window.ClientBounds.Width - paddle_rect.Width)
paddle_rect.X = (Window.ClientBounds.Width - paddle_rect.Width);
if (paddle_rect.X < 0)
paddle_rect.X = 0;
if (paddle_rect.Intersects(ball_rect))
{
ball_speed.Y *= -1;
ball_rect.Y += (int)ball_speed.Y;
if (holdingleft == true)
{
ball_speed.X -= 3;
}
else if (holdingright == true)
{
ball_speed.X += 3;
}
else if (resetballspeed == true)
{
ball_speed.X = 1;
}
}
if (points == highscore)
{
sw = new StreamWriter("highscore.txt");
sw.WriteLine(points);
sw.Close();
}
for (int j = 1; j < block.Count; j++)
{
if (ball_rect.Intersects(block[j]))
{
ball_speed.Y *= -1;
points += 1;
block.RemoveAt(j);
if (points > 9)
{
paddle_rect.Width = 60;
}
if (points > highscore)
{
highscore = points;
}
}
}
for (int k = 1; k < block2.Count; k++)
{
if (ball_rect.Intersects(block2[k]))
{
ball_speed.Y *= -1;
points += 5;
block2.RemoveAt(k);
if (points > 9)
{
paddle_rect.Width = 60;
}
if (points > highscore)
{
highscore = points;
}
}
}
holdingleft = false;
holdingright = false;
counter++;
if (counter == 60)
{
seconds++;
counter = 0;
}
base.Update(gameTime);
}
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.Black);
// TODO: Add your drawing code here
spriteBatch.Begin();
if (lives > 0)
{
spriteBatch.Draw(ball_texture, ball_rect, Color.White);
spriteBatch.Draw(paddle_texture, paddle_rect, Color.White);
spriteBatch.DrawString(spritefont, "Lives left: " + lives, Vector2.Zero, Color.White);
spriteBatch.DrawString(spritefont, "Points: " + points, new Vector2(350, 0), Color.White);
spriteBatch.DrawString(spritefont, "Timer: " + seconds, new Vector2(350, 600), Color.White);
spriteBatch.DrawString(spritefont, "Highscore: " + highscore, new Vector2(660, 0), Color.White);
foreach (Rectangle g in block)
{
spriteBatch.Draw(blockgreen_texture, g, Color.White);
}
foreach (Rectangle t in block2)
{
spriteBatch.Draw(blockred_texture, t, Color.White);
}
}
else if (block.Count == 1 && block2.Count == 1)
{
spriteBatch.Draw(gameover_texture, gameover_rect, Color.White);
}
else if (lives == 0)
{
spriteBatch.Draw(gameover_texture, gameover_rect, Color.White);
}
spriteBatch.End();
base.Draw(gameTime);
}
}
Fixed the problem now, by putting the else if-statement inside "if (lives > 0)"
The original code is:
partial class Game1 : Microsoft.Xna.Framework.Game
{
public enum GameState
{
StateMainMenu,
StatePlaying,
StateGameOver,
StateHelp,
}
GameState currentState = GameState.StateMainMenu;
KeyboardState kbState;
Keys[] pressedKeys;
Queue<FallingCharacter> Letters = new Queue<FallingCharacter>();
float nextLetterTime = 0.6f;
int NextSpeedup = 20; // in 20 points lets speed it up
int iSpeed = 2;
int Score = 0;
GraphicsDeviceManager graphics;
SpriteBatch spriteBatch;
SpriteFont spriteFont;
public Game1()
{
graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
graphics.PreferredBackBufferWidth = 800;
graphics.PreferredBackBufferHeight = 600;
graphics.ApplyChanges();
}
protected override void LoadContent()
{
spriteBatch = new SpriteBatch(GraphicsDevice);
spriteFont = Content.Load<SpriteFont>("GameFont");
base.LoadContent();
}
public void OnKeyPressed(Keys k)
{
if ((currentState == GameState.StateMainMenu ||
currentState == GameState.StateGameOver)
&& k == Keys.Enter)
{
currentState = GameState.StatePlaying;
nextLetterTime = 0.0f;
NextSpeedup = 20; // in 20 points lsets speed it up
iSpeed = 1;
Score = 0;
}
else if (currentState == GameState.StatePlaying)
{
string sName = Enum.GetName(typeof(Keys), k);
if (Letters.Count > 0 &&
String.Compare(Letters.Peek().character.ToString(), sName) == 0)
{
Score += 100;
Letters.Dequeue();
NextSpeedup--;
if (NextSpeedup <= 0)
{
iSpeed++;
NextSpeedup = 20;
}
}
}
if (k == Keys.Escape)
{
this.Exit();
}
}
protected override void Update(GameTime gameTime)
{
// The time since Update was called last
float elapsed = (float)gameTime.ElapsedGameTime.TotalSeconds;
kbState = Keyboard.GetState();
Keys[] newKeys = (Keys[])kbState.GetPressedKeys().Clone();
if (pressedKeys != null)
{
foreach (Keys k in newKeys)
{
bool bFound = false;
foreach (Keys k2 in pressedKeys)
{
if (k == k2)
{
bFound = true;
break;
}
}
if (!bFound)
{
OnKeyPressed(k);
}
}
}
pressedKeys = newKeys;
if (currentState == GameState.StatePlaying)
{
foreach (FallingCharacter fc in Letters)
{
if (fc.Pos.Y + 50 > graphics.PreferredBackBufferHeight)
{
currentState = GameState.StateGameOver;
Letters.Clear();
break;
}
else
{
fc.Pos.Y += (elapsed * (float)(iSpeed * 40));
}
}
nextLetterTime -= elapsed;
if (nextLetterTime <= 0 && currentState != GameState.StateGameOver)
{
nextLetterTime = 0.75f - (iSpeed * .03f);
Random r = new Random();
Letters.Enqueue(new FallingCharacter(
r.Next(graphics.PreferredBackBufferWidth - 30), -30,
Color.LightGreen, (char)((int)'A' + r.Next(25))));
}
}
base.Update(gameTime);
}
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);
spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.AlphaBlend);
switch (currentState)
{
case GameState.StateMainMenu:
{
spriteBatch.DrawString(spriteFont,
"Press Enter to begin",
new Vector2(graphics.PreferredBackBufferWidth / 4,
graphics.PreferredBackBufferHeight / 2),
Color.White);
}
break;
case GameState.StatePlaying:
{
spriteBatch.DrawString(spriteFont,
"Score: " + Score.ToString(),
new Vector2(10, 10), Color.White);
foreach (FallingCharacter fc in Letters)
{
fc.Render(spriteBatch, spriteFont);
}
}
break;
case GameState.StateGameOver:
{
spriteBatch.DrawString(spriteFont,
"Score: " + Score.ToString(),
new Vector2(10, 10), Color.White);
spriteBatch.DrawString(spriteFont,
"Game Over",
new Vector2(graphics.PreferredBackBufferWidth / 3,
graphics.PreferredBackBufferHeight / 2),
Color.LightBlue);
spriteBatch.DrawString(spriteFont,
"Press Return to Continue",
new Vector2(graphics.PreferredBackBufferWidth / 6,
graphics.PreferredBackBufferHeight / 2 + 50),
Color.LightBlue);
}
break;
}
spriteBatch.End();
base.Draw(gameTime);
}
}
}
and I need change the quque to list().
after I changed Queue Letters = new Queue();
to List Letters = new List();
Can anyone help me what need change next.
I feel really confused about this, thank you very much.
If you want to keep the same behavior of the Queue (First-In-First-Out), you must do the following changes(changes in bold):
if (Letters.Count > 0 &&
String.Compare(Letters.Peek().character.ToString(),
sName) == 0)
changes to
if (Letters.Count > 0 &&
String.Compare(Letters.First().character.ToString(),
sName) == 0)
to keep the behavior where Peek returns the first character.
Letters.Dequeue();
changes to
Letters.RemoveAt(0);
to remove the first element like Dequeue does.
Note that you could do a check to make sure that the List is not empty.
Letters.Enqueue(new FallingCharacter(
r.Next(graphics.PreferredBackBufferWidth
- 30), -30,
Color.LightGreen, (char)((int)'A' + r.Next(25))));
changes to
Letters.Add(new FallingCharacter(
r.Next(graphics.PreferredBackBufferWidth
- 30), -30,
Color.LightGreen, (char)((int)'A' + r.Next(25))));
to append the FallingCharacter to the end of the list.