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