Initial Version Working
This commit is contained in:
@@ -0,0 +1 @@
|
|||||||
|
/target
|
||||||
Generated
+1385
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,9 @@
|
|||||||
|
[package]
|
||||||
|
name = "RustyPong"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
tetra = "0.7"
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 583 B |
Binary file not shown.
|
After Width: | Height: | Size: 1.2 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 991 B |
+161
@@ -0,0 +1,161 @@
|
|||||||
|
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
|
||||||
|
// https://tetra.seventeencups.net/tutorial/01-creating-a-project
|
||||||
|
use tetra::graphics::{self, Color, Rectangle, Texture};
|
||||||
|
use tetra::input::{self, Key};
|
||||||
|
use tetra::math::Vec2;
|
||||||
|
use tetra::window;
|
||||||
|
use tetra::{Context, ContextBuilder, State};
|
||||||
|
|
||||||
|
const WINDOW_WIDTH:f32 = 640.0;
|
||||||
|
const WINDOW_HEIGHT:f32 = 480.0;
|
||||||
|
const PADDLE_SPEED:f32 = 8.0;
|
||||||
|
const BALL_SPEED:f32 = 5.0;
|
||||||
|
const PADDLE_SPIN: f32 = 4.0;
|
||||||
|
const BALL_ACC:f32 = 0.05;
|
||||||
|
|
||||||
|
struct Entity {
|
||||||
|
texture: Texture,
|
||||||
|
position: Vec2<f32>,
|
||||||
|
velocity: Vec2<f32>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Entity{
|
||||||
|
fn new(texture: Texture,position: Vec2<f32>) -> Self{
|
||||||
|
Entity::with_velocity(texture,position,Vec2::zero())
|
||||||
|
}
|
||||||
|
fn with_velocity(texture: Texture,position: Vec2<f32>,velocity: Vec2<f32>) -> Self {
|
||||||
|
Entity{
|
||||||
|
texture,
|
||||||
|
position,
|
||||||
|
velocity,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn centre(&self)-> Vec2<f32>{
|
||||||
|
Vec2::new(
|
||||||
|
self.position.x + (self.width() / 2.0),
|
||||||
|
self.position.y + (self.height() / 2.0),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
fn width(&self) -> f32{
|
||||||
|
self.texture.width() as f32
|
||||||
|
}
|
||||||
|
fn height(&self) -> f32{
|
||||||
|
self.texture.height() as f32
|
||||||
|
}
|
||||||
|
fn bounds(&self) -> Rectangle {
|
||||||
|
Rectangle::new(
|
||||||
|
self.position.x,
|
||||||
|
self.position.y,
|
||||||
|
self.width(),
|
||||||
|
self.height(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct GameState {
|
||||||
|
player1: Entity,
|
||||||
|
player2: Entity,
|
||||||
|
ball: Entity,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl GameState{
|
||||||
|
fn new(ctx: &mut Context) -> tetra::Result<GameState>{
|
||||||
|
let player1_texture:Texture = Texture::new(ctx,"./resources/player1.png")?;
|
||||||
|
let player2_texture:Texture = Texture::new(ctx,"./resources/player2.png")?;
|
||||||
|
let ball_texture:Texture = Texture::new(ctx,"./resources/ball.png")?;
|
||||||
|
|
||||||
|
let player1_position =
|
||||||
|
Vec2::new(16.0,(WINDOW_HEIGHT - player1_texture.height() as f32) / 2.0);
|
||||||
|
let player2_position =
|
||||||
|
Vec2::new(WINDOW_WIDTH - player2_texture.width() as f32 -16.0,(WINDOW_HEIGHT - player2_texture.height() as f32) / 2.0);
|
||||||
|
let ball_position =
|
||||||
|
Vec2::new(WINDOW_WIDTH / 2.0 - (ball_texture.width() as f32 / 2.0) as f32,WINDOW_HEIGHT / 2.0 - (ball_texture.height() as f32 / 2.0) as f32);
|
||||||
|
|
||||||
|
let ball_speed = Vec2::new(-BALL_SPEED,0.0);
|
||||||
|
|
||||||
|
Ok(GameState {
|
||||||
|
player1: Entity::new(player1_texture,player1_position),
|
||||||
|
player2: Entity::new(player2_texture,player2_position),
|
||||||
|
ball: Entity::with_velocity(ball_texture,ball_position,ball_speed),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl State for GameState{
|
||||||
|
|
||||||
|
fn draw(&mut self, ctx: &mut Context) -> tetra::Result {
|
||||||
|
graphics::clear(ctx,Color::rgb(0.329,0.584,0.929));
|
||||||
|
|
||||||
|
self.player1.texture.draw(ctx,self.player1.position);
|
||||||
|
self.player2.texture.draw(ctx,self.player2.position);
|
||||||
|
self.ball.texture.draw(ctx,self.ball.position);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
fn update(&mut self,ctx: &mut Context) -> tetra::Result{
|
||||||
|
//Player 1 movements
|
||||||
|
if input::is_key_down(ctx, Key::W) && self.player1.position.y as i32 > 0{
|
||||||
|
self.player1.position.y -= PADDLE_SPEED;
|
||||||
|
}
|
||||||
|
if input::is_key_down(ctx, Key::S) && ((self.player1.position.y as i32 + self.player1.texture.height()) as f32) < WINDOW_HEIGHT{
|
||||||
|
self.player1.position.y += PADDLE_SPEED;
|
||||||
|
}
|
||||||
|
//player 2 movements
|
||||||
|
if input::is_key_down(ctx, Key::Up) && self.player2.position.y as i32 > 0{
|
||||||
|
self.player2.position.y -= PADDLE_SPEED;
|
||||||
|
}
|
||||||
|
if input::is_key_down(ctx, Key::Down) && ((self.player2.position.y as i32 + self.player1.texture.height()) as f32) < WINDOW_HEIGHT{
|
||||||
|
self.player2.position.y += PADDLE_SPEED;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Collisions
|
||||||
|
|
||||||
|
let player1_bounds:Rectangle = self.player1.bounds();
|
||||||
|
let player2_bounds:Rectangle = self.player2.bounds();
|
||||||
|
let ball_bounds:Rectangle = self.ball.bounds();
|
||||||
|
|
||||||
|
let paddle_hit = if ball_bounds.intersects(&player1_bounds) {
|
||||||
|
Some(&self.player1)
|
||||||
|
}else if ball_bounds.intersects(&player2_bounds){
|
||||||
|
Some(&self.player2)
|
||||||
|
}else{
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Some(paddle) = paddle_hit{
|
||||||
|
//increase ball velocity before flipping it
|
||||||
|
self.ball.velocity.x =
|
||||||
|
-(self.ball.velocity.x + (BALL_ACC * self.ball.velocity.x.signum()));
|
||||||
|
|
||||||
|
//Calculate the offset between the paddle center and the ball
|
||||||
|
let offset = (paddle.centre().y - self.ball.centre().y) / paddle.height();
|
||||||
|
|
||||||
|
self.ball.velocity.y += PADDLE_SPIN * -offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.ball.position += self.ball.velocity;
|
||||||
|
|
||||||
|
//check borders
|
||||||
|
if self.ball.position.y <= 0.0 || self.ball.position.y + self.ball.height() >= WINDOW_HEIGHT{
|
||||||
|
self.ball.velocity.y = -self.ball.velocity.y;
|
||||||
|
}
|
||||||
|
//check winner
|
||||||
|
if self.ball.position.x <= 0.0{
|
||||||
|
window::quit(ctx);
|
||||||
|
println!("Player 2 won!");
|
||||||
|
}
|
||||||
|
if self.ball.position.x + self.ball.width() >= WINDOW_WIDTH{
|
||||||
|
window::quit(ctx);
|
||||||
|
println!("Player 1 won!");
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() -> tetra::Result{
|
||||||
|
ContextBuilder::new("Pong",WINDOW_WIDTH as i32,WINDOW_HEIGHT as i32)
|
||||||
|
.quit_on_escape(true)
|
||||||
|
.build()?
|
||||||
|
.run(GameState::new)
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user