Allegro.cc - Online Community

Allegro.cc Forums » Game Design & Concepts » Virtual Screen for starters...

This thread is locked; no one can reply to it. rss feed Print
Virtual Screen for starters...
Hans Spirit
Member #8,650
May 2007
avatar

Hi,

I need some help with virtual screen. I started using allegro for a month now and hadn't had any problems with it until I tried to use virtual screen.
in:
set_gfx_mode(GFX_AUTODETECT, MAX_X, MAX_Y, V_MAX_X, V_MAX_Y)

I tried to use MAX_X = 800
MAX_Y = 600
V_MAX_X = 960
V_MAX_Y = 960

Then I just couldn't start my program >:(, it crashes because the gfx_mode can't be started. My objective was to use a screen divided into 48x48 tiles, but 800x600 does not fit it and is also small for my purpose. Is there a way to use virtual screen like this ????, or is there another way do to it ;)?

Thanks anyway :)
And excuse me for any mistakes in the message, for my poor brazilian english still needs to be trained a lot more. ;D

My Project:
Shining Legends:
http://members.allegro.cc/HansSpirit

Thomas Fjellstrom
Member #476
June 2000
avatar

Yeah, the Virtual screen is a hold over from the DOS days. Its basically only supported in DOS and possibly linux console, where it creates a "Screen" thats larger than the mode, and allows you to scroll.

--
Thomas Fjellstrom - [website] - [email] - [Allegro Wiki] - [Allegro TODO]
"If you can't think of a better solution, don't try to make a better solution." -- weapon_S
"The less evidence we have for what we believe is certain, the more violently we defend beliefs against those who don't agree" -- https://twitter.com/neiltyson/status/592870205409353730

Elverion
Member #6,239
September 2005
avatar

The virtual screen, as Thomas Fjellstrom said, really isn't used anymore. There really is no need for it anymore. You can just keep track of world coordinates for your game objects, then draw everything by translating by those coordinates. I make use of a 2d camera class for this, since it makes things a bit easier. If you would like, I can give you the source for the camera class I've made.

--
SolarStrike Software - MicroMacro home - Automation software.

Hans Spirit
Member #8,650
May 2007
avatar

If you please :).
Are you guys seeing my Avatar? Just to know if it's working, 'cause i had some trouble making it work.

My Project:
Shining Legends:
http://members.allegro.cc/HansSpirit

HardTranceFan
Member #7,317
June 2006
avatar

We can see your avatar, if it's a single image (i.e. not an animated gif)

--
"Shame your mind don't shine like your possessions do" - Faithless (I want more part 1)

Elverion
Member #6,239
September 2005
avatar

camera.h

1#ifndef CAMERA_H
2#define CAMERA_H
3 
4 #include <cw/cw.h> // ignore this -> self-made library
5 #include <allegro.h>
6
7 
8 /* How "Smooth" to make the transitions between update calls
9 Higher smoothness means it takes longer to actually focus
10 upon the given point */
11 #define SMOOTH_AMOUNT 20
12 
13 class CCamera;
14 typedef CCamera Camera;
15
16 class CCamera
17 {
18 private:
19 cw::Rect view;
20
21 public:
22 CCamera();
23 void CCamera::set(float, float);
24 void update(float, float);
25 void set_view(const cw::Rect &);
26 cw::Rect get_view();
27 float camx, camy;
28 };
29 
30#endif

camera.cpp

1#include "camera.h"
2 
3CCamera::CCamera()
4{
5 camx = 0;
6 camy = 0;
7 view.x = 0;
8 view.y = 0;
9 view.w = SCREEN_W;
10 view.h = SCREEN_H;
11}
12 
13void CCamera::set_view(const cw::Rect &_v)
14{
15 view = (cw::Rect &)_v;
16}
17 
18cw::Rect CCamera::get_view()
19{
20 return view;
21}
22 
23void CCamera::set(float x, float y)
24{
25 if( x + SCREEN_W > view.x + view.w )
26 x = view.x + view.w - SCREEN_W;
27 if( x < view.x )
28 x = view.x;
29 
30 if( y + SCREEN_H > view.y + view.h )
31 y = view.y + view.h - SCREEN_H;
32 if( y < view.y )
33 y = view.y;
34 
35 camx += (x - camx);
36 camy += (y - camy);
37}
38 
39void CCamera::update(float x, float y)
40{
41 if( x + SCREEN_W > view.x + view.w )
42 x = view.x + view.w - SCREEN_W;
43 if( x < view.x )
44 x = view.x;
45
46 if( y + SCREEN_H > view.y + view.h )
47 y = view.y + view.h - SCREEN_H;
48 if( y < view.y )
49 y = view.y;
50
51 camx += (x - camx) / SMOOTH_AMOUNT;
52 camy += (y - camy) / SMOOTH_AMOUNT;
53}

In case you are wondering about the rects, they are just simple classes with double x,y,w, and h.
rect.h

1 class cwRect;
2 typedef cwRect Rect;
3
4 class cwRect
5 {
6 public:
7 double x,y, w, h;
8 cwRect(double, double, double, double);
9 cwRect(double, double);
10 cwRect();
11
12 bool operator = (cwRect &r2)
13 {
14 x = r2.x;
15 y = r2.y;
16 w = r2.w;
17 h = r2.h;
18 }
19
20 Rect collision(const Rect &);
21 };

So basically, the "view" of the camera is just a rectangle that encompasses the map. Generally, you go from (0,0) to (map_width, map_height) where map's width and height are in pixels. So far it's sounding pretty complicated I assume, but just check the example and you'll better understand.

Example:

1int main()
2{
3 /* all your initialization stuff here */
4 
5 /* Now we create the camera. the map width and height here
6 is in tiles, so we must multiply by the tilesize for
7 the camera's view.
8 Then, we "set" the camera (move it to a position). */
9 Camera cam;
10 cam.set_view( Rect(0, 0, map.get_width()*map.get_tilesize(),
11 map.get_height()*map.get_tilesize()) );
12 cam.set(player.get_x() - SCREEN_W/2, player.get_y() - SCREEN_H/2 - 100);
13 
14 /* other junk here */
15 
16 while( running ) // main loop here
17 {
18 while( logic )
19 { // do your logic here...
20 
21 /* Now we use the "update" as opposed to set...
22 update just means to use smooth transitioning */
23 cam.update(player.get_x() - SCREEN_W/2,
24 player.get_y() - SCREEN_H/2 - 100);
25 }
26 
27 // draw time.
28 /* we need to pass the cam to the player.
29 It will use the cam to correctly position it's
30 sprites on the screen. */
31 player.draw(&cam);
32 }
33 
34 return 0;
35}
36 
37 Player::draw(Camera *)
38 {
39 /* To draw the player's sprite correctly onto the screen,
40 we just need to subtract the player's coordinates by
41 the camera's coordinates. */
42 draw_sprite(screen, my_sprite, x - cam->camx, y - cam->camy);
43 }

There are some things to note. Do not actually try to compile the example. It won't run as-is due to missing code segments (obviously). You do not need to check and make sure your camera is within view. It does that automatically when using update or set.

--
SolarStrike Software - MicroMacro home - Automation software.

Matt Weir
Member #7,476
July 2006
avatar

To take it even further I would make the camera a game object like a player, enemy, magic donut etc.

This way it's trivial to create multiply cameras, cameras that move realistically, cameras with AI etc. The camera can have physics like a game object so as the player moves away from the center the camera will accelerate to catch up, a simple effect that makes things much more interesting.

Hans Spirit
Member #8,650
May 2007
avatar

Wow thanks a lot. I'm sure this will help. Now i just got to study it, and make one of my own to understand the idea. Thanks a lot for the help again.

My Project:
Shining Legends:
http://members.allegro.cc/HansSpirit

clovekx
Member #3,479
April 2003
avatar

It's not a good OO practice to have a public variables in a class. Rather make them private and use get_variablename() method. Sure this takes more time to write, but it is cleaner and easier to maintain.

Dustin Dettmer
Member #3,935
October 2003
avatar

Quote:

Sure this takes more time to write, but it is cleaner and easier to maintain.

I'd say its uglier and harder to maintain. The benifit as I see it is scalability. Later on you may want to set an allowable range for an attribute or something.

Tobias Dammers
Member #2,604
August 2002
avatar

Quote:

It's not a good OO practice to have a public variables in a class.

It depends.
Variables that may be set to any value at any time without causing any problems to the inner workings of the class can be public, there is no harm in that. I admit, though, that this is very rare.
But then, the following is just as pointless:

class cFoo {
  private:
    int a;
  public:
    int get_a() const { return a; }
    void set_a(int _a) { a = _a; }
};

Even Java allows public member variables. Plus over-OO-ing things isn't good either. There was this story on worsethanfailure.com where they had a pacman clone that used a few thousand threads and required a 3 GHz CPU to be playable; all that due to a strict OO design.

---
Me make music: Triofobie
---
"We need Tobias and his awesome trombone, too." - Johan Halmén

Michael Jensen
Member #2,870
October 2002
avatar

Actually, it wasn't the OOP that slowed the game design down, it was the fact that every sprite object allocated, and used it's own thread to keep track of animation, etc -- even the dots...

I agree though, unless you have special needs on a variable (ex: it has a range, or you can't just let the programmer modify it anytime he pleases) make it public. Private should only be for things that you want to protect, or execute logic on when they change, etc...

Thomas Fjellstrom
Member #476
June 2000
avatar

You don't know if you won't need to provide special cases on variables/properties. Thats why its best to start with the access routines. so the API/ABI stays 100% consistent throughout the process. imo.

--
Thomas Fjellstrom - [website] - [email] - [Allegro Wiki] - [Allegro TODO]
"If you can't think of a better solution, don't try to make a better solution." -- weapon_S
"The less evidence we have for what we believe is certain, the more violently we defend beliefs against those who don't agree" -- https://twitter.com/neiltyson/status/592870205409353730

Tobias Dammers
Member #2,604
August 2002
avatar

Quote:

Actually, it wasn't the OOP that slowed the game design down, it was the fact that every sprite object allocated, and used it's own thread to keep track of animation, etc -- even the dots...

Which, one could argue, is a case of encapsulation-to-the-max. Each objects runs in its own "world".

Quote:

You don't know if you won't need to provide special cases on variables/properties. Thats why its best to start with the access routines. so the API/ABI stays 100% consistent throughout the process. imo.

Generally, yes. But for some kinds of classes (I like to call them "data classes"), some parameters can be set freely to anything by design. Examples are implementations of 3d vectors, fractional numbers, ... - using getters / setters on these makes things more clumsy without adding anything. Observe:

class vec3d {
 public:
  float x;
  float y;
  float z;

  vec3d(float _x, float _y, float _z): x(_x), y(_y), z(_z) {}
  vec3d(const vec3d& rhs): x(rhs.x), y(rhs.y), z(rhs.z) {}
  // ...snip...
};

vs.:

1class vec3d {
2 private:
3 float x;
4 float y;
5 float z;
6 public:
7 vec3d(float _x, float _y, float _z): x(_x), y(_y), z(_z) {}
8 vec3d(const vec3d& rhs): x(rhs.get_x()), y(rhs.get_y()), z(rhs.get_z()) {}
9 float get_x() const { return x; }
10 float get_y() const { return y; }
11 float get_z() const { return z; }
12 void set_x(float f) { x = f; }
13 void set_y(float f) { y = f; }
14 void set_z(float f) { z = f; }
15 // ...snip...
16};

And there is not a single value you wouldn't possibly want in a vector.

---
Me make music: Triofobie
---
"We need Tobias and his awesome trombone, too." - Johan Halmén

Thomas Fjellstrom
Member #476
June 2000
avatar

That's quite thread unfriendly.

--
Thomas Fjellstrom - [website] - [email] - [Allegro Wiki] - [Allegro TODO]
"If you can't think of a better solution, don't try to make a better solution." -- weapon_S
"The less evidence we have for what we believe is certain, the more violently we defend beliefs against those who don't agree" -- https://twitter.com/neiltyson/status/592870205409353730

Tobias Dammers
Member #2,604
August 2002
avatar

Haven't done any proper multi-threaded stuff yet, so I wouldn't really know. What exactly is the problem here?

---
Me make music: Triofobie
---
"We need Tobias and his awesome trombone, too." - Johan Halmén

Kitty Cat
Member #2,815
October 2002
avatar

Quote:

And there is not a single value you wouldn't possibly want in a vector.

What about NaN or Inf? Or where vec3d.magnitude() > FLT_MAX?

--
"Do not meddle in the affairs of cats, for they are subtle and will pee on your computer." -- Bruce Graham

Tobias Dammers
Member #2,604
August 2002
avatar

You wouldn't want these in a float either. Something like a vec3d::contains_nan() method would be useful though.
vec3d().magnitude() > FLT_MAX is a problem, but I don't see how I'd catch that in the getters / setters in a trivial way.

---
Me make music: Triofobie
---
"We need Tobias and his awesome trombone, too." - Johan Halmén

Thomas Fjellstrom
Member #476
June 2000
avatar

Quote:

What exactly is the problem here?

Threads accessing and changing the var at the same time can cause problems. If say you're checking for something, between the check and the execution of the code, the var could be changed and no longer actually be within the range that was checked for.

--
Thomas Fjellstrom - [website] - [email] - [Allegro Wiki] - [Allegro TODO]
"If you can't think of a better solution, don't try to make a better solution." -- weapon_S
"The less evidence we have for what we believe is certain, the more violently we defend beliefs against those who don't agree" -- https://twitter.com/neiltyson/status/592870205409353730

Kitty Cat
Member #2,815
October 2002
avatar

Quote:

You wouldn't want these in a float either. Something like a vec3d::contains_nan() method would be useful though.
vec3d().magnitude() > FLT_MAX is a problem, but I don't see how I'd catch that in the getters / setters in a trivial way.

Depending on how it's used:

1private:
2 float v[3];
3 float mag;
4 
5 void update_magnitude()
6 {
7 mag = sqrt(v[0]*v[0] + v[1]*v[1] + v[2]*v[2]);
8 if(mag == NaN || mag > FLT_MAX)
9 throw;
10 }
11 
12public:
13 void set_x(float x)
14 {
15 v[0] = x;
16 update_magnitude();
17 }
18 void set_y(float y)
19 {
20 v[1] = y;
21 update_magnitude();
22 }
23 void set_z(float z)
24 {
25 v[2] = z;
26 update_magnitude();
27 }
28 void set_vec(float x, float y, float z)
29 {
30 v[0] = x;
31 v[1] = y;
32 v[2] = z;
33 update_magnitude();
34 }
35 float magnitude()
36 { return mag; }

If you use a vector's magnitude a lot compared to how often it's changed, it'd be more efficient to calculate it when the vector changes, instead of when you need it. Or optionally you could set a flag when x, y, or z changes and when the magnitude is requested, update it if it's "dirty".

--
"Do not meddle in the affairs of cats, for they are subtle and will pee on your computer." -- Bruce Graham

Tobias Dammers
Member #2,604
August 2002
avatar

Yes, if I needed the magnitude a lot between subsequent changes, then I would probably go for the "dirty" approach, which would of course involve getters/setters.

Quote:

Threads accessing and changing the var at the same time can cause problems. If say you're checking for something, between the check and the execution of the code, the var could be changed and no longer actually be within the range that was checked for.

And how would I avoid that using getters/setters? Can't I just lock / mutex / whatever the entire vector before accessing it?

---
Me make music: Triofobie
---
"We need Tobias and his awesome trombone, too." - Johan Halmén

Go to: