Calculating the average of raw data for hand tracking - c#

I have been trying to calculate the average of the raw data that I have been receiving from my camera. The reason is that at the moment I am just using the raw data and this causes quite abit of jitter. Therefore I am wanting the past 5 locations and then an average to be calculated as this would make the hand tracking experience much more smoother.
I have been trying to store the previous 5 locations but when I attempted this I only get the latest raw data which then get stored and overwrites it for the locations.
The OnNewFrame() method is where I get the raw data.
Help on how I would do this would great.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;
using SDKAttempt;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using System.Drawing;
//The sdk module tracks geometric nodes for every frame
namespace PercUtils
{
class DepthPipeline : UtilMPipeline
{
double screenWidth = GraphicsAdapter.DefaultAdapter.CurrentDisplayMode.Width;
double screenHeight = GraphicsAdapter.DefaultAdapter.CurrentDisplayMode.Height;
PXCMGesture.GeoNode nData; //data the we will get from the camera
double xPos = 0;
double yPos = 0;
double zPos = 0;
double handOpeness = 0;
private bool finished;
PXCMGesture.GeoNode[] nodeData = new PXCMGesture.GeoNode[1]; //data from hand
public DepthPipeline()
: base()
{
finished = false;
EnableImage(PXCMImage.ColorFormat.COLOR_FORMAT_DEPTH);
EnableGesture(); //This function is called to enable finger tracking and gesture recognition
}
public override void OnGestureSetup(ref PXCMGesture.ProfileInfo pinfo) //the application can override this function to fine-tune any parameters during module initilisation
{
base.OnGestureSetup(ref pinfo);
}
public override void OnGesture(ref PXCMGesture.Gesture gesture) //the application needs to receive pose/gesture, the application can override the ongesture function
{
if (gesture.label == PXCMGesture.Gesture.Label.LABEL_POSE_THUMB_UP)
{
Console.WriteLine("Thumb Up"); //debug
}
base.OnGesture(ref gesture);
}
public override void OnAlert(ref PXCMGesture.Alert alert) //the application can override the OnAlert function to receive alert notifications
{
base.OnAlert(ref alert);
}
public override bool OnNewFrame()
{
double xRatio = screenWidth / 160; //corrects the ratio of the x axis of the camera to work with the width screen - scales the camera cood for the screen being used
double yRatio = screenHeight / 120; //corrects the ratio of the y axis of the camera to work with the height screen - scales the camera cood for the screen being used
PXCMGesture gesture = QueryGesture();
pxcmStatus sts = gesture.QueryNodeData(0, PXCMGesture.GeoNode.Label.LABEL_BODY_HAND_LEFT, out nData); //gets the status of the left hand, out nData because the value isn't set and the function must set it before returning it
if (sts >= pxcmStatus.PXCM_STATUS_NO_ERROR)
{
xPos = (screenWidth - (nData.positionImage.x * xRatio)) + (screenWidth / 2);
yPos = ((nData.positionImage.y * yRatio) - (screenHeight / 2));
zPos = nData.positionWorld.y * 100;
handOpeness = nData.openness;
TitleScreen.setX(xPos); //this corrects the inverted control of the dot
TitleScreen.setY(yPos);
TitleScreen.getHandOpenness(handOpeness);
PlayGame.setX(xPos); //this corrects the inverted control of the dot
PlayGame.setY(yPos);
PlayGame.getHandOpeness(handOpeness);
PlayGame.getZ(zPos); //gets the z coordnidate of the users hand.
PlayGameEasy.setX(xPos); //this corrects the inverted control of the dot
PlayGameEasy.setY(yPos);
PlayGameEasy.getHandOpeness(handOpeness);
PlayGameEasy.getZ(zPos); //gets the z coordnidate of the users hand.
CollisionClass.setX(xPos);
CollisionClass.setY(yPos);
CollisionClass.getZ(zPos);
Button.setX(xPos);
Button.setY(yPos);
Button.getHandOpeness(handOpeness);
ReplayScreen.getX(xPos);
ReplayScreen.getY(yPos);
HighScore.getX(xPos);
HighScore.getY(yPos);
DifficultyScreen.getX(xPos);
DifficultyScreen.getY(yPos);
}
return !finished;
}
public void Finish()
{
finished = true;
}
public bool IsFinished()
{
return finished;
}
public void StartWork()
{
finished = false;
this.LoopFrames();
}
}
}

Could you add an array of 5 double for each xpos, ypos, zpos and an indexAverage
Make all of them private class variables
In your new frame function use:
Xpos_array [indexAverage]= (screenWidth - (nData.positionImage.x * xRatio)) + (screenWidth / 2);
Xpos = Xpos_array.select(x => x / 5.0).sum();
[.....]
indexAverage = (indexAverage+1)%5;

Related

Compute shader isn't updating

I have two files (NewComputeShader.compute and ShaderRun.cs). ShaderRun.cs runs shader and draws it's texture on a camera (script is camera's component)
On start, unity draws one white pixel in a bottom-left corner.
(Twidth = 256, Theight = 256, Agentsnum = 10)
NewComputeShader.compute:
// Each #kernel tells which function to compile; you can have many kernels
#pragma kernel CSUpdate
// Create a RenderTexture with enableRandomWrite flag and set it
// with cs.SetTexture
RWTexture2D<float4> Result;
uint width = 256;
uint height = 256;
int numAgents = 10;
float moveSpeed = 100;
uint PI = 3.1415926535;
float DeltaTime = 1;
uint hash(uint state) {
state ^= 2747636419u;
state *= 2654435769u;
state ^= state >> 16;
state *= 2654435769u;
state ^= state >> 16;
state *= 2654435769u;
return state;
}
uint scaleToRange01(uint state) {
state /= 4294967295.0;
return state;
}
struct Agent {
float2 position;
float angle;
};
RWStructuredBuffer<Agent> agents;
[numthreads(8,8,1)]
void CSUpdate(uint3 id : SV_DispatchThreadID)
{
//if (id.x >= numAgents) { return; }
Agent agent = agents[id.x];
uint random = hash(agent.position.y * width + agent.position.x + hash(id.x));
float2 direction = float2(cos(agent.angle), sin(agent.angle));
float2 newPos = agent.position + direction * moveSpeed * DeltaTime;
if (newPos.x < 0 || newPos.x >= width || newPos.y < 0 || newPos.y >= height) {
newPos.x = min(width - 0.01, max(0, newPos.x));
newPos.y = min(height - 0.01, max(0, newPos.y));
agents[id.x].angle = scaleToRange01(random) * 2 * PI;
}
agents[id.x].position = newPos;
Result[int2(newPos.x, newPos.y)] = float4(1,1,1,1);
}
ShaderRun.cs:
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ShaderRun : MonoBehaviour
{
public ComputeShader computeShader;
public RenderTexture renderTexture;
public int twidth;
public int theight;
public int agentsnum;
ComputeBuffer agentsBuffer;
struct MyAgent
{
public Vector2 position;
public float angle;
};
// Start is called before the first frame update
void Start()
{
renderTexture = new RenderTexture(twidth, theight, 24);
renderTexture.enableRandomWrite = true;
renderTexture.Create();
computeShader.SetTexture(0, "Result", renderTexture);
agentsBuffer = new ComputeBuffer(agentsnum, sizeof(float)*3); //make new compute buffer with specified size, and specified "stride" //stride is like the size of each element, in your case it would be 3 floats, since Vector3 is 3 floats.
ResetAgents();
computeShader.SetBuffer(0, "agents", agentsBuffer); //Linking the compute shader and cs shader buffers
computeShader.Dispatch(0, renderTexture.width / 8, renderTexture.height / 8, 1);
}
void OnRenderImage(RenderTexture src, RenderTexture dest)
{
Graphics.Blit(renderTexture, dest);
}
private void ResetAgents()
{
MyAgent[] aArray = new MyAgent[agentsnum];
for (int i=0; i<agentsnum; i++)
{
MyAgent a = new MyAgent();
a.position = new Vector2(128, 128);
a.angle = 2 * (float)Math.PI * (i / agentsnum);
aArray[i] = a;
}
agentsBuffer.SetData(aArray);
ComputeStepFrame();
}
private void ComputeStepFrame()
{
computeShader.SetFloat("DeltaTime", Time.deltaTime);
int kernelHandle = computeShader.FindKernel("CSUpdate");
computeShader.SetBuffer(kernelHandle, "agents", agentsBuffer);
computeShader.Dispatch(0, renderTexture.width / 8, renderTexture.height / 8, 1);
}
// Update is called once per frame
void Update()
{
ComputeStepFrame();
}
}
Also this is an attempt of recreating this code: https://www.youtube.com/watch?v=X-iSQQgOd1A&t=730s (part: Side-tracked by Slime). Result must be like on a first demonstration of agents in video.
Edit: I really recommend to check this video. It is very good!
I'm doing the same. To start the scaleToRange01 function should probably return a float. As for location you might want to look at the C# side, how are you initializing agents and getting that data into the buffer? Need to create a similar struct in C# then assign it something like below.
int totalSize = (sizeof(float) * 2) + (sizeof(float));
agentBuffer = new ComputeBuffer(agents.Length, totalSize);
agentBuffer.SetData(agents);
computeShader.SetBuffer(0, "agents", agentBuffer);
I am also attempting to recreate this. The problem is Sebastian leaves out his c# code and some of his HLSL so it's hard to put together the pieces that aren't there. I worked nonstop all day yesterday and finally got it to perform demonstration 2. The most difficult thing for me is getting the threading correctly and having the GPU compute all the items I need it to. I am dreading starting the trail dissipation and trail sense but honestly, it felt great getting to demo 2 and it's what is pushing me to keep at it. Everything is very touchy with this project and it is not for the casual programmer. (Also learn a bit about HLSL if you haven't.) Another thing is I don't use his random angle generator I just created my own. I know this doesn't help but just know other people are attempting to struggle through this also. Sebastian is a genius.
Found this question after so much time. But theme is still interesting. Maybe my answer will help passersby here later.
BTW look at this video.
Slime is a game life form now!
The problem with the code from original question is ambiguity with what are you going to process with kernel.
[numthreads(8,8,1)]
void CSUpdate(uint3 id : SV_DispatchThreadID)
{
//if (id.x >= numAgents) { return; }
Agent agent = agents[id.x];
//etc...
}
In this kernel you are intended to process 1D array of agents. You need to dispatch this code like this:
shader.Dispatch(kernelUpdateAgents,
Mathf.CeilToInt(numAgents / (float) xKernelThreadGroupSize),
1,
1);
And of course you need to correct kernel TGS:
[numthreads(8,1,1)]
void CSUpdate(uint3 id : SV_DispatchThreadID)
For 2D texture you need to keep kernel like
[numthreads(8,8,1)]
void ProcessTexture(uint3 id : SV_DispatchThreadID)
{
//some work
}
And only then it is okay to dispatch it with second dimension:
shader.Dispatch(kernelProcessTexture,
Mathf.CeilToInt(TextureWidth / (float) xKernelThreadGroupSize),
Mathf.CeilToInt(TextureHeight / (float) yKernelThreadGroupSize),
1);
P.S. And there is a link to github repo under video.

Black screen when trying to draw model [read edit]

I'm trying to make a world object that can use a camera and draw multiple models at once, each with their own position (and rotation, etc. in the future). Except it comes up with a black screen and I don't know why.
I've tried changing the way the matrices are created, adjusted the positions, and nothing.
World:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Xna.Framework;
using Simple3DWorld.Objects;
namespace Simple3DWorld
{
public class World
{
public Camera Camera;
public ModelObject[] Objects;
public World()
{
Camera = new Camera(new Vector3(0, 0, 1), Vector3.Zero);
Objects = new ModelObject[100];
AddObject(new Landscape(new Vector3(0, 0, -1)));
}
public void AddObject(ModelObject obj)
{
bool added = false;
for (int i = 0; i < Objects.Length && !added; i++)
{
if (Objects[i] == null)
{
Objects[i] = obj;
added = true;
}
}
}
public void Update(GameTime gt)
{
for (int i = 0; i < Objects.Length; i++)
{
if (Objects[i] != null)
{
Objects[i].Update(gt);
}
}
}
public void Draw()
{
for (int i = 0; i < Objects.Length; i++)
{
if (Objects[i] != null)
{
Objects[i].Draw(Camera);
}
}
}
}
}
Camera:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
namespace Simple3DWorld
{
public class Camera
{
public Vector3 Position;
public Vector3 LookingAt;
public float FieldOfView;
public float AspectRatio;
public Camera(Vector3 pos, Vector3 lookAt)
{
Position = pos;
LookingAt = lookAt;
FieldOfView = MathHelper.PiOver4;
AspectRatio = STDW.Width / STDW.Height;
}
}
}
ModelObject:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
namespace Simple3DWorld
{
public class ModelObject
{
public Model Model;
public Vector3 Position;
public ModelObject(Model model, Vector3 pos)
{
Model = model;
Position = pos;
}
public virtual void Update(GameTime gt)
{
}
public virtual void Draw(Camera camera)
{
foreach (ModelMesh mesh in Model.Meshes)
{
foreach (BasicEffect effect in mesh.Effects)
{
effect.EnableDefaultLighting();
effect.PreferPerPixelLighting = true;
effect.World = Matrix.CreateTranslation(Position);
effect.View = Matrix.CreateLookAt(camera.Position, camera.LookingAt, Vector3.UnitZ);
effect.Projection = Matrix.CreatePerspectiveFieldOfView(camera.FieldOfView, camera.AspectRatio, 1f, 100f);
}
mesh.Draw();
}
}
}
}
And yes, I have made sure that all methods are being called correctly. What should be showing on screen is my landscape model.
EDIT: Solved. For some stupid, frustrating reason, MonoGame will not render your models if your camera's X and Y (not the up vector) are both 0. If anyone could somehow explain this, I would be infinitely grateful.
Your Camera's Position and LookAt vectors cannot both be equal on the two axes perpendicular to the Up vector. This results in a NaN(not a number).
This situation can also be characterized as a Gimbol Lock, since the rotations about the X(Roll) and Y(Pitch) axes are aligned, making it impossible to determine the Z(Yaw) from the information provided.
The problem occurs in the creation of the View matrix in the following line:
effect.View = Matrix.CreateLookAt(camera.Position, camera.LookingAt, Vector3.UnitZ);
Substituting the argument values:
effect.View = Matrix.CreateLookAt(new Vector3(0,0,1), new Vector3(0,0,0), new Vector3(0,0,1));
Annotated partial source for CreateLookAt at implementation(see here for pass the through call)
public static void CreateLookAt(ref Vector3 cameraPosition, ref Vector3 cameraTarget, ref Vector3 cameraUpVector, out Matrix result)
{
var vector = Vector3.Normalize(cameraPosition - cameraTarget);
Normalize((0,0,1) - (0,0,0)) -> (x,y,z)/Length
Length = (0 - 0)² + (0 - 0)² + (0 - 1)² -> 1
(0/Length,0/Length,1/Length) -> (0/1,0/1,1/1) ->(0,0,1) *OK
var vector2 = Vector3.Normalize(Vector3.Cross(cameraUpVector, vector));
Working inside out:
Cross((0,0,1),(0,0,1)) -> (y1 * z2 - z1 * y2, z1 * x2 - x1 *z2, x1 * y2 - y1 *x2) ->
(0 * 1 - 1 * 0, 1 * 0 - 0 * 1, 0 * 0 - 0 * 0) -> (0,0,0) *Mathematically OK, Geometrically undefined(does not define a plane perpendicular to the input points)
Normalize(Cross((0,0,1),(0,0,1))) -> Normalize(0,0,0)
Length = (0 - 0)² + (0 - 0)² + (0 - 0)² -> 0
(0/Length,0/Length,0/Length) -> (0/0,0/0,0/0) ->(NaN,NaN,NaN) *UH-OH
The NaN results from the division by zero with the 0 being unsigned as defined by IEEE 754.
Since any operation on a NaN results in NaN. The NaN propagates to the World and Projection matrices, resulting in a black screen.
To put it another way:
If you were standing up looking (Camera.Position=(0,0,6)), ignoring the fact your head has to tilt to see them, at your feet(Camera.LookAt =(0,0,0)), is it possible to determine the compass direction, where the Up vector equals Vector3.UnitZ, that you are facing? No. It is not possible, you could be facing any direction on the plane.
If I ask for the World coordinate one unit in front of your feet(1,0,0), I can tell which direction you are facing.
Fixed. All I had to do was move my camera off of 0,0,0. 0,1,0 1,0,0 and 1,1,0 all seemed to work, which means the camera's other two coordinates (not the one that determines whether it's up or down) can't be at the origin. Not too sure why this is a thing, but at least it's fixed now.

Brickbreaker clone, ball brick collision and ball behavior on brick collision

I started learning c# monogame a few weeks ago and i wanted to start a project.
The project I choose is a brickbreaker clone and everything goes well. But I stumbled on something that I have spent hours looking on google for without a answer.
The problem I have is with collision detection between the ball and the bricks.
Between the paddle and the ball work I have a working solution.
Which is :
// Collision between the ball and player
public void Collision(Player player, Ball ball)
{
MinX = (int)player.PlayerPosition.X - ball.Width;
MaxX = (int)player.PlayerPosition.X + player.Width + ball.Width;
MinY = 0;
MaxY = (int)player.PlayerPosition.Y - ball.Height;
Rectangle BallRectangle = new Rectangle((int)ball.BallPosition.X, (int)ball.BallPosition.Y, ball.Width, ball.Height);
Rectangle PlayerRectangle = new Rectangle((int)player.PlayerPosition.X, (int)player.PlayerPosition.Y, player.Width, player.Height);
if (BallRectangle.Intersects(PlayerRectangle))
{
ball.BallPosition.Y = MathHelper.Clamp(ball.BallPosition.Y, MinY, MaxY);
ball.BallPosition.X = MathHelper.Clamp(ball.BallPosition.X, MinX, MaxX);
ball.BallSpeed.Y *= -1;
float BallMiddlePoint = ball.BallPosition.X + (ball.Width / 2);
float PlayerMiddlePoint = player.PlayerPosition.X + (player.Width / 2);
ball.BallSpeed.X = (BallMiddlePoint - PlayerMiddlePoint) / 10 + ball.ExtraSpeedOverTime;
}
}
Now back to my problem, I use Rectangle.Intersect(Rectangle) to check for collision.
The main problem is: How do I let the ball bounce correctly on the bricks?
I hope I give enough information.
My ball class:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
namespace BrickBreakerV2
{
class Ball
{
// The texture of the ball
Texture2D BallTexture;
// The position of the ball
public Vector2 BallPosition;
// The speed of the ball
public Vector2 BallSpeed;
// The speed that gets added over time
public float ExtraSpeedOverTime;
// Time values used in incrementing the speed over time
TimeSpan IncreaseSpeed;
TimeSpan PreviousSpeedIncrease;
// The "active" state of the ball
public bool Active;
// The state of movement of the ball
public bool Moveball;
// The Width of the ball
public int Width
{
get { return BallTexture.Width; }
}
// The Height of the ball
public int Height
{
get { return BallTexture.Height; }
}
// Construct a class for Boundaries
CollisionHandler Collision = new CollisionHandler();
public void Initialize(ContentManager Content, GraphicsDevice graphicsDevice, Player player)
{
BallTexture = Content.Load<Texture2D>("Graphics\\ball.png");
BallPosition = new Vector2(player.PlayerPosition.X + (player.Width / 2) - (Width / 2),
player.PlayerPosition.Y - Height - 5);
BallSpeed = new Vector2(5.0f, -5.0f);
ExtraSpeedOverTime = 1.0f;
IncreaseSpeed = TimeSpan.FromSeconds(12f);
PreviousSpeedIncrease = TimeSpan.Zero;
Active = true;
Moveball = false;
}
public void Update(GraphicsDevice graphicsDevice, GameTime gameTime, Player player)
{
if (Moveball)
{
BallPosition += BallSpeed;
}
else
{
BallPosition = new Vector2(player.PlayerPosition.X + (player.Width / 2) - (Width / 2),
player.PlayerPosition.Y - Height - 5);
}
if (gameTime.TotalGameTime - PreviousSpeedIncrease > IncreaseSpeed)
{
ExtraSpeedOverTime += 0.01f;
BallSpeed.X *= ExtraSpeedOverTime;
BallSpeed.Y *= ExtraSpeedOverTime;
PreviousSpeedIncrease = gameTime.TotalGameTime;
}
// Makes sure that the ball doesn't go to fast
if (BallSpeed.X > 10.50f)
BallSpeed.X = 10.50f;
if (BallSpeed.Y > 10.50f)
BallSpeed.Y = 10.50f;
if (BallSpeed.X < -10.50f)
BallSpeed.X = -10.50f;
if (BallSpeed.Y < -10.50f)
BallSpeed.Y = -10.50f;
// Keep the ball in the boundaries
Collision.GetBoundaries(graphicsDevice, this);
// Detect collision between ball and player
Collision.Collision(player, this);
}
public void Update(Brick brick)
{
// Detect collision between ball and brick
Collision.Collision(this, brick);
}
public void Draw(SpriteBatch spriteBatch)
{
spriteBatch.Draw(BallTexture, BallPosition, null, Color.White, 0f, Vector2.Zero, 1f, SpriteEffects.None, 1f);
}
}
}
My Brick class:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
namespace BrickBreakerV2
{
class Brick
{
// The texture of the brick
public Texture2D BrickTexture;
// The position of the bricks
public Vector2 BrickPosition;
// The color tint of the brick
public Color ColorTint;
// The "active" state of the brick
public bool Active;
// The width of the brick
public int Width
{
get { return BrickTexture.Width; }
}
// The height of the brick
public int Height
{
get { return BrickTexture.Height; }
}
// Construct a class for collisionhandler
CollisionHandler Collision;
public void Initialize(ContentManager Content)
{
BrickTexture = Content.Load<Texture2D>("Graphics\\brick.png");
BrickPosition = new Vector2(600, 500);
Active = true;
ColorTint = Color.White;
Collision = new CollisionHandler();
}
public void Update(Ball ball)
{
Collision.Collision(ball, this);
}
public void Draw(SpriteBatch spriteBatch)
{
spriteBatch.Draw(BrickTexture, BrickPosition, null, ColorTint, 0f, Vector2.Zero, 1f, SpriteEffects.None, 1f);
}
}
}
And my code block that handles the collision between the ball and bricks in CollisionHandler.cs:
// Collision between ball and brick
public void Collision(Ball ball, Brick brick)
{
Rectangle BallRectangle = new Rectangle((int)ball.BallPosition.X, (int)ball.BallPosition.Y, ball.Width, ball.Height);
Rectangle BrickRectangle = new Rectangle((int)brick.BrickPosition.X, (int)brick.BrickPosition.Y, brick.Width, brick.Height);
if (BallRectangle.Intersects(BrickRectangle))
{
int XOverlap;
int YOverlap;
if (BallRectangle.Center.X < BrickRectangle.Center.X)
{
XOverlap = (BallRectangle.X + ball.Width) - BrickRectangle.X;
}
else
{
XOverlap = (BrickRectangle.X + brick.Width) - BallRectangle.X;
}
if (BallRectangle.Center.Y < BrickRectangle.Center.Y)
{
YOverlap = (BallRectangle.Y + ball.Height) - BrickRectangle.Y;
}
else
{
YOverlap = (BrickRectangle.Y + brick.Height) - BallRectangle.Y;
}
if (XOverlap == YOverlap)
{
ball.BallSpeed.X *= -1;
ball.BallSpeed.Y *= -1;
}
else if (XOverlap < YOverlap)
{
ball.BallSpeed.X *= -1;
}
else
{
ball.BallSpeed.Y *= -1;
}
brick.Active = false;
}
}
I want to help you, but I'm not going to debug your code. Fortunately basic 2D collision detection and brick breaker clones have been done many many times before.
A quick google search turned up the following tutorial. I haven't done it myself but if I where you I would start here:
http://xnagpa.net/xna4beginner.php
Good luck.

Physics Project in C#: Problems with threading and measuring time

I'm having some problems with a physics project I'm trying to make.
Its basically a Free Fall simulator. I set the gravitational acceleration and the height and the program should simulate the fall.
The problem is that it's getting the time wrong, don't know why. I'm using the Stopwatch class for measuring the time.
Here's the code:
FrmMain.cs:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Threading;
using System.Diagnostics;
namespace Physics
{
public partial class FrmMain : Form
{
public Settings config = new Settings();
public float displacement = 0f;
public Stopwatch timer = new Stopwatch();
public float timeElapsed; //in Seconds
public Thread thread;
public FrmMain()
{
InitializeComponent();
//New thread (Drawing)
thread = new Thread(new ThreadStart(Drawing));
thread.IsBackground = true;
thread.Start();
this.KeyDown +=new KeyEventHandler(FrmMain_KeyDown);
}
private void Drawing()
{
try
{
while (true)
{
if (config.objectPos.Y < config.sizeBitmap.Height)
timer.Start();
else
timer.Stop();
Bitmap screen = new Bitmap(this.pboxScreen.Width,
this.pboxScreen.Height);
SendScreen(screen);
}
}
catch (ThreadAbortException tae)
{
Console.WriteLine(tae.Message);
}
}
private void SendScreen(Bitmap Screen)
{
if (pboxScreen.InvokeRequired)
{
pboxScreen.Invoke(new MethodInvoker(delegate()
{
this.SendScreen(Screen);
}));
}
else
{ //Converting Milliseconds to Seconds
timeElapsed = timer.ElapsedMilliseconds / 1000f;
//Check if object isn't in the ground
if (config.objectPos.Y < config.sizeBitmap.Height)
{
displacement -= config.objectPos.Y;
config.objectPos.Y = config.objectPos.Y + 0.5f *
config.acceleration *
timeElapsed * timeElapsed;
displacement += config.objectPos.Y;
}
Graphics g = Graphics.FromImage(Screen);
g.Clear(Color.White);
//New rectangle
Rectangle rec = new Rectangle((int)config.objectPos.X,
(int)config.objectPos.Y, 5, 5);
g.FillRectangle((new Pen(Color.DarkRed)).Brush, rec);
g.DrawRectangle(new Pen(Color.Red, 2.0f), rec);
g.Dispose();
//Update txtbox (textbox)
txtboxX.Text = config.objectPos.X.ToString();
txtboxY.Text = config.objectPos.Y.ToString();
txtboxTempo.Text = timeElapsed.ToString();
txtboxD.Text = displacement.ToString();
pboxScreen.Image = Screen;
}
}
void FrmMain_KeyDown(object sender, KeyEventArgs e)
{
switch (e.KeyCode)
{
case Keys.Space:
if (config.objectPos.Y >= config.sizeBitmap.Height)
{
config.objectPos.Y -= 100;
timer.Reset();
}
break;
}
}
private void FrmMain_FormClosing(object sender, FormClosingEventArgs e)
{
if (thread.IsAlive) thread.Abort();
}
}
}
Settings.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
namespace Physics
{
public class Settings
{
public Size sizeBitmap; //bitmap resolution
public PointF objectPos; //Initial Position
public float acceleration;
public Settings()
{
sizeBitmap.Width = 560;
sizeBitmap.Height = 420;
objectPos.X = 560f / 2f;
objectPos.Y = 420f / 2f;
acceleration = 9.8f;
}
}
}
There's another problem, depending on height the object doesn't fall without interruption, it stay in the same position for a few, but noticeable, milliseconds. I think this is a threading problem, 'cause it's been a while I don't use it, so I might be missing something.
I'm measuring the height in meters, so the objectPos.Y = 420f / 2f represent a height of 210 meters. For this height, the object should take around 6.5 seconds to hit the ground, in my program it's taking less than 1 second, so I assumed that there's a time measuring problem.
I'm calculating the height with the uniform gravitational field without air resistance expression :
h(t)=h0+0.5*g*t²
where: h(t) is the height with respect to time, h0 the initial altitude, g acceleration due to gravity and t the time elapsed
Any help is much appreciated.
Thanks.
I believe your issue may be in the line
config.objectPos.Y = config.objectPos.Y + 0.5f *
config.acceleration *
timeElapsed * timeElapsed;
The YPosition at time t = t-sub-k (config.objectPos.Y) is the height at time t-sub-k. if t is total elapsed time, then this is equal to the Initial Y-Position (The Height at Time t = 0) + 1/2 gt^2, NOT the last Y-Position.
What you are doing is taking the last Y-Position (the height as of the previous calculation, and adding the drop in altitude during the elapsed time from time t=0 to t= t-sub-k. So it's no wonder that it is falling too fast.
Add an Initial Y-Position read-only property to your settings construct, and DO not Update or modify it.
Modify your code to use it as follows:
config.objectPos.Y = config.InitialY + 0.5f *
config.acceleration *
timeElapsed * timeElapsed;
I think your formula is wrong.
h0 should be the initial velocity (which in your case is 0 m/s) and it should be multiplied with time.
This is the correct one from
So having said that, Vi*t is always 0 since your initial velocity is 0. What's left is 0.5 * 9.8 * timeElapsed * timeElapsed.
config.objectPos.Y = 0 //initial velocity
+ 0.5f * config.acceleration * timeElapsed * timeElapsed;
Also objectPost.Y should always start from 0 meters since it's starting from the top and it's going to fall.
You can refer to this Console app code. Run it and see the time elapsed compared and compare it to the results in
It should be 1.32 seconds.
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace Physics_16783733
{
class Program
{
static void Main(string[] args)
{
MyClass c = new MyClass();
}
}
public class MyClass
{
public Settings config = new Settings();
public Stopwatch timer = new Stopwatch();
public float timeElapsed; //in Seconds
public Thread thread;
static ManualResetEvent control;
public MyClass()
{
control = new ManualResetEvent(false);
//New thread (Drawing)
thread = new Thread(new ThreadStart(Drawing));
thread.IsBackground = true;
thread.Start();
control.WaitOne();
}
public void Drawing()
{
try
{
while (true)
{
if (config.objectPos.Y < config.sizeBitmap.Height)
{
timer.Start();
}
else
{
timer.Stop();
control.Set();
}
//Bitmap screen = new Bitmap(this.pboxScreen.Width, this.pboxScreen.Height);
SendScreen();
}
}
catch (ThreadAbortException tae)
{
Console.WriteLine(tae.Message);
}
}
private void SendScreen()
{
timeElapsed = timer.ElapsedMilliseconds / 1000f; //Converting Milliseconds to Seconds
if (config.objectPos.Y < config.sizeBitmap.Height) //Check if object isn't in the ground
{
//formula used is in http://www.physicsclassroom.com/Class/1DKin/U1L6c.cfm
config.objectPos.Y = 0 //initial velocity
+ 0.5f * config.acceleration * timeElapsed * timeElapsed;
}
//Update txtbox (textbox)
Console.WriteLine("Object position Y: " + config.objectPos.Y.ToString());
Console.WriteLine("Time elapsed : " + timeElapsed.ToString()); //using the data from http://www.physicsclassroom.com/Class/1DKin/U1L6c.cfm, time elapsed should be 1.32 seconds
}
}
public class Settings
{
//I used data from http://www.physicsclassroom.com/Class/1DKin/U1L6c.cfm
//where the given is:
//vi = 0.0 m/s
//d = -8.52 m
//a = - 9.8 m/s2
public Size sizeBitmap; //height of the place where the object will start free falling
public PointF objectPos; //Initial Position
public float acceleration;
public Settings()
{
sizeBitmap.Height = 8.52;
objectPos.Y = 0;
acceleration = 9.8f;
}
}
public struct PointF
{
public float Y { get; set; }
}
public struct Size
{
public double Height { get; set; }
}
}

Create jump algorithm using sine

i am writing a 2D game in C# windows form application.
I want to create Bubble Trouble game, but i'm troubling with the jump algorithm.
I found that i have to use sine function to make it realistic.
There is the ball class:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Windows.Forms;
namespace BubbleTrouble
{
class Ball
{
int level,gapX=2,gapY=2,x,y;
bool up;
public static int[] levelsPX={0,1,2,3,6,8,9,11};
Panel panel;
Graphics gr;
public Ball(int lvl,int x,int y,bool isUp,Graphics gr)
{
this.gr = gr;
up = isUp;
this.x = x;
this.y = y;
if (up)
gapY = -gapY;
level = lvl;
}
public Ball[] pop()
{
if (level == 0)
return null;
else
{
bool up1 = true;
if(y>=20)
up1=false;
Ball first = new Ball(level - 1, x, y,up1,gr);
Ball second = new Ball(level - 1, first.x + 10 * levelsPX[level-1], y, up1,gr);
Ball[] a = { first, second };
level = 0;
return a;
}
}
public void paint()
{
gr.DrawImage(BubbleTrouble.Properties.Resources.ball, x, y, 10 * levelsPX[level], 10 * levelsPX[level]);
}
public void getNextPos()
{
if ((y <= 0) || (y + 10 * levelsPX[level] >= 364))
{
gapY = -gapY;
up = !up;
}
if ((x + 10 * levelsPX[level] >= 681) || (x <= 0))
gapX = -gapX;
if (y < 70)
gapY = -gapY;
//Math.sin
x=x+gapX;
y=y+gapY;
}
}
}
The ball has X and Y integers, and it also have 2 integers gapX and gapY.
gapX and gapY is used to change the direction of the ball, for example right now the ball is in position (30,30) so in that case, the next position will be (30+gapX,30+gapY), and after this (30+2gapX,30+2gapY) and when the ball is get out of the form bound so the gap change sign. For example if the position on X scale is more then the form bound, the change the gapX to -gapX so the ball will move in the other direction.
But, i want the ball jump in wave and i don't know how to do this using the X Y of the ball and the gapX and gapY.
I found that sine function will help me but i still don't know where and how to use this function.
Please help me i'm trying to figure it out but i don't find any solution.
Thank you,
Asaf.
A small method as a hint. You have to adjust to the height and width of your playground:
/// <summary>
/// Calculates ball bouncing.
/// </summary>
/// <param name="x">X position (0 .. 360)</param>
/// <returns>Returns y position (0 .. 1)</returns>
private double Position(double x)
{
x *= Math.PI / 180;
return Math.Abs(Math.Cos(x)); // Always positive
}

Categories

Resources