mirror of
https://github.com/doukutsu-rs/doukutsu-rs
synced 2025-03-25 03:19:27 +00:00
Touch controls, Android support
This commit is contained in:
parent
3c5f5c7496
commit
82cce198ee
18
Cargo.toml
18
Cargo.toml
|
@ -14,7 +14,7 @@ min_sdk_version = 26
|
|||
build_targets = ["aarch64-linux-android"]
|
||||
package_name = "io.github.doukutsu_rs.android"
|
||||
apk_label = "doukutsu-rs"
|
||||
opengles_version = [2, 0]
|
||||
opengles_version = [3, 1]
|
||||
fullscreen = true
|
||||
orientation = "sensorLandscape"
|
||||
permission = [
|
||||
|
@ -55,11 +55,11 @@ directories = "2"
|
|||
gfx = "0.18"
|
||||
gfx_core = "0.9"
|
||||
gfx_device_gl = {git = "https://github.com/doukutsu-rs/gfx.git", branch = "pre-ll"}
|
||||
ggez = {git = "https://github.com/doukutsu-rs/ggez.git", rev = "aad56b0d173ca9f4aeb28599075b5af49ab9214e"}
|
||||
glutin = {git = "https://github.com/doukutsu-rs/glutin.git", branch = "android-support"}
|
||||
imgui = {git = "https://github.com/Gekkio/imgui-rs.git", rev = "a990a538b66cb67dba3a072bf299b6a51c001447"}
|
||||
imgui-gfx-renderer = {git = "https://github.com/Gekkio/imgui-rs.git", rev = "a990a538b66cb67dba3a072bf299b6a51c001447"}
|
||||
imgui-winit-support = {git = "https://github.com/Gekkio/imgui-rs.git", default-features = false, features = ["winit-23"], rev = "a990a538b66cb67dba3a072bf299b6a51c001447"}
|
||||
ggez = {git = "https://github.com/doukutsu-rs/ggez.git", rev = "43631b0401271d4bc8fe4a5afba8aad63976dba1"}
|
||||
glutin = {git = "https://github.com/doukutsu-rs/glutin.git", branch = "master"}
|
||||
imgui = {git = "https://github.com/Gekkio/imgui-rs.git", rev = "7e2293bde67f869750ab0e649fbfbd842fb0c785"}
|
||||
imgui-gfx-renderer = {git = "https://github.com/Gekkio/imgui-rs.git", rev = "7e2293bde67f869750ab0e649fbfbd842fb0c785"}
|
||||
imgui-winit-support = {git = "https://github.com/Gekkio/imgui-rs.git", default-features = false, features = ["winit-23"], rev = "7e2293bde67f869750ab0e649fbfbd842fb0c785"}
|
||||
image = {version = "0.22", default-features = false, features = ["png_codec", "pnm", "bmp"]}
|
||||
itertools = "0.9.0"
|
||||
lazy_static = "1.4.0"
|
||||
|
@ -77,9 +77,9 @@ strum_macros = "0.18.0"
|
|||
# remove and replace when drain_filter is in stable
|
||||
vec_mut_scan = "0.3.0"
|
||||
webbrowser = "0.5.5"
|
||||
winit = {version = "0.23.0", features = ["serde"]}
|
||||
winit = {version = "0.24.0", features = ["serde"]}
|
||||
|
||||
[target.'cfg(target_os = "android")'.dependencies]
|
||||
ndk = "0.2.0"
|
||||
ndk-glue = "0.2.0"
|
||||
ndk = "0.2"
|
||||
ndk-glue = "0.2"
|
||||
jni = "0.17"
|
||||
|
|
|
@ -67,10 +67,10 @@ impl BMFontRenderer {
|
|||
|
||||
|
||||
pub fn draw_text<I: Iterator<Item=char>>(&self, iter: I, x: f32, y: f32, constants: &EngineConstants, texture_set: &mut TextureSet, ctx: &mut Context) -> GameResult {
|
||||
self.draw_colored_text(iter, x, y, (255, 255, 255), constants, texture_set, ctx)
|
||||
self.draw_colored_text(iter, x, y, (255, 255, 255, 255), constants, texture_set, ctx)
|
||||
}
|
||||
|
||||
pub fn draw_colored_text<I: Iterator<Item=char>>(&self, iter: I, x: f32, y: f32, color: (u8, u8, u8),
|
||||
pub fn draw_colored_text<I: Iterator<Item=char>>(&self, iter: I, x: f32, y: f32, color: (u8, u8, u8, u8),
|
||||
constants: &EngineConstants, texture_set: &mut TextureSet, ctx: &mut Context) -> GameResult {
|
||||
if self.pages.len() == 1 {
|
||||
let batch = texture_set.get_or_load_batch(ctx, constants, self.pages.get(0).unwrap())?;
|
||||
|
|
13
src/builtin/shaders/basic_es100.frag.glsl
Normal file
13
src/builtin/shaders/basic_es100.frag.glsl
Normal file
|
@ -0,0 +1,13 @@
|
|||
#version 300 es
|
||||
|
||||
uniform mediump sampler2D t_Texture;
|
||||
varying mediump vec2 v_Uv;
|
||||
varying mediump vec4 v_Color;
|
||||
|
||||
//uniform mediump mat4 u_MVP;
|
||||
|
||||
mediump vec4 Target0;
|
||||
|
||||
void main() {
|
||||
gl_FragColor = texture2D(t_Texture, v_Uv) * v_Color;
|
||||
}
|
26
src/builtin/shaders/basic_es100.vert.glsl
Normal file
26
src/builtin/shaders/basic_es100.vert.glsl
Normal file
|
@ -0,0 +1,26 @@
|
|||
#version 300 es
|
||||
|
||||
attribute mediump vec2 a_Pos;
|
||||
attribute mediump vec2 a_Uv;
|
||||
attribute mediump vec4 a_VertColor;
|
||||
|
||||
attribute mediump vec4 a_Src;
|
||||
attribute mediump vec4 a_TCol1;
|
||||
attribute mediump vec4 a_TCol2;
|
||||
attribute mediump vec4 a_TCol3;
|
||||
attribute mediump vec4 a_TCol4;
|
||||
attribute mediump vec4 a_Color;
|
||||
|
||||
uniform mediump mat4 u_MVP;
|
||||
|
||||
varying mediump vec2 v_Uv;
|
||||
varying mediump vec4 v_Color;
|
||||
|
||||
void main() {
|
||||
v_Uv = a_Uv * a_Src.zw + a_Src.xy;
|
||||
v_Color = a_Color * a_VertColor;
|
||||
mat4 instance_transform = mat4(a_TCol1, a_TCol2, a_TCol3, a_TCol4);
|
||||
vec4 position = instance_transform * vec4(a_Pos, 0.0, 1.0);
|
||||
|
||||
gl_Position = u_MVP * position;
|
||||
}
|
27
src/builtin/shaders/basic_es300.vert.glsl
Normal file
27
src/builtin/shaders/basic_es300.vert.glsl
Normal file
|
@ -0,0 +1,27 @@
|
|||
#version 300 es
|
||||
|
||||
in vec2 a_Pos;
|
||||
in vec2 a_Uv;
|
||||
|
||||
in vec4 a_Src;
|
||||
in vec4 a_TCol1;
|
||||
in vec4 a_TCol2;
|
||||
in vec4 a_TCol3;
|
||||
in vec4 a_TCol4;
|
||||
in vec4 a_Color;
|
||||
|
||||
layout (std140) uniform Globals {
|
||||
mat4 u_MVP;
|
||||
};
|
||||
|
||||
out vec2 v_Uv;
|
||||
out vec4 v_Color;
|
||||
|
||||
void main() {
|
||||
v_Uv = a_Uv * a_Src.zw + a_Src.xy;
|
||||
v_Color = a_Color;
|
||||
mat4 instance_transform = mat4(a_TCol1, a_TCol2, a_TCol3, a_TCol4);
|
||||
vec4 position = instance_transform * vec4(a_Pos, 0.0, 1.0);
|
||||
|
||||
gl_Position = u_MVP * position;
|
||||
}
|
54
src/builtin/shaders/water_es300.frag.glsl
Normal file
54
src/builtin/shaders/water_es300.frag.glsl
Normal file
|
@ -0,0 +1,54 @@
|
|||
#version 300 es
|
||||
|
||||
precision mediump float;
|
||||
|
||||
uniform sampler2D t_Texture;
|
||||
in vec2 v_Uv;
|
||||
in vec4 v_Color;
|
||||
out vec4 Target0;
|
||||
|
||||
layout (std140) uniform Globals {
|
||||
mat4 u_MVP;
|
||||
};
|
||||
|
||||
layout (std140) uniform WaterShaderParams {
|
||||
vec2 u_Resolution;
|
||||
vec2 u_FramePos;
|
||||
float u_Tick;
|
||||
};
|
||||
|
||||
void main() {
|
||||
vec2 wave = v_Uv;
|
||||
wave.x += sin((-u_FramePos.y / u_Resolution.y + v_Uv.x * 16.0) + u_Tick / 20.0) * 2.0 / u_Resolution.x;
|
||||
wave.y -= cos((-u_FramePos.x / u_Resolution.x + v_Uv.y * 16.0) + u_Tick / 5.0) * 2.0 / u_Resolution.y;
|
||||
float off = 0.4 / u_Resolution.y;
|
||||
vec4 color = texture(t_Texture, wave);
|
||||
color.r = texture(t_Texture, wave + off).r;
|
||||
color.b = texture(t_Texture, wave - off).b;
|
||||
|
||||
Target0 = (vec4(0.4, 0.6, 0.8, 1.0) * 0.3) + (color * v_Color * 0.7);
|
||||
}
|
||||
|
||||
/*
|
||||
precision mediump float;
|
||||
|
||||
uniform sampler2D t_Texture;
|
||||
varying vec2 v_Uv;
|
||||
varying vec4 v_Color;
|
||||
|
||||
uniform mat4 u_MVP;
|
||||
uniform vec2 u_Resolution;
|
||||
uniform vec2 u_FramePos;
|
||||
uniform float u_Tick;
|
||||
|
||||
void main() {
|
||||
vec2 wave = v_Uv;
|
||||
wave.x += sin((-u_FramePos.y / u_Resolution.y + v_Uv.x * 16.0) + u_Tick / 20.0) * 2.0 / u_Resolution.x;
|
||||
wave.y -= cos((-u_FramePos.x / u_Resolution.x + v_Uv.y * 16.0) + u_Tick / 5.0) * 2.0 / u_Resolution.y;
|
||||
float off = 0.4 / u_Resolution.y;
|
||||
vec4 color = texture2D(t_Texture, wave);
|
||||
color.r = texture2D(t_Texture, wave + off).r;
|
||||
color.b = texture2D(t_Texture, wave - off).b;
|
||||
|
||||
gl_FragColor = (vec4(0.4, 0.6, 0.8, 1.0) * 0.3) + (color * v_Color * 0.7);
|
||||
}*/
|
Binary file not shown.
Before Width: | Height: | Size: 967 B After Width: | Height: | Size: 16 KiB |
|
@ -111,9 +111,12 @@ impl BuiltinFS {
|
|||
FSNode::File("builtin_font_0.png", include_bytes!("builtin/builtin_font_0.png")),
|
||||
FSNode::File("builtin_font_1.png", include_bytes!("builtin/builtin_font_1.png")),
|
||||
FSNode::File("pixtone.pcm", include_bytes!("builtin/pixtone.pcm")),
|
||||
FSNode::File("touch.png", include_bytes!("builtin/touch.png")),
|
||||
FSNode::Directory("shaders", vec![
|
||||
FSNode::File("basic_150.vert.glsl", include_bytes!("builtin/shaders/basic_150.vert.glsl")),
|
||||
FSNode::File("water_150.frag.glsl", include_bytes!("builtin/shaders/water_150.frag.glsl")),
|
||||
FSNode::File("basic_es300.vert.glsl", include_bytes!("builtin/shaders/basic_es300.vert.glsl")),
|
||||
FSNode::File("water_es300.frag.glsl", include_bytes!("builtin/shaders/water_es300.frag.glsl")),
|
||||
]),
|
||||
FSNode::Directory("lightmap", vec![
|
||||
FSNode::File("spot.png", include_bytes!("builtin/lightmap/spot.png")),
|
||||
|
|
|
@ -56,8 +56,8 @@ impl HUD {
|
|||
}
|
||||
}
|
||||
|
||||
impl GameEntity<(&Player, &Inventory)> for HUD {
|
||||
fn tick(&mut self, state: &mut SharedGameState, (player, inventory): (&Player, &Inventory)) -> GameResult {
|
||||
impl GameEntity<(&Player, &mut Inventory)> for HUD {
|
||||
fn tick(&mut self, state: &mut SharedGameState, (player, inventory): (&Player, &mut Inventory)) -> GameResult {
|
||||
let (ammo, max_ammo) = inventory.get_current_ammo();
|
||||
let (xp, max_xp, max_level) = inventory.get_current_max_exp(&state.constants);
|
||||
|
||||
|
@ -104,6 +104,56 @@ impl GameEntity<(&Player, &Inventory)> for HUD {
|
|||
self.weapon_x_pos += 2;
|
||||
}
|
||||
|
||||
if player.cond.alive() {
|
||||
if player.controller.trigger_next_weapon() {
|
||||
state.sound_manager.play_sfx(4);
|
||||
inventory.next_weapon();
|
||||
self.weapon_x_pos = 32;
|
||||
}
|
||||
|
||||
if player.controller.trigger_prev_weapon() {
|
||||
state.sound_manager.play_sfx(4);
|
||||
inventory.prev_weapon();
|
||||
self.weapon_x_pos = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// touch handler
|
||||
if state.settings.touch_controls && self.weapon_count != 0 {
|
||||
let mut rect = Rect::new(0, 0, 0, 16);
|
||||
let weapon_offset = match self.alignment {
|
||||
Alignment::Left => 0,
|
||||
Alignment::Right => (state.canvas_size.0 - 104.0) as isize,
|
||||
};
|
||||
|
||||
for a in 0..self.weapon_count {
|
||||
let mut pos_x = ((a as isize - self.current_weapon) * 16) + self.weapon_x_pos as isize;
|
||||
|
||||
if pos_x < 8 {
|
||||
pos_x += 48 + self.weapon_count as isize * 16;
|
||||
} else if pos_x >= 24 {
|
||||
pos_x += 48;
|
||||
}
|
||||
|
||||
if pos_x >= 72 + ((self.weapon_count as isize - 1) * 16) {
|
||||
pos_x -= 48 + self.weapon_count as isize * 16;
|
||||
} else if pos_x < 72 && pos_x >= 24 {
|
||||
pos_x -= 48;
|
||||
}
|
||||
|
||||
let wtype = unsafe { *self.weapon_types.get_unchecked(a) };
|
||||
if wtype != 0 {
|
||||
rect = Rect::new_size(pos_x + weapon_offset - 4, 16 - 4, 24, 24);
|
||||
|
||||
if state.touch_controls.consume_click_in(rect) {
|
||||
state.sound_manager.play_sfx(4);
|
||||
inventory.current_weapon = a as u16;
|
||||
self.weapon_x_pos = 32;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
|
@ -3,12 +3,14 @@ use ggez::{Context, GameResult};
|
|||
use crate::common::Rect;
|
||||
use crate::entity::GameEntity;
|
||||
use crate::frame::Frame;
|
||||
use crate::input::touch_controls::TouchControlType;
|
||||
use crate::player::Player;
|
||||
use crate::shared_game_state::SharedGameState;
|
||||
use crate::text_script::ScriptMode;
|
||||
|
||||
pub struct StageSelect {
|
||||
pub current_teleport_slot: u8,
|
||||
prev_teleport_slot: u8,
|
||||
stage_select_text_y_pos: usize,
|
||||
tick: usize,
|
||||
}
|
||||
|
@ -17,6 +19,7 @@ impl StageSelect {
|
|||
pub fn new() -> StageSelect {
|
||||
StageSelect {
|
||||
current_teleport_slot: 0,
|
||||
prev_teleport_slot: 0,
|
||||
stage_select_text_y_pos: 54,
|
||||
tick: 0,
|
||||
}
|
||||
|
@ -30,6 +33,8 @@ impl StageSelect {
|
|||
|
||||
impl GameEntity<(&Player, &Player)> for StageSelect {
|
||||
fn tick(&mut self, state: &mut SharedGameState, (player1, player2): (&Player, &Player)) -> GameResult {
|
||||
state.touch_controls.control_type = TouchControlType::None;
|
||||
|
||||
let slot_count = state.teleporter_slots.iter()
|
||||
.filter(|&&(index, _event_num)| index != 0)
|
||||
.count();
|
||||
|
@ -44,9 +49,9 @@ impl GameEntity<(&Player, &Player)> for StageSelect {
|
|||
|
||||
let left_pressed = player1.controller.trigger_left() || player2.controller.trigger_left();
|
||||
let right_pressed = player1.controller.trigger_right() || player2.controller.trigger_right();
|
||||
let ok_pressed = player1.controller.trigger_jump() || player1.controller.trigger_menu_ok()
|
||||
let mut ok_pressed = player1.controller.trigger_jump() || player1.controller.trigger_menu_ok()
|
||||
|| player2.controller.trigger_jump() || player2.controller.trigger_menu_ok();
|
||||
let cancel_pressed = player1.controller.trigger_shoot() || player2.controller.trigger_shoot();
|
||||
let mut cancel_pressed = player1.controller.trigger_shoot() || player2.controller.trigger_shoot();
|
||||
|
||||
if left_pressed {
|
||||
if self.current_teleport_slot == 0 {
|
||||
|
@ -62,7 +67,8 @@ impl GameEntity<(&Player, &Player)> for StageSelect {
|
|||
}
|
||||
}
|
||||
|
||||
if left_pressed || right_pressed {
|
||||
if self.prev_teleport_slot != self.current_teleport_slot {
|
||||
self.prev_teleport_slot = self.current_teleport_slot;
|
||||
state.sound_manager.play_sfx(1);
|
||||
if let Some(&(index, _event_num)) = state.teleporter_slots.get(self.current_teleport_slot as usize) {
|
||||
state.textscript_vm.start_script(1000 + index);
|
||||
|
@ -71,6 +77,34 @@ impl GameEntity<(&Player, &Player)> for StageSelect {
|
|||
}
|
||||
}
|
||||
|
||||
if state.settings.touch_controls {
|
||||
let slot_offset = ((state.canvas_size.0 - 40.0 * slot_count as f32) / 2.0).floor();
|
||||
let mut slot_rect;
|
||||
|
||||
for i in 0..slot_count {
|
||||
slot_rect = Rect::new_size(slot_offset as isize + i as isize * 40 - 2, 64 - 8, 36, 32);
|
||||
|
||||
if state.touch_controls.consume_click_in(slot_rect) {
|
||||
if self.current_teleport_slot as usize == i {
|
||||
ok_pressed = true;
|
||||
} else {
|
||||
state.sound_manager.play_sfx(1);
|
||||
self.current_teleport_slot = i as u8;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
slot_rect = Rect::new_size(state.canvas_size.0 as isize - 34, 8, 26, 26);
|
||||
|
||||
if state.touch_controls.consume_click_in(slot_rect) {
|
||||
state.sound_manager.play_sfx(5);
|
||||
cancel_pressed = true;
|
||||
}
|
||||
}
|
||||
|
||||
if ok_pressed || cancel_pressed {
|
||||
self.reset();
|
||||
state.textscript_vm.set_mode(ScriptMode::Map);
|
||||
|
@ -121,6 +155,14 @@ impl GameEntity<(&Player, &Player)> for StageSelect {
|
|||
|
||||
batch.draw(ctx)?;
|
||||
|
||||
if state.settings.touch_controls {
|
||||
let close_rect = Rect { left: 110, top: 110, right: 128, bottom: 128 };
|
||||
let batch = state.texture_set.get_or_load_batch(ctx, &state.constants, "builtin/touch")?;
|
||||
|
||||
batch.add_rect(state.canvas_size.0 - 30.0, 12.0, &close_rect);
|
||||
batch.draw(ctx)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -707,7 +707,7 @@ impl EngineConstants {
|
|||
"Title" => (320, 48),
|
||||
},
|
||||
textscript: TextScriptConsts {
|
||||
encoding: TextScriptEncoding::ShiftJIS,
|
||||
encoding: TextScriptEncoding::UTF8,
|
||||
encrypted: true,
|
||||
animated_face_pics: false,
|
||||
textbox_rect_top: Rect { left: 0, top: 0, right: 244, bottom: 8 },
|
||||
|
@ -741,7 +741,7 @@ impl EngineConstants {
|
|||
},
|
||||
font_path: "builtin/builtin_font.fnt".to_string(),
|
||||
font_scale: 1.0,
|
||||
font_space_offset: -3.0,
|
||||
font_space_offset: 0.0,
|
||||
organya_paths: vec![
|
||||
str!("/org/"), // NXEngine
|
||||
str!("/base/Org/"), // CS+
|
||||
|
|
|
@ -14,7 +14,7 @@ impl DummyPlayerController {
|
|||
}
|
||||
|
||||
impl PlayerController for DummyPlayerController {
|
||||
fn update(&mut self, _state: &SharedGameState, _ctx: &mut Context) -> GameResult {
|
||||
fn update(&mut self, _state: &mut SharedGameState, _ctx: &mut Context) -> GameResult {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
|
@ -23,7 +23,7 @@ bitfield! {
|
|||
pub next_weapon, set_next_weapon: 8;
|
||||
pub prev_weapon, set_prev_weapon: 9;
|
||||
pub escape, set_escape: 10;
|
||||
pub enter, set_enter: 10;
|
||||
pub enter, set_enter: 11;
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
|
@ -46,7 +46,7 @@ impl KeyboardController {
|
|||
}
|
||||
|
||||
impl PlayerController for KeyboardController {
|
||||
fn update(&mut self, state: &SharedGameState, ctx: &mut Context) -> GameResult {
|
||||
fn update(&mut self, state: &mut SharedGameState, ctx: &mut Context) -> GameResult {
|
||||
let keymap = match self.target {
|
||||
TargetPlayer::Player1 => &state.settings.player1_key_map,
|
||||
TargetPlayer::Player2 => &state.settings.player2_key_map,
|
||||
|
|
|
@ -3,3 +3,4 @@ pub mod dummy_player_controller;
|
|||
pub mod keyboard_player_controller;
|
||||
pub mod player_controller;
|
||||
pub mod touch_controls;
|
||||
pub mod touch_player_controller;
|
||||
|
|
|
@ -3,7 +3,7 @@ use ggez::{Context, GameResult};
|
|||
use crate::shared_game_state::SharedGameState;
|
||||
|
||||
pub trait PlayerController: PlayerControllerClone {
|
||||
fn update(&mut self, state: &SharedGameState, ctx: &mut Context) -> GameResult;
|
||||
fn update(&mut self, state: &mut SharedGameState, ctx: &mut Context) -> GameResult;
|
||||
|
||||
fn update_trigger(&mut self);
|
||||
|
||||
|
|
|
@ -5,20 +5,37 @@ use crate::common::Rect;
|
|||
use crate::engine_constants::EngineConstants;
|
||||
use crate::texture_set::TextureSet;
|
||||
|
||||
struct TouchPoint {
|
||||
#[derive(Copy, Clone, PartialEq, Eq)]
|
||||
pub enum TouchControlType {
|
||||
None,
|
||||
Dialog,
|
||||
Controls,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct TouchPoint {
|
||||
id: u64,
|
||||
touch_id: u64,
|
||||
position: (f64, f64),
|
||||
last_position: (f64, f64),
|
||||
}
|
||||
|
||||
pub struct TouchControls {
|
||||
points: Vec<TouchPoint>,
|
||||
pub control_type: TouchControlType,
|
||||
pub points: Vec<TouchPoint>,
|
||||
pub interact_icon: bool,
|
||||
touch_id_counter: u64,
|
||||
clicks: Vec<TouchPoint>,
|
||||
}
|
||||
|
||||
impl TouchControls {
|
||||
pub fn new() -> TouchControls {
|
||||
TouchControls {
|
||||
control_type: TouchControlType::None,
|
||||
touch_id_counter: 0,
|
||||
interact_icon: false,
|
||||
points: Vec::with_capacity(8),
|
||||
clicks: Vec::with_capacity(8),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -27,22 +44,61 @@ impl TouchControls {
|
|||
TouchPhase::Started | TouchPhase::Moved => {
|
||||
if let Some(point) = self.points.iter_mut().find(|p| p.id == touch.id) {
|
||||
point.last_position = point.position;
|
||||
point.position = (touch.location.x, touch.location.y);
|
||||
point.position = (touch.location.x / scale as f64, touch.location.y / scale as f64);
|
||||
} else {
|
||||
self.points.push(TouchPoint {
|
||||
self.touch_id_counter = self.touch_id_counter.wrapping_add(1);
|
||||
|
||||
let point = TouchPoint {
|
||||
id: touch.id,
|
||||
position: (touch.location.x, touch.location.y),
|
||||
touch_id: self.touch_id_counter,
|
||||
position: (touch.location.x / scale as f64, touch.location.y / scale as f64),
|
||||
last_position: (0.0, 0.0),
|
||||
});
|
||||
};
|
||||
self.points.push(point);
|
||||
|
||||
if touch.phase == TouchPhase::Started {
|
||||
self.clicks.push(point);
|
||||
}
|
||||
}
|
||||
}
|
||||
TouchPhase::Ended | TouchPhase::Cancelled => {
|
||||
self.points.retain(|p| p.id != touch.id);
|
||||
self.clicks.retain(|p| p.id != touch.id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn draw(&self, constants: &EngineConstants, texture_set: &mut TextureSet, ctx: &mut Context) -> GameResult {
|
||||
pub fn point_in(&self, bounds: Rect) -> Option<u64> {
|
||||
for point in self.points.iter() {
|
||||
if (point.position.0 as isize) > bounds.left
|
||||
&& (point.position.0 as isize) < bounds.right
|
||||
&& (point.position.1 as isize) > bounds.top
|
||||
&& (point.position.1 as isize) < bounds.bottom {
|
||||
return Some(point.touch_id);
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
pub fn consume_click_in(&mut self, bounds: Rect) -> bool {
|
||||
self.clicks.retain(|p| p.touch_id != 0);
|
||||
|
||||
for point in self.clicks.iter_mut() {
|
||||
if (point.position.0 as isize) > bounds.left
|
||||
&& (point.position.0 as isize) < bounds.right
|
||||
&& (point.position.1 as isize) > bounds.top
|
||||
&& (point.position.1 as isize) < bounds.bottom {
|
||||
point.touch_id = 0;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
|
||||
pub fn draw(&self, canvas_size: (f32, f32), constants: &EngineConstants, texture_set: &mut TextureSet, ctx: &mut Context) -> GameResult {
|
||||
let batch = texture_set.get_or_load_batch(ctx, constants, "Caret")?;
|
||||
let rect = Rect::new_size(104, 120, 24, 24);
|
||||
for point in self.points.iter() {
|
||||
|
@ -51,6 +107,38 @@ impl TouchControls {
|
|||
|
||||
batch.draw(ctx)?;
|
||||
|
||||
if self.control_type == TouchControlType::Controls {
|
||||
let batch = texture_set.get_or_load_batch(ctx, constants, "builtin/touch")?;
|
||||
let color = (255, 255, 255, 160);
|
||||
|
||||
for x in 0..3 {
|
||||
for y in 0..3 {
|
||||
let mut icon_x = x;
|
||||
let icon_y = y;
|
||||
|
||||
if self.interact_icon && x == 1 && y == 2 {
|
||||
icon_x = 3;
|
||||
}
|
||||
|
||||
batch.add_rect_tinted(4.0 + 48.0 * x as f32 + 8.0,
|
||||
(canvas_size.1 - 4.0 - 48.0 * 3.0) + 48.0 * y as f32 + 8.0,
|
||||
color,
|
||||
&Rect::new_size(icon_x * 32, icon_y * 32, 32, 32));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
batch.add_rect_tinted(canvas_size.0 - (4.0 + 48.0) + 8.0, canvas_size.1 - (4.0 + 48.0) + 8.0,
|
||||
color,
|
||||
&Rect::new_size(3 * 32, 32, 32, 32));
|
||||
|
||||
batch.add_rect_tinted(canvas_size.0 - (4.0 + 48.0) + 8.0, canvas_size.1 - (4.0 + 48.0) * 2.0 + 8.0,
|
||||
color,
|
||||
&Rect::new_size(3 * 32, 0, 32, 32));
|
||||
|
||||
batch.draw(ctx)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
219
src/input/touch_player_controller.rs
Normal file
219
src/input/touch_player_controller.rs
Normal file
|
@ -0,0 +1,219 @@
|
|||
use ggez::{Context, GameResult};
|
||||
|
||||
use crate::bitfield;
|
||||
use crate::common::Rect;
|
||||
use crate::input::player_controller::PlayerController;
|
||||
use crate::input::touch_controls::TouchControlType;
|
||||
use crate::shared_game_state::SharedGameState;
|
||||
|
||||
/// A no-op implementation of player controller.
|
||||
#[derive(Clone)]
|
||||
pub struct TouchPlayerController {
|
||||
state: KeyState,
|
||||
old_state: KeyState,
|
||||
trigger: KeyState,
|
||||
prev_touch_len: usize,
|
||||
}
|
||||
|
||||
bitfield! {
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct KeyState(u16);
|
||||
impl Debug;
|
||||
|
||||
pub left, set_left: 0;
|
||||
pub right, set_right: 1;
|
||||
pub up, set_up: 2;
|
||||
pub down, set_down: 3;
|
||||
pub map, set_map: 4;
|
||||
pub inventory, set_inventory: 5;
|
||||
pub jump, set_jump: 6;
|
||||
pub shoot, set_shoot: 7;
|
||||
pub next_weapon, set_next_weapon: 8;
|
||||
pub prev_weapon, set_prev_weapon: 9;
|
||||
pub pause, set_pause: 10;
|
||||
}
|
||||
|
||||
impl TouchPlayerController {
|
||||
pub fn new() -> TouchPlayerController {
|
||||
TouchPlayerController {
|
||||
state: KeyState(0),
|
||||
old_state: KeyState(0),
|
||||
trigger: KeyState(0),
|
||||
prev_touch_len: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PlayerController for TouchPlayerController {
|
||||
fn update(&mut self, state: &mut SharedGameState, _ctx: &mut Context) -> GameResult {
|
||||
match state.touch_controls.control_type {
|
||||
TouchControlType::None => {}
|
||||
TouchControlType::Dialog => {
|
||||
self.state.set_jump(state.touch_controls.point_in(Rect::new_size(0, 0, state.canvas_size.0 as isize, state.canvas_size.1 as isize)).is_some());
|
||||
|
||||
if state.touch_controls.points.len() > 1 && self.prev_touch_len != state.touch_controls.points.len() {
|
||||
self.prev_touch_len = state.touch_controls.points.len();
|
||||
self.old_state.set_jump(false);
|
||||
}
|
||||
}
|
||||
TouchControlType::Controls => {
|
||||
self.state.0 = 0;
|
||||
// left
|
||||
self.state.set_left(self.state.left() || state.touch_controls.point_in(Rect::new_size(4, state.canvas_size.1 as isize - 4 - 48 * 2, 48, 48)).is_some());
|
||||
|
||||
// up
|
||||
self.state.set_up(self.state.up() || state.touch_controls.point_in(Rect::new_size(48 + 4, state.canvas_size.1 as isize - 4 - 48 * 3, 48, 48)).is_some());
|
||||
|
||||
// right
|
||||
self.state.set_right(self.state.right() || state.touch_controls.point_in(Rect::new_size(4 + 48 * 2, state.canvas_size.1 as isize - 4 - 48 * 2, 48, 48)).is_some());
|
||||
|
||||
// down
|
||||
self.state.set_down(self.state.down() || state.touch_controls.point_in(Rect::new_size(48 + 4, state.canvas_size.1 as isize - 4 - 48, 48, 48)).is_some());
|
||||
|
||||
// left+up
|
||||
self.state.set_left(self.state.left() || state.touch_controls.point_in(Rect::new_size(4, state.canvas_size.1 as isize - 4 - 48 * 3, 48, 48)).is_some());
|
||||
self.state.set_up(self.state.up() || state.touch_controls.point_in(Rect::new_size(4, state.canvas_size.1 as isize - 4 - 48 * 3, 48, 48)).is_some());
|
||||
|
||||
// right+up
|
||||
self.state.set_right(self.state.right() || state.touch_controls.point_in(Rect::new_size(4 + 48 * 2, state.canvas_size.1 as isize - 4 - 48 * 3, 48, 48)).is_some());
|
||||
self.state.set_up(self.state.up() || state.touch_controls.point_in(Rect::new_size(4 + 48 * 2, state.canvas_size.1 as isize - 4 - 48 * 3, 48, 48)).is_some());
|
||||
|
||||
// left+down
|
||||
self.state.set_left(self.state.left() || state.touch_controls.point_in(Rect::new_size(4, state.canvas_size.1 as isize - 48 - 4, 48, 48)).is_some());
|
||||
self.state.set_down(self.state.down() || state.touch_controls.point_in(Rect::new_size(4, state.canvas_size.1 as isize - 48 - 4, 48, 48)).is_some());
|
||||
|
||||
// right+down
|
||||
self.state.set_right(self.state.right() || state.touch_controls.point_in(Rect::new_size(4 + 48 * 2, state.canvas_size.1 as isize - 48 - 4, 48, 48)).is_some());
|
||||
self.state.set_down(self.state.down() || state.touch_controls.point_in(Rect::new_size(4 + 48 * 2, state.canvas_size.1 as isize - 48 - 4, 48, 48)).is_some());
|
||||
|
||||
self.state.set_jump(self.state.jump() || state.touch_controls.point_in(Rect::new_size(state.canvas_size.0 as isize - 48 - 4, state.canvas_size.1 as isize - 48 - 4, 48, 48)).is_some());
|
||||
self.state.set_shoot(self.state.shoot() || state.touch_controls.point_in(Rect::new_size(state.canvas_size.0 as isize - 48 - 4, state.canvas_size.1 as isize - (48 - 4) * 2, 48, 48)).is_some());
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn update_trigger(&mut self) {
|
||||
let mut trigger = self.state.0 ^ self.old_state.0;
|
||||
trigger &= self.state.0;
|
||||
self.old_state = self.state;
|
||||
self.trigger = KeyState(trigger);
|
||||
}
|
||||
|
||||
fn move_up(&self) -> bool {
|
||||
self.state.up()
|
||||
}
|
||||
|
||||
fn move_left(&self) -> bool {
|
||||
self.state.left()
|
||||
}
|
||||
|
||||
fn move_down(&self) -> bool {
|
||||
self.state.down()
|
||||
}
|
||||
|
||||
fn move_right(&self) -> bool {
|
||||
self.state.right()
|
||||
}
|
||||
|
||||
fn prev_weapon(&self) -> bool {
|
||||
self.state.prev_weapon()
|
||||
}
|
||||
|
||||
fn next_weapon(&self) -> bool {
|
||||
self.state.next_weapon()
|
||||
}
|
||||
|
||||
fn jump(&self) -> bool {
|
||||
self.state.jump()
|
||||
}
|
||||
|
||||
fn shoot(&self) -> bool {
|
||||
self.state.shoot()
|
||||
}
|
||||
|
||||
fn trigger_up(&self) -> bool {
|
||||
self.trigger.up()
|
||||
}
|
||||
|
||||
fn trigger_left(&self) -> bool {
|
||||
self.trigger.left()
|
||||
}
|
||||
|
||||
fn trigger_down(&self) -> bool {
|
||||
self.trigger.down()
|
||||
}
|
||||
|
||||
fn trigger_right(&self) -> bool {
|
||||
self.trigger.right()
|
||||
}
|
||||
|
||||
fn trigger_prev_weapon(&self) -> bool {
|
||||
self.trigger.prev_weapon()
|
||||
}
|
||||
|
||||
fn trigger_next_weapon(&self) -> bool {
|
||||
self.trigger.next_weapon()
|
||||
}
|
||||
|
||||
fn trigger_jump(&self) -> bool {
|
||||
self.trigger.jump()
|
||||
}
|
||||
|
||||
fn trigger_shoot(&self) -> bool {
|
||||
self.trigger.shoot()
|
||||
}
|
||||
|
||||
fn trigger_menu_ok(&self) -> bool {
|
||||
self.trigger.jump()
|
||||
}
|
||||
|
||||
fn trigger_menu_back(&self) -> bool {
|
||||
self.trigger.shoot()
|
||||
}
|
||||
|
||||
fn trigger_menu_pause(&self) -> bool {
|
||||
self.trigger.pause()
|
||||
}
|
||||
|
||||
fn look_up(&self) -> bool {
|
||||
self.state.up()
|
||||
}
|
||||
|
||||
fn look_left(&self) -> bool {
|
||||
self.state.left()
|
||||
}
|
||||
|
||||
fn look_down(&self) -> bool {
|
||||
self.state.down()
|
||||
}
|
||||
|
||||
fn look_right(&self) -> bool {
|
||||
self.state.right()
|
||||
}
|
||||
|
||||
fn move_analog_x(&self) -> f64 {
|
||||
if self.state.left() && self.state.right() {
|
||||
0.0
|
||||
} else if self.state.left() {
|
||||
-1.0
|
||||
} else if self.state.right() {
|
||||
1.0
|
||||
} else {
|
||||
0.0
|
||||
}
|
||||
}
|
||||
|
||||
fn move_analog_y(&self) -> f64 {
|
||||
if self.state.up() && self.state.down() {
|
||||
0.0
|
||||
} else if self.state.up() {
|
||||
-1.0
|
||||
} else if self.state.down() {
|
||||
1.0
|
||||
} else {
|
||||
0.0
|
||||
}
|
||||
}
|
||||
}
|
20
src/lib.rs
20
src/lib.rs
|
@ -148,7 +148,7 @@ impl Game {
|
|||
if let Some(scene) = self.scene.as_mut() {
|
||||
scene.draw(&mut self.state, ctx)?;
|
||||
if self.state.settings.touch_controls {
|
||||
self.state.touch_controls.draw(&self.state.constants, &mut self.state.texture_set, ctx)?;
|
||||
self.state.touch_controls.draw(self.state.canvas_size, &self.state.constants, &mut self.state.texture_set, ctx)?;
|
||||
}
|
||||
|
||||
graphics::set_transform(ctx, self.def_matrix);
|
||||
|
@ -244,6 +244,13 @@ pub fn android_main() {
|
|||
init().unwrap();
|
||||
}
|
||||
|
||||
#[cfg(target_os = "android")]
|
||||
static BACKENDS: [Backend; 2] = [
|
||||
Backend::OpenGLES { major: 3, minor: 0 },
|
||||
Backend::OpenGLES { major: 2, minor: 0 }
|
||||
];
|
||||
|
||||
#[cfg(not(target_os = "android"))]
|
||||
static BACKENDS: [Backend; 4] = [
|
||||
Backend::OpenGL { major: 3, minor: 2 },
|
||||
Backend::OpenGLES { major: 3, minor: 2 },
|
||||
|
@ -263,10 +270,15 @@ fn init_ctx<P: Into<path::PathBuf> + Clone>(event_loop: &winit::event_loop::Even
|
|||
.backend(*backend)
|
||||
.build(event_loop);
|
||||
|
||||
if let Ok(mut ctx) = ctx {
|
||||
mount_vfs(&mut ctx, Box::new(BuiltinFS::new()));
|
||||
match ctx {
|
||||
Ok(mut ctx) => {
|
||||
mount_vfs(&mut ctx, Box::new(BuiltinFS::new()));
|
||||
|
||||
return Ok(ctx);
|
||||
return Ok(ctx);
|
||||
}
|
||||
Err(err) => {
|
||||
log::warn!("Failed to create backend using config {:?}: {}", backend, err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
use crate::common::Rect;
|
||||
use ggez::{Context, GameResult};
|
||||
use crate::shared_game_state::SharedGameState;
|
||||
|
||||
use crate::common::Rect;
|
||||
use crate::input::combined_menu_controller::CombinedMenuController;
|
||||
use crate::shared_game_state::SharedGameState;
|
||||
|
||||
pub enum MenuEntry {
|
||||
Active(String),
|
||||
|
@ -9,6 +10,12 @@ pub enum MenuEntry {
|
|||
Toggle(String, bool),
|
||||
}
|
||||
|
||||
impl MenuEntry {
|
||||
pub fn height(&self) -> f64 {
|
||||
14.0
|
||||
}
|
||||
}
|
||||
|
||||
pub enum MenuSelectionResult<'a> {
|
||||
None,
|
||||
Canceled,
|
||||
|
@ -160,7 +167,7 @@ impl Menu {
|
|||
state.font.draw_text(name.chars(), self.x as f32 + 20.0, y, &state.constants, &mut state.texture_set, ctx)?;
|
||||
}
|
||||
MenuEntry::Disabled(name) => {
|
||||
state.font.draw_colored_text(name.chars(), self.x as f32 + 20.0, y, (0xa0, 0xa0, 0xff), &state.constants, &mut state.texture_set, ctx)?;
|
||||
state.font.draw_colored_text(name.chars(), self.x as f32 + 20.0, y, (0xa0, 0xa0, 0xff, 0xff), &state.constants, &mut state.texture_set, ctx)?;
|
||||
}
|
||||
MenuEntry::Toggle(name, value) => {
|
||||
let value_text = if *value { "ON" } else { "OFF" };
|
||||
|
@ -172,7 +179,7 @@ impl Menu {
|
|||
}
|
||||
}
|
||||
|
||||
y += 14.0;
|
||||
y += entry.height() as f32;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
@ -211,15 +218,23 @@ impl Menu {
|
|||
}
|
||||
}
|
||||
|
||||
if controller.trigger_ok() && !self.entries.is_empty() {
|
||||
if let Some(entry) = self.entries.get_mut(self.selected) {
|
||||
match entry {
|
||||
MenuEntry::Active(_) | MenuEntry::Toggle(_, _) => {
|
||||
state.sound_manager.play_sfx(18);
|
||||
return MenuSelectionResult::Selected(self.selected, entry);
|
||||
}
|
||||
_ => {}
|
||||
let mut y = self.y as f32 + 6.0;
|
||||
for (idx, entry) in self.entries.iter_mut().enumerate() {
|
||||
let entry_bounds = Rect::new_size(self.x, y as isize, self.width as isize, entry.height() as isize);
|
||||
y += entry.height() as f32;
|
||||
|
||||
if !((controller.trigger_ok() && self.selected == idx)
|
||||
|| state.touch_controls.consume_click_in(entry_bounds)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
match entry {
|
||||
MenuEntry::Active(_) | MenuEntry::Toggle(_, _) => {
|
||||
self.selected = idx;
|
||||
state.sound_manager.play_sfx(18);
|
||||
return MenuSelectionResult::Selected(idx, entry);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -286,6 +286,11 @@ impl Player {
|
|||
}
|
||||
}
|
||||
|
||||
if state.settings.touch_controls && npc.npc_flags.interactable() && flags.0 != 0 {
|
||||
// todo make it less hacky
|
||||
state.touch_controls.interact_icon = true;
|
||||
}
|
||||
|
||||
if npc.npc_flags.interactable() && !state.control_flags.interactions_disabled() && flags.0 != 0 && self.cond.interacted() {
|
||||
state.control_flags.set_tick_world(true);
|
||||
state.control_flags.set_interactions_disabled(true);
|
||||
|
|
|
@ -29,6 +29,7 @@ use crate::text_script::{ConfirmSelection, ScriptMode, TextScriptExecutionState,
|
|||
use crate::texture_set::SizedBatch;
|
||||
use crate::ui::Components;
|
||||
use crate::weapon::WeaponType;
|
||||
use crate::input::touch_controls::TouchControlType;
|
||||
|
||||
pub struct GameScene {
|
||||
pub tick: usize,
|
||||
|
@ -492,7 +493,7 @@ impl GameScene {
|
|||
}
|
||||
|
||||
fn draw_light(&self, x: f32, y: f32, size: f32, color: (u8, u8, u8), batch: &mut SizedBatch) {
|
||||
batch.add_rect_scaled_tinted(x - size * 32.0, y - size * 32.0, color,
|
||||
batch.add_rect_scaled_tinted(x - size * 32.0, y - size * 32.0, (color.0, color.1, color.2, 255),
|
||||
size,
|
||||
size,
|
||||
&Rect::new(0, 0, 64, 64))
|
||||
|
@ -1111,36 +1112,8 @@ impl GameScene {
|
|||
weapon.shoot_bullet(&self.player2, TargetPlayer::Player2, &mut self.bullet_manager, state);
|
||||
}
|
||||
|
||||
if self.player1.cond.alive() {
|
||||
if self.player1.controller.trigger_next_weapon() {
|
||||
state.sound_manager.play_sfx(4);
|
||||
self.inventory_player1.next_weapon();
|
||||
self.hud_player1.weapon_x_pos = 32;
|
||||
}
|
||||
|
||||
if self.player1.controller.trigger_prev_weapon() {
|
||||
state.sound_manager.play_sfx(4);
|
||||
self.inventory_player1.prev_weapon();
|
||||
self.hud_player1.weapon_x_pos = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if self.player2.cond.alive() {
|
||||
if self.player2.controller.trigger_next_weapon() {
|
||||
state.sound_manager.play_sfx(4);
|
||||
self.inventory_player2.next_weapon();
|
||||
self.hud_player2.weapon_x_pos = 32;
|
||||
}
|
||||
|
||||
if self.player2.controller.trigger_prev_weapon() {
|
||||
state.sound_manager.play_sfx(4);
|
||||
self.inventory_player2.prev_weapon();
|
||||
self.hud_player2.weapon_x_pos = 0;
|
||||
}
|
||||
}
|
||||
|
||||
self.hud_player1.tick(state, (&self.player1, &self.inventory_player1))?;
|
||||
self.hud_player2.tick(state, (&self.player2, &self.inventory_player2))?;
|
||||
self.hud_player1.tick(state, (&self.player1, &mut self.inventory_player1))?;
|
||||
self.hud_player2.tick(state, (&self.player2, &mut self.inventory_player2))?;
|
||||
self.boss_life_bar.tick(state, &self.npc_map)?;
|
||||
}
|
||||
|
||||
|
@ -1187,7 +1160,7 @@ impl GameScene {
|
|||
|
||||
let text = format!("{}:{}:{}", npc.id, npc.npc_type, npc.action_num);
|
||||
state.font.draw_colored_text(text.chars(), ((npc.x - self.frame.x) / 0x200) as f32, ((npc.y - self.frame.y) / 0x200) as f32,
|
||||
((npc.id & 0xf0) as u8, (npc.cond.0 >> 8) as u8, (npc.id & 0x0f << 4) as u8),
|
||||
((npc.id & 0xf0) as u8, (npc.cond.0 >> 8) as u8, (npc.id & 0x0f << 4) as u8, 255),
|
||||
&state.constants, &mut state.texture_set, ctx)?;
|
||||
|
||||
Ok(())
|
||||
|
@ -1266,6 +1239,16 @@ impl Scene for GameScene {
|
|||
self.player2.controller.update(state, ctx)?;
|
||||
self.player2.controller.update_trigger();
|
||||
|
||||
state.touch_controls.control_type = if state.control_flags.control_enabled() {
|
||||
TouchControlType::Controls
|
||||
} else {
|
||||
TouchControlType::Dialog
|
||||
};
|
||||
|
||||
if state.settings.touch_controls {
|
||||
state.touch_controls.interact_icon = false;
|
||||
}
|
||||
|
||||
if self.intro_mode && (self.player1.controller.trigger_menu_ok() || self.tick >= 500) {
|
||||
state.next_scene = Some(Box::new(TitleScene::new()));
|
||||
}
|
||||
|
@ -1400,21 +1383,21 @@ impl Scene for GameScene {
|
|||
if self.player2.x + 8 * 0x200 < self.frame.x {
|
||||
state.font.draw_colored_text(P2_LEFT_TEXT.chars(),
|
||||
9.0, y + 1.0,
|
||||
(0, 0, 130), &state.constants, &mut state.texture_set, ctx)?;
|
||||
(0, 0, 130, 255), &state.constants, &mut state.texture_set, ctx)?;
|
||||
|
||||
state.font.draw_colored_text(P2_LEFT_TEXT.chars(),
|
||||
8.0, y,
|
||||
(96, 96, 255), &state.constants, &mut state.texture_set, ctx)?;
|
||||
(96, 96, 255, 255), &state.constants, &mut state.texture_set, ctx)?;
|
||||
} else if self.player2.x - 8 * 0x200 > self.frame.x + state.canvas_size.0 as isize * 0x200 {
|
||||
let width = state.font.text_width(P2_RIGHT_TEXT.chars(), &state.constants);
|
||||
|
||||
state.font.draw_colored_text(P2_RIGHT_TEXT.chars(),
|
||||
state.canvas_size.0 - width - 8.0 + 1.0, y + 1.0,
|
||||
(0, 0, 130), &state.constants, &mut state.texture_set, ctx)?;
|
||||
(0, 0, 130, 255), &state.constants, &mut state.texture_set, ctx)?;
|
||||
|
||||
state.font.draw_colored_text(P2_RIGHT_TEXT.chars(),
|
||||
state.canvas_size.0 - width - 8.0, y,
|
||||
(96, 96, 255), &state.constants, &mut state.texture_set, ctx)?;
|
||||
(96, 96, 255, 255), &state.constants, &mut state.texture_set, ctx)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ use crate::menu::{Menu, MenuEntry, MenuSelectionResult};
|
|||
use crate::scene::Scene;
|
||||
use crate::shared_game_state::{SharedGameState, TimingMode};
|
||||
use crate::input::combined_menu_controller::CombinedMenuController;
|
||||
use crate::input::touch_controls::TouchControlType;
|
||||
|
||||
#[derive(PartialEq, Eq, Copy, Clone)]
|
||||
#[repr(u8)]
|
||||
|
@ -121,6 +122,7 @@ impl Scene for TitleScene {
|
|||
}
|
||||
|
||||
fn tick(&mut self, state: &mut SharedGameState, ctx: &mut Context) -> GameResult {
|
||||
state.touch_controls.control_type = TouchControlType::None;
|
||||
self.controller.update(state, ctx)?;
|
||||
self.controller.update_trigger();
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@ use winit::event::VirtualKeyCode;
|
|||
use crate::input::keyboard_player_controller::KeyboardController;
|
||||
use crate::input::player_controller::PlayerController;
|
||||
use crate::player::TargetPlayer;
|
||||
use crate::input::touch_player_controller::TouchPlayerController;
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct Settings {
|
||||
|
@ -31,6 +32,10 @@ impl Settings {
|
|||
}
|
||||
|
||||
pub fn create_player1_controller(&self) -> Box<dyn PlayerController> {
|
||||
if self.touch_controls {
|
||||
return Box::new(TouchPlayerController::new());
|
||||
}
|
||||
|
||||
Box::new(KeyboardController::new(TargetPlayer::Player1))
|
||||
}
|
||||
|
||||
|
|
|
@ -26,8 +26,8 @@ impl Shaders {
|
|||
Ok(Shaders {
|
||||
water_shader: Shader::new(
|
||||
ctx,
|
||||
"/builtin/shaders/basic_150.vert.glsl",
|
||||
"/builtin/shaders/water_150.frag.glsl",
|
||||
"/builtin/shaders/basic_es300.vert.glsl",
|
||||
"/builtin/shaders/water_es300.frag.glsl",
|
||||
water_shader_params,
|
||||
"WaterShaderParams",
|
||||
None,
|
||||
|
|
|
@ -197,8 +197,9 @@ fn run<T>(rx: Receiver<PlaybackMessage>, bank: SoundBank,
|
|||
org_engine.set_sample_rate(sample_rate as usize);
|
||||
org_engine.loops = usize::MAX;
|
||||
|
||||
let mut bgm_buf = vec![0x8080; 441];
|
||||
let mut pxt_buf = vec![0x8000; 441];
|
||||
let buf_size = sample_rate as usize * 30 / 1000;
|
||||
let mut bgm_buf = vec![0x8080; buf_size];
|
||||
let mut pxt_buf = vec![0x8000; buf_size];
|
||||
let mut bgm_index = 0;
|
||||
let mut pxt_index = 0;
|
||||
let mut frames = org_engine.render_to(&mut bgm_buf);
|
||||
|
|
|
@ -79,6 +79,11 @@ impl SizedBatch {
|
|||
self.add_rect_scaled(x, y, self.scale_x, self.scale_y, rect)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn add_rect_tinted(&mut self, x: f32, y: f32, color: (u8, u8, u8, u8), rect: &common::Rect<u16>) {
|
||||
self.add_rect_scaled_tinted(x, y, color, self.scale_x, self.scale_y, rect)
|
||||
}
|
||||
|
||||
pub fn add_rect_scaled(&mut self, mut x: f32, mut y: f32, scale_x: f32, scale_y: f32, rect: &common::Rect<u16>) {
|
||||
if (rect.right - rect.left) == 0 || (rect.bottom - rect.top) == 0 {
|
||||
return;
|
||||
|
@ -100,7 +105,7 @@ impl SizedBatch {
|
|||
self.batch.add(param);
|
||||
}
|
||||
|
||||
pub fn add_rect_scaled_tinted(&mut self, x: f32, y: f32, color: (u8, u8, u8), scale_x: f32, scale_y: f32, rect: &common::Rect<u16>) {
|
||||
pub fn add_rect_scaled_tinted(&mut self, x: f32, y: f32, color: (u8, u8, u8, u8), scale_x: f32, scale_y: f32, rect: &common::Rect<u16>) {
|
||||
if (rect.right - rect.left) == 0 || (rect.bottom - rect.top) == 0 {
|
||||
return;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue