1 module player;
2 
3 import std.math;
4 import std.datetime;
5 import std.datetime.stopwatch : StopWatch;
6 
7 import helpers : asSeconds;
8 import resourcemanager;
9 import dsfml.graphics;
10 import collidable;
11 import collider;
12 
13 static this() {
14   assert(resource_manager.register!Texture("assets/dino_crouch1.png", "crouch1", make_collider));
15   assert(resource_manager.register!Texture("assets/dino_crouch2.png", "crouch2", make_collider));
16   assert(resource_manager.register!Texture("assets/dino_jump.png", "jump", make_collider));
17   assert(resource_manager.register!Texture("assets/dino1.png", "step1", make_collider));
18   assert(resource_manager.register!Texture("assets/dino2.png", "step2", make_collider));
19   assert(resource_manager.register!Texture("assets/dead.png", "dead", make_collider));
20 }
21 
22 /// Class representing the dinosaur
23 class Player : Drawable, Collidable {
24   private StopWatch delta_time_clock;
25   private StopWatch leg_swap_clock;
26   private float total_displacement = 0;
27   private float delta_seconds = 0;
28   private bool crouch;
29   private bool leg;
30 
31   /// Dead Player has a different texture
32   bool dead;
33 
34   /// Distance from the left side of the window at which a player stays
35   static immutable float horizontal_offset = 60;
36 
37   /// Size of the standing player
38   static immutable Vector2f size_normal = Vector2f(40, 43);
39   /// Size of the crouching player
40   static immutable Vector2f size_crouching = Vector2f(55, 26);
41 
42   /// Initial vertical speed immediately after jumping
43   static immutable float initial_jump_speed = 750;
44   /// Gravitational acceleration
45   static immutable float gravity_acc = 3000;
46 
47   /// Height of the window in which player resides
48   float window_height;
49 
50   /// Actual downards acceleration
51   float gravity() const { return gravity_acc * (Keyboard.isKeyPressed(Keyboard.Key.Down) ? 3 : 1); }
52 
53   /// Distance that the player has covered in the LAST FRAME
54   float displacement() const { return dead ? 0 : delta_seconds * speed; }
55 
56   /// Returns the total displacement
57   float displacement_tot() const { return total_displacement; }
58 
59   /// Speed at which the player moves to the right
60   float speed = 450;
61   /// Distance from the ground
62   float height = 0;
63   /// Vertical velocity, positive means up
64   float vert_velocity = 0;
65 
66   private string texture_name() const {
67     if(dead) {
68       return "dead";
69     }
70     if(height > 0) {
71       return "jump";
72     }
73     if(crouch) {
74       return leg ? "crouch1" : "crouch2";
75     }
76 
77     return leg ? "step1" : "step2";
78   }
79 
80   /// Default constructor
81   this() {
82     delta_time_clock.start();
83     leg_swap_clock.start();
84   }
85 
86   /// Effective size
87   Vector2f size() const {
88     return (crouch && !dead) ? size_crouching : size_normal;
89   }
90 
91   /// Current texture
92   const(Texture) texture() const {
93     return resource_manager.get!Texture(texture_name);
94   }
95 
96   /// Position of the player
97   Vector2f position() const {
98     return Vector2f(horizontal_offset, window_height - size.y - height);
99   }
100 
101   /// Attempts to jump
102   bool jump() {
103     if(height == 0) {
104       vert_velocity = initial_jump_speed;
105       crouch = false;
106       return true;
107     }
108     return false;
109   }
110 
111   /// Applies gravitational acceleration, moves the player etc.
112   void update() {
113     crouch = Keyboard.isKeyPressed(Keyboard.Key.Down) && height == 0;
114 
115     delta_seconds = delta_time_clock.peek.asSeconds;
116     delta_time_clock.reset();
117 
118     if(!dead) {
119       vert_velocity -= delta_seconds * gravity;
120       height += delta_seconds * vert_velocity;
121       speed += delta_seconds / 100 * (1500 - speed);
122 
123       if(height < 0) {
124         height = 0;
125         vert_velocity = 0;
126       }
127       if(leg_swap_clock.peek.asSeconds * sqrt(speed / 450) > 0.1f) {
128         leg = !leg;
129         leg_swap_clock.reset();
130       }
131     }
132 
133     total_displacement += displacement;
134   }
135 
136   /* Override methods from Drawable and Collidable */
137   override void draw(RenderTarget target, RenderStates states) const {
138     auto rt = new RectangleShape;
139     rt.position(position);
140     rt.size(size);
141     rt.fillColor(Color.White);
142     rt.setTexture(texture);
143 
144     target.draw(rt, states);
145 
146 		target.draw(collider);
147   }
148 
149   override Collider collider() const {
150 		return resource_manager.get!Collider(texture_name).translate(position);
151   }
152 }