=D Thank you so much for your time Phantomotap - I'm getting there.
Well, I don't have a good fetch from "persistent storage/load to memory - save to persistent storage/unload from memory" algorithm yet. But I read your post and reworked some things in a more "proof of concept" format. (I got rid of my 192 tile terrain sprite sheet and fabricated a simple 4 block sheet for example) Here is what I have so far:
I use only the SFML library, and C++11 settings on GCC so my vector<vector>> syntax is nice. Nothing way out in left field here:
NOTE: I grant permission for the user of this forum to use this code in any way shape or form serving educational purposes.
NOTE: If you compile this, tap 'minus' a few times to zoom out, then use WASD to move around a bit. You'll notice my 'culling' algorithm has a bug that culls properly on the North, east and South sides - but that the western edge culls in large 'chunks' 32 tiles wide. This bug is stalling my progress towards more of your idea's being implemented - but I've been over the math for 2 hours and can't find it.
main.cpp
Code:
#include <SFML/Graphics.hpp>
#include <iostream>
#include <vector>
#include "coord.h"
#include "zone.h"
#include "area.h"
using namespace std;
using namespace sf;
int main()
{
// Create the main window
sf::RenderWindow App(sf::VideoMode(1024, 768), "2D Tile Engine");
// Load a sprite to represent the camera
Image CamImage(32, 32, Color(255, 0, 0, 128));
Sprite Cam(CamImage);
// Build the Terrain Sprites
Image BlackImage(32, 32, Color(0, 0, 0));
Sprite Black(BlackImage);
Image GreenImage(32, 32, Color(0, 255, 0));
Sprite Green(GreenImage);
Image BlueImage(32, 32, Color(0, 0, 255));
Sprite Blue(BlueImage);
Image BrownImage(32, 32, Color(150, 75, 0));
Sprite Brown(BrownImage);
// Build the Terrain Vector
vector<Sprite> Terrain;
Terrain.push_back(Black);
Terrain.push_back(Green);
Terrain.push_back(Blue);
Terrain.push_back(Brown);
// Build Start Area
Area MyArea;
for (int i = -4; i < 4; ++i)
{
for (int j = -4; j < 4; ++j)
{
Zone TempZone;
TempZone.Create(Coord(i, j));
MyArea.Zones.push_back(TempZone);
}
}
// Key Array
vector<bool> KeyArray(512, false);
// The view
Coord CamPos(512, 384);
Vector2f Center(512, 384);
Vector2f HalfSize(512, 384);
View MyView(Center, HalfSize);
App.SetView(MyView);
float Speed(500.0);
// Start the game loop
while (App.IsOpened())
{
// Process events
sf::Event Event;
while (App.GetEvent(Event))
{
// Close window : exit
if (Event.Type == sf::Event::Closed) App.Close();
if (Event.Type == sf::Event::KeyPressed) KeyArray[Event.Key.Code] = true;
if (Event.Type == sf::Event::KeyReleased) KeyArray[Event.Key.Code] = false;
}
float Offset = Speed * App.GetFrameTime();
if (KeyArray[sf::Key::Escape]) App.Close();
if (KeyArray[sf::Key::W]) CamPos.y -= Offset;
if (KeyArray[sf::Key::S]) CamPos.y += Offset;
if (KeyArray[sf::Key::A]) CamPos.x -= Offset;
if (KeyArray[sf::Key::D]) CamPos.x += Offset;
if (KeyArray[sf::Key::Add]) MyView.Zoom(1.101f);
if (KeyArray[sf::Key::Subtract]) MyView.Zoom(0.899f);
// Clear screen
App.Clear();
// DRAW
MyView.SetCenter(CamPos.x, CamPos.y);
Cam.SetPosition(CamPos.x, CamPos.y);
MyArea.Draw(App, CamPos, Terrain);
App.Draw(Cam);
// Update the window
App.Display();
}
return EXIT_SUCCESS;
}
area.h
Code:
#ifndef AREA_H_INCLUDED
#define AREA_H_INCLUDED
//
// Copyright © 2000-2012
// Matthew Tober
//
// Permission to use, copy, modify, distribute and sell this software and its documentation for any
// purpose is hereby granted without fee, provided that the above copyright notice appears in all
// copies and that both that copyright notice and this permission notice appear in supporting
// documentation. Matthew Tober makes no representations about the suitability of this software for
// any purpose. It is provided "as is" without express or implied warranty.
//
#include <SFML/Graphics.hpp>
#include <iostream>
#include "zone.h"
class Area
{
public:
Area() : ID(0), Zones(0) {};
int ID;
std::vector<Zone> Zones;
void Draw(sf::RenderWindow &Screen, Coord Cam, std::vector<sf::Sprite>& Terrain);
};
void Area::Draw(sf::RenderWindow &Screen, Coord Cam, std::vector<sf::Sprite>& Terrain)
{
static float infotimer = 0.0;
static bool info = false;
using namespace std;
infotimer += Screen.GetFrameTime();
if (infotimer > 1.0)
{
info = true;
infotimer = 0.0;
}
sf::Sprite TempSprite;
std::vector<Zone>::iterator iter = Zones.begin();
for (iter = Zones.begin(); iter != Zones.end(); ++iter)
{
// For each Zone:
for (int y = 0; y < TileRowsY; ++y)
{
for (int x = 0; x < TileColsX; ++x)
{
//counter++;
float fx = (iter->ZonePos.x * 1024.0) + (iter->Data[y][x].Pos.x * 32.0);
float fy = (iter->ZonePos.y * 768.0) + (iter->Data[y][x].Pos.y * 32.0);
if (info)
{
cout << "Fx,y: " << fx << ", " << fy;
cout << "Cam : " << Cam.x << ", " << Cam.y;
cout << " FPS: " << (1.0f / Screen.GetFrameTime()) << endl;
info = false;
}
if ( false
|| fx < (Cam.x - 512)
|| fx > (Cam.x + 480)
|| fy < (Cam.y - 384)
|| fy > (Cam.y + 352)
) break;
int id = iter->Data[y][x].ID;
TempSprite = Terrain[id];
TempSprite.SetPosition(fx, fy);
Screen.Draw(TempSprite);
}
}
}
}
#endif // AREA_H_INCLUDED
zone.h
Code:
//
// Copyright © 2000-2012
// Matthew Tober
//
// Permission to use, copy, modify, distribute and sell this software and its documentation for any
// purpose is hereby granted without fee, provided that the above copyright notice appears in all
// copies and that both that copyright notice and this permission notice appear in supporting
// documentation. Matthew Tober makes no representations about the suitability of this software for
// any purpose. It is provided "as is" without express or implied warranty.
//
#ifndef ZONE_H
#define ZONE_H
#include <vector>
#include "tile.h"
#include <iostream> // debug purposes
#include <cstdlib> // random
const int TileColsX = 1024/32;
const int TileRowsY = 768/32;
typedef std::vector<Tile> Row;
class Zone
{
public:
// Ctor
Zone() : ZonePos(0,0), Data(0) {};
// Data
Coord ZonePos;
std::vector<Row> Data;
// Functions
void Create(Coord Origin);
};
void Zone::Create(Coord Origin)
{
int counter = 0;
ZonePos = Origin;
Data.clear();
std::vector<Tile> NewRow;
for (int y = 0; y < TileRowsY; ++y)
{
NewRow.clear();
for (int x = 0; x < TileColsX; ++x)
{
Tile NewTile;
NewTile.ID = (rand()%3)+1;
NewTile.Type = 0;
NewTile.Pos.x = x;
NewTile.Pos.y = y;
//std::cout << x << "/" << y << std::endl;
NewRow.push_back(NewTile);
++counter;
}
Data.push_back(NewRow);
}
}
#endif // ZONE_H
tile.h
Code:
#ifndef TILE_H_INCLUDED
#define TILE_H_INCLUDED
//
// Copyright © 2000-2012
// Matthew Tober
//
// Permission to use, copy, modify, distribute and sell this software and its documentation for any
// purpose is hereby granted without fee, provided that the above copyright notice appears in all
// copies and that both that copyright notice and this permission notice appear in supporting
// documentation. Matthew Tober makes no representations about the suitability of this software for
// any purpose. It is provided "as is" without express or implied warranty.
//
#include "coord.h"
class Tile
{
public:
Tile() : ID(0), Type(0), Pos(0, 0) {}
int ID;
int Type;
Coord Pos;
};
#endif // TILE_H_INCLUDED
coord.h
Code:
#ifndef COORD_H_INCLUDED
#define COORD_H_INCLUDED
//
// Copyright © 2000-2012 Matthew Tober
//
// Permission to use, copy, modify, distribute and sell this software and its
// documentation for any purpose is hereby granted without fee, provided that
// the above copyright notice appears in all copies and that both that copyright
// notice and this permission notice appear in supporting documentation.
// Matthew Tober makes no representations about the suitability of this software
// for any purpose. It is provided "as is" without express or implied warranty.
//
class Coord
{
public:
Coord() : x(0.0), y(0.0) {}
Coord(float _x, float _y) : x(_x), y(_y) {}
float x, y;
friend bool operator==(Coord &lhs, Coord &rhs);
friend bool operator!=(Coord &lhs, Coord &rhs);
friend bool operator< (Coord &lhs, Coord &rhs);
friend bool operator> (Coord &lhs, Coord &rhs);
friend bool operator<=(Coord &lhs, Coord &rhs);
friend bool operator>=(Coord &lhs, Coord &rhs);
};
bool operator== (Coord &lhs, Coord &rhs)
{
return (lhs.x == rhs.x && lhs.y == rhs.y);
};
bool operator!= (Coord &lhs, Coord &rhs)
{
return (lhs.x != rhs.x || lhs.y != rhs.y);
};
bool operator< (Coord &lhs, Coord &rhs)
{
if (lhs.x < rhs.x) return true;
if ((lhs.x == rhs.x) && (lhs.y < rhs.y)) return true;
return false;
};
bool operator> (Coord &lhs, Coord &rhs)
{
if (lhs.x > rhs.x) return true;
if ((lhs.x == rhs.x) && (lhs.y > rhs.y)) return true;
return false;
};
bool operator<= (Coord &lhs, Coord &rhs)
{
if (lhs.x < rhs.x) return true;
if ((lhs.x == rhs.x) && (lhs.y < rhs.y)) return true;
if (lhs.x == rhs.x && lhs.y == rhs.y) return true;
return false;
};
bool operator>= (Coord &lhs, Coord &rhs)
{
if (lhs.x > rhs.x) return true;
if ((lhs.x == rhs.x) && (lhs.y > rhs.y)) return true;
if (lhs.x == rhs.x && lhs.y == rhs.y) return true;
return false;
};
#endif // COORD_H_INCLUDED