Merge branch 'master' into assets

This commit is contained in:
wm-c 2021-04-25 16:06:50 -04:00
commit f1a071f5da
15 changed files with 260 additions and 65 deletions

3
.gitignore vendored
View File

@ -15,4 +15,5 @@ Cargo.lock
/target
.project
.project
savestate.json

View File

@ -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
View 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);
}

View File

@ -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 ./

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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");
}

View File

@ -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));

View File

@ -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;
}
}

View File

@ -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,

View File

@ -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
View 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;
}
}

View File

@ -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

View File

@ -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")?,