--- /dev/null
+use ggez::graphics::{self, DrawParam, Image, Rect};
+use ggez::{Context, GameResult};
+
+const DEFAULT_RADIUS: f32 = 70f32;
+
+pub struct Door {
+ is_open: bool,
+ x: f32,
+ y: f32,
+ id: usize,
+ enter_radius: f32,
+}
+
+impl Door {
+ pub fn new(is_open: bool, x: f32, y: f32, id: usize) -> Self {
+ Door {
+ is_open,
+ x,
+ y,
+ id,
+ enter_radius: DEFAULT_RADIUS,
+ }
+ }
+
+ pub fn draw(&self, ctx: &mut Context, door_image: &Image) -> GameResult<()> {
+ if self.is_open {
+ graphics::draw(
+ ctx,
+ door_image,
+ DrawParam::new()
+ .src(Rect::new(0f32, 0.8f32, 1f32, 0.2f32))
+ .dest([self.x, self.y]),
+ )?;
+ } else {
+ graphics::draw(ctx, door_image, DrawParam::new().dest([self.x, self.y]))?;
+ }
+ Ok(())
+ }
+
+ pub fn get_open(&self) -> bool {
+ self.is_open
+ }
+
+ pub fn set_open(&mut self, is_open: bool) {
+ self.is_open = is_open;
+ }
+
+ pub fn toggle_open(&mut self) -> bool {
+ self.is_open = !self.is_open;
+ self.is_open
+ }
+
+ pub fn get_id(&self) -> usize {
+ self.id
+ }
+
+ pub fn is_within_range(&self, x: f32, y: f32) -> bool {
+ let a = (self.x + 96f32 / 2f32) - x;
+ let b = (self.y + 80f32) - y;
+ (a * a + b * b).sqrt() <= self.enter_radius
+ }
+
+ pub fn get_x(&self) -> f32 {
+ self.x
+ }
+
+ pub fn get_y(&self) -> f32 {
+ self.y
+ }
+
+ pub fn get_center_x(&self) -> f32 {
+ self.x + 96f32 / 2f32
+ }
+
+ pub fn get_center_y(&self) -> f32 {
+ self.y + 80f32
+ }
+}
--- /dev/null
+use ggez::graphics::{self, Color, DrawMode, DrawParam, Mesh, Rect};
+use ggez::{Context, GameResult};
+
+const DEFAULT_RADIUS: f32 = 70f32;
+
+#[derive(Copy, Clone, PartialEq)]
+pub enum InteractableType {
+ Door(usize),
+}
+
+pub struct Interactable {
+ itype: InteractableType,
+ x: f32,
+ y: f32,
+ radius: f32,
+}
+
+impl Interactable {
+ pub fn new(itype: InteractableType, x: f32, y: f32) -> Self {
+ Self {
+ itype,
+ x,
+ y,
+ radius: DEFAULT_RADIUS,
+ }
+ }
+
+ pub fn is_within_range(&self, x: f32, y: f32) -> bool {
+ let a = self.x - x;
+ let b = self.y - y;
+ (a * a + b * b).sqrt() <= self.radius
+ }
+
+ pub fn get_type(&self) -> InteractableType {
+ self.itype
+ }
+
+ pub fn get_radius(&mut self) -> f32 {
+ self.radius
+ }
+
+ pub fn set_radius(&mut self, radius: f32) {
+ self.radius = radius;
+ }
+
+ pub fn get_x(&self) -> f32 {
+ self.x
+ }
+
+ pub fn get_y(&self) -> f32 {
+ self.y
+ }
+
+ pub fn draw(&self, ctx: &mut Context) -> GameResult<()> {
+ match self.itype {
+ InteractableType::Door(_) => {
+ let panel_mesh = Mesh::new_rectangle(
+ ctx,
+ DrawMode::fill(),
+ Rect::new(0f32, 0f32, 14f32, 16f32),
+ Color::from_rgb(0x16, 0x9c, 0xd8),
+ )?;
+ graphics::draw(
+ ctx,
+ &panel_mesh,
+ DrawParam::new().dest([self.x - 7f32, self.y - 8f32]),
+ )?;
+ }
+ }
+
+ Ok(())
+ }
+}
use ggez::{Context, GameResult};
use super::Scene;
+use crate::door::Door;
+use crate::interactable::{Interactable, InteractableType};
use crate::player::Player;
const DARKNESS_PAN_RATE: f32 = 40f32;
enum Room {
StasisPod,
+ LeftOfPod,
}
enum WalkingState {
index: usize,
room: Room,
walking_state: WalkingState,
+ door_image: Image,
+ interactables: Vec<Interactable>,
+ interact_text: Text,
+ doors: Vec<Door>,
+ door_text: Text,
}
impl MainScene {
let mut music = Source::new(ctx, "/music00.ogg").unwrap();
music.set_repeat(true);
// music.play().unwrap();
- let mut current_text = Text::new("".to_owned());
+ let mut current_text = Text::new("");
current_text.set_font(font, Scale::uniform(26f32));
+ let mut interact_text = Text::new("[E] or Left Click to Interact");
+ interact_text.set_font(font, Scale::uniform(20f32));
+ let mut door_text = Text::new("[W] or Right Click to enter door");
+ door_text.set_font(font, Scale::uniform(20f32));
Self {
font,
player,
index: 0usize,
room: Room::StasisPod,
walking_state: WalkingState::Standing,
+ door_image: Image::new(ctx, "/door.png").unwrap(),
+ interactables: Vec::new(),
+ interact_text,
+ doors: Vec::new(),
+ door_text,
}
}
pub fn new_boxed(ctx: &mut Context, font: Font, player: Rc<RefCell<Player>>) -> Box<Self> {
Box::new(Self::new(ctx, font, player))
}
+
+ fn init_room(&mut self) {
+ match self.room {
+ Room::StasisPod => {
+ self.current_text = Text::new("A and D or Left and Right or Left Click to move");
+ self.current_text.set_font(self.font, Scale::uniform(26f32));
+ self.darkness_yoffset = -300f32;
+ self.interactables.clear();
+ self.doors.clear();
+ }
+ Room::LeftOfPod => {
+ self.current_text = Text::new("");
+ self.current_text.set_font(self.font, Scale::uniform(26f32));
+ self.interactables.clear();
+ self.interactables.push(Interactable::new(
+ InteractableType::Door(0),
+ 430f32,
+ 450f32,
+ ));
+ self.darkness_yoffset = -300f32;
+ self.doors.clear();
+ self.doors
+ .push(Door::new(false, 300f32, 600f32 - 160f32 - 50f32, 0));
+ }
+ }
+ }
+
+ fn draw_room_arrows(&mut self, ctx: &mut Context) -> GameResult<()> {
+ let mut draw_left = false;
+ let mut draw_right = false;
+ match self.room {
+ Room::StasisPod => {
+ draw_left = true;
+ }
+ Room::LeftOfPod => {
+ draw_right = true;
+ }
+ }
+
+ if draw_left {
+ let mesh = Mesh::from_triangles(
+ ctx,
+ &[[32f32, 0f32], [32f32, 32f32], [0f32, 16f32]],
+ graphics::WHITE,
+ )?;
+ graphics::draw(ctx, &mesh, DrawParam::new().dest([32f32, 530f32]))?;
+ }
+ if draw_right {
+ let mesh = Mesh::from_triangles(
+ ctx,
+ &[[0f32, 0f32], [32f32, 16f32], [0f32, 32f32]],
+ graphics::WHITE,
+ )?;
+ graphics::draw(ctx, &mesh, DrawParam::new().dest([800f32 - 64f32, 530f32]))?;
+ }
+
+ Ok(())
+ }
+
+ fn check_exit_left(&mut self) {
+ match self.room {
+ Room::StasisPod => {
+ self.room = Room::LeftOfPod;
+ self.player.borrow_mut().x = 800f32 - 70f32;
+ self.init_room();
+ }
+ Room::LeftOfPod => (),
+ }
+ }
+
+ fn check_exit_right(&mut self) {
+ match self.room {
+ Room::StasisPod => (),
+ Room::LeftOfPod => {
+ self.room = Room::StasisPod;
+ self.player.borrow_mut().x = 70f32;
+ self.init_room();
+ }
+ }
+ }
+
+ fn use_interactable(&mut self, itype: InteractableType) {
+ match itype {
+ InteractableType::Door(id) => {
+ self.doors[id].toggle_open();
+ }
+ }
+ }
}
impl EventHandler for MainScene {
} else if self.timer <= 0f32 {
self.state = State::Investigate;
self.music.play()?;
+ self.init_room();
}
}
State::Investigate => {
- let mut player = self.player.borrow_mut();
match self.walking_state {
WalkingState::Standing => {
- player.set_walking(false);
+ self.player.borrow_mut().set_walking(false);
}
WalkingState::Left => {
- player.x -= dt * PLAYER_MOVEMENT_SPEED;
- if player.x <= 0f32 {
- player.x = 0f32;
+ self.player.borrow_mut().x -= dt * PLAYER_MOVEMENT_SPEED;
+ if self.player.borrow().x <= 0f32 {
+ self.player.borrow_mut().x = 0f32;
self.walking_state = WalkingState::Standing;
- player.set_walking(false);
+ self.player.borrow_mut().set_walking(false);
+ self.check_exit_left();
} else {
- player.set_walking(true);
- player.set_xflip(true);
+ self.player.borrow_mut().set_walking(true);
+ self.player.borrow_mut().set_xflip(true);
}
}
WalkingState::Right => {
- player.x += dt * PLAYER_MOVEMENT_SPEED;
- if player.x + 64f32 >= 800f32 {
- player.x = 800f32 - 64f32;
+ self.player.borrow_mut().x += dt * PLAYER_MOVEMENT_SPEED;
+ if self.player.borrow().x + 64f32 >= 800f32 {
+ self.player.borrow_mut().x = 800f32 - 64f32;
self.walking_state = WalkingState::Standing;
- player.set_walking(false);
+ self.player.borrow_mut().set_walking(false);
+ self.check_exit_right();
} else {
- player.set_walking(true);
- player.set_xflip(false);
+ self.player.borrow_mut().set_walking(true);
+ self.player.borrow_mut().set_xflip(false);
}
}
}
+ match self.room {
+ Room::StasisPod => (),
+ Room::LeftOfPod => (),
+ }
}
}
self.player.borrow_mut().update(ctx)?;
DrawParam::new().dest([600f32, 170f32]).rotation(0.7f32),
)?;
}
+ Room::LeftOfPod => {}
+ }
+ for door in &self.doors {
+ door.draw(ctx, &self.door_image)?;
+ }
+ for interactable in &self.interactables {
+ interactable.draw(ctx)?;
}
self.player.borrow_mut().draw(ctx)?;
}
)?;
}
State::GetOutOfPod => (),
- State::Investigate => (),
+ State::Investigate => {
+ match self.room {
+ Room::StasisPod => {
+ graphics::draw(
+ ctx,
+ &self.current_text,
+ DrawParam::new()
+ .dest([100f32, 100f32])
+ .color(graphics::WHITE),
+ )?;
+ }
+ Room::LeftOfPod => {
+ for interactable in &self.interactables {
+ if interactable.is_within_range(
+ self.player.borrow().x + 32f32,
+ self.player.borrow().y + 64f32,
+ ) {
+ let text_offset = (self.interact_text.width(ctx) / 2) as f32;
+ graphics::draw(
+ ctx,
+ &self.interact_text,
+ DrawParam::new().dest([
+ interactable.get_x() - text_offset,
+ interactable.get_y() - 50f32,
+ ]),
+ )?;
+ }
+ }
+ for door in &self.doors {
+ if door.is_within_range(
+ self.player.borrow().x + 32f32,
+ self.player.borrow().y + 64f32,
+ ) && door.get_open()
+ {
+ let text_offset = (self.door_text.width(ctx) / 2) as f32;
+ graphics::draw(
+ ctx,
+ &self.door_text,
+ DrawParam::new().dest([
+ door.get_center_x() - text_offset,
+ door.get_y() - 15f32,
+ ]),
+ )?;
+ }
+ }
+ }
+ }
+
+ self.draw_room_arrows(ctx)?;
+ }
}
Ok(())
State::GetOutOfPod => (),
State::Investigate => {
if button == MouseButton::Left {
- let player = self.player.borrow();
- if player.x > x {
+ let mut itype: Option<InteractableType> = None;
+ for interactable in &self.interactables {
+ if interactable.is_within_range(
+ self.player.borrow().x + 32f32,
+ self.player.borrow().y + 64f32,
+ ) && interactable.is_within_range(x, y)
+ {
+ itype = Some(interactable.get_type());
+ break;
+ }
+ }
+ if let Some(it) = itype {
+ self.use_interactable(it);
+ } else if self.player.borrow().x > x {
self.walking_state = WalkingState::Left;
- } else if player.x + 64f32 < x {
+ } else if self.player.borrow().x + 64f32 < x {
self.walking_state = WalkingState::Right;
}
}
if self.player.borrow().x + 64f32 < 800f32 {
self.walking_state = WalkingState::Right;
}
+ } else if keycode == KeyCode::E {
+ let mut itype: Option<InteractableType> = None;
+ for interactable in &self.interactables {
+ if interactable.is_within_range(
+ self.player.borrow().x + 32f32,
+ self.player.borrow().y + 64f32,
+ ) {
+ itype = Some(interactable.get_type());
+ break;
+ }
+ }
+ if let Some(it) = itype {
+ self.use_interactable(it);
+ }
}
}
}