1 /// 2 module isodi.camera; 3 4 import std.math; 5 import std.typecons; 6 7 import isodi.object3d; 8 9 private immutable rad = PI / 180; 10 11 12 @safe: 13 14 15 /// Represents a camera, giving a view into the Isodi world. 16 struct Camera { 17 18 alias Offset = Tuple!( 19 float, "x", 20 float, "y", 21 float, "height", 22 ); 23 24 /// Represents the angle the camera is looking at. 25 struct Angle { 26 27 private float _x = 45; 28 invariant(_x >= 0, "Somehow camera angle X is negative, this shouldn't be possible."); 29 invariant(_x < 360, "Somehow camera angle X is >= 360, this shouldn't be possible."); 30 invariant(!_x.isNaN, "Camera angle X is NaN, did you forget to initialize a float?"); 31 32 /// Y, vertical angle of the camera. 33 /// 34 /// Must be between 0° (side view) and 90° (top-down), defaults to 45° 35 float y = 45; 36 invariant(y >= 0, "Camera angle Y must be at least 0°."); 37 invariant(y <= 90, "Camera angle Y must be at most 90°."); 38 invariant(!y.isNaN, "Camera angle Y is NaN, did you forget to initialize a float?"); 39 40 /// X, horizontal angle of the camera. 41 /// 42 /// Automatically modulated by 360°. 43 @property 44 float x() const { return _x; } 45 46 /// Ditto 47 @property 48 float x(float value) { 49 50 // Modulate 51 value %= 360; 52 53 // Prevent being negative 54 if (value < 0) value += 360; 55 56 return _x = value; 57 58 } 59 60 } 61 62 /// Object this camera follows. 63 /// 64 /// This can be null. If so, follows position (0, 0, 0). 65 Object3D follow; 66 67 /// Angle the camera is looking from. 68 Angle angle; 69 70 /// Distance between the camera and the followed object. 71 /// 72 /// Uses cells as the unit. `display.cellSize * distance` will be the cell distance in the renderer. 73 float distance = 15; 74 75 /// Offset between camera and the followed object. 76 auto offset = Offset(0, 0, 1); 77 78 /// Change the offset relative to the screen 79 void offsetScreenX(float value) { 80 81 const alpha = (angle.x+90) * rad; 82 offset.x += value * alpha.sin; 83 offset.y += value * alpha.cos; 84 85 } 86 87 /// Change the offset relative to the screen 88 void offsetScreenY(float value) { 89 90 const alpha = angle.x * rad; 91 offset.x += value * alpha.sin; 92 offset.y += value * alpha.cos; 93 94 } 95 96 }