Merge branch 'master' into assets
This commit is contained in:
commit
f1a071f5da
3
.gitignore
vendored
3
.gitignore
vendored
@ -15,4 +15,5 @@ Cargo.lock
|
||||
|
||||
/target
|
||||
|
||||
.project
|
||||
.project
|
||||
savestate.json
|
@ -1,5 +1,5 @@
|
||||
[package]
|
||||
name = "one-breath"
|
||||
name = "pink-man-swim"
|
||||
version = "0.1.0"
|
||||
authors = ["Evan Pratten <ewpratten@gmail.com>"]
|
||||
edition = "2018"
|
||||
|
32
assets/shaders/pixel.fs
Normal file
32
assets/shaders/pixel.fs
Normal file
@ -0,0 +1,32 @@
|
||||
#version 330
|
||||
|
||||
// Input vertex attributes (from vertex shader)
|
||||
in vec2 fragTexCoord;
|
||||
in vec4 fragColor;
|
||||
|
||||
// Input uniform values
|
||||
uniform sampler2D texture0;
|
||||
uniform vec4 colDiffuse;
|
||||
|
||||
// Output fragment color
|
||||
out vec4 finalColor;
|
||||
|
||||
// Viewport dimensions
|
||||
const float renderWidth = 1080;
|
||||
const float renderHeight = 720;
|
||||
|
||||
// Pixel scaling
|
||||
uniform float pixelWidth = 2.0;
|
||||
uniform float pixelHeight = 2.0;
|
||||
|
||||
void main()
|
||||
{
|
||||
float dx = pixelWidth * (1.0 / renderWidth);
|
||||
float dy = pixelHeight * (1.0 / renderHeight);
|
||||
|
||||
vec2 coord = vec2(dx * floor(fragTexCoord.x / dx), dy * floor(fragTexCoord.y / dy));
|
||||
|
||||
vec3 tc = texture(texture0, coord).rgb;
|
||||
|
||||
finalColor = vec4(tc, 1.0);
|
||||
}
|
@ -9,10 +9,10 @@ set -e
|
||||
# Make a uni-bundle
|
||||
echo "Creating a fat bundle for all platforms"
|
||||
rm -rf ./bundle/release
|
||||
rm -rf ./bundle/one-breath.zip
|
||||
rm -rf ./bundle/pink-man-swim.zip
|
||||
mkdir -p ./bundle/release
|
||||
cp -r ./assets ./bundle/release
|
||||
cp ./bundle/linux/release/one-breath ./bundle/release/one-breath
|
||||
cp ./bundle/windows/release/one-breath.exe ./bundle/release/one-breath.exe
|
||||
cp ./bundle/linux/release/pink-man-swim ./bundle/release/pink-man-swim
|
||||
cp ./bundle/windows/release/pink-man-swim.exe ./bundle/release/pink-man-swim.exe
|
||||
cd ./bundle/release
|
||||
zip -r ../one-breath.zip ./
|
||||
zip -r ../pink-man-swim.zip ./
|
@ -12,7 +12,7 @@ rm -rf ./bundle/linux/release-x86_64-unknown-linux-gnu.zip
|
||||
mkdir -p ./bundle/linux/release
|
||||
|
||||
echo "Copying binary"
|
||||
cp ./target/x86_64-unknown-linux-gnu/release/one-breath ./bundle/linux/release
|
||||
cp ./target/x86_64-unknown-linux-gnu/release/pink-man-swim ./bundle/linux/release
|
||||
|
||||
echo "Copying assets"
|
||||
cp -r ./assets ./bundle/linux/release
|
||||
|
@ -11,7 +11,7 @@ rm -rf ./bundle/windows/release-x86_64-pc-windows-gnu.zip
|
||||
mkdir -p ./bundle/windows/release
|
||||
|
||||
echo "Copying binary"
|
||||
cp ./target/x86_64-pc-windows-gnu/release/one-breath.exe ./bundle/windows/release
|
||||
cp ./target/x86_64-pc-windows-gnu/release/pink-man-swim.exe ./bundle/windows/release
|
||||
|
||||
echo "Copying assets"
|
||||
cp -r ./assets ./bundle/windows/release
|
||||
|
@ -1,4 +1,8 @@
|
||||
use crate::{lib::utils::calculate_linear_slide, pallette::{TRANSLUCENT_RED_64, TRANSLUCENT_WHITE_128, TRANSLUCENT_WHITE_64}, player::Player};
|
||||
use crate::{
|
||||
lib::utils::calculate_linear_slide,
|
||||
pallette::{TRANSLUCENT_RED_64, TRANSLUCENT_WHITE_128, TRANSLUCENT_WHITE_64},
|
||||
player::Player,
|
||||
};
|
||||
|
||||
use super::base::EnemyBase;
|
||||
use rand::{prelude::ThreadRng, Rng};
|
||||
@ -71,7 +75,8 @@ impl EnemyBase for Octopus {
|
||||
|
||||
// Every once in a while, start sucking air
|
||||
if (context_2d.get_time() % OCTOPUS_SUCK_AIR_DELAY) < 0.1
|
||||
&& self.suck_air_time_remaining == 0.0 && !is_octopus_stunned
|
||||
&& self.suck_air_time_remaining == 0.0
|
||||
&& !is_octopus_stunned
|
||||
{
|
||||
self.suck_air_time_remaining = OCTOPUS_SUCK_AIR_DURATION;
|
||||
self.has_taken_air_from_player = false;
|
||||
@ -107,15 +112,22 @@ impl EnemyBase for Octopus {
|
||||
self.suck_air_bubbles.clear();
|
||||
}
|
||||
|
||||
// TODO: TMP
|
||||
context_2d.draw_circle_v(self.current_position, 10.0, Color::RED);
|
||||
// Render animation
|
||||
if self.suck_air_time_remaining > 0.0 {
|
||||
resources
|
||||
.octopus_animation_attack
|
||||
.draw(context_2d, self.current_position, 0.0);
|
||||
} else {
|
||||
resources
|
||||
.octopus_animation_regular
|
||||
.draw(context_2d, self.current_position, 0.0);
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_logic(&mut self, player: &mut crate::player::Player, dt: f64) {
|
||||
if self.suck_air_time_remaining > 0.0 && !self.has_taken_air_from_player {
|
||||
if player.position.distance_to(self.current_position).abs() <= OCTOPUS_SUCK_AIR_RANGE {
|
||||
// Take air from the player
|
||||
println!("Stealing");
|
||||
player.breath_percent -= OCTOPUS_SUCK_AIR_AMOUNT;
|
||||
|
||||
// Set the flag
|
||||
|
@ -25,7 +25,8 @@ pub enum GameState {
|
||||
GameQuit,
|
||||
InGame,
|
||||
GameEnd,
|
||||
InShop
|
||||
InShop,
|
||||
WinGame
|
||||
}
|
||||
|
||||
impl fmt::Display for GameState {
|
||||
@ -87,7 +88,7 @@ impl GameProgress {
|
||||
// self.fastest_time = self.fastest_time.min(new_progress.fastest_time);
|
||||
|
||||
// Write to file
|
||||
let result = self.to_file("./assets/savestate.json".to_string());
|
||||
let result = self.to_file("./savestate.json".to_string());
|
||||
if result.is_err() {
|
||||
println!("Could not save game state. Holding in RAM");
|
||||
}
|
||||
|
@ -25,9 +25,8 @@ impl Screen for GameEndScreen {
|
||||
audio_system: &mut AudioPlayer,
|
||||
game_core: &mut GameCore,
|
||||
) -> Option<GameState> {
|
||||
let mouse_position = draw_handle.get_mouse_position();
|
||||
// draw_handle.clear_background(Color::GRAY);
|
||||
// // TODO: Maybe we can stick some art here?
|
||||
draw_handle.clear_background(Color::GRAY);
|
||||
// TODO: Maybe we can stick some art here?
|
||||
|
||||
// Render the background
|
||||
draw_handle.draw_texture(&game_core.resources.shop_background, 0, 0, Color::WHITE);
|
||||
@ -71,7 +70,7 @@ impl Screen for GameEndScreen {
|
||||
Color::BLACK,
|
||||
);
|
||||
|
||||
// Render button
|
||||
// Creates
|
||||
let go_to_menu_button = OnScreenButton::new(
|
||||
String::from("Return to shop"),
|
||||
Rectangle {
|
||||
@ -88,8 +87,10 @@ impl Screen for GameEndScreen {
|
||||
true,
|
||||
);
|
||||
|
||||
// render button
|
||||
go_to_menu_button.render(draw_handle);
|
||||
|
||||
// If the player clicks on the button send them to shop
|
||||
if go_to_menu_button.is_hovered(draw_handle) && draw_handle.is_mouse_button_pressed(MouseButton::MOUSE_LEFT_BUTTON){
|
||||
|
||||
game_core.switch_state(GameState::InShop, Some(draw_handle));
|
||||
|
@ -154,9 +154,6 @@ impl Screen for InGameScreen {
|
||||
// Calculate DT
|
||||
let dt = draw_handle.get_time() - game_core.last_frame_time;
|
||||
|
||||
// Clear frame
|
||||
draw_handle.clear_background(Color::BLACK);
|
||||
|
||||
// Handle the pause menu being opened
|
||||
if draw_handle.is_key_pressed(KeyboardKey::KEY_ESCAPE) {
|
||||
return Some(GameState::PauseMenu);
|
||||
@ -176,38 +173,68 @@ impl Screen for InGameScreen {
|
||||
|
||||
// Open a 2D context
|
||||
{
|
||||
let mut context_2d = draw_handle.begin_mode2D(game_core.master_camera);
|
||||
|
||||
// Render the world
|
||||
self.render_world(&mut context_2d, game_core, dt);
|
||||
if game_core.show_simple_debug_info {
|
||||
self.render_colliders(&mut context_2d, game_core);
|
||||
unsafe {
|
||||
raylib::ffi::BeginTextureMode(*game_core.resources.shader_texture);
|
||||
}
|
||||
{
|
||||
let mut context_2d = draw_handle.begin_mode2D(game_core.master_camera);
|
||||
|
||||
// Render entities
|
||||
for jellyfish in game_core.world.jellyfish.iter_mut() {
|
||||
jellyfish.handle_logic(&mut game_core.player, dt);
|
||||
jellyfish.render(
|
||||
&mut context_2d,
|
||||
&mut game_core.player,
|
||||
&mut game_core.resources,
|
||||
dt,
|
||||
);
|
||||
}
|
||||
for octopus in game_core.world.octopus.iter_mut() {
|
||||
octopus.handle_logic(&mut game_core.player, dt);
|
||||
octopus.render(
|
||||
&mut context_2d,
|
||||
&mut game_core.player,
|
||||
&mut game_core.resources,
|
||||
dt,
|
||||
);
|
||||
}
|
||||
// Clear frame
|
||||
context_2d.clear_background(Color::BLACK);
|
||||
|
||||
// Render Player
|
||||
game_core
|
||||
.player
|
||||
.render(&mut context_2d, &mut game_core.resources, dt);
|
||||
// Render the world
|
||||
self.render_world(&mut context_2d, game_core, dt);
|
||||
if game_core.show_simple_debug_info {
|
||||
self.render_colliders(&mut context_2d, game_core);
|
||||
}
|
||||
|
||||
// Render entities
|
||||
for jellyfish in game_core.world.jellyfish.iter_mut() {
|
||||
jellyfish.handle_logic(&mut game_core.player, dt);
|
||||
jellyfish.render(
|
||||
&mut context_2d,
|
||||
&mut game_core.player,
|
||||
&mut game_core.resources,
|
||||
dt,
|
||||
);
|
||||
}
|
||||
for octopus in game_core.world.octopus.iter_mut() {
|
||||
octopus.handle_logic(&mut game_core.player, dt);
|
||||
octopus.render(
|
||||
&mut context_2d,
|
||||
&mut game_core.player,
|
||||
&mut game_core.resources,
|
||||
dt,
|
||||
);
|
||||
}
|
||||
|
||||
// Render Player
|
||||
game_core
|
||||
.player
|
||||
.render(&mut context_2d, &mut game_core.resources, dt);
|
||||
}
|
||||
unsafe {
|
||||
raylib::ffi::EndTextureMode();
|
||||
}
|
||||
}
|
||||
|
||||
// Render the 2D context via the ripple shader
|
||||
{
|
||||
let mut shader_context =
|
||||
draw_handle.begin_shader_mode(&game_core.resources.pixel_shader);
|
||||
|
||||
// Blit the texture
|
||||
shader_context.draw_texture_rec(
|
||||
&game_core.resources.shader_texture,
|
||||
Rectangle {
|
||||
x: 0.0,
|
||||
y: 0.0,
|
||||
width: game_core.resources.shader_texture.width() as f32,
|
||||
height: (game_core.resources.shader_texture.height() as f32) * -1.0,
|
||||
},
|
||||
Vector2::zero(),
|
||||
Color::WHITE,
|
||||
);
|
||||
}
|
||||
|
||||
// Render the darkness layer
|
||||
@ -216,12 +243,15 @@ impl Screen for InGameScreen {
|
||||
// Render the hud
|
||||
hud::render_hud(draw_handle, game_core, window_center);
|
||||
|
||||
|
||||
// Handle player out of breath
|
||||
if game_core.player.breath_percent == 0.0 {
|
||||
return Some(GameState::GameEnd);
|
||||
}
|
||||
|
||||
if game_core.world.end_position.distance_to(game_core.player.position) <= 70.0{
|
||||
return Some(GameState::WinGame);
|
||||
}
|
||||
|
||||
return None;
|
||||
}
|
||||
}
|
||||
|
@ -35,8 +35,8 @@ impl Screen for MainMenuScreen {
|
||||
|
||||
// Render title
|
||||
draw_handle.draw_text(
|
||||
"ONE BREATH",
|
||||
(win_height / 2) - 80,
|
||||
"PINK MAN SWIM",
|
||||
(win_height / 2) - 120,
|
||||
win_width / 8,
|
||||
80,
|
||||
Color::BLACK,
|
||||
|
@ -4,4 +4,5 @@ pub mod mainmenu;
|
||||
pub mod pausemenu;
|
||||
pub mod ingame;
|
||||
pub mod gameend;
|
||||
pub mod shop;
|
||||
pub mod shop;
|
||||
pub mod winscreen;
|
93
src/logic/winscreen.rs
Normal file
93
src/logic/winscreen.rs
Normal file
@ -0,0 +1,93 @@
|
||||
use raylib::prelude::*;
|
||||
|
||||
use crate::lib::utils::button::OnScreenButton;
|
||||
use crate::{
|
||||
gamecore::{GameCore, GameState},
|
||||
lib::wrappers::audio::player::AudioPlayer,
|
||||
};
|
||||
|
||||
use super::screen::Screen;
|
||||
|
||||
const SCREEN_PANEL_SIZE: Vector2 = Vector2 { x: 300.0, y: 300.0 };
|
||||
|
||||
pub struct WinScreen {}
|
||||
|
||||
impl WinScreen {
|
||||
pub fn new() -> Self {
|
||||
return Self {};
|
||||
}
|
||||
}
|
||||
|
||||
impl Screen for WinScreen {
|
||||
fn render(
|
||||
&mut self,
|
||||
draw_handle: &mut RaylibDrawHandle,
|
||||
thread: &RaylibThread,
|
||||
audio_system: &mut AudioPlayer,
|
||||
game_core: &mut GameCore,
|
||||
) -> Option<GameState> {
|
||||
let win_height = draw_handle.get_screen_height();
|
||||
let win_width = draw_handle.get_screen_width();
|
||||
|
||||
// Render the backing to the menu itself
|
||||
draw_handle.draw_rectangle(
|
||||
(win_width / 2) - ((SCREEN_PANEL_SIZE.x as i32 + 6) / 2),
|
||||
(win_height / 2) - ((SCREEN_PANEL_SIZE.y as i32 + 6) / 2),
|
||||
SCREEN_PANEL_SIZE.x as i32 + 6,
|
||||
SCREEN_PANEL_SIZE.y as i32 + 6,
|
||||
Color::BLACK,
|
||||
);
|
||||
draw_handle.draw_rectangle(
|
||||
(win_width / 2) - (SCREEN_PANEL_SIZE.x as i32 / 2),
|
||||
(win_height / 2) - (SCREEN_PANEL_SIZE.y as i32 / 2),
|
||||
SCREEN_PANEL_SIZE.x as i32,
|
||||
SCREEN_PANEL_SIZE.y as i32,
|
||||
Color::WHITE,
|
||||
);
|
||||
|
||||
// Render heading text
|
||||
draw_handle.draw_text(
|
||||
"You've Won!!",
|
||||
(win_width / 2) - ((SCREEN_PANEL_SIZE.x as i32 + 6) / 2) + 60,
|
||||
(win_height / 2) - (SCREEN_PANEL_SIZE.y as i32 / 2) + 10,
|
||||
30,
|
||||
Color::BLACK,
|
||||
);
|
||||
|
||||
// Render message
|
||||
draw_handle.draw_text(
|
||||
"You can use the transponder to \ncontact help!",
|
||||
((win_width / 2) - ((SCREEN_PANEL_SIZE.x as i32 + 6) / 2)) + (0.15 * SCREEN_PANEL_SIZE.x)as i32,
|
||||
(win_height / 2) - (SCREEN_PANEL_SIZE.y as i32 / 2) + 80,
|
||||
15,
|
||||
Color::BLACK,
|
||||
);
|
||||
|
||||
// Render button
|
||||
let go_to_menu_button = OnScreenButton::new(
|
||||
String::from("Return to menu"),
|
||||
Rectangle {
|
||||
x: (((win_width / 2) - ((SCREEN_PANEL_SIZE.x as i32 + 6) / 2) + 5)
|
||||
+ (0.15 * SCREEN_PANEL_SIZE.x) as i32) as f32,
|
||||
y: (((win_height / 2) - (SCREEN_PANEL_SIZE.y as i32 / 2) + 90) as f32) + 100.0,
|
||||
width: 210.0,
|
||||
height: 50.0,
|
||||
},
|
||||
Color::WHITE,
|
||||
Color::BLACK,
|
||||
Color::GRAY,
|
||||
25,
|
||||
true,
|
||||
);
|
||||
|
||||
go_to_menu_button.render(draw_handle);
|
||||
|
||||
if go_to_menu_button.is_hovered(draw_handle)
|
||||
&& draw_handle.is_mouse_button_pressed(MouseButton::MOUSE_LEFT_BUTTON)
|
||||
{
|
||||
game_core.switch_state(GameState::MainMenu, Some(draw_handle));
|
||||
}
|
||||
|
||||
return None;
|
||||
}
|
||||
}
|
14
src/main.rs
14
src/main.rs
@ -11,10 +11,7 @@ mod world;
|
||||
use gamecore::{GameCore, GameProgress, GameState};
|
||||
use lib::{utils::profiler::GameProfiler, wrappers::audio::player::AudioPlayer};
|
||||
use log::info;
|
||||
use logic::{
|
||||
gameend::GameEndScreen, ingame::InGameScreen, loadingscreen::LoadingScreen,
|
||||
mainmenu::MainMenuScreen, pausemenu::PauseMenuScreen, screen::Screen, shop::ShopScreen,
|
||||
};
|
||||
use logic::{gameend::GameEndScreen, ingame::InGameScreen, loadingscreen::LoadingScreen, mainmenu::MainMenuScreen, pausemenu::PauseMenuScreen, screen::Screen, shop::ShopScreen, winscreen::{self, WinScreen}};
|
||||
use raylib::prelude::*;
|
||||
use world::{load_world_colliders, World};
|
||||
|
||||
@ -54,7 +51,7 @@ fn main() {
|
||||
.expect("Failed to load main world JSON");
|
||||
|
||||
// Load the game progress
|
||||
let game_progress = GameProgress::try_from_file("./assets/savestate.json".to_string());
|
||||
let game_progress = GameProgress::try_from_file("./savestate.json".to_string());
|
||||
|
||||
// Set up the game's core state
|
||||
let mut game_core = GameCore::new(&mut raylib, &raylib_thread, world, game_progress);
|
||||
@ -75,6 +72,7 @@ fn main() {
|
||||
let mut ingame_screen = InGameScreen::new();
|
||||
let mut game_end_screen = GameEndScreen::new();
|
||||
let mut shop_screen = ShopScreen::new();
|
||||
let mut win_screen = WinScreen::new();
|
||||
|
||||
// Main rendering loop
|
||||
while !raylib.window_should_close() {
|
||||
@ -119,6 +117,12 @@ fn main() {
|
||||
&mut audio_system,
|
||||
&mut game_core,
|
||||
),
|
||||
GameState::WinGame => win_screen.render(
|
||||
&mut draw_handle,
|
||||
&raylib_thread,
|
||||
&mut audio_system,
|
||||
&mut game_core,
|
||||
)
|
||||
};
|
||||
|
||||
// If needed, update the global state
|
||||
|
@ -1,9 +1,5 @@
|
||||
use failure::Error;
|
||||
use raylib::{
|
||||
math::Vector2,
|
||||
texture::{Image, Texture2D},
|
||||
RaylibHandle, RaylibThread,
|
||||
};
|
||||
use raylib::{RaylibHandle, RaylibThread, math::Vector2, shaders::Shader, texture::{Image, RenderTexture2D, Texture2D}};
|
||||
|
||||
use crate::lib::wrappers::animation::FrameAnimationWrapper;
|
||||
|
||||
@ -24,10 +20,14 @@ pub struct GlobalResources {
|
||||
|
||||
// Cave
|
||||
pub cave_mid_layer: Texture2D,
|
||||
pub pixel_shader: Shader,
|
||||
pub shader_texture: RenderTexture2D,
|
||||
|
||||
// Enemies
|
||||
pub jellyfish_animation_regular: FrameAnimationWrapper,
|
||||
pub jellyfish_animation_attack: FrameAnimationWrapper,
|
||||
pub octopus_animation_regular: FrameAnimationWrapper,
|
||||
pub octopus_animation_attack: FrameAnimationWrapper,
|
||||
|
||||
// Darkness layer
|
||||
pub darkness_overlay: Texture2D,
|
||||
@ -125,6 +125,8 @@ impl GlobalResources {
|
||||
&thread,
|
||||
&Image::load_image("./assets/img/map/cave.png")?,
|
||||
)?,
|
||||
pixel_shader: raylib.load_shader(&thread, None, Some("./assets/shaders/pixel.fs"))?,
|
||||
shader_texture: raylib.load_render_texture(&thread, raylib.get_screen_width() as u32, raylib.get_screen_height() as u32)?,
|
||||
jellyfish_animation_regular: FrameAnimationWrapper::new(
|
||||
raylib.load_texture_from_image(
|
||||
&thread,
|
||||
@ -143,6 +145,24 @@ impl GlobalResources {
|
||||
15,
|
||||
4,
|
||||
),
|
||||
octopus_animation_regular: FrameAnimationWrapper::new(
|
||||
raylib.load_texture_from_image(
|
||||
&thread,
|
||||
&Image::load_image("./assets/img/enemies/octopus.png")?,
|
||||
)?,
|
||||
Vector2 { x: 20.0, y: 20.0 },
|
||||
6,
|
||||
4,
|
||||
),
|
||||
octopus_animation_attack: FrameAnimationWrapper::new(
|
||||
raylib.load_texture_from_image(
|
||||
&thread,
|
||||
&Image::load_image("./assets/img/enemies/octopusSuck.png")?,
|
||||
)?,
|
||||
Vector2 { x: 30.0, y: 20.0 },
|
||||
4,
|
||||
4,
|
||||
),
|
||||
darkness_overlay: raylib.load_texture_from_image(
|
||||
&thread,
|
||||
&Image::load_image("./assets/img/map/darkness.png")?,
|
||||
|
Reference in New Issue
Block a user