2c145dafb5998cb1df47250a5f0c23d4f7e4632d
[supertux.git] / src / camera.cpp
1 //  $Id$
2 //
3 //  SuperTux -  A Jump'n Run
4 //  Copyright (C) 2004 Matthias Braun <matze@braunis.de
5 //
6 //  This program is free software; you can redistribute it and/or
7 //  modify it under the terms of the GNU General Public License
8 //  as published by the Free Software Foundation; either version 2
9 //  of the License, or (at your option) any later version.
10 //
11 //  This program is distributed in the hope that it will be useful,
12 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
13 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 //  GNU General Public License for more details.
15 //
16 //  You should have received a copy of the GNU General Public License
17 //  along with this program; if not, write to the Free Software
18 //  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
19 #include "camera.h"
20
21 #include <math.h>
22 #include "lispwriter.h"
23 #include "player.h"
24 #include "level.h"
25 #include "globals.h"
26
27 Camera::Camera(Player* newplayer, Level* newlevel)
28   : player(newplayer), level(newlevel), scrollchange(NONE)
29 {
30   if(!player || !level)
31     mode = MANUAL;
32   else
33     mode = NORMAL;
34 }
35
36 Camera::~Camera()
37 {
38 }
39
40 void
41 Camera::set_translation(const Vector& newtranslation)
42 {
43   translation = newtranslation;
44 }
45
46 void
47 Camera::write(LispWriter& writer)
48 {
49   writer.start_list("camera");
50   
51   if(mode == NORMAL) {
52     writer.write_string("mode", "normal");
53   } else if(mode == AUTOSCROLL) {
54     writer.write_string("mode", "autoscroll");
55   } else if(mode == MANUAL) {
56     writer.write_string("mode", "manual");
57   }
58                      
59   writer.end_list("camera");
60 }
61
62 static const float EPSILON = .00001;
63 static const float max_speed_y = 1.4;
64
65 void
66 Camera::action(float elapsed_time)
67 {
68   if(mode == NORMAL)
69     scroll_normal(elapsed_time);
70   else if(mode == AUTOSCROLL)
71     scroll_autoscroll(elapsed_time);
72 }
73
74 void
75 Camera::scroll_normal(float elapsed_time)
76 {
77   assert(level != 0 && player != 0);
78   
79   // check that we don't have division by zero later
80   if(elapsed_time < EPSILON)
81     return;
82
83   bool do_y_scrolling = true;
84
85   if(player->dying || level->height == 19)
86     do_y_scrolling = false;
87
88   if(do_y_scrolling) {
89     float target_y;
90     if(player->fall_mode == Player::JUMPING)
91       target_y = player->last_ground_y + player->base.height;
92     else
93       target_y = player->base.y + player->base.height;
94
95     float delta_y = translation.y - (target_y - screen->h/2);
96     float speed_y = delta_y / elapsed_time;
97
98     if(player->fall_mode != Player::FALLING 
99         && player->fall_mode != Player::TRAMPOLINE_JUMP) {
100       if(speed_y > max_speed_y)
101         speed_y = max_speed_y;
102       else if(speed_y < -max_speed_y)
103         speed_y = -max_speed_y;
104     }
105
106     translation.y -= speed_y * elapsed_time;
107
108     // don't scroll before the start or after the level's end
109     if(translation.y > level->height * 32 - screen->h)
110       translation.y = level->height * 32 - screen->h;
111     if(translation.y < 0)
112       translation.y = 0; 
113   }
114
115   if((player->dir == ::LEFT && scrollchange == RIGHT)
116       || (player->dir == ::RIGHT && scrollchange == LEFT))
117     scrollchange = NONE;
118   if(player->base.x < translation.x + screen->w/3 && level->back_scrolling)
119     scrollchange = LEFT;
120   else if(player->base.x > translation.x + screen->w/3*2)
121     scrollchange = RIGHT;
122
123   float target_x;
124   if(scrollchange == LEFT)
125     target_x = player->base.x - screen->w/3*2;
126   else if(scrollchange == RIGHT)
127     target_x = player->base.x - screen->w/3;
128   else
129     target_x = translation.x;
130
131   float delta_x = translation.x - target_x;
132   float speed_x = delta_x / elapsed_time;
133
134   float maxv = 1 + fabsf(player->physic.get_velocity_x() * 1.3);
135   if(speed_x > maxv)
136     speed_x = maxv;
137   else if(speed_x < -maxv)
138     speed_x = -maxv;
139   
140   translation.x -= speed_x * elapsed_time;
141
142   // don't scroll before the start or after the level's end
143   if(translation.x > level->width * 32 - screen->w)
144     translation.x = level->width * 32 - screen->w;
145   if(translation.x < 0)
146     translation.x = 0;   
147 }
148
149 void
150 Camera::scroll_autoscroll(float elapsed_time)
151 {
152   // TODO
153 }