I can't get RGB values from surfaceView. I'm working with xamarin, C#.
tried to use getBitmap, but this method not for SurfaceView..
I need to get rgb from camera live stream by touching some place at surfaceView.
Maybe i need to use something else instead of surfaceView?
`
public class MainActivity : Activity, ISurfaceHolderCallback, Camera.IPreviewCallback, View.IOnTouchListener
{
Camera _camera;
SurfaceView _surfaceview;
int redValue,blueValue,greenValue;
int pixel;
Bitmap bitmap;
TextView _textview;
protected override void OnCreate (Bundle savedInstanceState)
{
base.OnCreate (savedInstanceState);
SetContentView (Resource.Layout.Main);
_surfaceview = (SurfaceView)FindViewById (Resource.Id.surfaceView1);
_surfaceview.SetOnTouchListener (this);
var holder = _surfaceview.Holder;
holder.AddCallback (this);
holder.SetType (Android.Views.SurfaceType.PushBuffers);
TabHost tabhost = FindViewById<TabHost> (Resource.Id.myTab);
tabhost.Setup ();
TabHost.TabSpec tabhost1 = tabhost.NewTabSpec ("Tab1");
tabhost1.SetContent (Resource.Id.tab1);
tabhost1.SetIndicator ("CAMERA");
tabhost.AddTab (tabhost1);
TabHost.TabSpec tabhost2 = tabhost.NewTabSpec ("Tab2");
tabhost2.SetContent (Resource.Id.tab2);
tabhost2.SetIndicator ("RGB");
tabhost.AddTab (tabhost2);
_textview = (TextView)FindViewById (Resource.Id.textView1);
}
public bool OnTouch(View v, MotionEvent e)
{
switch (e.Action)
{
case MotionEventActions.Down:
break;
case MotionEventActions.Up:
pixel = bitmap.GetPixel ((int)e.GetX (), (int)e.GetY ());
var _color = new Color (pixel);
redValue = _color.R;
blueValue = _color.G;
greenValue = _color.B;
_textview.Text = "Hello";
break;
}
return true;
}
public void SurfaceCreated(ISurfaceHolder holder)
{
try{
_camera = Android.Hardware.Camera.Open();
Android.Hardware.Camera.Parameters p = _camera.GetParameters();
p.PictureFormat = Android.Graphics.ImageFormatType.Jpeg;
_camera.SetParameters(p);
_camera.SetPreviewCallback(this);
_camera.Lock();
_camera.SetDisplayOrientation(90);
_camera.SetPreviewDisplay(holder);
_camera.StartPreview();
}
catch(System.IO.IOException e){
}
}
public void SurfaceDestroyed(ISurfaceHolder holder){
_camera.Unlock ();
_camera.StopPreview ();
_camera.Release ();
}
public void SurfaceChanged(ISurfaceHolder holder,Android.Graphics.Format f,int i, int j)
{
}
void Camera.IPreviewCallback.OnPreviewFrame(byte[] b, Android.Hardware.Camera c)
{
}
}}
`
in PreviewCallBack:
Camera.Parameters parameters = camera.getParameters();
Camera.Size size = parameters.getPreviewSize();
Camera.CameraInfo info = new Camera.CameraInfo();
Camera.getCameraInfo(0, info);
if(mBitmapWidth == 0 || mBitmapHeight == 0) {
mBitmapWidth = size.width;
mBitmapHeight = size.height;
}
mCurrentImageRGB = new int[mBitmapWidth*mBitmapHeight];
Recognize.decodeYUV420SP2(mCurrentImageRGB, data, mBitmapWidth, mBitmapHeight);
in CameraPreview:
mCamera.getParameters().setPreviewFormat(ImageFormat.NV21);
in surfaceChanged:
setCameraDisplayOrientation((Activity)mContext,0,mCamera);
and setCameraDisplayOrientation (this method i added in CameraPreview class):
public static void setCameraDisplayOrientation(Activity activity, int cameraId, android.hardware.Camera camera) {
android.hardware.Camera.CameraInfo info = new android.hardware.Camera.CameraInfo();
android.hardware.Camera.getCameraInfo(cameraId, info);
int rotation = activity.getWindowManager().getDefaultDisplay().getRotation();
int degrees = 0;
switch (rotation) {
case Surface.ROTATION_0:
degrees = 0;
break;
case Surface.ROTATION_90:
degrees = 90;
break;
case Surface.ROTATION_180:
degrees = 180;
break;
case Surface.ROTATION_270:
degrees = 270;
break;
}
int result;
if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
result = (info.orientation + degrees) % 360;
result = (360 - result) % 360;
} else {
result = (info.orientation - degrees + 360) % 360;
}
camera.setDisplayOrientation(result);
}
hope this will help )
in mCurrentImageRGB will be your int array with RGB integers for this image, you can them do with it whatever you want )
int middlePixel = mCurrentImageRGB[mBitmapWidth/2 + mBitmapHeight/2]; // this is your rgb pixel somewhere in center of image :)
I forget, decoder:
public static void decodeYUV420SP2(int[] rgb, byte[] yuv420sp, int width, int height) {
final int frameSize = width * height;
for (int j = 0, yp = 0; j < height; j++) {
int uvp = frameSize + (j >> 1) * width, u = 0, v = 0;
for (int i = 0; i < width; i++, yp++) {
int y = (0xff & ((int) yuv420sp[yp])) - 16;
if (y < 0)
y = 0;
if ((i & 1) == 0) {
v = (0xff & yuv420sp[uvp++]) - 128;
u = (0xff & yuv420sp[uvp++]) - 128;
}
int y1192 = 1192 * y;
int r = (y1192 + 1634 * v);
int g = (y1192 - 833 * v - 400 * u);
int b = (y1192 + 2066 * u);
if (r < 0)
r = 0;
else if (r > 262143)
r = 262143;
if (g < 0)
g = 0;
else if (g > 262143)
g = 262143;
if (b < 0)
b = 0;
else if (b > 262143)
b = 262143;
rgb[yp] = 0xff000000 | ((r << 6) & 0xff0000) | ((g >> 2) & 0xff00) | ((b >> 10) & 0xff);
}
}
}
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; }
}
I'm building a tile engine for my first game ever and i've been following a guide step by step (can't link it because i'm limited to 2). I have however, made a few modifications to the tilemap so that i can continue with my project.
And while testing my program a noticed a bug that i was hoping you guys could help me resolve...
...The tile engine is drawing the wrong tiles!
This is my TileMap (with numbers assigned to each tile) and this is what my engine draws.
While it should follow the order as seen below (the code is self-explanatory)
rows[0].columns[3].tileID = 0;
rows[0].columns[4].tileID = 1;
rows[0].columns[5].tileID = 2;
rows[0].columns[6].tileID = 3;
rows[0].columns[7].tileID = 4;
rows[1].columns[3].tileID = 5;
rows[1].columns[4].tileID = 6;
rows[1].columns[5].tileID = 7;
rows[1].columns[6].tileID = 8;
rows[1].columns[7].tileID = 9;
rows[2].columns[3].tileID = 10;
rows[2].columns[4].tileID = 11;
rows[2].columns[5].tileID = 12;
rows[2].columns[6].tileID = 13;
rows[2].columns[7].tileID = 14;
rows[3].columns[3].tileID = 15;
rows[3].columns[4].tileID = 16;
rows[3].columns[5].tileID = 17;
rows[3].columns[6].tileID = 18;
rows[3].columns[7].tileID = 19;
rows[4].columns[3].tileID = 20;
rows[4].columns[4].tileID = 21;
rows[4].columns[5].tileID = 22;
rows[4].columns[6].tileID = 23;
rows[4].columns[7].tileID = 24;
rows[5].columns[3].tileID = 25;
rows[5].columns[4].tileID = 26;
rows[5].columns[5].tileID = 27;
rows[5].columns[6].tileID = 28;
rows[5].columns[7].tileID = 29;
Code Essentials
The Important parts of my code
Tile.class
Where i define the tile size and have a function which navigates the tilemap to find my deiserd tile.
namespace TileEngine
{
static class Tile
{
static public Texture2D tileSetTexture;
static public int tileWidth = 48;
static public int tileHeight = 48;
static public Rectangle getSourceRectangle(int tileIndex)
{
int tileY = tileIndex / (tileSetTexture.Width / tileWidth);
int tileX = tileIndex % (tileSetTexture.Height / tileHeight);
return new Rectangle(tileX * tileWidth, tileY * tileHeight, tileWidth, tileHeight);
}
}
}
MapCell
Where i define the tileID
class MapCell
{
public List<int> baseTiles = new List<int>();
public int tileID
{
get { return baseTiles.Count > 0 ? baseTiles[0] : 0; }
set
{
if (baseTiles.Count > 0)
baseTiles[0] = value;
else
addBaseTile(value);
}
}
public void addBaseTile(int tileID)
{
baseTiles.Add(tileID);
}
public MapCell(int tileID)
{
this.tileID = tileID;
}
}
TileMap
Where i build the map
class MapRow
{
public List<MapCell> columns = new List<MapCell>();
}
class TileMap
{
public List<MapRow> rows = new List<MapRow>();
public int mapWidth = 50;
public int mapHeight = 50;
public TileMap()
{
for (int y = 0; y < mapHeight; y++)
{
MapRow thisRow = new MapRow();
for (int x = 0; x < mapWidth; x++)
{
thisRow.columns.Add(new MapCell(0));
}
rows.Add(thisRow);
}
}
}
Draw
And lastly my draw code.
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.Black);
spriteBatch.Begin();
Vector2 firstSquare = new Vector2(Camera.location.X / Tile.tileWidth, Camera.location.Y / Tile.tileHeight);
int firstX = (int)firstSquare.X;
int firstY = (int)firstSquare.Y;
Vector2 squareOffset = new Vector2(Camera.location.X % Tile.tileWidth, Camera.location.Y % Tile.tileHeight);
int offsetX = (int)squareOffset.X;
int offsetY = (int)squareOffset.Y;
for (int y = 0; y < squaresDown; y++)
{
for (int x = 0; x < squaresAcross; x++)
{
foreach (int tileID in myMap.rows[y + firstY].columns[x + firstX].baseTiles)
{
spriteBatch.Draw(
Tile.tileSetTexture,
new Rectangle(
(x * Tile.tileWidth) - offsetX, (y * Tile.tileHeight) - offsetY,
Tile.tileWidth, Tile.tileHeight),
Tile.getSourceRectangle(tileID),
Color.White);
}
}
}
spriteBatch.End();
base.Draw(gameTime);
}
I want to realize method "Draw" of class Polygon
I have WindForms project, form, and the pictureBox1,
I want that "Draw" drawing polygon in pictureBox1 and I have opportunity to move image
I don't konw how to realize it. Help, please.
public class Polygon
{
public Point[] vertexes { get; protected set; }
public Polygon(params int[] vertex)
{
if (vertex == null || vertex.Length <= 2)
throw new Exception("someText");
if (vertex.Length % 2 != 0)
throw new Exception("someText");
vertexes = new Point[vertex.Length / 2];
ColorContour = System.Drawing.Color.DarkRed;
Priming = false;
for (int i = 0, j = 0; i < vertexes.Length; i++, j += 2)
vertexes[i] = new Point(vertex[j], vertex[j + 1]);
vertexes = Point.Sort(vertexes);
if (vertexes == null || vertexes.Length <= 2)
throw new Exception("someText");
}
public double Perimetr
{
get
{
double res = 0;
for (int i = 1; i < vertexes.Length; i++)
res += Point.Length(vertexes[i - 1], vertexes[i]);
return res;
}
}
public override void Move(int deltax, int deltay)
{
vertexes[0].x = deltax;
vertexes[0].y = deltay;
for (int i = 1; i < vertexes.Length; i++)
{
vertexes[i].x -= deltax;
vertexes[i].y -= deltay;
}
}
public void Zoom(double size)
{
if (size == 0)
return;
Point firstP = new Point(vertexes[0].x, vertexes[0].y);
Point Center = Point.CentrMass(vertexes);
for (int i = 0; i < vertexes.Length; ++i)
{
vertexes[i].x = Convert.ToInt32(size * (vertexes[i].x - Center.x) + Center.x);
vertexes[i].y = Convert.ToInt32(size * (vertexes[i].y - Center.y) + Center.y);
}
Move(firstP.x, firstP.y);
}
public void Draw( ??)
{
**????**
}
publicabstract double Square { get; }
You need to take in a System.Drawing.Graphics as a parameter, and call Graphics.DrawPolygon() function. Then in the picturebox, override or implement the OnPaint() event, and call your draw function with the Graphics you receive as a parameter (child of the eventargs) in OnPaint().
I know there's a lot of Fibonacci questions and answers on Stack overflow and the web in general, but this is a problem that's been vexing me for a while now, and i can't seem to crack it or find a solution.
Creating Fibonacci algorithms are easy enough, there's plenty of them, but i'm trying to create the boxes in a spiral formation graphically using C#. This is not for Uni or anything, it's just a problem that i've spent way too much time on that i now need to find a solution for, if you know what i mean?
Here's what i've got so far, now i did have a better configuration, but with countless hours of revising the code, this is what i have at the moment:
public partial class Form1 : Form
{
public const int FIBNUM = 6;
public const int CENTRE = 10;
public const int SIZE = 10;
public const int OFFSET = 100;
public Form1()
{
InitializeComponent();
drawSpiral();
}
private int fib(int n)
{
switch (n)
{
case 0:
return 0;
case 1:
return 1;
default:
return fib(n - 1) + fib(n - 2);
}
}
private void drawSpiral()
{
if (pictureBox1.Image == null)
{
pictureBox1.Image = new Bitmap(pictureBox1.Width, pictureBox1.Height);
}
using (Graphics g = Graphics.FromImage(pictureBox1.Image))
{
Rectangle r = new Rectangle(0, 0, 0, 0);
int fibnum = 0;
int centre = 0;
int size = 0;
int cnt = 0;
for (int n = 1; n <= FIBNUM; n++)
{
fibnum = fib(n);
centre = fibnum * CENTRE;
size = fibnum * SIZE;
++cnt;
if (cnt == 1)
{
if (n == 1)
{
r = new Rectangle(fibnum + OFFSET, fibnum + OFFSET, size, size);
g.DrawRectangle(Pens.Red, r);
r = new Rectangle((fibnum + size) + OFFSET, fibnum + OFFSET, size, size);
g.DrawRectangle(Pens.Purple, r);
n++;
}
else
{
r = new Rectangle((centre - size) + OFFSET, (centre - size) + OFFSET, size, size);
g.DrawRectangle(Pens.Black, r);
}
continue;
}
if(cnt == 2)
{
r = new Rectangle((fibnum) + OFFSET, (fibnum - size) + OFFSET, size, size);
g.DrawRectangle(Pens.Blue, r);
continue;
}
if (cnt == 3)
{
r = new Rectangle((fibnum - size) + OFFSET, (fibnum - size) + OFFSET, size, size);
g.DrawRectangle(Pens.Green, r);
continue;
}
if (cnt == 4)
{
r = new Rectangle((fibnum - size / 2) + OFFSET, (fibnum - size) + OFFSET, size, size);
g.DrawRectangle(Pens.Gray, r);
}
cnt = 0;
}
}
pictureBox1.Invalidate();
}
I've taken an image from wikipedia of what it is i'm trying to create graphically :
Thanks in advance.
I think your code is too complicated, because you try to do a lot at once. Consider the following code where the spiral is drawn around the origin, without scaling and translating:
// the current fibonacci numbers
int current = 1;
int previous = 0;
// the current bounding box
int left = 0;
int right = 1;
int top = 0;
int bottom = 0;
// the number of boxes you want to draw
const int N = 10;
for (int i = 0; i < N; i++) {
switch (i % 4) {
case 0: // attach to bottom of current rectangle
drawRectangle(g, left, right, bottom, bottom + current);
bottom += current;
break;
case 1: // attach to right of current rectangle
drawRectangle(g, right, right + current, top, bottom);
right += current;
break;
case 2: // attach to top of current rectangle
drawRectangle(g, left, right, top - current, top);
top -= current;
break;
case 3: // attach to left of current rectangle
drawRectangle(g, left - current, left, top, bottom);
left -= current;
break;
}
// update fibonacci number
int temp = current;
current += previous;
previous = temp;
}
You can then deal with the actual drawing part in the separate method drawRectangle (I left out all details about the actual graphics objects, but you can probably do that yourself).
const int SCALE = 5;
const int OFFSET = 150;
private void drawRectangle(Graphics g, int left, int right, int top, int bottom)
{
g.DrawRectangle(Pens.Red, new Rectangle(SCALE * left + OFFSET,
SCALE * top + OFFSET,
SCALE * (right - left),
SCALE * (bottom - top)));
}
Output:
Here you go :
public partial class Form1 : Form
{
public const int FIBNUM = 8;
public const int CENTERX = 300;
public const int CENTERY = 300;
public const int ZOOM = 10;
public Form1()
{
InitializeComponent();
drawSpiral();
}
private int fib(int n, int p = 0, int q = 1)
{
switch (n)
{
case 0: return 0;
case 1: return q;
default: return fib(n - 1, q, p + q);
}
}
private void drawSpiral()
{
if (pictureBox1.Image == null)
{
pictureBox1.Image = new Bitmap(pictureBox1.Width, pictureBox1.Height);
}
using (Graphics g = Graphics.FromImage(pictureBox1.Image))
{
Rectangle r = new Rectangle(0, 0, 0, 0);
int x = CENTERX;
int y = CENTERY;
for (int n = 1; n <= FIBNUM; n++)
{
int fibnum = fib(n)*ZOOM;
r = new Rectangle(x, y, fibnum, fibnum);
g.DrawRectangle(Pens.Red, r);
switch (n % 4)
{
case 0:
{
y += fibnum;
break;
}
case 1:
{
x += fibnum;
y -= fib(n - 1) * ZOOM;
break;
}
case 2:
{
x -= fib(n - 1)*ZOOM;
y -= fib(n + 1)*ZOOM;
break;
}
case 3:
{
x -= fib(n + 1) * ZOOM;
break;
}
}
}
pictureBox1.Invalidate();
}
}
}
Note that i have changed your fibonacci function with a better performing one ; in particular, mine calculates the next fibonacci number in linear time.
With some MatheMagic ( sorry for the joke :) ) you can make it even smarter, and obtain
private int move(int n, int a, int currentFib)
{
switch (a)
{
case 1: return currentFib;
case 2: return -fib(n - 1) * ZOOM;
case 3: return -fib(n + 1) * ZOOM;
default: return 0;
}
}
private void drawSpiral()
{
if (pictureBox1.Image == null)
{
pictureBox1.Image = new Bitmap(pictureBox1.Width, pictureBox1.Height);
}
using (Graphics g = Graphics.FromImage(pictureBox1.Image))
{
Rectangle r = new Rectangle(0, 0, 0, 0);
int x = CENTERX;
int y = CENTERY;
for (int n = 1; n <= FIBNUM; n++)
{
int fibnum = fib(n)*ZOOM;
r = new Rectangle(x, y, fibnum, fibnum);
g.DrawRectangle(Pens.Red, r);
x += move(n, n % 4, fibnum);
y += move(n, (n + 1) % 4, fibnum);
}
pictureBox1.Invalidate();
}
}
private int fib(int n)
{
switch (n)
{
case 0:
return 0;
case 1:
return 1;
default:
return fib(n - 1) + fib(n - 2);
}
}
That is enough slow,maybe it doesn't matter in this task but isn't it better to use an array fib[1..n] (fib[0]=0 fib[1]=1 for(i = 2;i<=n;i++)fib[i]=fib[i-1]+fib[i-2]) that will work in O(n) not in O(n*(1.7^n))