void Player::check_bounds(Camera* camera) { /* Keep tux in bounds: */ if (get_pos().x < 0) { // Lock Tux to the size of the level, so that he doesn't fall of // on the left side set_pos(Vector(0, get_pos().y)); } /* Keep in-bounds, vertically: */ if (get_pos().y > Sector::current()->solids->get_height() * 32) { kill(true); return; } bool adjust = false; // can happen if back scrolling is disabled if(get_pos().x < camera->get_translation().x) { set_pos(Vector(camera->get_translation().x, get_pos().y)); adjust = true; } if(get_pos().x >= camera->get_translation().x + SCREEN_WIDTH - bbox.get_width()) { set_pos(Vector( camera->get_translation().x + SCREEN_WIDTH - bbox.get_width(), get_pos().y)); adjust = true; } if(adjust) { // FIXME #if 0 // squished now? if(collision_object_map(bbox)) { kill(KILL); return; } #endif } }
void Player::action(double frame_ratio) { bool jumped_in_solid = false; if (input.fire == UP) holding_something = false; /* Move tux: */ previous_base = base; /* --- HANDLE TUX! --- */ if(dying == DYING_NOT) handle_input(); physic.apply(frame_ratio, base.x, base.y); if(dying == DYING_NOT) { base_type target = base; collision_swept_object_map(&old_base, &base); // Don't accelerate Tux if he is running against a wall if (target.x != base.x) { physic.set_velocity_x(0); } // special exception for cases where we're stuck under tiles after // being ducked. In this case we drift out if(!duck && on_ground() && old_base.x == base.x && old_base.y == base.y && collision_object_map(base)) { base.x += frame_ratio * WALK_SPEED * (dir ? 1 : -1); previous_base = old_base = base; } // Land: if (!on_ground()) { physic.enable_gravity(true); if(under_solid()) { // fall down physic.set_velocity_y(0); jumped_in_solid = true; } } else { /* Land: */ if (physic.get_velocity_y() < 0) { base.y = (int)(((int)base.y / 32) * 32); physic.set_velocity_y(0); } physic.enable_gravity(false); /* Reset score multiplier (for multi-hits): */ player_status.score_multiplier = 1; } if(jumped_in_solid) { if (isbrick(base.x, base.y) || isfullbox(base.x, base.y)) { World::current()->trygrabdistro(base.x, base.y - 32,BOUNCE); World::current()->trybumpbadguy(base.x, base.y - 64); World::current()->trybreakbrick(base.x, base.y, size == SMALL, RIGHT); bumpbrick(base.x, base.y); World::current()->tryemptybox(base.x, base.y, RIGHT); } if (isbrick(base.x+ 31, base.y) || isfullbox(base.x+ 31, base.y)) { World::current()->trygrabdistro(base.x+ 31, base.y - 32,BOUNCE); World::current()->trybumpbadguy(base.x+ 31, base.y - 64); if(size == BIG) World::current()->trybreakbrick(base.x+ 31, base.y, size == SMALL, LEFT); bumpbrick(base.x+ 31, base.y); World::current()->tryemptybox(base.x+ 31, base.y, LEFT); } } grabdistros(); if (jumped_in_solid) { ++base.y; ++old_base.y; if(on_ground()) { /* Make sure jumping is off. */ jumping = false; } } } /* ---- DONE HANDLING TUX! --- */ // check some timers skidding_timer.check(); invincible_timer.check(); safe_timer.check(); kick_timer.check(); }
void BadGuy::action_mriceblock(double frame_ratio) { Player& tux = *World::current()->get_tux(); if(mode != HELD) fall(); /* Move left/right: */ if (mode != HELD) { // move physic.apply(frame_ratio, base.x, base.y); if (dying != DYING_FALLING) collision_swept_object_map(&old_base,&base); } else if (mode == HELD) { /* FIXME: The pbad object shouldn't know about pplayer objects. */ /* If we're holding the iceblock */ dir = tux.dir; if(dir==RIGHT) { base.x = tux.base.x + 16; base.y = tux.base.y + tux.base.height/1.5 - base.height; } else /* facing left */ { base.x = tux.base.x - 16; base.y = tux.base.y + tux.base.height/1.5 - base.height; } if(collision_object_map(base)) { base.x = tux.base.x; base.y = tux.base.y + tux.base.height/1.5 - base.height; } if(tux.input.fire != DOWN) /* SHOOT! */ { if(dir == LEFT) base.x -= 24; else base.x += 24; old_base = base; mode=KICK; tux.kick_timer.start(KICKING_TIME); set_sprite(img_mriceblock_flat_left, img_mriceblock_flat_right); physic.set_velocity_x((dir == LEFT) ? -3.5 : 3.5); play_sound(sounds[SND_KICK],SOUND_CENTER_SPEAKER); } } if (!dying) { int changed = dir; check_horizontal_bump(); if(mode == KICK && changed != dir) { /* handle stereo sound (number 10 should be tweaked...)*/ if (base.x < scroll_x + screen->w/2 - 10) play_sound(sounds[SND_RICOCHET], SOUND_LEFT_SPEAKER); else if (base.x > scroll_x + screen->w/2 + 10) play_sound(sounds[SND_RICOCHET], SOUND_RIGHT_SPEAKER); else play_sound(sounds[SND_RICOCHET], SOUND_CENTER_SPEAKER); } } /* Handle mode timer: */ if (mode == FLAT) { if(!timer.check()) { mode = NORMAL; set_sprite(img_mriceblock_left, img_mriceblock_right); physic.set_velocity( (dir == LEFT) ? -.8 : .8, 0); } } }
BadGuy::BadGuy(float x, float y, BadGuyKind kind_, bool stay_on_platform_) : removable(false), squishcount(0) { base.x = x; base.y = y; base.width = 0; base.height = 0; base.xm = 0; base.ym = 0; stay_on_platform = stay_on_platform_; mode = NORMAL; dying = DYING_NOT; kind = kind_; old_base = base; dir = LEFT; seen = false; animation_offset = 0; sprite_left = sprite_right = 0; physic.reset(); timer.init(true); if(kind == BAD_MRBOMB) { physic.set_velocity(-BADGUY_WALK_SPEED, 0); set_sprite(img_mrbomb_left, img_mrbomb_right); } else if (kind == BAD_MRICEBLOCK) { physic.set_velocity(-BADGUY_WALK_SPEED, 0); set_sprite(img_mriceblock_left, img_mriceblock_right); } else if(kind == BAD_JUMPY) { set_sprite(img_jumpy_left_up, img_jumpy_left_up); } else if(kind == BAD_BOMB) { set_sprite(img_mrbomb_ticking_left, img_mrbomb_ticking_right); // hack so that the bomb doesn't hurt until it expldes... dying = DYING_SQUISHED; } else if(kind == BAD_FLAME) { base.ym = 0; // we misuse base.ym as angle for the flame physic.enable_gravity(false); set_sprite(img_flame, img_flame); } else if(kind == BAD_BOUNCINGSNOWBALL) { physic.set_velocity(-1.3, 0); set_sprite(img_bouncingsnowball_left, img_bouncingsnowball_right); } else if(kind == BAD_STALACTITE) { physic.enable_gravity(false); set_sprite(img_stalactite, img_stalactite); } else if(kind == BAD_FISH) { set_sprite(img_fish, img_fish); physic.enable_gravity(true); } else if(kind == BAD_FLYINGSNOWBALL) { set_sprite(img_flyingsnowball, img_flyingsnowball); physic.enable_gravity(false); } else if(kind == BAD_SPIKY) { physic.set_velocity(-BADGUY_WALK_SPEED, 0); set_sprite(img_spiky_left, img_spiky_right); } else if(kind == BAD_SNOWBALL) { physic.set_velocity(-BADGUY_WALK_SPEED, 0); set_sprite(img_snowball_left, img_snowball_right); } // if we're in a solid tile at start correct that now if(kind != BAD_FLAME && kind != BAD_FISH && collision_object_map(base)) { std::cout << "Warning: badguy started in wall: kind: " << badguykind_to_string(kind) << " pos: (" << base.x << ", " << base.y << ")" << std::endl; while(collision_object_map(base)) --base.y; } }
void GameSession::restart_level() { game_pause = false; exit_status = ES_NONE; end_sequence = NO_ENDSEQUENCE; fps_timer.init(true); frame_timer.init(true); float old_x_pos = -1; if (world) { // Tux has lost a life, so we try to respawn him at the nearest reset point old_x_pos = world->get_tux()->base.x; } delete world; if (st_gl_mode == ST_GL_LOAD_LEVEL_FILE) { world = new World(subset); } else if (st_gl_mode == ST_GL_DEMO_GAME) { world = new World(subset); } else { world = new World(subset, levelnb); } // Set Tux to the nearest reset point if (old_x_pos != -1) { ResetPoint best_reset_point = { -1, -1 }; for(std::vector<ResetPoint>::iterator i = get_level()->reset_points.begin(); i != get_level()->reset_points.end(); ++i) { if (i->x - screen->w/2 < old_x_pos && best_reset_point.x < i->x) best_reset_point = *i; } if (best_reset_point.x != -1) { world->get_tux()->base.x = best_reset_point.x; world->get_tux()->base.y = best_reset_point.y; world->get_tux()->old_base = world->get_tux()->base; world->get_tux()->previous_base = world->get_tux()->base; if(collision_object_map(world->get_tux()->base)) { std::cout << "Warning: reset point inside a wall.\n"; } scroll_x = best_reset_point.x - screen->w/2; } } if (st_gl_mode != ST_GL_DEMO_GAME) { if(st_gl_mode == ST_GL_PLAY || st_gl_mode == ST_GL_LOAD_LEVEL_FILE) levelintro(); } time_left.init(true); start_timers(); world->play_music(LEVEL_MUSIC); }
void collision_swept_object_map(base_type* old, base_type* current) { int steps; /* Used to speed up the collision tests, by stepping every 16pixels in the path. */ int h; float lpath; /* Holds the longest path, which is either in X or Y direction. */ float xd,yd; /* Hold the smallest steps in X and Y directions. */ float temp, xt, yt; /* Temporary variable. */ lpath = 0; xd = 0; yd = 0; if(old->x == current->x && old->y == current->y) { return; } else if(old->x == current->x && old->y != current->y) { lpath = current->y - old->y; if(lpath < 0) { yd = -1; lpath = -lpath; } else { yd = 1; } h = 1; xd = 0; } else if(old->x != current->x && old->y == current->y) { lpath = current->x - old->x; if(lpath < 0) { xd = -1; lpath = -lpath; } else { xd = 1; } h = 2; yd = 0; } else { lpath = current->x - old->x; if(lpath < 0) lpath = -lpath; if(current->y - old->y > lpath || old->y - current->y > lpath) lpath = current->y - old->y; if(lpath < 0) lpath = -lpath; h = 3; xd = (current->x - old->x) / lpath; yd = (current->y - old->y) / lpath; } steps = (int)(lpath / (float)16); float orig_x = old->x; float orig_y = old->y; old->x += xd; old->y += yd; for(float i = 0; i <= lpath; old->x += xd, old->y += yd, ++i) { if(steps > 0) { old->y += yd*16.; old->x += xd*16.; steps--; } if(collision_object_map(*old)) { switch(h) { case 1: current->y = old->y - yd; while(collision_object_map(*current)) current->y -= yd; break; case 2: current->x = old->x - xd; while(collision_object_map(*current)) current->x -= xd; break; case 3: xt = current->x; yt = current->y; current->x = old->x - xd; current->y = old->y - yd; while(collision_object_map(*current)) { current->x -= xd; current->y -= yd; } temp = current->x; current->x = xt; if(!collision_object_map(*current)) break; current->x = temp; temp = current->y; current->y = yt; if(!collision_object_map(*current)) { break; } else { current->y = temp; while(!collision_object_map(*current)) current->y += yd; current->y -= yd; break; } break; default: break; } break; } } if((xd > 0 && current->x < orig_x) || (xd < 0 && current->x > orig_x)) current->x = orig_x; if((yd > 0 && current->y < orig_y) || (yd < 0 && current->y > orig_y)) current->y = orig_y; *old = *current; }