`timescale 1ns / 1ps

// VGA Pong v1.0     Chris Fallin <cfallin@nd.edu>

module motion(
	clk,
	paddle1_up,
	paddle1_down,
	paddle2_up,
	paddle2_down,
	paddle1_v,
	paddle2_v,
	ball_v_dir,
	ball_h_dir,
	ball_v,
	ball_h,
	game, reset);
	
   input clk;
	input paddle1_up;
   input paddle1_down;
   input paddle2_up;
   input paddle2_down;
	output ball_v_dir;
	output ball_h_dir;
   output [9:0] paddle1_v;
   output [9:0] paddle2_v;
   output [9:0] ball_v;
   output [9:0] ball_h;
   output game;
	input reset;

	reg [9:0] paddle1_v;
	reg [9:0] paddle2_v;
	reg [9:0] ball_v;
	reg [9:0] ball_h;
	reg ball_v_dir;
	reg ball_h_dir;
	reg game; // game over

	wire paddle1_inrange;
	assign paddle1_inrange = (ball_v + 16) >= paddle1_v && ball_v < (paddle1_v + 48);
	
	wire paddle2_inrange;
	assign paddle2_inrange = (ball_v + 16) >= paddle2_v && ball_v < (paddle2_v + 48);
	
	// these collision-detections leave 1-pixel buffer because of 1-cycle delay on bounces
	
	wire collide_top;
	assign collide_top = (ball_v == 1) && (ball_v_dir == 0);
	
	wire collide_bottom;
	assign collide_bottom = ((ball_v + 16) == 479) && (ball_v_dir == 1);
	
	wire collide_side1;
	assign collide_side1 = ball_h == (16 + 1) && (ball_h_dir == 0);
	
	wire collide_side2;
	assign collide_side2 = (ball_h + 16) == (640 - 16 - 1) && (ball_h_dir == 1);
	
	initial begin
		// keep in sync with reset block below
		paddle1_v <= 480 / 2;
		paddle2_v <= 280;
		ball_v <= 480 / 2;
		ball_h <= 480 / 2;
		ball_v_dir <= 1;
		ball_h_dir <= 1;
		game <= 0;
	end
	
	always @(posedge reset or posedge clk) begin
		
		if(reset) begin
			paddle1_v <= 480 / 2;
			paddle2_v <= 280; // so the ball gets the first bounce
			ball_v <= 480 / 2;
			ball_h <= 480 / 2;
			ball_v_dir <= 1;
			ball_h_dir <= 1;
			game <= 0;
		end
		
		else if(~game) begin
		
			if(collide_top | collide_bottom)
				ball_v_dir <= ~ball_v_dir;
				
			if(collide_side1) begin
				if(paddle1_inrange)
					ball_h_dir <= ~ball_h_dir;
				else
					game <= 1;
			end
			else if(collide_side2) begin
				if(paddle2_inrange)
					ball_h_dir <= ~ball_h_dir;
				else
					game <= 1;
			end
			
			if(ball_v_dir)
				ball_v <= ball_v + 1;
			else
				ball_v <= ball_v - 1;
				
			if(ball_h_dir)
				ball_h <= ball_h + 1;
			else
				ball_h <= ball_h - 1;
				
			if(paddle1_up)
				paddle1_v <= paddle1_v - 1;
			else if(paddle1_down)
				paddle1_v <= paddle1_v + 1;
				
			if(paddle2_up)
				paddle2_v <= paddle2_v - 1;
			else if(paddle2_down)
				paddle2_v <= paddle2_v + 1;
		
		end
		
	end

endmodule
