Hallo,
die Frage ist vielleicht eher was für ein C++-Programmierforum, aber vielleicht kann ja jemand hier auch was damit anfangen. Also: Hier hat jemand sehr eindrucksvoll gezeigt, wie man sehr kurz (das klassische Pseudo-3D-Spiel) "Outrun" bauen kann. Benutzt wird SFML (sowas ähnliches wie SDL); es sollte die neueste Version sein.
In der Videobeschreibung ist auch der Code mit den Grafiken ("images/1.png", usw.). Ich hab' den Code noch etwas aufgeräumt, hier:
Ich kann das mit folgender Zeile kompilieren (wobei SFML sich in "/usr/local/lib" und "/usr/local/include/" befindet):
Ich möchte das gern nach Python übersetzen. Es gibt Python-Bindings "PySFML"; und es geht auch schon alles bis auf die Palmen (und die anderen Sprites). Auf die es mir aber gerade ankam.
Es werden im Code 1600 "Lines"-Objekte erzeugt. Weiterhin gibt es ein Array mit 7 Sprites, für jedes Bild ein Sprite. Bestimmten "Lines" werden die Sprites aus dem Array (wiederholt) zugewiesen.
Dann geht eine Schleife über einen Teil der "Lines" und ruft jeweils die Methode "drawSprite()" auf. Im Ergebnis werden so die Sprites auf dem Bildschirm dargestellt.
Mein Problem ist jetzt: Nur einem Teil der "Lines" werden Sprites zugewiesen. In den anderen heißt es nur:
Die Klasse hat also ein Attribut "sprite" vom Typ "Sprite". Das aber nicht näher defniert wird. Mit den Python-Bindings geht das nicht. Wenn man dort "Sprite" instantiiert, wird verlangt, daß man die zugehörige "Texture" mitliefert (gut, was man noch umgehen könnte, wenn man eine "Default-Texture" verwenden würde - aber das Zeichnen an der richtigen Stelle klappt trotzdem nicht).
Weiterhin heißt es in der Methode "drawSprite()":
Was soll das? Es wird also ein Objekt "s" vom Typ "Sprite" erzeugt, dem "sprite" zugewiesen wird. Wozu?
Das Merkwürdige ist: Das Zeichnen der Palmen, usw. funktioniert in der C++-Version ohne diese Zeile nicht, wenn man also das ursprüngliche "sprite" statt "s" verwendet. Das verstehe ich nicht. Versteht das jemand? Würde mich freuen.
die Frage ist vielleicht eher was für ein C++-Programmierforum, aber vielleicht kann ja jemand hier auch was damit anfangen. Also: Hier hat jemand sehr eindrucksvoll gezeigt, wie man sehr kurz (das klassische Pseudo-3D-Spiel) "Outrun" bauen kann. Benutzt wird SFML (sowas ähnliches wie SDL); es sollte die neueste Version sein.
In der Videobeschreibung ist auch der Code mit den Grafiken ("images/1.png", usw.). Ich hab' den Code noch etwas aufgeräumt, hier:
Code:
#include <SFML/Graphics.hpp>
using namespace sf;
int WIDTH = 1024;
int HEIGHT = 768;
int ROADW = 2000;
int SEGL = 200; //segment length
float CAMD = 0.84; //camera depth
void drawQuad(RenderWindow &w, Color c, int x1,int y1,int w1,int x2,int y2,int w2) {
ConvexShape shape(4);
shape.setFillColor(c);
shape.setPoint(0, Vector2f(x1 - w1, y1));
shape.setPoint(1, Vector2f(x2 - w2, y2));
shape.setPoint(2, Vector2f(x2 + w2, y2));
shape.setPoint(3, Vector2f(x1 + w1, y1));
w.draw(shape);
}
struct Line {
float x,y,z; //3d center of line
float X,Y,W; //screen coord
float curve, spriteX, clip, scale;
Sprite sprite;
Line()
{spriteX=curve=x=y=z=0;}
void project(int camX, int camY, int camZ) {
scale = CAMD / (z-camZ);
X = (1 + scale * (x - camX)) * WIDTH / 2;
Y = (1 - scale * (y - camY)) * HEIGHT / 2;
W = scale * ROADW * WIDTH / 2;
}
void drawSprite(RenderWindow &app) {
Sprite s = sprite;
int w = s.getTextureRect().width;
int h = s.getTextureRect().height;
float destX = X + scale * spriteX * WIDTH / 2;
float destY = Y + 4;
float destW = w * W / 266;
float destH = h * W / 266;
destX += destW * spriteX; //offsetX
destY -= destH; //offsetY
float clipH = destY + destH - clip;
if (clipH < 0) {
clipH = 0;
}
if (clipH >= destH) {
return;
}
s.setTextureRect(IntRect(0, 0, w, h - h * clipH / destH));
s.setScale(destW / w, destH / h);
s.setPosition(destX, destY);
app.draw(s);
/*
printf("w: %d\n", w);
printf("h: %d\n", h);
printf("destX: %f\n", destX);
printf("destY: %f\n", destY);
printf("destW: %f\n", destW);
printf("destH: %f\n", destH);
printf("spriteX: %f\n", spriteX);
printf("\n");
*/
}
};
int main() {
RenderWindow app(VideoMode(WIDTH, HEIGHT), "Outrun Racing!");
app.setFramerateLimit(60);
Texture t[50];
Sprite object[50];
for(int i=1;i<=7;i++) {
t[i].loadFromFile("images/"+std::to_string(i)+".png");
t[i].setSmooth(true);
object[i].setTexture(t[i]);
}
Texture bg;
bg.loadFromFile("images/bg.png");
bg.setRepeated(true);
Sprite sBackground(bg);
sBackground.setTextureRect(IntRect(0,0,5000,411));
sBackground.setPosition(-2000,0);
std::vector<Line> lines;
for (int i=0; i < 1600; i++) {
Line line;
line.z = i * SEGL;
if (i > 300 && i < 700) {
line.curve = 0.5;
}
if (i > 1100) {
line.curve = -0.7;
}
if (i > 750) {
line.y = sin(i / 30.0) * 1500;
}
if (i < 300 && i % 20 == 0) {
line.spriteX = -2.5;
line.sprite = object[5];
}
if (i % 17 == 0) {
line.spriteX = 2.0;
line.sprite = object[6];
}
if (i > 300 && i % 20 == 0) {
line.spriteX = -0.7;
line.sprite = object[4];
}
if (i > 800 && i % 20 == 0) {
line.spriteX = -1.2;
line.sprite = object[1];
}
if (i == 400) {
line.spriteX = -1.2;
line.sprite = object[7];
}
lines.push_back(line);
}
int N = lines.size();
float playerX = 0;
int pos = 0;
int H = 1500;
while (app.isOpen()) {
Event e;
while (app.pollEvent(e)) {
if (e.type == Event::Closed) {
app.close();
}
}
int speed=0;
if (Keyboard::isKeyPressed(Keyboard::Right)) playerX += 0.1;
if (Keyboard::isKeyPressed(Keyboard::Left)) playerX -= 0.1;
if (Keyboard::isKeyPressed(Keyboard::Up)) speed = 200;
if (Keyboard::isKeyPressed(Keyboard::Down)) speed = -200;
if (Keyboard::isKeyPressed(Keyboard::Tab)) speed *= 3;
if (Keyboard::isKeyPressed(Keyboard::W)) H += 100;
if (Keyboard::isKeyPressed(Keyboard::S)) H -= 100;
pos += speed;
while (pos >= N * SEGL) {
pos -= N * SEGL;
}
while (pos < 0) {
pos += N * SEGL;
}
app.clear(Color(105,205,4));
app.draw(sBackground);
int startPos = pos / SEGL;
int camH = lines[startPos].y + H;
if (speed > 0) {
sBackground.move(-lines[startPos].curve * 2, 0);
}
if (speed < 0) {
sBackground.move(lines[startPos].curve * 2, 0);
}
int maxy = HEIGHT;
float x = 0;
float dx = 0;
///////draw road////////
for(int i = startPos; i < startPos + 300; i++) {
Line &l = lines[i % N];
if (i >= N) {
l.project(playerX * ROADW - x, camH, (startPos - N) * SEGL);
} else {
l.project(playerX * ROADW - x, camH, startPos * SEGL);
}
x += dx;
dx += l.curve;
l.clip = maxy;
if (l.Y >= maxy) {
continue;
}
maxy = l.Y;
Color grass = (i/3) % 2 ? Color(16,200,16) : Color(0,154,0);
Color rumble = (i/3) % 2 ? Color(255,255,255) : Color(0,0,0);
Color road = (i/3) % 2 ? Color(107,107,107) : Color(105,105,105);
Line p = lines[(i-1) % N]; //previous line
drawQuad(app, grass, 0, p.Y, WIDTH, 0, l.Y, WIDTH);
drawQuad(app, rumble, p.X, p.Y, p.W * 1.2, l.X, l.Y, l.W * 1.2);
drawQuad(app, road, p.X, p.Y, p.W, l.X, l.Y, l.W);
}
////////draw objects////////
for (int i = startPos + 300; i > startPos; i--) {
lines[i % N].drawSprite(app);
}
app.display();
}
return 0;
}
Code:
g++ main.cpp -o outrun -std=c++11 -I/usr/local/include/SFML -L/usr/local/lib -lsfml-audio -lsfml-graphics -lsfml-window -lsfml-system
Es werden im Code 1600 "Lines"-Objekte erzeugt. Weiterhin gibt es ein Array mit 7 Sprites, für jedes Bild ein Sprite. Bestimmten "Lines" werden die Sprites aus dem Array (wiederholt) zugewiesen.
Dann geht eine Schleife über einen Teil der "Lines" und ruft jeweils die Methode "drawSprite()" auf. Im Ergebnis werden so die Sprites auf dem Bildschirm dargestellt.
Mein Problem ist jetzt: Nur einem Teil der "Lines" werden Sprites zugewiesen. In den anderen heißt es nur:
Code:
Sprite sprite;
Weiterhin heißt es in der Methode "drawSprite()":
Code:
Sprite s = sprite;
Das Merkwürdige ist: Das Zeichnen der Palmen, usw. funktioniert in der C++-Version ohne diese Zeile nicht, wenn man also das ursprüngliche "sprite" statt "s" verwendet. Das verstehe ich nicht. Versteht das jemand? Würde mich freuen.