liblashgame

Pathfinder and path decision making library for 2D tile game
git clone git://holbrook.no/liblashgame.git
Info | Log | Files | Refs

slopecollide.cpp (9958B)


      1 // Physics slope experiment with lash_game_sprite
      2 
      3 #include "SDL.h"
      4 #include "SDL_gfxPrimitives.h"
      5 #include "../lash_game_sprite.h"
      6 #include <math.h>
      7 #include <stdio.h>
      8 #include <string.h>
      9 
     10 #define SCREEN_WIDTH 800
     11 #define SCREEN_HEIGHT 600
     12 #define BALL_RADIUS 30
     13 #define BPP 32
     14 #define FPS 60
     15 #define GRAVITY 9.8
     16 #define PIXELS_METER 100
     17 #define COLLISION_CUTOFF 0.3
     18 #define BOUNCE 0.25
     19 
     20 /// \todo bounce was never implemented in this test
     21 
     22 int applyBounce() {
     23 	
     24 	return 0;
     25 }
     26 
     27 
     28 
     29 int main(int argc, char *argv[]) {	
     30 
     31 	int i;
     32 	
     33 	unsigned long frametime;
     34 	unsigned long lastframetime;
     35 	unsigned long startframetime;
     36 	float minframetime = 1000 / (float)FPS;	
     37 	int run = 1;
     38 	int state = 0;
     39 
     40 	Lash_Sprite_2D_Simple *sprite;
     41 	
     42 	SDL_Event event;
     43 	SDL_Surface *screen;
     44 
     45 	SDL_Rect screen_r;
     46 	SDL_Rect ball_r;
     47 
     48 	uint32_t screen_c;
     49 	uint32_t ball_c;
     50 	uint32_t slope_c;
     51 	
     52 	uint32_t ball_slope_offset_y;
     53 	float p_ball_force_net;
     54 	float p_ball_force_norm;
     55 	float slope_friction;
     56 	
     57 	float slope_angle_1, slope_angle_2, slope_gap;
     58 	float momentum_spill;
     59 	float bounce_vel;
     60 	
     61 	uint8_t slope_v_size = 5;
     62 	Sint16 *slope_v_x;
     63 	Sint16 *slope_v_y;
     64 	
     65 	float ballxinit;
     66 	float ballyinit_1, ballyinit_2;
     67 	float monitoroldv, monitorv, monitorrv, monitora, monitorra;
     68 	
     69 	char debugstring[255];
     70 	unsigned int framesrun;
     71 	unsigned long timestart;
     72 	unsigned long monitorframesturn;
     73 	
     74 	float *debugframevels;
     75 	float *debugframevelrads;
     76 	
     77 	if (argc < 4) {
     78 		printf("Usage: %s slope_angle_left_in_degrees slope_angle_right_in_degrees ball_mass_in_grammes slope_friction_coeffcient\n", argv[0]);
     79 		return 1;
     80 	}
     81 	
     82 	
     83 	sprite = new Lash_Sprite_2D_Simple(BALL_RADIUS * 2, BALL_RADIUS * 2, 0.f, 0.f);
     84 	sprite->setMass(atof(argv[3]));
     85 
     86 	//radians
     87 	slope_angle_1 = (atof(argv[1]) * M_PI) / 180;
     88 	slope_angle_2 = (atof(argv[2]) * M_PI) / 180;
     89 	slope_gap = M_PI - slope_angle_1 - slope_angle_2;
     90 	
     91 	slope_friction = atof(argv[4]);
     92 	if (!slope_friction)
     93 		slope_friction = 0.f;
     94 	
     95 	SDL_Init(SDL_INIT_VIDEO);
     96 	screen = SDL_SetVideoMode(SCREEN_WIDTH, SCREEN_HEIGHT, BPP, SDL_HWSURFACE|SDL_DOUBLEBUF);
     97 	
     98 	if (screen == NULL)	
     99 		return 1;
    100 		
    101 	slope_v_x = (Sint16*)malloc(sizeof(Sint16)*slope_v_size);
    102 	slope_v_y = (Sint16*)malloc(sizeof(Sint16)*slope_v_size);
    103 
    104 	if (slope_v_x == NULL || slope_v_y == NULL)
    105 		return 1;
    106 	
    107 	debugframevels = (float*)malloc(sizeof(float) * 10000); // should be ample
    108 	debugframevelrads = (float*)malloc(sizeof(float) * 10000);
    109 
    110 	monitorframesturn = 0;
    111 	
    112 	screen_r.x = 0;
    113 	screen_r.y = 0;
    114 	screen_r.w = SCREEN_WIDTH;
    115 	screen_r.h = SCREEN_HEIGHT;
    116 	
    117 	ball_r.x = 0;
    118 	ball_r.y = 0;
    119 	ball_r.w = BALL_RADIUS * 2;
    120 	ball_r.h = BALL_RADIUS * 2;
    121 	
    122 	screen_c = SDL_MapRGBA(screen->format, 255, 255, 255, 255);
    123 	slope_c = SDL_MapRGBA(screen->format, 0, 0, 255, 255);
    124 	ball_c = SDL_MapRGBA(screen->format, 255, 0, 0, 255);
    125 
    126 	*slope_v_y = SCREEN_HEIGHT;
    127 	*(slope_v_y + 1) = (SCREEN_HEIGHT / 2) - ((SCREEN_WIDTH / 2) * tan(slope_angle_1));
    128 	*(slope_v_y + 2) = SCREEN_HEIGHT / 2;
    129 	*(slope_v_y + 3) = (SCREEN_HEIGHT / 2) - ((SCREEN_WIDTH / 2) * tan(slope_angle_2));
    130 	*(slope_v_y + 4) = SCREEN_HEIGHT;
    131 	
    132 	*slope_v_x = 0;
    133 	*(slope_v_x + 1) = 0;
    134 	*(slope_v_x + 2) = SCREEN_WIDTH / 2;
    135 	*(slope_v_x + 3) = SCREEN_WIDTH;
    136 	*(slope_v_x + 4) = SCREEN_WIDTH;
    137 	
    138 	ballxinit = BALL_RADIUS;
    139 	ballyinit_1 = (BALL_RADIUS / cos(slope_angle_1));
    140 	ballyinit_2 = (BALL_RADIUS / cos(slope_angle_2));
    141 	sprite->setY((int)((tan(slope_angle_1) * BALL_RADIUS) + *(slope_v_y + 1) - ballyinit_1));
    142 	sprite->setX((int)ballxinit);
    143 	
    144 	p_ball_force_net = sin(slope_angle_1) * (GRAVITY * sprite->getMass());
    145 	p_ball_force_norm = cos(slope_angle_1) * (GRAVITY * sprite->getMass());
    146 	if (p_ball_force_net < 0.f)
    147 		p_ball_force_net = 0.f;
    148 	
    149 	// divide by FPS twice, as it's m/s²
    150 	sprite->setAcceleration((((p_ball_force_net / sprite->getMass()) * PIXELS_METER) / FPS) / FPS, -slope_angle_1);
    151 	// resistance is friction translated to m/s
    152 	sprite->setResistance(((p_ball_force_norm / sprite->getMass()) * slope_friction) / FPS);
    153 
    154 	float tmpav, tmpar;
    155 	sprite->getAcceleration(&tmpav, &tmpar, 0);
    156 	printf("# FPS: %d\n# Pixels per meter: %d\n# Sprite: x %.1fpx, y %.1fpx, mass %.2fkg\n# Slope left: angle %f, resistance %fm/s, distance %f\n# Slope right: angle %f, distance %f\n# Object force %.2fN, accel: %f m/s/s | %f px/frame, radians %f\n", FPS, PIXELS_METER, sprite->getX(), sprite->getY(), sprite->getMass(), slope_angle_1, sprite->getResistance(), (SCREEN_WIDTH / 2) / cos(slope_angle_1), slope_angle_2, (SCREEN_WIDTH / 2) / cos(slope_angle_2), p_ball_force_net, ((float)p_ball_force_net / sprite->getMass()), tmpav * FPS, tmpar);
    157 		
    158 	SDL_WM_SetCaption("Slope Physics Test", 0);
    159 	
    160 	while (run) {
    161 
    162 		frametime = SDL_GetTicks();
    163 
    164 		while (SDL_PollEvent(&event)) {
    165 			switch(event.type) {
    166 				case SDL_KEYDOWN:
    167 					if (event.key.keysym.sym == SDLK_ESCAPE) {
    168 						run = 0;
    169 					} else if (event.key.keysym.sym == SDLK_SPACE) {
    170 						sprite->walkRight();
    171 						framesrun = 0;
    172 						timestart = frametime;
    173 					} else if (event.key.keysym.sym == SDLK_r) {
    174 						sprite->stop();
    175 						sprite->setVel(0.f, 0.f);
    176 						sprite->setY((int)((tan(slope_angle_1) * BALL_RADIUS) + *(slope_v_y + 1) - ballyinit_1));
    177 						sprite->setX((int)ballxinit);
    178 						sprite->setAcceleration((((p_ball_force_net / sprite->getMass()) * PIXELS_METER) / FPS) / FPS, -slope_angle_1);
    179 						state = 0;
    180 					} else if (event.key.keysym.sym == SDLK_s) {
    181 						state = 2;
    182 					} 
    183 					break;
    184 			}
    185 
    186 		}
    187 			
    188 		if (sprite->isWalking(0)) {
    189 			
    190 			sprite->move();			
    191 			sprite->accelerate();
    192 			
    193 			if (state != 2) {
    194 				float newaccelangle;
    195 				float newvelangle;
    196 				float newymod;
    197 				const char *directionstring = "ltr\0";
    198 				int newstate;
    199 				int newdirection  = 0;
    200 				
    201 				// check if we're to land
    202 				if (sprite->isBouncing()) {
    203 					if (state == 1) {
    204 						newymod = ballyinit_1 - ballyinit_2;
    205 						newvelangle = slope_angle_2;	
    206 					}
    207 					else {
    208 						newymod = ballyinit_2 - ballyinit_1;
    209 						newvelangle = -slope_angle_1 + M_PI;
    210 					}
    211 					if (ball->getY() <= tan(newvelangle) * abs(ball->getX() - SCREEN_WIDTH / 2) - newymod) {
    212 						ball->finish();
    213 						sprite->setAcceleration((((p_ball_force_net / sprite->getMass()) * PIXELS_METER) / FPS) / FPS, newaccelangle);	
    214 						sprite->setVel();
    215 					}
    216 				}
    217 				
    218 				// enter right slope
    219 				if (sprite->getX() > SCREEN_WIDTH / 2 && state != 1) {
    220 					
    221 					newaccelangle = slope_angle_2 - M_PI;
    222 					newvelangle = slope_angle_2;
    223 					newymod = ballyinit_1 - ballyinit_2;
    224 					directionstring = "ltr\0";
    225 					newstate = 1;
    226 					newdirection = 1;
    227 				
    228 				// enter left slope (from right slope)
    229 				} else if (sprite->getX() < SCREEN_WIDTH / 2 && state != 0) {
    230 					
    231 					newaccelangle = -slope_angle_1;
    232 					newvelangle = -slope_angle_1 - M_PI;
    233 					newymod = ballyinit_2 - ballyinit_1;
    234 					directionstring = "rtl\0";
    235 					newstate = 0;
    236 					newdirection = 1;
    237 		
    238 				}
    239 			
    240 				if (newdirection) {
    241 					momentum_spill = sprite->getVel() * sin(slope_gap);					
    242 					monitoroldv = monitorv;
    243 					sprite->getVel(&monitorv, &monitorrv);
    244 					sprite->getAcceleration(&monitora, &monitorra, 0);
    245 					sprite->setVel(sprite->getVel() - momentum_spill, newvelangle);
    246 									
    247 					if (sprite->getVel() < COLLISION_CUTOFF - (COLLISION_CUTOFF * slope_friction)) {
    248 						sprite->stop();
    249 					} else {
    250 						
    251 						bounce_vel = momentum_spill * BOUNCE;
    252 						if (applyBounce(sprite, momentum_spill, monitoroldv)) {
    253 							
    254 						} else {
    255 							sprite->setAcceleration((((p_ball_force_net / sprite->getMass()) * PIXELS_METER) / FPS) / FPS, newaccelangle);	
    256 						}
    257 						
    258 						if (bounce_vel * monitoroldv > 1.0) {
    259 							sprite->bounce();
    260 							sprite->addVel(bounce_vel, monitorrv + M_PI);
    261 							sprite->setAcceleration(((GRAVITY * PIXELS_METER) / FPS) / FPS, 3 * (M_PI_2));	
    262 						} else {
    263 							
    264 						}
    265 
    266 					}
    267 
    268 					printf("# %s spill %f from vel %f (%f post-accel) new vel %f a %f (%f at %d frames)\n", directionstring, momentum_spill, monitoroldv, monitorv, sprite->getVel(), monitora, monitorra, framesrun);
    269 
    270 					sprite->setY(sprite->getY() + newymod);
    271 					monitorframesturn = framesrun;
    272 					state = newstate;
    273 				}
    274 			} // if state != 2
    275 			
    276 			
    277 			// if screen boundaries are hit
    278 			if (sprite->getY() >= SCREEN_HEIGHT - BALL_RADIUS || sprite->getX() >= SCREEN_WIDTH - BALL_RADIUS || sprite->getVel() == 0.f) {
    279 				if (sprite->getY() >= SCREEN_HEIGHT - BALL_RADIUS || sprite->getX() >= SCREEN_WIDTH - BALL_RADIUS) {
    280 					sprite->setX(SCREEN_WIDTH - BALL_RADIUS);
    281 				}
    282 				sprite->stop();
    283 				
    284 			}
    285 			
    286 			if (debugframevels != NULL) {
    287 				sprite->getVel(&tmpav, &tmpar);
    288 				*(debugframevels + framesrun) = tmpav;
    289 				*(debugframevelrads + framesrun) = tmpar;
    290 			}
    291 			
    292 			// if we're done
    293 			if (!sprite->isWalking(0) || state == 2) {
    294 				if (state == 2)
    295 					printf("# ABORTED!\n");
    296 				printf("# End velocity: %f px/frame (%f m/s) after %.2f secs, %d frames\n", *(debugframevels + framesrun - 1), ((*(debugframevels + framesrun - 1) / PIXELS_METER) * FPS), (frametime - timestart) / (float)1000, framesrun);
    297 				
    298 				sprite->stop();
    299 				
    300 				if (debugframevels != NULL) {
    301 					for (i = 0; i <= framesrun; i++) {
    302 						//printf("Frame %d: %f @ %f\n", i, *(debugframevels+i), (*(debugframevelrads+i) / M_PI) * 180);
    303 						printf("%d\t%f\n", i, *(debugframevels+i), (*(debugframevelrads+i) / M_PI) * 180);
    304 					}
    305 				}	
    306 			}
    307 			
    308 			framesrun++;
    309 			
    310 		}
    311 		
    312 		sprintf(debugstring, "Frametime %lu", frametime - lastframetime);
    313 		SDL_FillRect(screen, &screen_r, screen_c);
    314 		filledPolygonColor(screen, slope_v_x, slope_v_y, slope_v_size, 0x0000ffff);
    315 		filledCircleColor(screen, sprite->getXPixels(), sprite->getYPixels(), BALL_RADIUS, 0xff0000ff);
    316 		stringColor(screen, 10, SCREEN_HEIGHT - 15, debugstring, 0xffffff99);
    317 		SDL_Flip(screen);
    318 		
    319 		lastframetime = frametime;
    320 		
    321 		//if (lastframetime - frametime < minframetime)
    322 			//SDL_Delay (minframetime - (SDL_GetTicks () - frametime));
    323 		SDL_Delay(minframetime);
    324 		
    325 		
    326 	}
    327 	
    328 	delete(sprite);
    329 	SDL_FreeSurface(screen);
    330 	SDL_Quit();
    331 	
    332 	return 0;
    333 }