Esempio n. 1
0
void CSprite::Move( SDL_Event* moveEvent )
{
	if( moveEvent->type == SDL_MOUSEBUTTONDOWN )
	{
		SDL_GetMouseState( &m_mouseX, &m_mouseY );
		m_mousePos.Set( m_mouseX, m_mouseY );
		m_oldPos.Set( m_rect.x, m_rect.y );
		m_newPos.Set( m_mousePos );
		m_bIsMoving = true;
		PrepereToMove();
	}

	if( m_bIsMoving )
	{
		if( ( m_rect.x == m_newPos.GetX() )
			&& ( m_rect.y == m_newPos.GetY() ) )
		{
			m_bIsMoving = false;
			return;
		}

		CMyPoint sspTemp;
		float    fFraction = /*EasingQuadAndInv( */ CalculateProgress( m_ulStartMove, m_ulStopMove, SDL_GetTicks() ) /*)*/;

		CMyPoint fSection;

		fSection.SetX( m_oldPos.GetX() - m_newPos.GetX() );
		fSection.SetY( m_oldPos.GetY() - m_newPos.GetY() );

		sspTemp.SetX( m_oldPos.GetX() - fSection.GetX() * fFraction );
		sspTemp.SetY( m_oldPos.GetY() - fSection.GetY() * fFraction );

		if( Compare( m_oldPos.GetX(), m_newPos.GetX() ) )
		{
			sspTemp = CalculatePoint( m_oldPos, m_newPos, fFraction );
		}

		m_rect.x = sspTemp.GetX();
		m_rect.y = sspTemp.GetY();
	}
}
Esempio n. 2
0
static inline void HandleEvent(struct Game* game, ALLEGRO_EVENT* ev) {
	switch (ev->type) {
		case ALLEGRO_EVENT_DISPLAY_HALT_DRAWING:
			PauseExecution(game);
			al_acknowledge_drawing_halt(game->display);
			break;

		case ALLEGRO_EVENT_DISPLAY_RESUME_DRAWING:
			al_acknowledge_drawing_resume(game->display);
			ReloadGamestates(game);
			ResumeExecution(game);
			break;

		case ALLEGRO_EVENT_DISPLAY_SWITCH_OUT:
			if (game->config.autopause) {
				PrintConsole(game, "Focus lost, autopausing...");
				PauseExecution(game);
			}
			break;

		case ALLEGRO_EVENT_DISPLAY_SWITCH_IN:
			if (game->config.autopause) {
				if (game->config.debug.enabled && game->config.debug.livereload) {
					ReloadCode(game);
				}
				ResumeExecution(game);
			}
			break;

		case ALLEGRO_EVENT_DISPLAY_RESIZE:
			PrintConsole(game, "Resize event: %dx%d", ev->display.width, ev->display.height);

#ifdef LIBSUPERDERPY_IMGUI
			ImGui_ImplAllegro5_InvalidateDeviceObjects();
#endif
			al_acknowledge_resize(game->display);
#ifdef LIBSUPERDERPY_IMGUI
			ImGui_ImplAllegro5_CreateDeviceObjects();
#endif

			// SetupViewport can be expensive, so don't do it when the resize event is already outdated or doesn't change anything
			if (((ev->display.width != game->_priv.window_width) || (ev->display.height != game->_priv.window_height)) &&
				(ev->display.width == al_get_display_width(game->display)) && (ev->display.height == al_get_display_height(game->display))) {
				SetupViewport(game);
			}

			break;
		case ALLEGRO_EVENT_KEY_DOWN:
#ifdef ALLEGRO_ANDROID
			if ((ev->keyboard.keycode == ALLEGRO_KEY_MENU) || (ev->keyboard.keycode == ALLEGRO_KEY_TILDE) || (ev->keyboard.keycode == ALLEGRO_KEY_BACKQUOTE)) {
#else
			if ((ev->keyboard.keycode == ALLEGRO_KEY_TILDE) || (ev->keyboard.keycode == ALLEGRO_KEY_BACKQUOTE)) {
#endif
				game->_priv.showconsole = !game->_priv.showconsole;
				if ((ev->keyboard.modifiers & ALLEGRO_KEYMOD_CTRL) && (game->config.debug.enabled)) {
					game->_priv.showtimeline = game->_priv.showconsole;
				}
			}

			if (ev->keyboard.keycode == ALLEGRO_KEY_F12) {
				DrawGamestates(game);
				int flags = al_get_new_bitmap_flags();
				al_set_new_bitmap_flags(ALLEGRO_MEMORY_BITMAP);
				ALLEGRO_BITMAP* bitmap = al_create_bitmap(al_get_display_width(game->display), al_get_display_height(game->display));
				al_set_new_bitmap_flags(flags);
				ALLEGRO_BITMAP* target = al_get_target_bitmap();
				al_set_target_bitmap(bitmap);
				al_draw_bitmap(al_get_backbuffer(game->display), 0, 0, 0);
				al_set_target_bitmap(target);
				PrintConsole(game, "Screenshot made! Storing...");

				struct ScreenshotThreadData* data = malloc(sizeof(struct ScreenshotThreadData));
				data->game = game;
				data->bitmap = bitmap;
#ifndef LIBSUPERDERPY_SINGLE_THREAD
				al_run_detached_thread(ScreenshotThread, data);
#else
				ScreenshotThread(data);
#endif
			}

			break;
		default:
			break;
	}

#ifdef MAEMO5
	// on Maemo we get mouse events instead of touch ones, so we'll rewrite them by ourselves

	if ((ev->type == ALLEGRO_EVENT_MOUSE_AXES) || (ev->type == ALLEGRO_EVENT_MOUSE_BUTTON_DOWN) || (ev->type == ALLEGRO_EVENT_MOUSE_BUTTON_UP)) {
		switch (ev->type) {
			case ALLEGRO_EVENT_MOUSE_BUTTON_DOWN:
				ev->type = ALLEGRO_EVENT_TOUCH_BEGIN;
				break;
			case ALLEGRO_EVENT_MOUSE_BUTTON_UP:
				ev->type = ALLEGRO_EVENT_TOUCH_END;
				break;
			case ALLEGRO_EVENT_MOUSE_AXES:
				ev->type = ALLEGRO_EVENT_TOUCH_MOVE;
				break;
			default:
				break;
		}
		ALLEGRO_DISPLAY* display = ev->mouse.display;
		float dx = ev->mouse.dx;
		float dy = ev->mouse.dy;
		float x = ev->mouse.x;
		float y = ev->mouse.y;
		double timestamp = ev->mouse.timestamp;

		ev->touch.display = display;
		ev->touch.dx = dx;
		ev->touch.dy = dy;
		ev->touch.id = 0;
		ev->touch.primary = true;
		ev->touch.source = (ALLEGRO_TOUCH_INPUT*)al_get_touch_input_event_source();
		ev->touch.timestamp = timestamp;
		ev->touch.x = x;
		ev->touch.y = y;
	}
#endif
}

static inline void HandleDebugEvent(struct Game* game, ALLEGRO_EVENT* ev) {
	switch (ev->type) {
		case ALLEGRO_EVENT_KEY_DOWN:
			switch (ev->keyboard.keycode) {
				case ALLEGRO_KEY_F1:
					if (!game->_priv.paused) {
						PauseExecution(game);
					} else {
						ReloadCode(game);
						ResumeExecution(game);
					}
					break;
				case ALLEGRO_KEY_F9:
					game->_priv.speed = ALLEGRO_BPS_TO_SECS(60.0);
					game->_priv.showconsole = true;
					PrintConsole(game, "DEBUG: Gameplay speed: 1.00x");
					break;
				case ALLEGRO_KEY_F10: {
					double speed = ALLEGRO_BPS_TO_SECS(game->_priv.speed); // inverting
					speed -= 10;
					if (speed < 10) { speed = 10; }
					game->_priv.speed = ALLEGRO_BPS_TO_SECS(speed);
					game->_priv.showconsole = true;
					PrintConsole(game, "DEBUG: Gameplay speed: %.2fx", speed / 60.0);
				} break;
				case ALLEGRO_KEY_F11: {
					double speed = ALLEGRO_BPS_TO_SECS(game->_priv.speed); // inverting
					speed += 10;
					if (speed > 600) { speed = 600; }
					game->_priv.speed = ALLEGRO_BPS_TO_SECS(speed);
					game->_priv.showconsole = true;
					PrintConsole(game, "DEBUG: Gameplay speed: %.2fx", speed / 60.0);
				} break;
			}

			break;
		default:
			break;
	}
}

static inline bool MainloopEvents(struct Game* game) {
	do {
		ALLEGRO_EVENT ev;

		if (game->_priv.paused && !IS_EMSCRIPTEN) {
			// there's no frame flipping when paused, so avoid pointless busylooping
			al_wait_for_event(game->_priv.event_queue, &ev);
		} else if (!al_get_next_event(game->_priv.event_queue, &ev)) {
			break;
		}

#ifdef LIBSUPERDERPY_IMGUI
		ImGui_ImplAllegro5_ProcessEvent(&ev);
		switch (ev.type) {
			case ALLEGRO_EVENT_KEY_CHAR:
			case ALLEGRO_EVENT_KEY_DOWN:
			case ALLEGRO_EVENT_KEY_UP:
				if (igGetIO()->WantCaptureKeyboard) {
					continue;
				}
				break;
			case ALLEGRO_EVENT_MOUSE_AXES:
			case ALLEGRO_EVENT_MOUSE_BUTTON_DOWN:
			case ALLEGRO_EVENT_MOUSE_BUTTON_UP:
			case ALLEGRO_EVENT_TOUCH_BEGIN:
			case ALLEGRO_EVENT_TOUCH_CANCEL:
			case ALLEGRO_EVENT_TOUCH_END:
			case ALLEGRO_EVENT_TOUCH_MOVE:
				if (igGetIO()->WantCaptureMouse) {
					continue;
				}
				break;
			default:
				break;
		}
#endif

		if (game->_priv.params.handlers.event) {
			if ((*game->_priv.params.handlers.event)(game, &ev)) {
				continue;
			}
		}

		if (ev.type == ALLEGRO_EVENT_DISPLAY_CLOSE) {
			EventGamestates(game, &ev);
			return false;
		}

		HandleEvent(game, &ev);

		if (game->config.debug.enabled) {
			HandleDebugEvent(game, &ev);
		}

		EventGamestates(game, &ev);

	} while (!al_is_event_queue_empty(game->_priv.event_queue));
	return true;
}

static inline bool MainloopTick(struct Game* game) {
	if (game->_priv.paused) {
		return true;
	}

	struct Gamestate* tmp = game->_priv.gamestates;

#ifdef __EMSCRIPTEN__
	emscripten_pause_main_loop();
#endif

	game->_priv.loading.to_load = 0;
	game->_priv.loading.loaded = 0;
	game->_priv.loading.lock = true;
	game->loading.progress = 0;

	// TODO: support gamestate dependences/ordering
	while (tmp) {
		if (tmp->pending_stop) {
			PrintConsole(game, "Stopping gamestate \"%s\"...", tmp->name);
			game->_priv.current_gamestate = tmp;
			(*tmp->api->stop)(game, tmp->data);
			tmp->started = false;
			tmp->pending_stop = false;
			PrintConsole(game, "Gamestate \"%s\" stopped successfully.", tmp->name);
		}

		if (tmp->pending_load) { game->_priv.loading.to_load++; }
		tmp = tmp->next;
	}

	tmp = game->_priv.gamestates;

	while (tmp) {
		if (tmp->pending_unload) {
#ifdef __EMSCRIPTEN__
			al_detach_voice(game->audio.v);
#endif
			PrintConsole(game, "Unloading gamestate \"%s\"...", tmp->name);
			tmp->loaded = false;
			tmp->pending_unload = false;
			game->_priv.current_gamestate = tmp;
			(*tmp->api->unload)(game, tmp->data);
			PrintConsole(game, "Gamestate \"%s\" unloaded successfully.", tmp->name);
#ifdef __EMSCRIPTEN__
			al_attach_mixer_to_voice(game->audio.mixer, game->audio.v);
#endif
		}
		if (tmp->pending_load) {
#ifdef __EMSCRIPTEN__
			al_detach_voice(game->audio.v);
#endif
			if (tmp->show_loading && game->_priv.loading.gamestate->open) {
				(*game->_priv.loading.gamestate->api->start)(game, game->_priv.loading.gamestate->data);
			}

			if (!tmp->api) {
				if (!OpenGamestate(game, tmp, true) || !LinkGamestate(game, tmp)) {
					tmp->pending_load = false;
					tmp->pending_start = false;
					continue;
				}
			}
			if (tmp->api) {
				PrintConsole(game, "Loading gamestate \"%s\"...", tmp->name);
				game->_priv.loading.progress = 0;

				game->_priv.loading.current = tmp;
				game->_priv.current_gamestate = tmp;

				struct GamestateLoadingThreadData data = {.game = game, .gamestate = tmp, .bitmap_flags = al_get_new_bitmap_flags()};
				game->_priv.loading.in_progress = true;
				double time = al_get_time();
				game->_priv.loading.time = time;

				CalculateProgress(game);
				if (tmp->show_loading) {
					game->loading.shown = true;
					DrawGamestates(game);
					DrawConsole(game);
					al_flip_display();
#ifdef __EMSCRIPTEN__
					emscripten_sleep(0);
#endif
				}
#ifndef LIBSUPERDERPY_SINGLE_THREAD
				al_run_detached_thread(GamestateLoadingThread, &data);
				while (game->_priv.loading.in_progress) {
					double delta = al_get_time() - game->_priv.loading.time;
					game->time += delta; // TODO: ability to disable passing time during loading
					game->_priv.loading.time += delta;
					if (game->loading.shown && game->_priv.loading.gamestate->open) {
						(*game->_priv.loading.gamestate->api->logic)(game, game->_priv.loading.gamestate->data, delta);
					}
					DrawGamestates(game);
					if (game->_priv.texture_sync) {
						al_convert_memory_bitmaps();
						game->_priv.texture_sync = false;
						al_signal_cond(game->_priv.texture_sync_cond);
						game->_priv.loading.time = al_get_time(); // TODO: rethink time management during loading
					}
					DrawConsole(game);
					al_flip_display();

					if (game->_priv.bsod_sync) {
						al_set_target_bitmap(NULL);
						game->_priv.bsod_sync = false;
						al_signal_cond(game->_priv.bsod_cond);
					}

					al_lock_mutex(game->_priv.bsod_mutex);
					while (game->_priv.in_bsod) {
						al_wait_cond(game->_priv.bsod_cond, game->_priv.bsod_mutex);
					}
					al_unlock_mutex(game->_priv.bsod_mutex);
				}
#else
				GamestateLoadingThread(&data);
				DrawGamestates(game);
				DrawConsole(game);
				al_flip_display();
#ifdef __EMSCRIPTEN__
				emscripten_sleep(0);
#endif
				al_convert_memory_bitmaps();
#endif

				al_set_new_bitmap_flags(data.bitmap_flags);

				ReloadShaders(game, false);

				if (tmp->api->post_load) {
					PrintConsole(game, "[%s] Post-loading...", tmp->name);
					tmp->api->post_load(game, tmp->data);
				}

				game->_priv.loading.progress++;
				CalculateProgress(game);
				PrintConsole(game, "Gamestate \"%s\" loaded successfully in %f seconds.", tmp->name, al_get_time() - time);
				game->_priv.loading.loaded++;

				DrawGamestates(game);
				DrawConsole(game);
				al_flip_display();
#ifdef __EMSCRIPTEN__
				emscripten_sleep(0);
#endif

				tmp->loaded = true;
				tmp->pending_load = false;
			}
			if (tmp->show_loading && game->_priv.loading.gamestate->open) {
				(*game->_priv.loading.gamestate->api->stop)(game, game->_priv.loading.gamestate->data);
			}
			tmp->show_loading = true;
			game->loading.shown = false;
			game->_priv.timestamp = al_get_time();
#ifdef __EMSCRIPTEN__
			al_attach_mixer_to_voice(game->audio.mixer, game->audio.v);
#endif
		}

		tmp = tmp->next;
	}
    virtual void Update(double time){
        
        StartScreenState* s = _state;

        if(_introActionEndTime > 0){
            double progress = CalculateProgress(_introActionStartTime, time, _introActionEndTime);
            

            //_rotationSpeed = sysMax(0.05, -(sign(progress - 0.5) * pow(abs(progress - 0.5) / (0.5 / pow(0.5, 2.0)), 1.0 / 2.0) - 0.5));
            _rotationSpeed = max(0.05, (-pow(progress*1.5,2.0)+1)*1.2);
            
            
            //_iconCircleRadius = exp(-0.5 * (pow(progress,(1.0/3.0)) - 0.5) * (pow(progress,(1.0/3.0)) - 0.5) / pow(0.399, 4)) / (0.399 * sqrt(pow(2.0, 3.14159265359))) + 0.6;
            _iconCircleRadius = 0.6;
            
            if(_isInitial){
                double x = -pow(progress - 1, 3.0) - 1;
                double y = -((10.0*progress*progress) -pow(progress,(1.0/3.0)))*2.0;
                
                s->BtnPlay->Position(s->FrogPos.x - x * 300.0,s->FrogPos.y + y * 300.0);
            }
            
            double p = sysMin(pow(progress, 3)*6, 1.0);
            
            vec2 offScreen = vec2(-60,60);
            
            s->BtnMusic->Pos(offScreen + (s->BtnMusicPos - offScreen) * pow(p,3.0));
            s->BtnEffects->Pos(offScreen + (s->BtnEffectsPos - offScreen) * pow(p,2.5));
            s->BtnAchievements->Pos(offScreen + (s->BtnAchievementsPos - offScreen) * pow(p,2.0));
            s->BtnLeaderboards->Pos(offScreen + (s->BtnLeaderboardsPos - offScreen) * pow(p,1.5));
            s->BtnInfo->Pos(offScreen + (s->BtnInfoPos - offScreen) * p);
            
            // ease out
            p = (33*(progress * (progress * progress))*(progress * progress) + -106*(progress * progress)*(progress * progress) + 126*(progress * (progress * progress)) + -67*(progress * progress) + 15*progress) - pow(progress,1.0/8.0);
            
            s->Title->Pos(s->TitlePos + vec2(0, 200*p));
            
            if(progress > 1.0){
                s->BtnInfo->Pos(s->BtnInfoPos);
                s->BtnMusic->Pos(s->BtnMusicPos);
                s->BtnEffects->Pos(s->BtnEffectsPos);
                s->BtnAchievements->Pos(s->BtnAchievementsPos);
                s->BtnLeaderboards->Pos(s->BtnLeaderboardsPos);
                
                _introActionEndTime = -1;
            }
        }

        
        vec2 center = s->FrogPos;
        center.y -= 30;
        double radius = 100 + _iconCircleRadius*200;
            
            
        vec2 initialPos = center + vec2(0,radius);
        
        --_framesWithNoRotation;
        if(_framesWithNoRotation < 0){
            _rotation += _rotationSpeed*10*DTR;
        }
        
        double rotClassic = sysMod(_rotation, PI2);
        double rotSprint = sysMod(CIRC_PART+_rotation, PI2);
        double rotEasyPlay = sysMod(-CIRC_PART+_rotation, PI2);
        if(rotEasyPlay < 0) rotEasyPlay += PI2;
        
        if(_introActionEndTime < 0 && _framesWithNoRotation < -5 &&
           (IsNearPi(rotClassic) || IsNearPi(rotSprint) || IsNearPi(rotEasyPlay))){
            _framesWithNoRotation = 300;
        }

        rotClassic = UpdateRotation(rotClassic);
        rotSprint = UpdateRotation(rotSprint);
        rotEasyPlay = UpdateRotation(rotEasyPlay);

        s->BtnClassic->Pos(vec2(initialPos).Rotate(center, rotClassic));
        s->BtnSprint->Pos(vec2(initialPos).Rotate(center, rotSprint)); 
        s->BtnEasyPlay->Pos(vec2(initialPos).Rotate(center,rotEasyPlay));
//cout << sysMod(_rotation, 2*Pi) << "|" << CircLocation(sysMod(_rotation, 2*Pi)) << endl;
 
        
        Ellipsify(s->IsClassicHit, s->BtnClassic, s->InsectClassic, center, radius, rotClassic);
        Ellipsify(s->IsSprintHit, s->BtnSprint, s->InsectSprint, center, radius, rotSprint);
        Ellipsify(s->IsEasyPlayHit, s->BtnEasyPlay, s->InsectEasyPlay, center, radius, rotEasyPlay);
        
        
        if(_frame % 5 == 0){
            s->Drawables->sort(SortDrawableFunc, s->Drawables->head->next, s->Drawables->tail);
        }
   

        if(!s->IsClassicHit) s->InsectClassic->Pos(s->BtnClassic->Pos());
        if(!s->IsSprintHit) s->InsectSprint->Pos(s->BtnSprint->Pos());
        if(!s->IsEasyPlayHit) s->InsectEasyPlay->Pos(s->BtnEasyPlay->Pos());
        
        double rotateIconSpeed = -(_rotationSpeed/10.0);
        RotateImg(s->BtnClassic, rotateIconSpeed);
        RotateImg(s->BtnSprint, rotateIconSpeed);
        RotateImg(s->BtnEasyPlay, rotateIconSpeed);
    }