How can I create slow motion effect for all currently playig sounds and music in my game? I'm using cocos2d v2.1 and ObjectAL.
I can set timescale for scheduler, but how I can do this for sound together?
Keep references to the CDSoundSource of each sound and bg output:
CDSoundSource *bgMusic = [[SimpleAudioEngine sharedEngine]soundSourceForFile:#"mysong1.mp3"];
[mySoundArray addObject:bgMusic];
Then create a method to ramp down the pitch of all references at a scheduled interval:
-(void)testUpdate:(ccTime)dt
{
float myRampVal = 0.05f;
float finalPitch = 0.5f;
for(CDSoundSource *sound in mySoundArray)
{
sound.pitch -= myRampVal;
if(sound.pitch < finalPitch)
{
sound.pitch = finalPitch;
}
}
}
Schedule by calling the following when you want to lower the pitch:
[self schedule:#selector(audioDownRamp:) interval:0.1f];
Related
in my SFML game, I'm trying to implement a Speed Boost option, however I don't quite know how to do it, here is a fragment of my code :
//Speed Boosts movement and collision
for(size_t i = 0; i < speedup.size(); i++){
speedup[i].shape.move(-0.2,0);
if(speedup[i].shape.getPosition().x <= 0 - speedup[i].shape.getGlobalBounds().width){
speedup.erase(speedup.begin()+i);
}
if(speedup[i].shape.getGlobalBounds().intersects(player.shape.getGlobalBounds())){
speedup.erase(speedup.begin()+i);
//SPEED UP HERE
}
Also, here's my player movement code:
//Player Movement
if(sf::Keyboard::isKeyPressed(sf::Keyboard::W))
player.shape.move(0,-0.5);
if(sf::Keyboard::isKeyPressed(sf::Keyboard::A))
player.shape.move(-0.5,0);
if(sf::Keyboard::isKeyPressed(sf::Keyboard::S))
player.shape.move(0,0.5);
if(sf::Keyboard::isKeyPressed(sf::Keyboard::D))
player.shape.move(0.5,0);
Now, I'd like, upon collision of the player with the speed boost sprite, for the players movement speed to be temporarily increased, however I don't quite know how to do it, should I use some fore loop and sf::Clock set the time of the boost? I also don't know how to change the movement speed temporarily.
I'd like more of a push in the right direction, than a complete code, so please give me hints how to realize that function
EDIT:
Proposed Speed boost implementation, it crashes:
if(speedup[i].shape.getGlobalBounds().intersects(player.shape.getGlobalBounds())){
speedup.erase(speedup.begin()+i);
float etime = clock.getElapsedTime().asSeconds();
while(etime<=10){
y_spd=2*y_spd;
x_spd=2*x_spd;
}
}
EDIT 2
I'm trying to figure out my timer so that it measures time from collision properly:
//Clock
sf::Clock dclock;
float dt = dclock.restart().asSeconds();
I declare this in my main(), I've tried doing it in many ways, none gives me proper time measurement.
//Speed Boost movement and collision
for(size_t i = 0; i < speedup.size(); i++){
speedup[i].shape.move(-5,0);
if(speedup[i].shape.getPosition().x <= 0 - speedup[i].shape.getGlobalBounds().width){
speedup.erase(speedup.begin()+i);
}
if(speedup[i].shape.getGlobalBounds().intersects(player.shape.getGlobalBounds())){
speedup.erase(speedup.begin()+i);
timer += dt;
}
}
//SPEED BOOSTING THE PLAYER
if(timer>=10){
y_spd=3;
x_spd=3;
timer = 0;
}
I'm trying to do an UWP game, and i came accross a problem where my game is much slower in release mode than it is in debug mode.
My game will draw a 3D view (Dungeon master style) and will have an UI part that draws over the 3D view. Because the 3D view can slow down to a small amount of frames per seconds (FPS), i decided to make my game running the UI part always at 60 FPS.
Here is how the main gameloop looks like, in some pseudo code:
Gameloop start
Update game datas
copy actual finished 3D view from buffer to screen
draw UI part
3D view loop start
If no more time to draw more textures on the 3D view exit 3D view loop
Draw one texture to 3D view buffer
3D view loop end --> 3D view loop start
Gameloop end --> Gameloop start
Here are the actual update and render functions:
void Dungeons_of_NargothMain::Update()
{
m_ritonTimer.startTimer(static_cast<int>(E_RITON_TIMER::UI));
m_ritonTimer.frameCountPlusOne((int)E_RITON_TIMER::UI_FRAME_COUNT);
m_ritonTimer.manageFramesPerSecond((int)E_RITON_TIMER::UI_FRAME_COUNT);
m_ritonTimer.manageFramesPerSecond((int)E_RITON_TIMER::LABY_FRAME_COUNT);
if (m_sceneRenderer->m_numberTotalOfTexturesToDraw == 0 ||
m_sceneRenderer->m_numberTotalOfTexturesToDraw <= m_sceneRenderer->m_numberOfTexturesDrawn)
{
m_sceneRenderer->m_numberTotalOfTexturesToDraw = 150000;
m_sceneRenderer->m_numberOfTexturesDrawn = 0;
}
}
// RENDER
bool Dungeons_of_NargothMain::Render()
{
//********************************//
// Render UI part here //
//********************************//
//**********************************//
// Render 3D view to 960X540 screen //
//**********************************//
m_sceneRenderer->setRenderTargetTo960X540Screen(); // 3D view buffer screen
bool screen960GotFullDrawn = false;
bool stillenoughTimeLeft = true;
while (stillenoughTimeLeft && (!screen960GotFullDrawn))
{
stillenoughTimeLeft = m_ritonTimer.enoughTimeForOneMoreTexture((int)E_RITON_TIMER::UI);
screen960GotFullDrawn = m_sceneRenderer->renderNextTextureTo960X540Screen();
}
if (screen960GotFullDrawn)
m_ritonTimer.frameCountPlusOne((int)E_RITON_TIMER::LABY_FRAME_COUNT);
return true;
}
I removed what is not essential.
Here is the timer part (RitonTimer):
#pragma once
#include "pch.h"
#include <wrl.h>
#include "RitonTimer.h"
Dungeons_of_Nargoth::RitonTimer::RitonTimer()
{
initTimer();
if (!QueryPerformanceCounter(&m_qpcGameStartTime))
{
throw ref new Platform::FailureException();
}
}
void Dungeons_of_Nargoth::RitonTimer::startTimer(int timerIndex)
{
if (!QueryPerformanceCounter(&m_qpcNowTime))
{
throw ref new Platform::FailureException();
}
m_qpcStartTime[timerIndex] = m_qpcNowTime.QuadPart;
m_framesPerSecond[timerIndex] = 0;
m_frameCount[timerIndex] = 0;
}
void Dungeons_of_Nargoth::RitonTimer::resetTimer(int timerIndex)
{
if (!QueryPerformanceCounter(&m_qpcNowTime))
{
throw ref new Platform::FailureException();
}
m_qpcStartTime[timerIndex] = m_qpcNowTime.QuadPart;
m_framesPerSecond[timerIndex] = m_frameCount[timerIndex];
m_frameCount[timerIndex] = 0;
}
void Dungeons_of_Nargoth::RitonTimer::frameCountPlusOne(int timerIndex)
{
m_frameCount[timerIndex]++;
}
void Dungeons_of_Nargoth::RitonTimer::manageFramesPerSecond(int timerIndex)
{
if (!QueryPerformanceCounter(&m_qpcNowTime))
{
throw ref new Platform::FailureException();
}
m_qpcDeltaTime = m_qpcNowTime.QuadPart - m_qpcStartTime[timerIndex];
if (m_qpcDeltaTime >= m_qpcFrequency.QuadPart)
{
m_framesPerSecond[timerIndex] = m_frameCount[timerIndex];
m_frameCount[timerIndex] = 0;
m_qpcStartTime[timerIndex] += m_qpcFrequency.QuadPart;
if ((m_qpcStartTime[timerIndex] + m_qpcFrequency.QuadPart) < m_qpcNowTime.QuadPart)
m_qpcStartTime[timerIndex] = m_qpcNowTime.QuadPart - m_qpcFrequency.QuadPart;
}
}
void Dungeons_of_Nargoth::RitonTimer::initTimer()
{
if (!QueryPerformanceFrequency(&m_qpcFrequency))
{
throw ref new Platform::FailureException();
}
m_qpcOneFrameTime = m_qpcFrequency.QuadPart / 60;
m_qpc5PercentOfOneFrameTime = m_qpcOneFrameTime / 20;
m_qpc10PercentOfOneFrameTime = m_qpcOneFrameTime / 10;
m_qpc95PercentOfOneFrameTime = m_qpcOneFrameTime - m_qpc5PercentOfOneFrameTime;
m_qpc90PercentOfOneFrameTime = m_qpcOneFrameTime - m_qpc10PercentOfOneFrameTime;
m_qpc80PercentOfOneFrameTime = m_qpcOneFrameTime - m_qpc10PercentOfOneFrameTime - m_qpc10PercentOfOneFrameTime;
m_qpc70PercentOfOneFrameTime = m_qpcOneFrameTime - m_qpc10PercentOfOneFrameTime - m_qpc10PercentOfOneFrameTime - m_qpc10PercentOfOneFrameTime;
m_qpc60PercentOfOneFrameTime = m_qpc70PercentOfOneFrameTime - m_qpc10PercentOfOneFrameTime;
m_qpc50PercentOfOneFrameTime = m_qpc60PercentOfOneFrameTime - m_qpc10PercentOfOneFrameTime;
m_qpc45PercentOfOneFrameTime = m_qpc50PercentOfOneFrameTime - m_qpc5PercentOfOneFrameTime;
}
bool Dungeons_of_Nargoth::RitonTimer::enoughTimeForOneMoreTexture(int timerIndex)
{
while (!QueryPerformanceCounter(&m_qpcNowTime));
m_qpcDeltaTime = m_qpcNowTime.QuadPart - m_qpcStartTime[timerIndex];
if (m_qpcDeltaTime < m_qpc45PercentOfOneFrameTime)
return true;
else
return false;
}
In debug mode the game's UI works at 60 FPS, and the 3D view is about 1 FPS on my PC. But even there i'm not sure why i have to stop my texture drawing at 45% of one game time and call present, to get the 60 FPS, if i wait longer i only get 30 FPS. (this valor is set in "enoughTimeForOneMoreTexture()" in RitonTimer.
In Release mode it drops dramatically, having like 10 FPS for the UI part, 1 FPS for the 3D part. I tried to find why for the last 2 days, didn't find it.
Also i have another small question: How do i tell visual studio that my game is actually a game and not an app ? Or does Microsoft do the "switch" when i send my game to their store ?
Here i have put my game on my OneDrive so everyone can download the source files and try to compile it, and see if you get the same results as me:
OneDrive link: https://1drv.ms/f/s!Aj7wxGmZTdftgZAZT5YAbLDxbtMNVg
compile in either x64 Debug, or x64 Release mode.
UPDATE:
I think i found the explanation why my game is slower in release mode.
The CPU is probably not waiting for the drawing instruction to be done, but simply adds it to a list which will be forward to the GPU at it's own pace in a separate task (or maybe the GPU does that cache himself). That would explain it all.
My plan was to draw the UI first and then to draw as many textures from the 3D view as possible till 95% of a 1/60th second frame time passed and then present it to the swapchain. The UI would always be at 60 FPS and the 3D view would be as fast as the system allows it (also at 60FPS if it can all be drawn in 95% of the frame time).
This didn't work because it probbably cached all the instructions my 3D view had (i was testing with 150000 BIG texture draw instructions for the 3D view) in one frame time, and so of course the UI was as slow as the 3D view at the end, or close to.
That is also why even in debug mode i didn't get 60FPS when i waited for 95% of a frame time, i had to wait for 45% of a frame time to get my 60 FPS i wanted for the UI.
I tested it with a lower value in release mode to verify that theory, and indeed i also get 60 FPS for the UI when i stop the Drawings at only 15% of a frame time.
I tought it worked like this only in DirectX12.
"How do i tell visual studio that my game is actually a game and not an app" - there's no difference, a game is an app.
I have your code running at 300-400 FPS now in debug mode.
Firstly I commented out your code that checks if you've got time to render another texture. Don't do that. Everything the player sees should render within a single frame. If your frame is taking more than 16ms (with 60fps target) look for expensive operations, or calls that are made repeatedly, possibly adding up to some unexpected cost. Look for code that might be doing something repeatedly when it only needs to do it once per frame or per resize. etc
So the issue is that you were rendering very large textures and a lot of them. You want to avoid overdraw (rendering a pixel where you've already rendered a pixel). You can have a bit of overdraw and that's sometimes preferable to being pedantic. But you were drawing 1000x2000 textures over and over again. So you were absolutely killing the pixel shader. It just can't render that many pixels. I didn't bother looking at the code that tries to control texture rendering based on frame time remaining. For what you're trying to do, that's not helpful.
Inside your render method comment out the while and if/else sections and use this to draw an array of your textures ..
// set sprite dimensions
int w = 64, h = 64;
for (int y = 0; y < 16; y++)
{
for (int x = 0; x < 16; x++)
{
m_sceneRenderer->renderNextTextureTo960X540Screen(x*64, y*64, w, h);
}
}
and in RenderNextTextureToScreen(int x, int y, int w, int h) ..
m_squareBuffer.sizeX = w; // 1000;
m_squareBuffer.sizeY = h; // 2000;
m_squareBuffer.posX = x; // (float)(rand() % 1920);
m_squareBuffer.posY = y; // (float)(rand() % 1080);
See how this code renders much smaller textures, the textures are 64x64 and there's no overdraw.
And just be aware that the GPU isn't all powerful, it can do a lot if you use it right, but if you just throw crazy operations at it, you can grind it to a halt, just like with the CPU. So try to render things that 'look normal', that you can imagine being in a game. You'll learn in time what's sensible and what isn't.
The most likely explanation for the code running slower in release mode is that your timing and rendering limiter code was broken. It wasn't working properly because the 3d view was running at 1fps, so then who knows what it's behaviour is. With the changes I've made, the program seems to run faster in release mode as expected. Your clock code is showing 600-1600fps in release mode now for me.
I am using SFML making a 2D platformer. I read so many timestep articles but they don't work well for me. I am implementing it like 2500 FPS timestep, on my desktop pc it's amazingly smooth, on my laptop it's getting 300 FPS(I check with Fraps), it's not that smooth at laptop but still playable.
Here are the code snippets:
sf::Clock clock;
const sf::Time TimePerFrame = sf::seconds(1.f/2500.f);
sf::Time TimeSinceLastUpdate = sf::Time::Zero;
sf::Time elapsedTime;
These are variables and here is the game loop,
while(!quit){
elapsedTime = clock.restart();
TimeSinceLastUpdate += elapsedTime;
while (TimeSinceLastUpdate > TimePerFrame){
TimeSinceLastUpdate -= TimePerFrame;
Player::instance()->handleAll();
}
Player::instance()->render();
}
In the Player.h, I've got movement constants,
const float GRAVITY = 0.35 /2500.0f; // Uses += every frame
const float JUMP_SPEED = -400.0f/2500.0f; //SPACE -> movementSpeed.y = JUMP_SPEED;
//When character is touching to ground
const float LAND_ACCEL = 0.075 /2500.0f; // These are using +=
const float LAND_DECEL = 1.5 /2500.0f;
const float LAND_FRICTION = 0.5 /2500.0f;
const float LAND_STARTING_SPEED = 0.075; // This uses =, instead of +=
In the handleAll function of Player class, there is
cImage.move(movementSpeed);
checkCollision();
And lastly, checkCollision function, simply checks if character's master bounding box intersects the object's rectangle from each side, sets the speed x or y to 0, then fixes the overlapping by setting character position to the edge.
//Collision
if(masterBB().intersects(objectsIntersecting[i]->GetAABB())){
//HORIZONTAL
if(leftBB().intersects(objectsIntersecting[i]->GetAABB())){
if(movementSpeed.x < 0)
movementSpeed.x = 0;
cImage.setPosition(objectsIntersecting[i]->GetAABB().left + objectsIntersecting[i]->GetAABB().width + leftBB().width , cImage.getPosition().y);
}
else if(rightBB().intersects(objectsIntersecting[i]->GetAABB())){
if(movementSpeed.x > 0)
movementSpeed.x = 0;
cImage.setPosition(objectsIntersecting[i]->GetAABB().left - rightBB().width , cImage.getPosition().y);
}
//VERTICAL
if(movementSpeed.y < 0 && topBB().intersects(objectsIntersecting[i]->GetAABB())){
movementSpeed.y = 0;
cImage.setPosition(cImage.getPosition().x , objectsIntersecting[i]->GetAABB().top + objectsIntersecting[i]->GetAABB().height + masterBB().height/2);
}
if(movementSpeed.y > 0 && bottomBB().intersects(objectsIntersecting[i]->GetAABB())){
movementSpeed.y = 0;
cImage.setPosition(cImage.getPosition().x , objectsIntersecting[i]->GetAABB().top - masterBB().height/2);
//and some state updates
}
}
I tried to use 60 FPS Timestep like million times but all speed variables become so slow, I can't simply do like *2500.0f / 60.0f to all constants, It doesn't feel same. If I get close constants, It feels "ok" but then when the collision happens, character's position is getting setted all the time and it flys out of the map because of the big lap on the object caused by high speed constants applied every frame I guess...
I need to add, Normally, the book I took the timestep code uses
cImage.move(movementSpeed*TimePerFrame.asSeconds());
but as you saw, I just put /2500.0f to every constant and I don't use it.
So, is 1/2500 seconds per frame good? If not, how can I change all of these to 1/60.0f?
You're doing it wrong.
Your monitor most likely has a refresh rate of 60 Hz (= 60 FPS), thus trying to render an image at 2500 FPS is a huge waste of resources. If the only reason for choosing 2500 FPS is that your movement doesn't work the same, haven't you ever thought about, that the problem then might be with the movement code?
At best you'd implement a fixed timestep (famous article), that way your physics can run at whatever rate you want (2500 "FPS" would still be crazy, so don't do it) and is independent from your rendering rate. So even if you get some varying FPS, it won't influence your physics.
I've been having a lot of trouble implementing a smooth and reliable touch-and-hold solution for firing bullet (sprites) - even after looking at other people's solutions.
The solution has to switch between touch-began, touch moved and touch ended seamlessly: always firing bullets at the touch location until the finger is released. At the moment I have many problems with reliability and stability with every case but touchmoved, which works fine.
The exact issue is around half the time a finger is held down (touchBegan + scheduler) the bullets appear but disappear a second later but other times they move towards the touch perfectly - something is deleting them and i don't have much experience with schedulers or actions to know what.
Heres my code, I've used 2 different firing methods: one scheduled to run every 0.05 seconds after touchBegan, and one triggered every time touchMoved is detected. The touchMoved one works fine, but getting it to work with the unreliable touchBegan one is trouble. The really annoying part is even if I remove the touch part and just schedule sprites to appear and run scheduled actions non-stop from init, the same reliability problem happens (disappearing/deletion). Maybe I dont understand getting schedulers and actions to play nice, or maybe theres a better touch and hold method? Thanks in advance for any help.
bool HelloWorld::init()
{
... miscellaneous sprite creation
this->schedule(schedule_selector(HelloWorld::fireBullets), 0.05);
}
void HelloWorld::ccTouchesBegan(CCSet *pTouches, CCEvent *pEvent)
{
CCTouch* touch = (CCTouch*)( pTouches->anyObject() ); // get single-touch as opposed to multitouch
touchLocation = CCDirector::sharedDirector()->convertToGL(touch->getLocationInView());
if (touchLocation.x > 400)
{
float dX = touchLocation.x - gun->getPosition().x;
float dY = touchLocation.y - gun->getPosition().y;
touchAngle = atan2(dY, dX);
gun->setRotation(-CC_RADIANS_TO_DEGREES(touchAngle));
cursor->setPosition(touchLocation);
screenHeld = true;
}
}
void HelloWorld::ccTouchesMoved(CCSet *pTouches, CCEvent *pEvent)
{
CCTouch* touch = (CCTouch*)( pTouches->anyObject() ); // for single-touch as opposed to multitouch
touchLocation = CCDirector::sharedDirector()->convertToGL(touch->getLocationInView());
if (touchLocation.x > 400)
{
float dX = touchLocation.x - gun->getPosition().x;
float dY = touchLocation.y - gun->getPosition().y;
float angle = atan2(dY, dX);
gun->setRotation(-CC_RADIANS_TO_DEGREES(angle));
cursor->setPosition(touchLocation);
screenHeld = false; //not technically true but touchMoved bullet firing works differently (not scheduled, every movement instead)
if (getTimeTick() - lastBulletFire > 50) //getTickTime is simple get system time method, works fine
{
fireBullet(angle);
}
}
}
//this is for touchBegan and has issues, scheduled to run every 50ms touch-held
void HelloWorld::fireBullets(CCTime dt)
{
if (screenHeld)
{
CCSprite* bullet = CCSprite::create("bullet.png");
bullet->setPosition(ccp(gun->getPosition().x, gun->getPosition().y));
bullet->setRotation(-CC_RADIANS_TO_DEGREES(touchAngle));
//send bullet towards touchlocation
bullet->runAction(CCSequence::create(CCMoveBy::create(1.5f, ccp(800 * cos(touchAngle), 800 * sin(touchAngle))), NULL));
this->addChild(bullet, 5);
}
}
//this is for touchMoved and works fine, everytime finger is moved bullet fired
void HelloWorld::fireBullet(float angle)
{
CCSprite* bullet = CCSprite::create("bullet.png");
bullet->setPosition(ccp(gun->getPosition().x, gun->getPosition().y)); //add a random spread to the y value (or maybe the y-value of the destination)
this->addChild(bullet, 5);
bullet->setRotation(-CC_RADIANS_TO_DEGREES(angle));
bullet->runAction(CCSequence::create(CCMoveBy::create(1.5f, ccp(800 * cos(angle), 800 * sin(angle))), NULL));
lastBulletFire = getTimeTick();
}
Found the solution, it wasn't anything to do with actions/schedulers but the fact that I wasn't calling retain() on the bullets. Normally I'd manage C++ memory manually but this hybrid style threw my off
I want to build a platform game with cocos2d/Box2D. I use CCFollow to follow the player sprite but CCFollow constantly puts it in the center of the screen. I want CCFollow to follow more naturally, like a human turning a camcorder with an acceptable lag, a small overshoot ...etc.
Here is a method of mine that didn't work: I attached (via a distance joint) a small physics body to the player that doesn't collide with anything, represented by a transparent sprite. I CCFollow'ed the transparent sprite. I was hoping this ghost body would act like a balloon attached to the player, hence a smooth shift in view. The problem is distance joint breaks with too heavy - too light objects. The balloon moves around randomly, and of course, it pulls the player back a little no matter how light it is.
What is a better way of following a moving sprite smoothly?
Try add this to CCActions in cocos2d libs.
-(void) step:(ccTime) dt
{
#define CLAMP(x,y,z) MIN(MAX(x,y),z)
CGPoint pos;
if(boundarySet)
{
// whole map fits inside a single screen, no need to modify the position - unless map boundaries are increased
if(boundaryFullyCovered) return;
CGPoint tempPos = ccpSub(halfScreenSize, followedNode_.position);
pos = ccp(CLAMP(tempPos.x,leftBoundary,rightBoundary), CLAMP(tempPos.y,bottomBoundary,topBoundary));
}
else {
// pos = ccpSub( halfScreenSize, followedNode_.position );
CCNode *n = (CCNode*)target_;
float s = n.scale;
pos = ccpSub( halfScreenSize, followedNode_.position );
pos.x *= s;
pos.y *= s;
}
CGPoint moveVect;
CGPoint oldPos = [target_ position];
double dist = ccpDistance(pos, oldPos);
if (dist > 1){
moveVect = ccpMult(ccpSub(pos,oldPos),0.05); //0.05 is the smooth constant.
oldPos = ccpAdd(oldPos, moveVect);
[target_ setPosition:oldPos];
}
#undef CLAMP
}
i get this from cocos2d forums.
Perhaps this http://www.cocos2d-iphone.org/wiki/doku.php/prog_guide:actions_ease can help you get an "acceleration" effect with CCFollow.