I am back with another question. I am still new to SFML so this one seemed a bit tough. I have tried using while loops and such but to no avail.
The game I am doing at the moment is a car going back and forth on the X axis and then I guess will be able to pick up points and stuff or simply just avoid objects coming towards the car until it eventually dies.
How do I make the movement smoother? Currently the car will move 8 units first, before moving 8 units in the desired direction until I let go of the button. It's the same when I do it the other way. I would like it to just instantly move and keep moving when I press either key.
static void OnKeyPressed(object sender, EventArgs e)
{
Vector2f newPos = new Vector2f(0, car.Position.Y);
KeyEventArgs ke = (KeyEventArgs)e;
if (ke.Code.Equals(Keyboard.Key.A))
{
if (car.Position.X != 0)
{
newPos.X = car.Position.X - 8;
car.Position = newPos;
}
else if (car.Position.X < 0)
{
newPos.X = 0;
car.Position = newPos;
}
else if(car.Position.X == 0)
{
// Do nothing
}
}
else if (ke.Code.Equals(Keyboard.Key.D))
{
if (car.Position.X != window.Size.X - 32)
{
newPos.X = car.Position.X + 8;
car.Position = newPos;
}
else if (car.Position.X > window.Size.X)
{
newPos.X = window.Size.X;
car.Position = newPos;
}
else if (car.Position.X == window.Size.X)
{
// Do nothing
}
}
}
And the entire thing for reference:
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using SFML.Audio;
using SFML.Graphics;
using SFML.Window;
namespace SFMLCarGame
{
class Program
{
private static RenderWindow window;
private static Sprite car;
static void Main(string[] args)
{
window = new RenderWindow(new VideoMode(256,512), "Car Game");
window.Closed += new EventHandler(OnClose);
window.KeyPressed += new EventHandler<KeyEventArgs>(OnKeyPressed);
Sprite bg = new Sprite(new Texture("road.png"));
car = new Sprite(new Texture("car.png"));
car.Position = new Vector2f(window.Size.X / 2, window.Size.Y - 96);
while (window.IsOpen())
{
window.DispatchEvents();
window.Clear();
window.Draw(bg);
window.Draw(car);
window.Display();
}
}
static void OnClose(object sender, EventArgs e)
{
RenderWindow window = (RenderWindow)sender;
window.Close();
}
static void OnKeyPressed(object sender, EventArgs e)
{
Vector2f newPos = new Vector2f(0, car.Position.Y);
KeyEventArgs ke = (KeyEventArgs)e;
if (ke.Code.Equals(Keyboard.Key.A))
{
if (car.Position.X != 0)
{
newPos.X = car.Position.X - 8;
car.Position = newPos;
}
else if (car.Position.X < 0)
{
newPos.X = 0;
car.Position = newPos;
}
else if(car.Position.X == 0)
{
// Do nothing
}
}
else if (ke.Code.Equals(Keyboard.Key.D))
{
if (car.Position.X != window.Size.X - 32)
{
newPos.X = car.Position.X + 8;
car.Position = newPos;
}
else if (car.Position.X > window.Size.X)
{
newPos.X = window.Size.X;
car.Position = newPos;
}
else if (car.Position.X == window.Size.X)
{
// Do nothing
}
}
}
}
}
You may want to read this short tutorial from the SFML's website.
The events are fired by the operating system, and are good for certain purposes (quit event, a key is pressed, the left mouse button is clicked) but aren't for things that need to be updated really often. Imagine that you are writing some text, and keep the 'A' key pressed. Your text will progressively grow like aaaaaaaaaaa but there is a little delay between the a spawns, imposed by the OS. You would get, say, 6 letters by second. This is the same with events. With a game running and displaying at 60 fps it is clear that your movement will not be smooth and barely manageable.
Hopefully SFML provides a way to check the instant state of the keyboard (and mouse and joystick). With the C# binding (I am assuming you are using the binding for 2.0 version, and if you don't then you should) you only have to check Keyboard.isKeyPressed(yourKey).
Doing this in the main loop will check at each frame that the key is pressed, and not wait for an OS event that is way slower.
On a side note, if your previous questions were answered correctly please mark them so by accepting an answer.
Edit : I haven't SFML for .NET installed on my computer but here is what it could look like
static void Main(string[] args)
{
window = new RenderWindow(new VideoMode(256,512), "Car Game");
window.Closed += new EventHandler(OnClose);
// Note this
// window.KeyPressed += new EventHandler<KeyEventArgs>(OnKeyPressed);
Sprite bg = new Sprite(new Texture("road.png"));
car = new Sprite(new Texture("car.png"));
car.Position = new Vector2f(window.Size.X / 2, window.Size.Y - 96);
while (window.IsOpen())
{
window.DispatchEvents();
CheckInputs(); // and this !
window.Clear();
window.Draw(bg);
window.Draw(car);
window.Display();
}
}
void CheckInputs()
{
if(Keyboard.isKeyPressed(Keyboard.key.A))
{
if(car.Position.X < 0)
car.Position.X = 0
else if(car.Position.X > 0)
car.Position.X -= 8; // shortcut for 'car.Position.X = car.Position.X - 8'
}
else if(Keyboard.isKeyPressed(Keyboard.key.D))
{
// etc
}
}
This way your transition should be much smoother, but beware, 8 pixels might be very fast !
I really recommend you to read the tutorial I have linked, because it explains the functionning of inputs in an language-agnostic way (even if the examples are in C++).
Also, you don't need your event handler anymore so I commented it. But if you are checking for other keys (like escape for pause or whatever) don't delete it, just remove the part you wrote about moving the car.
Related
Made progress on my game and now I need to make the second boss bounce up and down. I figured out how to make the boss go down, but once it touches the lower wall, it stops and won't bounce (move up).
void BossMove()
{
if((BOSS.Top + 10) <(this.Height - BOSS.Height))
{
BOSS.Top += 10;
}
if((BOSS.Height) > 0)
{
BOSS.Top -= 10;
}
}
Here's a simple example using a state variable to represent the direction:
private Boolean goingUp = true;
void BossMove()
{
if (goingUp)
{
if ((BOSS.Top + 10) < (this.Height - BOSS.Height))
{
BOSS.Top += 10;
}
else
{
// possibly force it to snap to specific position
// before going back down?
goingUp = false;
}
}
else
{
if (BOSS.Top > 450)
{
BOSS.Top -= 10;
}
else
{
// possibly force it to snap to specific position
// before going back up?
goingUp = true;
}
}
}
Im a beginner with C# I'm doing some School project using a Windows Form App, It's a simple game but I ran into some issues, I want to give a picture box control a bullet-like trajectory when the [Space] key is pressed but haven't been able to do it yet. I was instructed to do this only using Threads and NO timers.
Also I want this picture box to 'spawn' and start moving from another picture box named 'SpaceShip' but i don't know how i could do that
Of course, advice and suggestions are very welcome even if it means changing entire parts of my awful code
I tried using picturebox.Left = picturebox.Left +5; but I guess i'm doing something wrong
if (e.KeyCode == Keys.Space)
{
if(pbEnergy.Value <= 0)
{
pbEnergy.Value = 0;
System.Media.SoundPlayer SFX = new System.Media.SoundPlayer(#"C:\SFX\nolaser.wav");
SFX.Play();
}
else
{
System.Media.SoundPlayer SFX = new System.Media.SoundPlayer(#"C:\SFX\laser.wav");
SFX.Play();
pbEnergy.Value -= 10;
ThreadStart Delegate = new ThreadStart(phys);
Thread MovTh = new Thread(Delegate);
MovTh.Start();
}
}
public void phys()
{
for (int i = 0; i <= 60; i++)
{
Thread.Sleep(10);
Progress(i);
if (i == 60) //stop when value is reached
{
Thread.CurrentThread.Suspend();
}
}
}
delegate void Delegate(int n);
private void Progress(int num)
{
if (this.InvokeRequired)
{
Delegate d = new Delegate(Progress);
object[] Parameters = new object[] { num };
this.Invoke(d, Parameters);
}
else
{
picprj.Visible = true;
picprj.Left = picprj.Left + 5;
}
I expected the picture box to travel and then disappear but it finishes its trajectory and stays visible, I would appreciate some advice on this or even a better way to do it.
First of all, im totally new to C# and I have to work on an Windows Store App for a study project.
I decided to develop an App, where you have to keep a ball in the air (with a paddle at the bottom of the field, nearly the same as in the classic pong game), which was really stupid cause I literally have no idea how to do this.
My code looks like this at the moment:
void Timer_Tick(object sender, object e)
{
Rect rectBall = new Rect(BallTransform.TranslateX, BallTransform.TranslateY, RectBall.ActualWidth, RectBall.ActualHeight);
Rect rectPaddle = new Rect(PaddleTransform.TranslateX, PaddleTransform.TranslateY, RectPaddle.ActualWidth, RectPaddle.ActualHeight);
rectPaddle.Intersect(rectBall);
int counter = 0;
Score.Text = ("Score: " + counter);
if (rectPaddle.IsEmpty == true)
{
BallTransform.TranslateY += 20;
}
if (BallTransform.TranslateY - 50 > PaddleTransform.TranslateY)
{
BallTransform.TranslateY -= 20;
Result.Text = ("Game Over!");
}
//if (rectPaddle.IsEmpty == false)
//{
// counter += 1;
// BallTransform.TranslateY -= 20;
// Score.Text = ("Score: " + counter);
//}
}
void CoreWindow_KeyDown(Windows.UI.Core.CoreWindow sender, Windows.UI.Core.KeyEventArgs args)
{
switch (args.VirtualKey)
{
case Windows.System.VirtualKey.A:
PaddleTransform.TranslateX -= 40;
break;
case Windows.System.VirtualKey.D:
PaddleTransform.TranslateX += 40;
break;
case Windows.System.VirtualKey.Left:
PaddleTransform.TranslateX -= 40;
break;
case Windows.System.VirtualKey.Right:
PaddleTransform.TranslateX += 40;
break;
default:
break;
}
}
private void Grid_Loaded(object sender, RoutedEventArgs e)
{
PaddleTransform.TranslateY = Grid.ActualHeight - RectPaddle.ActualHeight - 20;
PaddleTransform.TranslateX = (Grid.ActualWidth / 2) - RectPaddle.ActualWidth;
BallTransform.TranslateX = (Grid.ActualWidth / 2) - RectBall.ActualWidth;
DispatcherTimer Timer = new DispatcherTimer();
Timer.Interval = new TimeSpan(100);
Timer.Tick += Timer_Tick;
Timer.Start();
}
}
}
I know that this is not really much, and it doesn´t really do anything than letting the ball fall down, if it touches the paddle, it just stays where it is and if it misses the paddle, it´s "game over".
My biggest problem is, to find out how to let the ball jump up again after falling on the paddle, and give it different bouncing directions after doing this. Also I don´t know how I should handle the speed of the ball.
I´d be really happy if someone could explain me what i should do.
Thanks in advance!
PS: I read a lot of "Pong" and "Ball physic" tutorials, but they didn´t really help me.
A simple way of doing this is to keep track of the velocity of the ball in a separate variable, and using that to update its translation.
ie something along the lines of this: (example is not complete, but i hope you get the gist of it)
float BallXVel = 10;
float BallYVel = 20;
void Timer_Tick(object sender, object e)
{
//always move the ball.
BallTransform.TranslateX += BallXVel;
BallTransform.TranslateY += BallYVel;
//bounce the ball up if it hits the paddle and is not already moving up
if (!rectPaddle.IsEmpty && BallYVel > 0)
{
BallYVel = 0-BallYVel;
}
if (BallTransform.TranslateY - 50 > PaddleTransform.TranslateY)
{
BallTransform.TranslateY -= 20;
Result.Text = ("Game Over!");
}
}
My friends I made some parts of this game but I have two problems in this game.
1)Problem about distinguishing ball collision with obstacles
1-1)A first problem is related to complex guidelines that I used them for simulation of ball collision with board or ball collision with blocks. These guidelines are not accurate especially when the ball meets with block corner or bottom.
If it is not better for collision distinguish I use a better code. I wrote this code. Are you think that are there better way?
2)How I can do a work that if the ball collision with any obstacle, the obstacle report the collision.
My aim is about using of events.
Are you thinking that I make obstacles as runtime?
If I make as a runtime, how I can make collision event for them?
With best regards
private Point MouseDownLocation;
int step = 2;
int stepleft = 2;
bool flagBottom;
bool flagTop;
private void Form1_Load(object sender, EventArgs e)
{
timer1.Interval = 10;
timer1.Enabled = true;
}
private void timer1_Tick(object sender, EventArgs e)
{
ball.Top += step;
ball.Left += stepleft;
//board simulate collision
bool collisonX = ball.Location.X + ball.Width > board.Location.X && ball.Location.X < board.Location.X + board.Width;
bool collisonY = ball.Top + ball.Height == board.Location.Y || ball.Top + ball.Height - 1 == board.Location.Y;
//board2(button1) simulate collision
bool collisonX2 = ball.Location.X + ball.Width > board2.Location.X && ball.Location.X < board2.Location.X + board2.Width;
bool collisonY2 = ball.Top + ball.Height == board2.Location.Y || ball.Top + ball.Height - 1 == board2.Location.Y;
//Collision the ball with under buttons
bool collsionButtonY = ball.Top - ball.Height == board2.Location.Y || ball.Top - ball.Height == board2.Location.Y - 1;
//collision leftwall
bool leftWall = ball.Left == 0 || ball.Left == -1 || ball.Left == 1;
//collision rightwall
bool topWall = ball.Top == 0 || ball.Top == -1 || ball.Top == 1;
bool bottomWall = collisonX && collisonY;
bool toppWall = collisonX2 && collisonY2;
//collision
bool barrier = collisonX2 && collsionButtonY;
//rightwall
bool rightWall = ball.Left + ball.Width == this.ClientSize.Width || ball.Left + ball.Width == this.ClientSize.Width - 1;
// sidewall = collision rightwall or leftwall
bool sideWall = leftWall || rightWall;
//Check the ball hit the ground
bool check = ball.Top + ball.Height < this.ClientSize.Height;
//if topWall true,This means that the ball is hit to the topwall
if (topWall)
{
flagBottom = false;
flagTop = true;
if (stepleft > 0)
{
step = 2;
}
else if (stepleft < 0)
{
step = 2;
}
}
//if bottomWall true,This means that the ball is hit to the board
else if (bottomWall)
{
flagBottom = true;
flagTop = false;
if (stepleft > 0)
{
step = step * -1;
}
else if (stepleft < 0)
{
step = step * -1;
}
}
//if barrier true and flagbottom true,This means that the ball is hit to the board2(button1)
else if (barrier && flagBottom)
{
if (stepleft > 0)
{
step = step * -1;
}
else if (stepleft < 0)
{
step = step * -1;
}
}
//if toppWall true and flagTop true,This means that the ball is hit to The top button is hit
else if (toppWall && flagTop)
{
if (stepleft > 0)
{
step = step * -1;
}
else if (stepleft < 0)
{
step = step * -1;
}
}
else if (sideWall)
{
//if leftwall true,This means that the ball is hit to the left side wall
if (leftWall)
{
if (flagTop)
{
stepleft = 2;
}
else if (flagBottom)
{
stepleft = 2;
}
}
//if rightWall true,This means that the ball is hit to the left side wall
else if (rightWall)
{
if (flagTop)
{
stepleft = -2;
}
else if (flagBottom)
{
stepleft = -2;
}
}
}
//check if ckeck==ture,this mean the ball is hit the ground
else if (!check)
{
timer1.Enabled = false;
}
}
private void board_MouseDown(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
MouseDownLocation = e.Location;
}
}
private void board_MouseMove(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
board.Left = e.X + board.Left - MouseDownLocation.X;
}
}
Define each "Wall" as an Object, this will increase your codes readablility. it will also allow you to define an Event for each wall, Listen to t. that way you know which wall has been hit
N.b. this is pseudo code. It wont compile :P
public class Wall
{
int X,Y,W,H;
//Define an event, add a listener to this, becuase we will fire this when there is a collision
public event EventHandler OnCollision;
public void CollisionCheck(Ball playerBall)
{
//1 Check for a collision with the "Ball" object
if(Ball.Rectangle().Intersects(this.Rectangle))
this.OnCollision(this, EventArgs.Empty); //Fire the event, null check might be requried
}
}
I do not know your game but (suspect 2D brick-like game)
Objects/Obstacles
all objects/obstacles can be simplified to rectangular objects
so make list of them with defined parameters like size and position
if they are movable/dropable then also speed and state...
type of object (affects color,scoring,capabilities...)
create member function like update(dt),draw()
create events you like OnHIt,OnCollision,...
for example (C++ pseudo code):
// game object types ...
enum _game_object_type_enum
{
_game_object_type_none=0,
_game_object_type_wall,
_game_object_type_brick1,
_game_object_type_brick2,
_game_object_type_brick3,
_game_object_type_bomb,
_game_object_type_joker1,
_game_object_type_joker2,
...
};
// game object class
class game_object
{
public;
int type; // type of object
float x,y,vx,vy,hx,hy; // position,speed,half size of rectangle
void update(float dt); // this call periodicaly in some timer updates positions,... and call events, dt is time passed
void draw(); // can add some rendering device context ...
};
// whole game class holds the game world/board/map and player(s) ...
class game_board
{
public;
game_object *go; int gos; // list of all objects in game
void update(float dt) { for (int i=0;i<gos;i++) go[i].update(dt); }
void draw() { for (int i=0;i<gos;i++) go[i].draw(); }
}
events and flow control
first define some events you need
either you use global function/pointers for that or as members
depends on your platform and to what you are used to
for example like this:
void OnCollisionFX(game_object o1,game_object o2)
{
// do something ...
}
void (*OnCollision)(game_object o1,game_object o2)=OnCollisionFX;
for player interactions only (like player controlled object collisions test only)
is better to handle this in game_object::update(dt) but you need to add player context
something like game_object::update(dt,plr)
where plr is pointer to player controlled object or player class
if you have massive interactivity between game objects (like brick/brick collisions)
then is better to handle this in game_board::update(dt)
because otherwise you will need to provide references for everything into update call
and that will quickly lead to heap/stack trashing and very slow performance
also more advanced multiple object collision/interaction approaches are better in main game class
here is an example for first case:
void game_object::update(float dt,game_object &plr)
{
// update position
x+=vx*dt;
y+=vy*dt;
// here you should make your own collision test of coarse
if (fabs(x-plr.x)<=hx+plr.hx)
if (fabs(y-plr.y)<=hy+plr.hy)
{
... do what you need like mirror or stop speed or clamp position ...
if (OnCollision) OnCollision(this,plr);
}
}
in second case you should check each object against each other
void game_board::update(float dt)
{
int i,j;
// update position
for (i=0;i<gos;i++)
{
go[i].x+=go[i].vx*dt;
go[i].y+=go[i].vy*dt;
}
// here you should make your own collision test of coarse
for (i=0;i<gos;i++)
for (j=i+1;j<gos;j++) // the lower indexes are already tested
if (fabs(go[i].x-go[j].x)<=go[i].hx+go[j].hx)
if (fabs(go[i].y-go[j].y)<=go[i].hy+go[j].hy)
{
... do what you need like mirror or stop speed or clamp position ...
if (OnCollision) OnCollision(go[i],go[j]);
}
}
performance
you can improve performance by use of type property
for example if some game objets are static then the do not need to update position
if some are indestructible then there can be also some processing avoided and so on ...
[notes]
dt/fps/speed should be combined
so in each frame your player controlled object or any moving object does not move further
then the half size of smallest object
if this is not true then you need better collision test
use line intersection algorithm
last position and actual position gives you one line
and object edge gives you the other one
if booth objects are moving then that is even more complicated :)
Recently I've been working on a Space Invaders like game, to help me boost my programming Skills. I've fallen into a few problems. I've been researching for a few days now, in how you would go about making a laser fire, on keyUp.
This is my attempt so far; I can get the laser to fire, but it has stumbled me why the laser doesn't carry on moving up...
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.IO;
namespace SpaceInvaders
{
public partial class Form1 : Form
{
public int spriteX = 226;
public int spriteY = 383;
bool bulletFire = false;
int fireTimer = 8;
int laserFired;
public Form1()
{
InitializeComponent();
}
private void exitToolStripMenuItem_Click(object sender, EventArgs e)
{
this.Close();
}
public void laserFire()
{
//on laser fire i wont the bulle to move up while bullet timer is enabled
//moving up slowly with set intervals
while (bulletTimer.Enabled == true)
{
PictureBox laser = new PictureBox();
laser.BackColor = Color.Chartreuse;
laser.Width = 5;
laser.Height = 30;
laserFired = spriteY;
laserFired = laserFired - 10;
this.Controls.Add(laser);
laser.Location = new Point(spriteX, laserFired);
}
}
private void Form1_KeyDown(object sender, KeyEventArgs e)
{
//Fire bullet
if (e.KeyCode == Keys.Up)
{
bulletFire = true;
if (bulletFire == true)
{
laserFire();
bulletTimer.Enabled = true;
}
}
//Controls Right movement
if (spriteX <448)
{
if (e.KeyCode == Keys.Right)
{
spriteX = spriteX + 20;
}
}
//Controls Left Movement
if (spriteX > 0)
{
if (e.KeyCode == Keys.Left)
{
spriteX = spriteX - 20;
}
}
//Points sprite to new location
pctSprite.Location = new Point(spriteX, spriteY);
}
private void bulletTimer_Tick(object sender, EventArgs e)
{
if (fireTimer == 0)
{
bulletTimer.Enabled = false;
}
else { fireTimer = fireTimer - 1; }
}
}
}
Help or advice would be much appreciated thanks.
The problem you have is that on every iteration of the loop, you reset the y position of the bullet by writing laserFired = spriteY;
However, once that is corrected, you will run into another problem: the while loop that moves the laser bullet is only executed in the laserFire method. This means that:
While the laser bullet moves, nothing else can move (because the loop only moves the laser)
Once the laser bullet stops moving, it will never start moving again (because you cannot go back into the loop without calling laserFire() again.
You need to have a single game loop that moves everything in your game, instead of having one loop for every moving object.
Your timer handler simply decrements fireTimer until it's zero. What instigates a re-rendering of the laser? Something needs to invoke laserFire to re-render the laser. Perhaps you meant to call laserFire from bulletTimer_Tick?