1 /// contains the simple box object class
2 module ysge.objects.simpleBox;
3 
4 import ysge.project;
5 
6 /// contains physics info
7 struct Physics {
8 	Vec2!int velocity;
9 	bool     drag;
10 	bool     gravityOn;
11 	Vec2!int gravity;
12 }
13 
14 /// box object with AABB collision
15 class SimpleBox : GameObject {
16 	SDL_Rect   box;
17 	bool       physicsOn;
18 	Physics    physics;
19 	RenderInfo render;
20 
21 	/// initialises with a box and a colour image
22 	this(SDL_Rect pbox, SDL_Color colour) {
23 		box          = pbox;
24 		render.type  = RenderType.Colour;
25 		render.value = RenderValue(colour);
26 	}
27 
28 	/// initialises with a box and a texture
29 	this(SDL_Rect pbox, Texture texture) {
30 		box          = pbox;
31 		render.type  = RenderType.Texture;
32 		render.value = RenderValue(texture);
33 	}
34 
35 	/// makes the object render as a coloured box
36 	void SetRenderColour(SDL_Color colour) {
37 		render.type  = RenderType.Colour;
38 		render.value = RenderValue(colour);
39 	}
40 
41 	/// makes the object render as a texture
42 	void SetRenderTexture(Texture texture) {
43 		render.type  = RenderType.Texture;
44 		render.value = RenderValue(texture);
45 	}
46 
47 	/// updates the object (physics etc)
48 	override void Update(Project parent) {
49 		if (physicsOn) {
50 			int old;
51 
52 			old    = box.x;
53 			box.x += physics.velocity.x;
54 			foreach (ref object ; parent.currentScene.objects) {
55 				if (object is this) {
56 					continue;
57 				}
58 				
59 				if (object.CollidesWith(this)) {
60 					box.x              = old;
61 					physics.velocity.x = 0;
62 					break;
63 				}
64 			}
65 
66 			old    = box.y;
67 			box.y += physics.velocity.y;
68 			foreach (ref object ; parent.currentScene.objects) {
69 				if (object is this) {
70 					continue;
71 				}
72 				
73 				if (object.CollidesWith(this)) {
74 					box.y              = old;
75 					physics.velocity.y = 0;
76 					break;
77 				}
78 			}
79 
80 			if (physics.drag) {
81 				if (physics.velocity.x > 0) {
82 					-- physics.velocity.x;
83 				}
84 				if (physics.velocity.y > 0) {
85 					-- physics.velocity.y;
86 				}
87 				if (physics.velocity.x < 0) {
88 					++ physics.velocity.x;
89 				}
90 				if (physics.velocity.y < 0) {
91 					++ physics.velocity.y;
92 				}
93 			}
94 
95 			if (physics.gravityOn) {
96 				physics.velocity.x += physics.gravity.x;
97 				physics.velocity.y += physics.gravity.y;
98 			}
99 		}
100 		return;
101 	}
102 
103 	/**
104 	* move the box right while checking collision
105 	* returns whether it did move
106 	*/
107 	bool MoveRight(Scene scene, int pixels) {
108 		for (int i = 0; i < pixels; ++ i) {
109 			int old = box.x;
110 			++ box.x;
111 
112 			foreach (ref object ; scene.objects) {
113 				if (object is this) {
114 					continue;
115 				}
116 
117 				if (object.CollidesWith(this)) {
118 					box.x = old;
119 					return false;
120 				}
121 			}
122 		}
123 
124 		return true;
125 	}
126 
127 	/**
128 	* move the box left while checking collision
129 	* returns whether it did move
130 	*/
131 	bool MoveLeft(Scene scene, int pixels) {
132 		for (int i = 0; i < pixels; ++ i) {
133 			int old = box.x;
134 			+--box.x;
135 
136 			foreach (ref object ; scene.objects) {
137 				if (object is this) {
138 					continue;
139 				}
140 
141 				if (object.CollidesWith(this)) {
142 					box.x = old;
143 					return false;
144 				}
145 			}
146 		}
147 
148 		return true;
149 	}
150 
151 	/**
152 	* move the box up while checking collision
153 	* returns whether it did move
154 	*/
155 	bool MoveUp(Scene scene, int pixels) {
156 		for (int i = 0; i < pixels; ++ i) {
157 			int old = box.y;
158 			-- box.y;
159 
160 			foreach (ref object ; scene.objects) {
161 				if (object is this) {
162 					continue;
163 				}
164 
165 				if (object.CollidesWith(this)) {
166 					box.y = old;
167 					return false;
168 				}
169 			}
170 		}
171 
172 		return true;
173 	}
174 
175 	/**
176 	* move the box down while checking collision
177 	* returns whether it did move
178 	*/
179 	bool MoveDown(Scene scene, int pixels) {
180 		for (int i = 0; i < pixels; ++ i) {
181 			int old = box.y;
182 			++ box.y;
183 
184 			foreach (ref object ; scene.objects) {
185 				if (object is this) {
186 					continue;
187 				}
188 
189 				if (object.CollidesWith(this)) {
190 					box.y = old;
191 					return false;
192 				}
193 			}
194 		}
195 
196 		return true;
197 	}
198 	
199 	/// uses AABB to check if it collides with another box
200 	override bool CollidesWith(SimpleBox other) {
201 		return (
202 			(box.x < other.box.x + other.box.w) &&
203 			(box.x + box.w > other.box.x) &&
204 			(box.y < other.box.y + other.box.h) &&
205 			(box.y + box.h > other.box.y)
206 		);
207 	}
208 
209 	/**
210 	* renders the object
211 	* should not be called by user
212 	*/
213 	override void Render(Project parent) {
214 		SDL_Rect screenBox  = box;
215 		screenBox.x        -= parent.currentScene.camera.x;
216 		screenBox.y        -= parent.currentScene.camera.y;
217 
218 		switch (render.type) {
219 			case RenderType.Colour: {
220 				SDL_SetRenderDrawColor(
221 					parent.renderer,
222 					render.value.colour.r,
223 					render.value.colour.g,
224 					render.value.colour.b,
225 					render.value.colour.a
226 				);
227 				SDL_RenderFillRect(parent.renderer, &screenBox);
228 				break;
229 			}
230 			case RenderType.Texture: {
231 				SDL_Rect* src;
232 
233 				if (render.props.doCrop) {
234 					src  = new SDL_Rect();
235 					*src = render.props.crop;
236 				}
237 			
238 				SDL_RenderCopy(
239 					parent.renderer, render.value.texture.texture, src,
240 					&screenBox
241 				);
242 				break;
243 			}
244 			default: assert(0);
245 		}
246 	}
247 }