When I start game fps is about 60 but on holding button "W" my fps decrease to 30.On release that button it became 60 again.This happens because line of code:
model->Load("img/characters.png", rec).
If I'll comment line like this "//" character gonna move smoothly with 60fps but w/o turning to top.
Entity *player;
void heroMovement()
{
if (sf::Keyboard::isKeyPressed(sf::Keyboard::W))
{
sf::IntRect top(32, 224, 32, 32);
this->player->Load("img/characters.png", top);
calculateTileAnimation(0, 32, 64, top , this->player);
velocity.y -= character_speed;
}
}
void calculateTileAnimation(int firstTile , int sizeTile , int
lastTile,sf::IntRect rec , Entity *model)
{
model->Load("img/characters.png", rec); // This line decreasing fps
if (clock.getElapsedTime().asSeconds() < 0.3f)
{
rec.left += sizeTile;
if (rec.left == lastTile)
rec.left = firstTile;
clock.restart();
}
}
void Load(std::string filename, sf::IntRect rec)
{
this->texture->loadFromFile(filename, rec);
this->setTexture(*this->texture);
}
Need to fix it , on holding button "w" character should be turned on top and move with 60fps.
You load the textures from disk on every keystroke. Don't. Load the textures from disk at the start of your game (you probably know those loading screens) and store them in variables.
Then use them, for example in the setTexture method.
Related
i wanted to make player a bit realistic instead of just hovering around like a ghost. this is my code just some basic gravity and movement, i want to make jumping animation, walking animation, turn left and turn right animation. how do i do that?
here code:
void Game::initTexture()
{
if (!texture.loadFromFile("/home/webmaster/Documents/vscode-sfml/src/Ball_and_Chain_Bot/pixil-frame-0(1).png"))
{
std::cout << "failed to load texture\n";
rect.setTexture(texture);
rect.setPosition(this->window->getView().getCenter());
rect.setScale(2,2);
}
}
rendering:
void Game::render()
{
this->window->clear(sf::Color(239, 235, 216));
this->window->draw(rect);
this->window->display();
}
You forgot to show your actual code, the headers are not very useful. Regardless:
Define some animations. Each animation should have a target length and a number of frames that cover that target. At the beginning it is easiest to make every frame be equally long, but nobody stops you from having frame 1 take 0.2s, frame 2 0.8s, and frame 3 0.15s.
add code to keep track of a "current animation" that properly cycles through the frames on the proper timescale (ie show each frame for 0.25s if you have 4 frames and a target of 1s). Some animations may cycle, such as the "running" or "idle" animation. A common technique for storing animations is a "texture atlas" that contains all frames of an animation. You can then use sf::Shape::setTextureRect to select a part of the texture to draw.
update your movement and input code to change the animation if the state of the character changes
Let us define the frames of an animation in terms of sf::IntRect sections of a given sprite sheet: (example sprite sheet)
std::vector<sf::IntRect> idle {
{0, 0, 35, 61}
};
std::vector<sf::IntRect> runningRight {
{657, 473, 43, 52}, // first frame is at 657x473 and is 43x52 pixels
// other frames.
};
We can define an Animation class with the following data and methods:
class Animation {
public:
Animation(const std::vector<sf::IntRect>& frames, float duration, bool cycles = true) : frames(frames), frameTime(duration / frames.size()), cycles(cycles) { reset(); }
void reset() {
currentFrame = 0;
currentFrameTime = 0;
}
void update(float dt);
const sf::IntRect& getCurrentRect() const { return frames[currentFrame]; }
private:
const std::vector<sf::IntRect>& frames;
const float frameTime;
bool cycles;
int currentFrame;
float currentFrameTime;
};
This implements most of step 2: keeping track of which frame should be on screen, assuming update(dt) is called every frame.
Now all that remains is the update method:
void Animation::update(float dt) {
currentFrameTime += dt;
// TODO: take `cycles` into account.
while (currentFrameTime >= frameTime) {
currentFrameTime -= frameTime;
currentFrame = (currentFrame + 1) % frames.size();
}
}
Finally, to hook this up, create the following variables:
sf::Texture textureAtlas = ...;
Animation currentAnimation{idle, 10.0f};
sf::Sprite player(textureAtlas, currentAnimation.getCurrentRect());
In your game's update() code, call currentAnimation.update(dt).
In the render function, make sure to call player.setTextureRect(currentAnimation.getCurrentRect()).
If you receive input, do something like currentAnimation = Animation{runningRight, 1.0f};
I am creating a billiards game and am having major problems with tunneling at high speeds. I figured using linear interpolation for animations would help quite a bit, but the problem persists. To see this, I drew a circle at the previous few positions an object has been. At the highest velocity the ball can travel, the path looks like this:
Surely, these increments of advancement are much too large even after using linear interpolation.
At each frame, every object's location is updated based on the amount of time since the window was last drawn. I noticed that the average time for the window to be redrawn is somewhere between 70 and 80ms. I would really like this game to work at 60 fps, so this is about 4 or 5 times longer than what I am looking for.
Is there a way to change how often the window is redrawn? Here is how I am currently redrawing the screen
#include "pch.h"
#include "framework.h"
#include "ChildView.h"
#include "DoubleBufferDC.h"
const int FrameDuration = 16;
void CChildView::OnPaint()
{
CPaintDC paintDC(this); // device context for painting
CDoubleBufferDC dc(&paintDC); // device context for painting
Graphics graphics(dc.m_hDC); // Create GDI+ graphics context
mGame.OnDraw(&graphics);
if (mFirstDraw)
{
mFirstDraw = false;
SetTimer(1, FrameDuration, nullptr);
LARGE_INTEGER time, freq;
QueryPerformanceCounter(&time);
QueryPerformanceFrequency(&freq);
mLastTime = time.QuadPart;
mTimeFreq = double(freq.QuadPart);
}
LARGE_INTEGER time;
QueryPerformanceCounter(&time);
long long diff = time.QuadPart - mLastTime;
double elapsed = double(diff) / mTimeFreq;
mLastTime = time.QuadPart;
mGame.Update(elapsed);
}
void CChildView::OnTimer(UINT_PTR nIDEvent)
{
RedrawWindow(NULL, NULL, RDW_UPDATENOW);
Invalidate();
CWnd::OnTimer(nIDEvent);
}
EDIT: Upon request, here is how the actual drawing is done:
void CGame::OnDraw(Gdiplus::Graphics* graphics)
{
// Draw the background
graphics->DrawImage(mBackground.get(), 0, 0,
mBackground->GetWidth(), mBackground->GetHeight());
mTable->Draw(graphics);
Pen pen(Color(500, 128, 0), 1);
Pen penW(Color(1000, 1000, 1000), 1);
this->mCue->Draw(graphics);
for (shared_ptr<CBall> ball : this->mBalls)
{
ball->Draw(graphics);
}
for (shared_ptr<CBall> ball : this->mSunkenSolidBalls)
{
ball->Draw(graphics);
}
for (shared_ptr<CBall> ball : this->mSunkenStripedBalls)
{
ball->Draw(graphics);
}
this->mPowerBar->Draw(graphics);
}
Game::OnDraw will call Draw on all of the game items, which draw on the graphics object they receive as an argument.
I create a little game on cocos2d-x and have some problem in mobile version. Game have layer with terrain and character and layer with ui/info objects. Layer with terrain does not move. And layer with ui/info move with character (so it static on screen).
In mobile version all sprites from ui layer are trembling, but only sprites, labels are static. In PC version sprites and labels are also static.
Create label and sprite. Label static on PC (Win and Mac) and mobile (Android), sprite static on PC and tremble on mobile:
auto infoLayer = m_params->getGameInfoDelegate(); // class GameInfo
auto size = Director::getInstance()->getVisibleSize();
TTFConfig ttfconfig("fonts/Marker Felt.ttf", 100);
auto label = Label::createWithTTF(ttfconfig, "0");
label->setPosition(Vec2(size.width / 2, size.height / 2 + 40));
label->setString("Hello");
infoLayer->getLayer()->addChild(label, 10);
auto spr = Sprite::create();
spr->setColor(Color3B(200, 100, 100));
spr->setTextureRect(Rect(0, 0, 150, 150));
spr->setPosition(Vec2(size.width / 2, size.height / 2 - 40));
infoLayer->getLayer()->addChild(spr, 9);
Update position layer and camera:
update(float t)
{
...
m_cameraFollow->update();
...
}
void CameraFollow::update()
{
float moveX;
float moveY;
...
m_camera->move(Vec2(moveX, moveY)); // class GameCamera
}
void GameCamera::move(const cocos2d::Vec2& m)
{
float x;
float y;
...
m_position.x = x;
m_position.y = y;
m_camera->setPosition(m_position); // class cocos2d::Camera
auto infoPanel = m_params->getGameInfoDelegate(); // class GameInfo
if(infoPanel)
{
infoPanel->setMoving(m_position - m_startPosition);
}
}
class GameInfo : public cocos2d::Layer, public GameInfoDelegate
void GameInfo::setMoving(const cocos2d::Vec2 &position)
{
this->setPosition(position);
}
So, how i can fix it?
The answer to your question is complicated. The main reason is that your phone does not have the same processing power as your computer, and Cocos2d-x uses some clever optimizations to try and hide that. With moving sprites, it has to redraw them every frame (usually 30-60 fps), and slight inconsistencies can lead to this effect.
To remedy this, I would double check that your fps is 60, because 30 fps will lead to trembling. Also, if you're updating the sprite's position in update(float dt), I would try and use the physics engine instead, with velocities. If that isn't an option, maybe try to have less layers, because the more sprites you draw ontop of one another, the more it will look like it is jittering. Let me know if any of these solutions work.
The issue may be related to how you are moving the camera. Setting new X,Y coordinates through your update method without factoring in the delta time on each update call will result in jerky movement on screen.
You need to smooth out the movement from one location to another.
Try this:
update(float dt)
{
...
m_cameraFollow->update(dt);
...
}
void CameraFollow::update(float dt)
{
float moveX;
float moveY;
float speed = 1.0f;
...
Vec2 cameraPosition = m_camera->getPosition();
Vec2 targetPosition = Vec2(moveX, moveY);
Vec2 newPosition = cameraPosition.lerp(targetPosition, dt * speed);
m_camera->move(newPosition);
}
I am working through Greg Borenstein's book "Making Things See" and have figured out how to create a cursor that tracks the movement of the closest thing to the Kinect. Right now the cursor is a simple red ball. So I am able to track my finger over
image(kinect.getVideoImage(), 0, 0)
I have also created buttons that apply a filter to the video image when I put the cursor ball in the area of the button.
Its kind of fun but the novelty has run out so now I want to turn the cursor ball into an animated graphic using particles or something fun like that. This animated graphic should still track my finger and be drawn over the video image.
When I try to write this, the graphic comes out wrong because the video image keeps redrawing over the particles so it doesn't look right.
I was thinking I could use the capture() method to draw the video image under the graphics but I can't figure out how to do it with video from the Kinect.
Does anyone have any ideas on how I could do this? Any help would be greatly appreciated.
A sample of my kinect tracker and filter button is below. If you copy and paste it into processing and have a kinect plugged in it should run. my apologies for the code's lack of eloquence. I'm still learning how to make beautiful code.
Instead of filters, I would like to trigger a new graphic for the red ball maybe apply particles or something.
//my kinect tracker
import org.openkinect.freenect.*;
import org.openkinect.processing.*;
Kinect kinect;
boolean ir = true;
boolean colorDepth = true;
boolean mirror = true;
float closestValue;
float closestX;
float closestY;
// create arrays to store recent closest x- and y-coordinates for averaging
int[] recentXValues = new int[3];
int[] recentYValues = new int[3];
// keep track of which is the current value in the array to be changed
int currentIndex = 0;
float circleButtonX, circleButtonY; // position of circle button
float circleButtonSize; // diameter of circle button
color circleButtonColor; // color of circle button
void setup() {
size(640, 480, P3D);
kinect = new Kinect(this);
kinect.initDepth();
kinect.initVideo();
//kinect.enableIR(ir);
kinect.enableMirror(mirror);
kinect.enableColorDepth(colorDepth);
circleButtonColor = color(0, 0, 255);
}
void draw() {
closestValue = 1700;
int[] depthValues = kinect.getRawDepth();
for(int y = 0; y < 480; y++) {
for(int x = 0; x < 640; x++) {
int i = x + y * 640;
int currentDepthValue = depthValues[i];
if(currentDepthValue > 0 && currentDepthValue < closestValue) {
//save its value
closestValue = currentDepthValue;
recentXValues[currentIndex] = x;
recentYValues[currentIndex] = y;
}
}
}
currentIndex++;
if(currentIndex > 2) {
currentIndex = 0;
}
// closetX and ClosestY become a running average
// with currentX and CurrentY
closestX = (recentXValues[0] + recentXValues[1] + recentXValues[2]) / 3;
closestY = (recentYValues[0] + recentYValues[1] + recentYValues[2]) / 3;
//draw the depth image on the screen
image(kinect.getVideoImage(), 0, 0);
fill(0, 0, 250);
ellipse(75, 75, 100, 100);
ellipse(200, 75, 100, 100);
ellipse(75, 200, 100, 100);
rect(540, 25, 75, 100);
//buttons
fill(255,0,0);
textSize(24);
text("Invert", 40, 85);
text("Blur", 50, 210);
textSize(18);
text("Threshold", 155, 85);
text("Stop", 560, 75);
ellipse(closestX, closestY, 25, 25);
if (closestX > 25 && closestX < 125 && closestY > 25 && closestY < 125) {
filter(INVERT);
};
if (closestX > 150 && closestX < 250 && closestY > 25 && closestY < 125) {
filter(THRESHOLD);
};
if (closestX > 25 && closestX < 125 && closestY > 150 && closestY < 250) {
filter(BLUR, 6);
};
if (closestX > 540 && closestX < 615 && closestY > 25 && closestY < 100) {
noLoop();
loop();
background(0);
};
I believe you're asking how to create a particle trail in Processing. This doesn't really have anything to do with kinect- a simple call to background() would also draw over any of your particles. So you currently have something like this:
void setup(){
size(500, 500);
}
void draw(){
background(0);
ellipse(mouseX, mouseY, 10, 10);
}
You're drawing something to the screen (in your code, a red ball, in my code, an ellipse), but it's cleared away (in your code, the kinect video, in my code, a call to background(0)). You're asking how to make it so the ellipse stays on the screen even after you draw the background.
The answer is this: You need to store the positions of your trail in a data structure and then redraw them every frame.
A simple way to do that is to create an ArrayList of PVector instances. To add a particle to the trail, you just add a PVector to the ArrayList. And then you just iterate over the trail and draw every PVector point.
ArrayList<PVector> trail = new ArrayList<PVector>();
void setup(){
size(500, 500);
}
void draw(){
background(0);
//add to the trail
trail.add(new PVector(mouseX, mouseY));
//draw the trail
for(PVector p : trail){
ellipse(p.x, p.y, 10, 10);
}
}
However, this trail will constantly grow, and you'll eventually run out of memory to hold every point. So to keep your trail from doing that, you need to limit its size:
ArrayList<PVector> trail = new ArrayList<PVector>();
void setup(){
size(500, 500);
}
void draw(){
background(0);
//add to the trail
trail.add(new PVector(mouseX, mouseY));
if(trail.size() > 10){
//trail is too long, remove the oldest point
trail.remove(0);
}
//draw the trail
for(PVector p : trail){
ellipse(p.x, p.y, 10, 10);
}
}
From here you can do fancier things: give each point in your trail a momentum or a color, or fade it out, or decrease its width. But the basics are this: you have to store the particles in a data structure, update that data structure to add or remove particles, and then iterate over that data structure to draw the trail.
I am making a small game in C++11 with Qt. However, I am having some issues with scaling.
The background of my map is an image. Each pixel of that image represents a tile, on which a protagonist can walk and enemies/healthpacks can be.
To set the size of a tile, I calculat the maximum amount like so (where imageRows & imageCols is amount of pixels on x- and y-axis of the background image):
QRect rec = QApplication::desktop()->screenGeometry();
int maxRows = rec.height() / imageRows;
int maxCols = rec.width() / imageCols;
if(maxRows < maxCols){
pixSize = maxRows;
} else{
pixSize = maxCols;
}
Now that I have the size of a tile, I add the background-image to the scene (in GameScene ctor, extends from QGraphicsScene):
auto background = new QGraphicsPixmapItem();
background->setPixmap(QPixmap(":/images/map.png").scaledToWidth(imageCols * pixSize));
this->addItem(background);
Then for adding enemies (they extend from a QGraphicsPixMapItem):
Enemy *enemy = new Enemy();
enemy->setPixmap(QPixmap(":/images/enemy.png").scaledToWidth(pixSize));
scene->addItem(enemy);
This all works fine, except that on large maps images get scaled once (to a height of lets say 2 pixels), and when zooming in on that item it does not get more clear, but stays a big pixel. Here is an example: the left one is on a small map where pixSize is pretty big, the second one has a pixSize of pretty small.
So how should I solve this? In general having a pixSize based on the screen resolution is not really useful, since the QGrapicsScene is resized to fit the QGraphicsView it is in, so in the end the view still determines how big the pixels show on the screen.
MyGraphicsView w;
w.setScene(gameScene);
w.fitInView(gameScene->sceneRect(), Qt::KeepAspectRatio);
I think you might want to look at the chip example from Qt (link to Qt5 but also works for Qt4).
The thing that might help you is in the chip.cpp file:
in the paint method:
const qreal lod = option->levelOfDetailFromTransform(painter->worldTransform());
where painter is simply a QPainter and option is of type QStyleOptionGraphicsItem. This quantity gives you back a measure of the current zoom level of your QGraphicsView and thus as in the example you can adjust what is being drawn at which level, e.g.
if (lod < 0.2) {
if (lod < 0.125) {
painter->fillRect(QRectF(0, 0, 110, 70), fillColor);
return;
}
QBrush b = painter->brush();
painter->setBrush(fillColor);
painter->drawRect(13, 13, 97, 57);
painter->setBrush(b);
return;
}
[...]
if (lod >= 2) {
QFont font("Times", 10);
font.setStyleStrategy(QFont::ForceOutline);
painter->setFont(font);
painter->save();
painter->scale(0.1, 0.1);
painter->drawText(170, 180, QString("Model: VSC-2000 (Very Small Chip) at %1x%2").arg(x).arg(y));
painter->drawText(170, 200, QString("Serial number: DLWR-WEER-123L-ZZ33-SDSJ"));
painter->drawText(170, 220, QString("Manufacturer: Chip Manufacturer"));
painter->restore();
}
Does this help?