Compare commits

...

5 Commits

4 changed files with 286 additions and 119 deletions

14
Cargo.lock generated
View File

@@ -2,13 +2,6 @@
# It is not intended for manual editing.
version = 3
[[package]]
name = "Test_SDL"
version = "0.1.0"
dependencies = [
"sdl2",
]
[[package]]
name = "bitflags"
version = "1.3.2"
@@ -56,6 +49,13 @@ dependencies = [
"version-compare",
]
[[package]]
name = "test_sdl"
version = "0.1.0"
dependencies = [
"sdl2",
]
[[package]]
name = "version-compare"
version = "0.1.0"

View File

@@ -1,5 +1,5 @@
[package]
name = "Test_SDL"
name = "test_sdl"
version = "0.1.0"
edition = "2021"

31
ReadMe.md Normal file
View File

@@ -0,0 +1,31 @@
# test_sdl
It is just a playground for me to test SDL2 features
## Run it
You need to download Rust
Then you clone this repository
And laucnh it with :
```Bash
cargo build --release
cargo run --release
```
## Controls
W,A,S,D and Arrow Keys are for moving around the ball.
Left Click teleports the ball to the cursors location.
Right Click cancels any velocity of the ball.
Tab toggles a debug mode where you can see the actual vector applied to the ball wich is render as a cube to see its hitbox (maybe even more in the futur)
Spacebar doubles the acceleration (to use with moderation)
Bonus: Maintain the left click and moving(s) key(s) at the same time and it will store some momentum wich you can use when you release the click. Enjoy :)

View File

@@ -1,150 +1,284 @@
use sdl2::pixels::Color;
use sdl2::event::Event;
use sdl2::keyboard::Keycode;
use sdl2::keyboard::Scancode;
use std::time::Duration;
use sdl2::rect::Point;
use sdl2::rect::Rect;
const WINDOW_HEIGHT:i32 = 600;
const WINDOW_WIDTH:i32 = 800;
const BLOC_SPEED:f32 = 3.0;
const MAX_SPEED:f32 = 20.0;
const WINDOW_HEIGHT:i32 = 800;
const WINDOW_WIDTH:i32 = 500;
const BALL_SPEED:f32 = 3.0;
const MAX_SPEED:f32 = 60.0;
const DEBUG_FX_SIZE_RATIO:i32 = 2;
const BOUNCE_RATIO:f32 = 60.0;
const DEFAULT_BALL_WIDTH:i32 = 20;
const DEFAULT_START_BALL_LOCATION_X:i32 = WINDOW_WIDTH / 2 - DEFAULT_BALL_WIDTH / 2;
const DEFAULT_START_BALL_LOCATION_Y:i32 = (WINDOW_HEIGHT / 5) * 4 - DEFAULT_BALL_WIDTH / 2;
pub struct Game{
main_bloc:Entity,
main_ball:Entity,
draw_debug:bool,
ball_released:bool,
}
impl Game{
pub fn render(&mut self,ctx:&mut sdl2::render::Canvas<sdl2::video::Window>){
ctx.set_draw_color(Color::RGB(0x6D, 0x6D, 0x64));
let main_ball_color:Color = Color::RGB(0xFA, 0xFD, 0xF6);
let main_ball_outline:Color = Color::RGB(0x17, 0x2A, 0x33);
let background_color:Color = Color::RGB(0x6A,0x9A,0x1D);
ctx.set_draw_color(background_color);
ctx.clear();
//Rendering main_bloc
ctx.set_draw_color(Color::RGB(0x33, 0x33, 0x33));
ctx.fill_rect(self.main_bloc.shape).expect("Could not fill the rectangle");
//ctx.set_draw_color(Color::RGB(0xFF, 0xFF, 0xFF));
//ctx.draw_rect(self.main_bloc.shape).expect("Could not outline the rectangle");
let center:Point = Point::new(self.main_ball.shape.x + (self.main_ball.shape.width() / 2) as i32,self.main_ball.shape.y + (self.main_ball.shape.width() / 2) as i32);
if self.draw_debug {
ctx.set_draw_color(main_ball_color);
ctx.fill_rect(self.main_ball.shape).expect("Could not fill the rectangle");
ctx.set_draw_color(main_ball_outline);
ctx.draw_rect(self.main_ball.shape).expect("Could not ouline the rectangle");
let apex:Point = Point::new(center.x + (self.main_ball.velocity.x * DEBUG_FX_SIZE_RATIO) as i32,center.y + (self.main_ball.velocity.y * DEBUG_FX_SIZE_RATIO) as i32);
ctx.draw_line(center,apex).expect("Could not render the Debug FX");
}else{
fill_circle(ctx, center.x, center.y,self.main_ball.shape.width() as i32 / 2, main_ball_color);
draw_circle(ctx,center.x,center.y,self.main_ball.shape.width() as i32 / 2, main_ball_outline);
draw_circle(ctx,center.x,center.y,self.main_ball.shape.width() as i32 / 2 + 1, main_ball_outline);
}
}
pub fn up(&mut self){
// 'w' or the up arrow has been pressed
//println!("DEBUG: Up is pressed");
self.main_bloc.velocity.y -= BLOC_SPEED as i32;
if self.main_bloc.velocity.y < -MAX_SPEED as i32{
self.main_bloc.velocity.y = -MAX_SPEED as i32;
self.main_ball.velocity.y -= BALL_SPEED as i32;
if self.main_ball.velocity.y < -MAX_SPEED as i32{
self.main_ball.velocity.y = -MAX_SPEED as i32;
}
}
pub fn down(&mut self){
// 's' or the down arrow has been pressed
//println!("DEBUG: Down is pressed");
self.main_bloc.velocity.y += BLOC_SPEED as i32;
if self.main_bloc.velocity.y > MAX_SPEED as i32{
self.main_bloc.velocity.y = MAX_SPEED as i32;
self.main_ball.velocity.y += BALL_SPEED as i32;
if self.main_ball.velocity.y > MAX_SPEED as i32{
self.main_ball.velocity.y = MAX_SPEED as i32;
}
}
pub fn left(&mut self){
// 'a' or the left arrow has been pressed
//println!("DEBUG: Left is pressed");
self.main_bloc.velocity.x -= BLOC_SPEED as i32;
if self.main_bloc.velocity.x < -MAX_SPEED as i32{
self.main_bloc.velocity.x = -MAX_SPEED as i32;
self.main_ball.velocity.x -= BALL_SPEED as i32;
if self.main_ball.velocity.x < -MAX_SPEED as i32{
self.main_ball.velocity.x = -MAX_SPEED as i32;
}
}
pub fn right(&mut self){
// 'd' or the right arrow has been pressed
//println!("DEBUG: Right is pressed");
self.main_bloc.velocity.x += BLOC_SPEED as i32;
if self.main_bloc.velocity.y > MAX_SPEED as i32{
self.main_bloc.velocity.y = MAX_SPEED as i32;
self.main_ball.velocity.x += BALL_SPEED as i32;
if self.main_ball.velocity.y > MAX_SPEED as i32{
self.main_ball.velocity.y = MAX_SPEED as i32;
}
}
pub fn toggle_debug(&mut self){
self.draw_debug = !self.draw_debug;
}
pub fn release(&mut self){
if self.ball_released{
self.main_ball.shape.set_x(DEFAULT_START_BALL_LOCATION_X);
self.main_ball.shape.set_y(DEFAULT_START_BALL_LOCATION_Y);
}
self.ball_released = !self.ball_released;
}
pub fn left_click(&mut self,mouse_position:Point){
// moves the bloc at the cursor position
self.main_ball.shape.set_x(mouse_position.x - (self.main_ball.shape.width() / 2) as i32);
self.main_ball.shape.set_y(mouse_position.y - (self.main_ball.shape.height() / 2) as i32);
}
pub fn right_click(&mut self,_mouse_position:Point){
// Removes any vectors
self.main_ball.velocity = Point::new(0,0);
}
pub fn update(&mut self){
let mut posx = self.main_bloc.shape.x;
let mut posy = self.main_bloc.shape.y;
posx += self.main_bloc.velocity.x;
posy += self.main_bloc.velocity.y;
let bloc_width:i32 = self.main_bloc.shape.width() as i32;
let bloc_height:i32 = self.main_bloc.shape.height() as i32;
let bloc = &mut self.main_ball;
let mut posx = bloc.shape.x;
let mut posy = bloc.shape.y;
let width = bloc.shape.width() as i32;
let height = bloc.shape.height() as i32;
if posx + bloc_width > WINDOW_WIDTH{
posx = WINDOW_WIDTH - bloc_width as i32;
self.main_bloc.velocity.x = 0;
}else{
if posx < 0{
posx = 0;
self.main_bloc.velocity.x = 0;
}
if posy + height >= WINDOW_HEIGHT{
//we hit rock bottom
posy = WINDOW_HEIGHT - height;
bloc.velocity.y = -(bloc.velocity.y as f32 / 100.0 * BOUNCE_RATIO) as i32;
}
if posy + bloc_height > WINDOW_HEIGHT{
posy = WINDOW_HEIGHT - bloc_height as i32;
self.main_bloc.velocity.y = 0;
}else{
if posy < 0{
posy = 0;
self.main_bloc.velocity.y = 0;
}
if posy <= 0{
//we hit top
posy = 0;
bloc.velocity.y = -(bloc.velocity.y as f32 / 100.0 * BOUNCE_RATIO) as i32;
}
if posx + width >= WINDOW_WIDTH{
//we hit right
posx = WINDOW_WIDTH - width;
bloc.velocity.x = -(bloc.velocity.x as f32 / 100.0 * BOUNCE_RATIO) as i32;
}
if posx <= 0{
//we hit left
posx = 0;
bloc.velocity.x = -(bloc.velocity.x as f32 / 100.0 * BOUNCE_RATIO) as i32;
}
if self.main_bloc.velocity.x > 0{
if self.main_bloc.velocity.x < BLOC_SPEED as i32{
self.main_bloc.velocity.x = 0;
}else{
self.main_bloc.velocity.x -= (BLOC_SPEED / 2.0) as i32;
}
}else{
if self.main_bloc.velocity.x > -BLOC_SPEED as i32{
self.main_bloc.velocity.x = 0;
}else{
self.main_bloc.velocity.x += (BLOC_SPEED / 2.0) as i32;
}
if bloc.velocity.x > MAX_SPEED as i32{
bloc.velocity.x = MAX_SPEED as i32;
}
if bloc.velocity.x < -MAX_SPEED as i32{
bloc.velocity.x = -MAX_SPEED as i32;
}
if bloc.velocity.y > MAX_SPEED as i32{
bloc.velocity.y = MAX_SPEED as i32;
}
if bloc.velocity.y < -MAX_SPEED as i32{
bloc.velocity.y = -MAX_SPEED as i32;
}
if self.main_bloc.velocity.y > 0{
if self.main_bloc.velocity.y < BLOC_SPEED as i32{
self.main_bloc.velocity.y = 0;
}else{
self.main_bloc.velocity.y -= (BLOC_SPEED / 2.0) as i32;
}
}else{
if self.main_bloc.velocity.y > -BLOC_SPEED as i32{
self.main_bloc.velocity.y = 0;
}else{
self.main_bloc.velocity.y += (BLOC_SPEED / 2.0) as i32;
}
if self.ball_released {
posx += bloc.velocity.x;
posy += bloc.velocity.y;
}
bloc.shape.set_x(posx);
bloc.shape.set_y(posy);
self.main_bloc.shape.set_x(posx);
self.main_bloc.shape.set_y(posy);
}
}
//https://stackoverflow.com/questions/65723827/sdl2-function-to-draw-a-filled-circle ## Translated to Rust
pub fn fill_circle(ctx:&mut sdl2::render::Canvas<sdl2::video::Window>, x:i32, y:i32, radius:i32, color:Color)
{
ctx.set_draw_color(color);
let diameter = radius * 2;
for w in 0..diameter{
for h in 0..diameter{
let dx = radius - w; // horizontal offset
let dy = radius - h; // vertical offset
if (dx*dx + dy*dy) <= (radius * radius)
{
ctx.draw_point(Point::new(x + dx, y + dy)).expect("Trouble rendering the circle");
}
}
}
}
// https://stackoverflow.com/questions/38334081/howto-draw-circles-arcs-and-vector-graphics-in-sdl ## Translated to Rust
pub fn draw_circle(ctx:&mut sdl2::render::Canvas<sdl2::video::Window>, centre_x:i32, centre_y:i32, radius:i32, color:Color)
{
ctx.set_draw_color(color);
let diameter = radius * 2;
let mut x:i32 = radius - 1;
let mut y:i32 = 0;
let mut tx:i32 = 1;
let mut ty:i32 = 1;
let mut error:i32 = tx - diameter;
while x >= y
{
// Each of the following renders an octant of the circle
ctx.draw_point(Point::new(centre_x + x, centre_y - y)).expect("Trouble rendering the circle");
ctx.draw_point(Point::new(centre_x + x, centre_y + y)).expect("Trouble rendering the circle");
ctx.draw_point(Point::new(centre_x - x, centre_y - y)).expect("Trouble rendering the circle");
ctx.draw_point(Point::new(centre_x - x, centre_y + y)).expect("Trouble rendering the circle");
ctx.draw_point(Point::new(centre_x + y, centre_y - x)).expect("Trouble rendering the circle");
ctx.draw_point(Point::new(centre_x + y, centre_y + x)).expect("Trouble rendering the circle");
ctx.draw_point(Point::new(centre_x - y, centre_y - x)).expect("Trouble rendering the circle");
ctx.draw_point(Point::new(centre_x - y, centre_y + x)).expect("Trouble rendering the circle");
if error <= 0{
y+= 1;
error += ty;
ty += 2;
}
if error > 0{
x -= 1;
tx += 2;
error += tx - diameter;
}
}
}
pub struct Entity{
shape:Rect,
velocity:Point,
}
fn is_up_pressed(e: &sdl2::EventPump) -> bool {
e.keyboard_state().is_scancode_pressed(Scancode::W) || e.keyboard_state().is_scancode_pressed(Scancode::Up)
}
fn is_down_pressed(e: &sdl2::EventPump)-> bool{
e.keyboard_state().is_scancode_pressed(Scancode::S) || e.keyboard_state().is_scancode_pressed(Scancode::Down)
}
fn is_left_pressed(e: &sdl2::EventPump)-> bool{
e.keyboard_state().is_scancode_pressed(Scancode::A) || e.keyboard_state().is_scancode_pressed(Scancode::Left)
}
fn is_right_pressed(e: &sdl2::EventPump)-> bool{
e.keyboard_state().is_scancode_pressed(Scancode::D) || e.keyboard_state().is_scancode_pressed(Scancode::Right)
}
fn is_tab_pressed(e: &sdl2::EventPump)-> bool{
e.keyboard_state().is_scancode_pressed(Scancode::Tab)
}
fn is_space_pressed(e: &sdl2::EventPump)-> bool{
e.keyboard_state().is_scancode_pressed(Scancode::Space)
}
fn check_mouse_left_pressed(e: &sdl2::EventPump) -> Point{
if e.mouse_state().left(){
return Point::new(e.mouse_state().x(),e.mouse_state().y());
}else{
return Point::new(-1,-1);
}
}
fn check_mouse_right_pressed(e: &sdl2::EventPump) -> Point{
if e.mouse_state().right(){
return Point::new(e.mouse_state().x(),e.mouse_state().y());
}else{
return Point::new(-1,-1);
}
}
pub fn main_loop(canvas: &mut sdl2::render::Canvas<sdl2::video::Window>,event_pump:&mut sdl2::EventPump,game:&mut Game){
'running: loop {
canvas.clear();
//let (mut up_state,mut down_state,mut left_state,mut right_state) = (false,false,false,false);
let (mut tab_state,mut space_state) = (false,false);
let mut quit = false;
loop{
if is_up_pressed(event_pump){
game.up();
}
if is_down_pressed(event_pump){
game.down();
}
if is_left_pressed(event_pump){
game.left();
}
if is_right_pressed(event_pump){
game.right();
}
if is_tab_pressed(event_pump){
if tab_state == false{
//Keydown
tab_state = true;
game.toggle_debug();
}
}else{
if tab_state == true{
//keyUp
tab_state = false
}
}
if is_space_pressed(event_pump){
if space_state == false{
//KeyDown
space_state = true;
game.release();
}
}else{
if space_state == true{
//KeyDown
space_state = false;
}
}
let mut mouse_position:Point = check_mouse_left_pressed(event_pump);
if mouse_position.x >=0 && mouse_position.y >= 0{
game.left_click(mouse_position);
}
mouse_position = check_mouse_right_pressed(event_pump);
if mouse_position.x >=0 && mouse_position.y >= 0{
game.right_click(mouse_position);
}
for event in event_pump.poll_iter() {
match event {
Event::Quit {..} |
Event::KeyDown { keycode: Some(Keycode::Escape), .. } => {
break 'running
},
Event::KeyDown { keycode: Some(Keycode::W), .. } | Event::KeyDown {keycode: Some(Keycode::Up), ..} => {
//pressed up
game.up();
},
Event::KeyDown { keycode: Some(Keycode::S), .. } | Event::KeyDown { keycode: Some(Keycode::Down), .. } => {
//pressed up
game.down();
},
Event::KeyDown { keycode: Some(Keycode::A), .. } | Event::KeyDown { keycode: Some(Keycode::Left), .. } => {
//pressed up
game.left();
},
Event::KeyDown { keycode: Some(Keycode::D), .. } | Event::KeyDown { keycode: Some(Keycode::Right), .. } => {
//pressed up
game.right();
quit = true;
break
},
_ => {}
}
@@ -157,6 +291,10 @@ pub fn main_loop(canvas: &mut sdl2::render::Canvas<sdl2::video::Window>,event_pu
canvas.present();
::std::thread::sleep(Duration::new(0, 1_000_000_000u32 / 60));
if quit{
break;
}
}
}
@@ -164,7 +302,7 @@ pub fn main() {
let sdl_context = sdl2::init().unwrap();
let video_subsystem = sdl_context.video().unwrap();
let window = video_subsystem.window("Test SDL Rust", WINDOW_WIDTH as u32, WINDOW_HEIGHT as u32)
let window = video_subsystem.window("Rusty Golfy", WINDOW_WIDTH as u32, WINDOW_HEIGHT as u32)
.position_centered()
.build()
.unwrap();
@@ -174,15 +312,13 @@ pub fn main() {
canvas.set_draw_color(Color::RGB(0x6D, 0x6D, 0x64));
let main_bloc_width:i32 = 50;
let main_bloc_height:i32 = 50;
let main_bloc_position:Point = Point::new(WINDOW_WIDTH / 2 - main_bloc_width / 2,WINDOW_HEIGHT / 2 - main_bloc_height / 2);
let main_bloc_rectangle = Rect::new(main_bloc_position.x,main_bloc_position.y, main_bloc_width as u32, main_bloc_height as u32);
let main_bloc_velocity = Point::new(0,0);
let main_ball_rectangle = Rect::new(
DEFAULT_START_BALL_LOCATION_X,DEFAULT_START_BALL_LOCATION_Y, DEFAULT_BALL_WIDTH as u32, DEFAULT_BALL_WIDTH as u32);
let main_ball_velocity = Point::new(0,0);
let main_entity = Entity{
shape:main_bloc_rectangle,
velocity:main_bloc_velocity
shape:main_ball_rectangle,
velocity:main_ball_velocity
};
let mut game = Game{main_bloc:main_entity};
let mut game = Game{main_ball:main_entity,draw_debug:false,ball_released:false};
main_loop(&mut canvas,&mut event_pump,&mut game);
}