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
Related
This is a simplified snippet of a larger WPF project to illustrate the problem.
When the play button is pressed, this code plays the mp3's "1, 2, 3, 4, 5" then stops.
When the play button is pressed, the dispatch timer starts. On every Tick, the Metronome_Run event is called. The Metronome_Run event assigns a mp3 to play by indexing an array.
The problem is, it works fine the first time you press play, you get 1,2,3,4,5, but when pressing play again, you get 2,4,5, then pressing play again, you get 3,5! As if the indexing of the files seems to be offset each time play is pressed somehow.
When stepping through with the debugger, it runs perfect every time, yet without any breakpoints set, (like in the build), it works correctly only the first time and does not work correctly on further play button presses.
Any help is appreciated!
public partial class MainWindow : Window
{
private MediaPlayer mediaPlayer = new MediaPlayer();
List<int> NoteValArray = new List<int>() { 1,2,3,4,5 };
private DispatcherTimer timer1;
int numVal = 0;
int numIndex = 0;
private float tempo = 35f;
public MainWindow()
{
InitializeComponent();
timer1 = new DispatcherTimer();
}
private void Metronome_Run(object sender, EventArgs e)
{
if (NoteValArray.Count > numIndex) // if we are not outside the list bounds
{
numVal = NoteValArray[numIndex]; // get the value at this list index and place it in numVal
numIndex ++; // increment
}
else { timer1.Stop(); return; }
// Load the mp3 indicated by numVal
if (numVal == 1) { mediaPlayer.Open(new Uri("1.mp3", UriKind.Relative)); }
else if (numVal == 2) { mediaPlayer.Open(new Uri("2.mp3", UriKind.Relative)); }
else if (numVal == 3) { mediaPlayer.Open(new Uri("3.mp3", UriKind.Relative)); }
else if (numVal == 4) { mediaPlayer.Open(new Uri("4.mp3", UriKind.Relative)); }
else if (numVal == 5) { mediaPlayer.Open(new Uri("5.mp3", UriKind.Relative)); }
mediaPlayer.Play(); // play whats loaded
}
private void Start_Button_Click(object sender, RoutedEventArgs e)
{
numIndex = 0;
timer1.Tick += Metronome_Run; // run this at each tick
timer1.Interval = TimeSpan.FromMilliseconds(10000 / (tempo / 6));
timer1.Start();
}
}
}
Solved!
I moved "timer1 = new DispatcherTimer();" from the mainwindow function, and placed it in the "Start_Button_Click" event with the other timer code.
My guess is I was starting more than 1 timer with each play press, and that was causing the bug. Thanks to all who took time to look at my problem.
Like a play list with play,pause, next and back button I achieved it using if else in C# but like to use counter can some give me better idea.
public void nextSq()
{
if (CPU_Model.GetCurrentAnimatorStateInfo(0).IsName("Parent_1"))
{
CPU_Model.Play("Parent_2", -1, 0f);
CPU_Model.speed = 0.25f;
}
else if (CPU_Model.GetCurrentAnimatorStateInfo(0).IsName("Parent_2"))
{
CPU_Model.Play("Parent_3", -1, 0f);
CPU_Model.speed = 0.25f;
}
else if (CPU_Model.GetCurrentAnimatorStateInfo(0).IsName("Parent_3"))
{
CPU_Model.Play("Parent_4", -1, 0f);
CPU_Model.speed = 0.25f;
}
}
Use the Animation view, the playable graphs technology, or DOTween to sequence animations.
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.
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.
Hello everyone I have been following this tutorial here http://www.gogo-robot.com/2011/05/30/xna-skinned-model-animations/ and so far its great got the animations playing and everything, but now I want to expand it and stop the continuous loops say for instance i press the a key to make the model jump when i release the a key i want him to stop jumping but if i hold the a key i want him to keep jumping. Here what i have tried so far
and none of it works.
I am stumped here on how to do this thanks for any help with this.
private void HandleInput(GameTime gameTime)
{
currentGamePadState = GamePad.GetState(PlayerIndex.One);
// Check for changing anims
//SkinningData skinningData = model.Tag as SkinningData;
SkinningData sd = jumper.model.Tag as SkinningData;
if (currentGamePadState.Buttons.A == ButtonState.Pressed)
{
if (jumper.animationPlayer.CurrentClip.Name != "Fire")
jumper.animationPlayer.StartClip(sd.AnimationClips["Fire"]);
}
if (currentGamePadState.Buttons.X == ButtonState.Pressed)
{
if (jumper.animationPlayer.CurrentClip.Name != "DieF")
jumper.animationPlayer.StartClip(sd.AnimationClips["DieF"]);
}
//does not work
if (currentGamePadState.Buttons.X == ButtonState.Released)
{
if (jumper.animationPlayer.CurrentClip.Name == "DieF")
jumper.animationPlayer.StartClip(sd.AnimationClips["Idel"]);
}
if (currentGamePadState.Buttons.Y == ButtonState.Pressed)
{
if (jumper.animationPlayer.CurrentClip.Name != "Idel")
jumper.animationPlayer.StartClip(sd.AnimationClips["Idle"]);
}
//does not work
if (jumper.animationPlayer.CurrentTime == jumper.animationPlayer.CurrentClip.Duration)
{
//set him back to idel
jumper.animationPlayer.StartClip(sd.AnimationClips["Idle"]);
}
I have tried these configuration with no luck in the game
// Starts playing the entirety of the given clip
public void StartClip(string clip, bool loop)
{
AnimationClip clipVal = skinningData.AnimationClips[clip];
StartClip(clip, TimeSpan.FromSeconds(0), clipVal.Duration, loop);
}
// Plays a specific portion of the given clip, from one frame
// index to another
public void StartClip(string clip, int startFrame, int endFrame, bool loop)
{
AnimationClip clipVal = skinningData.AnimationClips[clip];
StartClip(clip, clipVal.Keyframes[startFrame].Time,
clipVal.Keyframes[endFrame].Time, loop);
}
// Plays a specific portion of the given clip, from one time
// to another
public void StartClip(string clip, TimeSpan StartTime, TimeSpan EndTime, bool loop)
{
CurrentClip = skinningData.AnimationClips[clip];
currentTime = TimeSpan.FromSeconds(0);
currentKeyframe = 0;
Done = false;
this.startTime = StartTime;
this.endTime = EndTime;
this.loop = loop;
// Copy the bind pose to the bone transforms array to reset the animation
skinningData.BindPose.CopyTo(BoneTransforms, 0);
}
Can you not attach a bool on the animation clip to tell it to play only once, or an active variable that can be called.