As tittle says, mouse movements are spaming event queue so i can't for example walk when i shake my mouse around. Is there any way ? Diffrent queue for mouse only or something.
SDL_Event event_;
CInputManager::Instance()->SetEvent(&event_);
InitializeGameFiles();
while (running)
{
if (SDL_PollEvent(&event_))
{
if (event_.type == SDL_QUIT)
{
running = false;
}
else if (event_.type == SDL_MOUSEMOTION)
{
CCrosshair::Instance()->OnUpdate();
}
}
OnUpdate(SDL_GetTicks() - currentTime);
currentTime = SDL_GetTicks();
OnRender();
}
void OnUpdate(unsigned int deltaTime)
{
//Game logic here
CInputManager* IM = CInputManager::Instance();
CPlayer* player = &CPlayer::PlayerControl;
IM->UpdateHeyHeld();
if (IM->IsKeyDown(SDLK_w))
{
cam[1] += speed * (deltaTime / 1000.f );
}
else if (IM->IsKeyDown(SDLK_s))
{
cam[1] -= speed * (deltaTime / 1000.f );
}
if (IM->IsKeyDown(SDLK_a))
{
cam[0] += speed * (deltaTime / 1000.f );
}
else if (IM->IsKeyDown(SDLK_d))
{
cam[0] -= speed * (deltaTime / 1000.f );
}
if (IM->IsKeyDown(SDLK_q))
{
player->OnRotate(- (int) asp * (deltaTime / 1000.f) );
}
if (IM->IsKeyDown(SDLK_e))
{
player->OnRotate((int)asp * (deltaTime / 1000.f));
}
if (IM->IsKeyDown(SDLK_x))
{
ent->animation->SetAnimation(0);
}
else if (IM->IsKeyDown(SDLK_c))
{
ent->animation->StopAnimation();
}
ent->animation->OnUpdate();
}
The mouse/crosshair handling is not really relevant here, even without it it lags
Your problem is here :
if (SDL_PollEvent(&event_)) // <--- Change if to while
{
if (event_.type == SDL_QUIT)
{
running = false;
}
else if (event_.type == SDL_MOUSEMOTION)
{
CCrosshair::Instance()->OnUpdate();
}
}
Running this in an if means you'll only take an event off the event queue per frame. SDL tends to spam mouse events even if you just move the mouse a little. And since you only take one event from the queue every frame, the number of mouse events in the queue will just keep increasing and the keydown/up events will get "lost" in the queue. far outnumbered by mouse events.
You can check out the SDL2 wiki for more information.
Related
I am trying to get my animation to cycle through two images when a directional key is pressed. Currently it switches images on each key press. I have been looking at tutorials and understand that I need some kind of timer to measure each frame time but everything I have tried to implement in to my code so far has failed so I am just posting my code that works at the moment.
Could anyone explain to me how to go about implementing this please?
void Frog::up(sf::Event event)
{
sf::IntRect frogUpAnimation[iNumFrames];
frogUpAnimation[0] = sf::IntRect(13, 362, 21, 23);
frogUpAnimation[1] = sf::IntRect(46, 367, 21, 23);
if (event.type == sf::Event::KeyPressed && event.key.code == sf::Keyboard::Up)
{
audio.frogjumpsound();
frogSprite.move(0.0f, -55.0f);
iScoreCounter = iScoreCounter + 10;
iCurrentFrame++;
if (iCurrentFrame >= iNumFrames) iCurrentFrame = 0;
frogSprite.setTextureRect(frogUpAnimation[iCurrentFrame]);
}
}
int main()
{
sf::RenderWindow window(sf::VideoMode(800, 800), "Frogger");
window.setFramerateLimit(60);
sf::Clock timer;
float fFrameTime = 1.0f / 60.0f;
float fElapsedTime;
sf::Event event;
Game game;
Frog frog;
Timer countdown;
Text text;
Audio gameaudio;
gameaudio.music();
while (window.isOpen())
{
while (window.pollEvent(event))
{
if (event.type == sf::Event::Closed)
{
window.close();
}
if (event.type == sf::Event::KeyPressed)
{
game.processKeyPress(event.key.code);
}
frog.up(event);
frog.down(event);
frog.left(event);
frog.right(event);
} // Event loop
countdown.gametime();
fElapsedTime = timer.getElapsedTime().asSeconds();
if (fElapsedTime > fFrameTime)
{
timer.restart();
}
//Update
game.checkPads(&frog);
game.checkWin();
game.gameOver();
frog.scorecounter(&countdown);
frog.update(fElapsedTime);
game.update(fElapsedTime);
text.update(fElapsedTime);
countdown.update(fElapsedTime);
game.collision(&frog);
// Drawing
window.clear();
window.draw(game);
window.draw(frog);
window.draw(countdown);
window.draw(text);
window.display();
} // main loop
}
First, I would only call 'frog.up()', 'frog.left()', etc. when the proper key is pressed. Otherwise, you're calling potentially 4 functions each iteration which do absolutely nothing.
if(sf::Keyboard::isKeyPressed(sf::Keyboard::Right) {
frog.right();
}
else if(sf::Keyboard::isKeyPressed(sf::Keyboard::Left) {
frog.left();
}
As for your timer issues, your fElapsedTime and fFrameTime look a little funky. Take a look at https://en.sfml-dev.org/forums/index.php?topic=10913.0 but I really recommend this guide: https://github.com/SFML/SFML/wiki/Source:-AnimatedSprite
I'm using Adobe Flash Professional CS6 to create the game. I'll post the code under. Be noticed that there are two symbol I've created using Flash that are not made by code. These symbols are the Crosshair symbol, and the Hitbox symbol. Basically, the objective of the game is to click the Hitbox symbol. My issue is that I am experiencing what seems to be bottlenecking issues. When I click the Hitbox symbol a lot of times with a fast timer the score doesn't register. I am pressuming that this comes from the (maybe) ineffective movement algorithm. But I can't really seem to find room for improvement. Some help would be appreciated.
Be noticed, I had to change the timer from Timer(1) to Timer(30). This made the bottlenecking issue a little bit better, but made the game less fluent.
Aah, and the reason as to why I am using the directionCheckerY and directionCheckerX variables is that I will later in the development add random movement. A random timer will change these to either 0 and 1, creating random movement.
import flash.events.MouseEvent;
import flash.events.TimerEvent;
// Variables
var directionCheckerX:int=0;
var directionCheckerY:int=0;
var pointChecker:int=0;
// Croshair
var crosshair:Crosshair = new Crosshair();
addChild(crosshair);
Mouse.hide();
function moveCrossEvent (evt: MouseEvent) {
crosshair.x = mouseX;
crosshair.y = mouseY;
evt.updateAfterEvent();
}
// Hitbox
var hitbox:Hitbox = new Hitbox();
addChild(hitbox);
hitbox.x=50;
hitbox.y=50;
// Timer
var myTimer:Timer = new Timer(30);
myTimer.addEventListener(TimerEvent.TIMER, timerEvent);
myTimer.start();
function timerEvent(evt:TimerEvent) {
// Border code (Keeps the Hitbox away from out of bounds)
if (hitbox.x <= 0) {
directionCheckerX = 1;
} else if (hitbox.x >= 550) {
directionCheckerX = 0;
}
if (directionCheckerX == 0) {
hitbox.x-=2;
} else {
hitbox.x+=2;
}
if (hitbox.y <= 0) {
directionCheckerY = 1;
} else if (hitbox.y >= 400) {
directionCheckerY = 0;
}
if (directionCheckerY == 0) {
hitbox.y-=2;
} else {
hitbox.y+=2;
}
}
// EventListeners
stage.addEventListener(MouseEvent.MOUSE_MOVE, moveCrossEvent);
hitbox.addEventListener(MouseEvent.CLICK, hitboxEvent);
stage.addEventListener(MouseEvent.CLICK, stageEvent);
function hitboxEvent (evt:MouseEvent) {
pointChecker+=1;
outputTxt.text = String(pointChecker);
evt.stopImmediatePropagation();
//evt.updateAfterEvent();
}
function stageEvent(evt:MouseEvent) {
pointChecker-=1;
outputTxt.text = String(pointChecker);
}
To be clear, I'm not a game developer.
Actually, sometimes there is no big difference between a Timer with 1 millisecond interval and another one with 30 milliseconds interval because it's depending on the SWF file's framerate or the runtime environment ... but here, what about using an Event.ENTER_FRAME event instead of a Timer ? because as Adobe said here about Timers versus ENTER_FRAME events :
Choose either timers or ENTER_FRAME events, depending on whether content is animated.
Timers are preferred over Event.ENTER_FRAME events for non-animated content that executes for a long time.
and in your case the content is animated (even if your game is still basic).
Then you can use a var to set the speed of your hitbox which you can update at any time :
var speed:int = 2;
function timerEvent(evt:TimerEvent): void
{
// ...
if (directionCheckerX == 0) {
hitbox.x -= speed;
} else {
hitbox.x += speed;
}
// ...
}
Hope that can help.
I have implemented a digital signature widget using the GWT 2.5 Canvas which works great with mouse events. Unfortunately it fails miserably for touch events and I have no idea why. On a touch screen the signature is drawn but canvas.toDataURL() alway return nothing ("data:," actually). Code snippets are:
_canvas.addMouseMoveHandler(new MouseMoveHandler() {
public void onMouseMove(MouseMoveEvent event) {
int thisX = event.getRelativeX(_canvas.getElement());
int thisY = event.getRelativeY(_canvas.getElement());
if (_lastX >= 0 && _lastY >= 0) {
_exists = true;
_context.moveTo(_lastX, _lastY);
_context.lineTo(thisX, thisY);
_context.stroke();
}
_lastX = thisX;
_lastY = thisY;
}
});
_canvas.addMouseUpHandler(new MouseUpHandler() {
public void onMouseUp(MouseUpEvent event) {
_lastX = -1;
_lastY = -1;
_drawing = false;
if (_exists) _handler.sigChanged(_canvas.toDataUrl());
}
});
_canvas.addTouchMoveHandler(new TouchMoveHandler() {
public void onTouchMove(TouchMoveEvent event) {
if (event.getTouches().length() > 0) {
Touch touch = event.getTouches().get(0);
int thisX = touch.getRelativeX(_canvas.getElement());
int thisY = touch.getRelativeY(_canvas.getElement());
if (_lastX >= 0 && _lastY >= 0) {
_context.moveTo(_lastX, _lastY);
_context.lineTo(thisX, thisY);
_context.stroke();
//_handler.sigChanged(_canvas.toDataUrl());
}
_lastX = thisX;
_lastY = thisY;
}
event.preventDefault();
event.stopPropagation();
}
});
_canvas.addTouchEndHandler(new TouchEndHandler() {
public void onTouchEnd(TouchEndEvent event) {
_handler.sigChanged(_canvas.toDataUrl());
com.google.gwt.user.client.Window.alert("onTouchEnd1: " + _canvas.toDataUrl());
}
event.preventDefault();
});
Again, toDataURL() works fine for the mouse events but always return nothing in the touch events, even if you call it from the touch move handler. Any help or suggestions would be greatly appreciated.
I borrowed a friends android phone that is running a newer version (4.1 vs 2.3) and it works. I don't understand it but I assume it's a bug with GWT 2.5 and I'm moving on.
James
im working with windows phone game using xna... and looking a way to make my object to move with holding some rectangle that i made as a button on screen....
i already tried this but it just read tap gesture only
foreach (GestureSample gestureSample in input.Gestures)
{
switch (gestureSample.GestureType)
{
case GestureType.Hold:
case GestureType.Tap:
Point tapLocation = new Point((int)gestureSample.Position.X, (int)gestureSample.Position.Y);
if (rightRectangle.Contains(tapLocation))
{
rightTouched = true;
player.Catapult.CurrentState = CatapultState.MoveRight;
playerPositionUpdate.X += 20;
player.catapultPosition.X += 20;
player.Catapult.catapultPosition.X += 20;
player.Catapult.projectilePositionUpdate.X += 20;
if (player.Catapult.catapultPosition.X == player.Catapult.catapultPosition.X + 20)
rightTouched = false;
CenterOnPosition(player.Catapult.Position - catapultCenterOffset);
}
break;
}
}
Gestures are discrete events. You want to poll the state of the touch panel every frame. Use TouchPanel.GetState() for that.
See Working with Touch Input (Windows Phone) for information.
As mentioned above you shouldn't use GestureSample for that purpose, because using dragcomplete and freedrag a bit tricky. Instead you should code your own gestures using TouchPanel.GetState()
TouchCollection touchCollection = TouchPanel.GetState();
if (touchCollection.Count == 1)
{
var touch = touchCollection[0];
switch (touch.State)
{
case TouchLocationState.Pressed:
if (rectangle.Contains((int) touch.Position.X, (int) touch.Position.Y))
{
isMoving = true;
}
break;
case TouchLocationState.Moved:
if (isMoving)
{
TouchLocation prevLocation;
touch.TryGetPreviousLocation(out prevLocation);
if (prevLocation.Position != touch.Position)
{
Vector2 delta = touch.Position - prevLocation.Position;
//offset your rectangle on delta
}
}
break;
case TouchLocationState.Released:
isMoving = false;
break;
}
}
else if (touchCollection.Count == 2)
{
var touchOne = touchCollection[0];
var touchTwo = touchCollection[1];
//pinch logic here
}
I guess you understand the idea.
I'm aware there are a lot of questions on this topic, and I've looked through most of them as well as Googling to help me solve this problem, to no avail.
What I'd like to do is post the relevant sections of my code that produce bitmaps and render bitmaps onto PictureBoxes in my UI, and I would like to know if anyone can spot what is specifically causing this error, and can suggest how to avoid or bypass it.
I'll start with the relevant bits (3) in my VideoRenderer class:
The timer event that continously calls MoveFrameToBitmap while video is running:
private void TimerTick(object sender, EventArgs e)
{
if (frameTransport.IsNewFrameAvailable())
{
if (frameTransport.GetFrame())
{
if (MoveFrameToBitmap())
{
double msSinceLastFrame = (Int32)DateTime.Now.Subtract(lastFrameTimestamp).TotalMilliseconds;
fps = 1000 / msSinceLastFrame;
lastFrameTimestamp = DateTime.Now;
}
}
else
{
if (frameTransport.channelKeyBufferBufidMismatch)
{
needsRestart = true;
}
}
}
}
MoveFrameToBitmap, which marshals in a video frame from FrameTransport, creates a bitmap if successful, clones it and queues the frame:
internal bool MoveFrameToBitmap()
{
bool result = false;
try
{
if (frameTransport.bitmapDataSize == 0)
{
return false;
}
bool ResolutionHasChanged = ((videoWidth != frameTransport.width) | (videoHeight != frameTransport.height));
videoHeight = frameTransport.height;
videoWidth = frameTransport.width;
Bitmap bitmap = new System.Drawing.Bitmap(videoWidth, videoHeight);
Rectangle rectangle = new System.Drawing.Rectangle(0, 0, videoWidth, videoHeight);
BitmapData bitmapData = new System.Drawing.Imaging.BitmapData();
bitmapData.Width = videoWidth;
bitmapData.Height = videoHeight;
bitmapData.PixelFormat = PixelFormat.Format24bppRgb;
bitmap.LockBits(rectangle, ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb, bitmapData);
Marshal.Copy(frameTransport.bitmapData, 0, bitmapData.Scan0, frameTransport.bitmapDataSize);
lock (frameQueueLock)
{
if (frameQueue.Count == 0)
{
frameQueue.Enqueue(bitmap.Clone());
}
}
bitmap.UnlockBits(bitmapData);
if (ResolutionHasChanged) skypeRef.events.FireOnVideoResolutionChanged(this, new RootEvents.OnVideoResolutionChangedArgs(videoWidth, videoHeight));
bitmap.Dispose();
result = true;
}
catch (Exception) { }
GC.Collect();
return result;
}
The property that exposes the queued frame, which can be safely accessed even when a frame is not currently queued:
public Bitmap QueuedFrame
{
get
{
try
{
lock (frameQueueLock)
{
return frameQueue.Dequeue() as Bitmap;
}
}
catch (Exception)
{
return null;
}
}
}
That's all for VideoRenderer. Now I'll show the relevant property of the static MyVideo class, which encapsulates, controls and returns frames from two video renderers. Here is the property which exposes the queued frame of the first renderer (every call to videoPreviewRenderer is locked with VPR_Lock):
public static Bitmap QueuedVideoPreviewFrame
{
get
{
lock (VPR_Lock) { return videoPreviewRenderer.QueuedFrame; }
}
}
The property for the second renderer is the same, except with its own lock object.
Moving on, here is the thread and its call in my UI that accesses the two queued frame properties in MyVideo and renders frames to the two PictureBoxes:
ThreadStart renderVCONF3501VideoThreadStart = new ThreadStart(new Action(() =>
{
while (MyAccount.IsLoggedIn)
{
if (MyVideo.VideoPreviewIsRendering)
{
if (MyVideo.VideoPreviewRenderer.NeedsRestart)
{
MyVideo.VideoPreviewRenderer.Stop();
MyVideo.VideoPreviewRenderer.Start();
MyVideo.VideoPreviewRenderer.NeedsRestart = false;
}
else
{
try
{
Bitmap newVideoPreviewFrame = MyVideo.QueuedVideoPreviewFrame;
if (newVideoPreviewFrame != null)
{
lock (VCONF3501_VPI_Lock)
{
VCONF3501_VideoPreview.Image = newVideoPreviewFrame;
}
}
}
catch (Exception) { continue; }
}
}
else
{
lock (VCONF3501_VPI_Lock)
{
VCONF3501_VideoPreview.Image = null;
}
}
if (MyVideo.LiveSessionParticipantVideoIsRendering)
{
if (MyVideo.LiveSessionParticipantVideoRenderer.NeedsRestart)
{
MyVideo.LiveSessionParticipantVideoRenderer.Stop();
MyVideo.LiveSessionParticipantVideoRenderer.Start();
MyVideo.LiveSessionParticipantVideoRenderer.NeedsRestart = false;
}
else
{
try
{
Bitmap newLiveSessionParticipantVideoFrame = MyVideo.QueuedLiveSessionParticipantVideoFrame;
if (newLiveSessionParticipantVideoFrame != null)
{
lock (VCONF3501_LSPVI_Lock)
{
VCONF3501_Video.Image = newLiveSessionParticipantVideoFrame;
}
}
}
catch (Exception) { continue; }
}
}
else
{
lock (VCONF3501_LSPVI_Lock)
{
VCONF3501_Video.Image = null;
}
}
GC.Collect();
}
}));
new Thread(renderVCONF3501VideoThreadStart).Start();
The GC.Collect() calls are to force bitmap memory release, as there was a memory leak (and still might be one--the cloned bitmaps aren't being manually disposed of and I'm not sure where to, at this point).
Where is the InvalidOperationException in System.Drawing, which causes a red cross to be drawn to the PictureBox coming from, what am I doing wrong in terms of locking and access, and how can I avoid/bypass this error?
I am trying to bypass it with the catch exception and continue logic in the thread, and that I have confirmed works . . . sometimes. At other times, the failed draw attempt seems to complete too far and draws the red cross anyway, and after that point, the PictureBox is thoroughly unresponsive and new frames cannot be drawn to it, even when the video is still running fine.
Perhaps there is a way to refresh the PictureBox so that it accepts new frames?
I was having a problem with the red cross, then I find this and it help me, I hope it helps you too:
WinForms controls and the red X