Last active
November 17, 2017 20:43
-
-
Save ollewelin/042de58c2612393eb3d765d6f324a87d to your computer and use it in GitHub Desktop.
Reinforced Machine Learning Pinball Game BASIC VERSION
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/// Add gamma parameter and use dice and network probability for make action decisions UP/DOWN. | |
/// Example of Reinforced Machine Learning attached on a simple Pinball game | |
/// The enviroment (enviroment = data feedback) for the Agient (Agient = machine learning system) | |
/// is the raw pixels 50x50 pixels (2500 input nodes) and 200 hidden nodes on 100 frames | |
/// So the input to hidden weights is 50x50x100x200 x4 bytes (float) = is 200Mbytes huges but it work anyway!! | |
///Enhancment to do in future. | |
///TODO: Add some layers of Convolutions (with unsupervised Learning for learning feature patches) will probably enhance preformance. | |
///TODO: Maybe add bias weigth is a good idee to enhance preformance or stability during training. | |
///#define USE_PRINT_OUTPUT_NODE_VALUE ///Uncomment this to see print out of output node value. Only used for evaluation | |
#include <opencv2/highgui/highgui.hpp> // OpenCV window I/O | |
#include <opencv2/imgproc/imgproc.hpp> // | |
#include <stdio.h> | |
///#include <raspicam/raspicam_cv.h> | |
#include <opencv2/opencv.hpp> | |
#include <opencv2/core/core.hpp> // Basic OpenCV structures (cv::Mat, Scalar) | |
#include <cstdlib> | |
#include <ctime> | |
#include <math.h> // exp | |
#include <stdlib.h>// exit(0); | |
#include <iostream> | |
using namespace std; | |
using namespace cv; | |
#include "pinball_game.hpp" | |
const float Relu_neg_gain = 0.01f;///A small positive value here will prevent ReLU neuoron from dying. 0.0f pure rectify (1.0 full linear = nothing change) | |
float relu(float input) | |
{ | |
float output=0; | |
output = input; | |
if(input < 0.0) | |
{ | |
output = input * Relu_neg_gain; | |
} | |
return output; | |
} | |
int main() | |
{ | |
FILE *fp2; | |
int nr_of_episodes=0; | |
int auto_save_w_counter =100; | |
const int auto_save_after = 200;///Auto Save weights after this number of episodes | |
int show_w_counter =19;///Show the weights graphical not ever episodes (to save CPU time) | |
const int show_w_after = 20;///Show the weights graphical not ever episodes (to save CPU time) | |
float pix2hid_learning_rate = 0.03f;///0.001 | |
float hid2out_learning_rate = 0.03f;///0.001 | |
float gamma = 0.97f; | |
printf("Reinforcment Learning Evaluation of pixels data input from a simple Pinball game\n"); | |
int pixel_height = 50;///The input data pixel height, note game_Width = 220 | |
int pixel_width = 50;///The input data pixel width, note game_Height = 200 | |
Mat resized_grapics, test, pix2hid_weight, hid2out_weight; | |
Size size(pixel_width,pixel_height);//the dst image size,e.g.100x100 | |
pinball_game gameObj1;///Instaniate the pinball game | |
gameObj1.init_game();///Initialize the pinball game with serten parametrers | |
gameObj1.slow_motion=0;///0=full speed game. 1= slow down | |
///========== Setup weights and nodes for the Reinforcemnt learning network ========================== | |
///This will contain all the training weigts for training. It will have exact same size as the grapics * number of frames * hidden nodes | |
///Use also here OpenCV Mat so it is easy to Visualize some of the data as well as store the weights | |
int Nr_of_hidden_nodes = 200;///Number of hidden nodes on one frame weight | |
float *input_node_stored;///This will have a record of all frames of the resized_grapics used for weight updates | |
input_node_stored = new float[pixel_width * pixel_height * gameObj1.nr_of_frames]; | |
int visual_nr_of_frames = 20;///Visualization weights of a only few frames othewize the image will be to large | |
int visual_nr_of_hid_node = 20;///Visualization weights of a only few hidden nodes othewize the image will be to large | |
pix2hid_weight.create(pixel_height * visual_nr_of_hid_node, pixel_width * visual_nr_of_frames, CV_32FC1);///Visualization weights of a only few frames and hidden nodes othewize the image will be to large CV_32FC1 is pixel format | |
float *pix2hid_weightB;///File data read/write connect to tied weights | |
pix2hid_weightB = new float[pixel_height * pixel_width * Nr_of_hidden_nodes * gameObj1.nr_of_frames];///File data is same size as all tied weights pix2hid_weight.create | |
float *hidden_node; | |
hidden_node = new float[gameObj1.nr_of_frames * Nr_of_hidden_nodes];///200 hidden nodes and 100 frames for example | |
float *hidden_delta; | |
hidden_delta = new float[gameObj1.nr_of_frames * Nr_of_hidden_nodes];///200 hidden nodes and 100 frames for example | |
hid2out_weight.create(gameObj1.nr_of_frames, Nr_of_hidden_nodes, CV_32FC1);///Use also here OpenCV Mat so it is easy to Visualize the data as well as store weights | |
float *hid2out_weightB; | |
hid2out_weightB = new float[gameObj1.nr_of_frames * Nr_of_hidden_nodes]; | |
float *output_node; | |
output_node = new float[gameObj1.nr_of_frames]; | |
float *output_delta; | |
output_delta = new float[gameObj1.nr_of_frames]; | |
float *action; | |
action = new float[gameObj1.nr_of_frames]; | |
///Some reports to user | |
printf("Number of hidden nodes to one frames = %d\n", Nr_of_hidden_nodes); | |
printf("Total number of hidden nodes fo all frames together = %d\n", gameObj1.nr_of_frames * Nr_of_hidden_nodes); | |
printf("Number of output nodes alway equal to the number of frames on one episode = %d\n", gameObj1.nr_of_frames); | |
///=================================================================================================== | |
///=================== index variable for the weights ==================== | |
int ix=0;///index to f_data[ix] | |
///======================================================================= | |
///============ Prepare pointers to make it possible to direct acces Mat data matrix ================== | |
test = gameObj1.gameGrapics.clone(); | |
resize(test, resized_grapics, size); | |
float *zero_ptr_res_grap = resized_grapics.ptr<float>(0);///zero_... Always point at first pixel | |
float *index_ptr_res_grap = resized_grapics.ptr<float>(0);///index_... Adjusted to abritary pixel | |
float *zero_ptr_pix2hid_w = pix2hid_weight.ptr<float>(0);///Only used for visualization of weights | |
float *index_ptr_pix2hid_w = pix2hid_weight.ptr<float>(0);///Only used for visualization of weights | |
float *zero_ptr_hid2out_w = hid2out_weight.ptr<float>(0);///Only used for visualization of weights | |
float *index_ptr_hid2out_w = hid2out_weight.ptr<float>(0);///Only used for visualization of weights | |
///==================================================================================================== | |
///================ Initialize weight with random noise ===================================== | |
printf("Insert noise to weights. Please wait...\n"); | |
srand (static_cast <unsigned> (time(0)));///Seed the randomizer (need to do only once) | |
float start_weight_noise_range = 0.05f; | |
float Rando=0.0f; | |
for(int i=0; i<(pixel_height * pixel_width * Nr_of_hidden_nodes * gameObj1.nr_of_frames); i++) | |
{ | |
Rando = (float) (rand() % 65535) / 65536;//0..1.0 range | |
Rando -= 0.5f; | |
Rando *= start_weight_noise_range; | |
pix2hid_weightB[i] = Rando;///Insert the noise to the weight pixel to hidden | |
} | |
printf("Noise to the weight pixel to hidden is inserted\n"); | |
for(int i=0; i<(gameObj1.nr_of_frames * Nr_of_hidden_nodes); i++) | |
{ | |
Rando = (float) (rand() % 65535) / 65536;//0..1.0 range | |
Rando -= 0.5f; | |
Rando *= start_weight_noise_range; | |
hid2out_weightB[i] = Rando; | |
} | |
printf("Noise to the weight hidden to output node is inserted\n"); | |
///==================== End of Initialize weight with random noise =========================== | |
///============ Regardning Load weights to file ========================== | |
char filename[100]; | |
printf("Would you like to load stored weights, pix2hid_weight.dat and hid2out_weight.dat <Y>/<N> \n"); | |
char answer_character; | |
answer_character = getchar(); | |
if(answer_character == 'Y' || answer_character == 'y') | |
{ | |
sprintf(filename, "pix2hid_weight.dat"); | |
fp2 = fopen(filename, "r"); | |
if (fp2 == NULL) | |
{ | |
printf("Error while opening file pix2hid_weight.dat"); | |
exit(0); | |
} | |
printf("Start so load pix2hid_weight.dat Please wait... The file size is = %d bytes\n", (sizeof pix2hid_weightB[0]) * (pixel_height * pixel_width * Nr_of_hidden_nodes * gameObj1.nr_of_frames)); | |
fread(pix2hid_weightB, sizeof pix2hid_weightB[0], (pixel_height * pixel_width * Nr_of_hidden_nodes * gameObj1.nr_of_frames), fp2);///+1 is because the bias. So the nr FLx_size+1 is the bias weight. | |
fclose(fp2); | |
printf("weights are loaded from pix2hid_weight.dat file\n"); | |
sprintf(filename, "hid2out_weight.dat"); | |
fp2 = fopen(filename, "r"); | |
if (fp2 == NULL) | |
{ | |
printf("Error while opening file hid2out_weight.dat"); | |
exit(0); | |
} | |
printf("Start so load hid2out_weight.dat Please wait... The file size is = %d bytes\n", (sizeof hid2out_weightB[0]) * (gameObj1.nr_of_frames * Nr_of_hidden_nodes)); | |
fread(hid2out_weightB, sizeof hid2out_weightB[0], (gameObj1.nr_of_frames * Nr_of_hidden_nodes), fp2); | |
fclose(fp2); | |
printf("weights are loaded from hid2out_weight.dat file\n"); | |
} | |
///============ End of Regardning Load weights to file ========================== | |
while(1) | |
{ | |
float dot_product = 0.0f; | |
gameObj1.start_episode();///Staring a new game turn | |
float action_dice=0;/// | |
for(int frame_g=0; frame_g<gameObj1.nr_of_frames; frame_g++) ///Loop throue each of the 100 frames | |
{ | |
action_dice = (float) (rand() % 65535) / 65536;///Update 2017-09-02 9:30 ===== Use dice with the policy network output probability for what action should be done | |
if(output_node[frame_g-1] > action_dice) | |
{ | |
action[frame_g] = 1.0f; | |
gameObj1.move_up = 1; | |
} | |
else | |
{ | |
action[frame_g] = 0.0f; | |
gameObj1.move_up = 0; | |
} | |
output_node[frame_g] = 0.0f;///Start with clear this node | |
gameObj1.frame = frame_g; | |
gameObj1.run_episode(); | |
test = gameObj1.gameGrapics.clone(); | |
resize(test, resized_grapics, size); | |
///=============== Forward data for this frame ================== | |
///Make the Dot product to this frames hidden nodes and output node | |
for(int i=0; i<Nr_of_hidden_nodes; i++) | |
{ | |
hidden_node[frame_g * Nr_of_hidden_nodes + i] = 0.0f;///Start with clear this value before sum up the dot product | |
dot_product = 0.0f;///Start with clear this value before sum up the dot product | |
for(int j=0; j<(pixel_height * pixel_width); j++) | |
{ | |
ix = ((pixel_width * Nr_of_hidden_nodes) * (pixel_height * frame_g + j/pixel_width) + (pixel_width * i) + j%pixel_width);///Prepare the index to point on the right place in the weight matrix pix2hid_weightB[] | |
index_ptr_res_grap = zero_ptr_res_grap + j;///Prepare the pointer address to point on the right place on the grapical image of this grapical frame | |
dot_product += pix2hid_weightB[ix] * (*index_ptr_res_grap);///Make the dot product of Weights * Game grapichs | |
input_node_stored[pixel_width * pixel_height * frame_g + j] = (*index_ptr_res_grap);///Save this grame grapich pixel must read this pixel later when update weights | |
} | |
///Relu this dot product | |
dot_product = relu(dot_product); | |
hidden_node[frame_g * Nr_of_hidden_nodes + i] = dot_product;///Put this finnish data in the hidden node neuron | |
ix = (frame_g * Nr_of_hidden_nodes + i); | |
output_node[frame_g] += hid2out_weightB[ix] * dot_product;///Take this hidden node data how is for the moment => hidden_node[frame_g * Nr_of_hidden_nodes + i] = dot_product; | |
} | |
output_node[frame_g] = 1.0/(1.0 + exp(-(output_node[frame_g])));///Sigmoid function. x = 1.0/(1.0 + exp(-(x))) | |
///=============== End Forward data for this frame ================== | |
imshow("resized_grapics", resized_grapics);/// resize(src, dst, size); | |
waitKey(1); | |
} | |
#ifdef USE_PRINT_OUTPUT_NODE_VALUE | |
for(int i=0; i<gameObj1.nr_of_frames; i++) | |
{ | |
printf("output_node[frame nr %d] = %f\n", gameObj1.nr_of_frames-1-i, output_node[gameObj1.nr_of_frames-1-i]); | |
} | |
#endif // USE_PRINT_OUTPUT_NODE_VALUE | |
///========== Auto save weights to files ==================== | |
if(auto_save_w_counter>auto_save_after) | |
{ | |
auto_save_w_counter=0; | |
sprintf(filename, "pix2hid_weight.dat"); | |
fp2 = fopen(filename, "w+"); | |
if (fp2 == NULL) | |
{ | |
printf("Error while opening file pix2hid_weight.dat"); | |
exit(0); | |
} | |
printf("Start so save pix2hid_weight.dat Please wait... The file size is = %d bytes\n", (sizeof pix2hid_weightB[0]) * (pixel_height * pixel_width * Nr_of_hidden_nodes * gameObj1.nr_of_frames)); | |
fwrite(pix2hid_weightB, sizeof pix2hid_weightB[0], (pixel_height * pixel_width * Nr_of_hidden_nodes * gameObj1.nr_of_frames), fp2); | |
fclose(fp2); | |
printf("weights are saved at hid2out_weight.dat file\n"); | |
sprintf(filename, "hid2out_weight.dat"); | |
fp2 = fopen(filename, "w+"); | |
if (fp2 == NULL) | |
{ | |
printf("Error while opening file hid2out_weight.dat"); | |
exit(0); | |
} | |
printf("Start so save hid2out_weight.dat Please wait... The file size is = %d bytes\n", (sizeof hid2out_weightB[0]) * (gameObj1.nr_of_frames * Nr_of_hidden_nodes)); | |
fwrite(hid2out_weightB, sizeof hid2out_weightB[0], (gameObj1.nr_of_frames * Nr_of_hidden_nodes), fp2); | |
fclose(fp2); | |
printf("weights are saved at hid2out_weight.dat file\n"); | |
} | |
else | |
{ | |
auto_save_w_counter++; | |
} | |
///========== End Auto save weights to files ==================== | |
///========== Show visualization of the weights not nessesary ========== | |
if(show_w_counter>show_w_after) | |
{ | |
show_w_counter=0; | |
for(int i=0; i<(gameObj1.nr_of_frames * Nr_of_hidden_nodes); i++) | |
{ | |
///Visualization of all hid2out weights | |
index_ptr_hid2out_w = zero_ptr_hid2out_w + i; | |
(*index_ptr_hid2out_w) = hid2out_weightB[i] + 0.5f;///(*index_ptr_hid2out_w) is the pointer to Mat hid2out_weight. +0.5 make a grayscale with gray center 0.5; | |
} | |
///int start_show_frame = gameObj1.nr_of_frames - visual_nr_of_frames-1;///Show only the last (20 = visual_nr_of_frames) frame weights | |
int show_ever5frame_start =0; | |
for(int si=0; si<(pixel_height * visual_nr_of_hid_node * pixel_width * visual_nr_of_frames); si++) ///si = visualize Mat itterator | |
{ | |
///Visualize pix2hid weight reagrding only few frames and few hidden nodes connections | |
///pix2hid_weight.create(pixel_height * visual_nr_of_hid_node, pixel_width * visual_nr_of_frames, CV_32FC1);/// | |
///The pix2hid_weightB[ix] is organized like this; | |
///ix = ((pixel_width * Nr_of_hidden_nodes) * (pixel_height * frame_g + j/pixel_width) + (pixel_width * i) + j%pixel_width); | |
///where.. | |
///j is itterator for (pixel_height * pixel_width) is the pixel area of the game (shrinked are rezised image) | |
///i is itterator for Nr_of_hidden_nodes | |
///frame_g is of course the frame number | |
int vis_colum = 0; | |
vis_colum = si%(pixel_width * visual_nr_of_hid_node); | |
int vis_row = 0; | |
vis_row = si/(pixel_width * visual_nr_of_hid_node); | |
index_ptr_pix2hid_w = zero_ptr_pix2hid_w + si; | |
///Map over frome the large weight vevtor to visualize Mat | |
///============== This make so each patch row have a jump by 5 frames in the game === | |
show_ever5frame_start = (si/(pixel_height * visual_nr_of_hid_node * pixel_width)) * ((gameObj1.nr_of_frames-1) / visual_nr_of_frames); | |
///===================================================================== | |
(*index_ptr_pix2hid_w) = pix2hid_weightB[(vis_row + show_ever5frame_start*pixel_height) * (pixel_width * Nr_of_hidden_nodes) + vis_colum%(pixel_width * Nr_of_hidden_nodes)];///Map over phuu... | |
(*index_ptr_pix2hid_w) += 0.5f;///make gray scale center at 0.5f | |
} | |
imshow("pix2hid_weight", pix2hid_weight);///Only few weights showed | |
imshow("hid2out_weight", hid2out_weight); | |
} | |
else | |
{ | |
show_w_counter++; | |
} | |
///========== End Show visualization of the weights ================= | |
printf("nr_of_episodes =%d\n", nr_of_episodes); | |
nr_of_episodes++; | |
float rewards =0.0f; | |
if(gameObj1.win_this_game == 1) | |
{ | |
rewards = +4.0f;///Yea.. the Ageint win this episode | |
} | |
else | |
{ | |
rewards = -1.0f;///We lose this episode | |
} | |
///================== Make the backprop now when the hole episode is done ============== | |
for(int frame_g = gameObj1.nr_of_frames; frame_g>0; true) ///This loop throue from last frame to first, will only go thorue here to make backpropagate (not play game in the gameObj1) { | |
{ | |
frame_g--;///Go from last frame (frame 99) to first frame (frame 0) because then we will decrease the rewards by gamma factor so the rewards get less in the first frames | |
/// ***** Make a pseudo target value = action[frame_g] ****** | |
///This is the cool stuff about Reinforcment Learning | |
///You pruduce a pseudo target value = action[frame_g] because the you can imidiet generate a gradient decent for this frame | |
///even if you don't know yet if this pseudo target is the right (in this case have right polarity +/- only because actions is only 2 = UP/DOWN ) | |
///When the episode is over you can fix this eventually wrong +/- by the rewards | |
output_delta[frame_g] = (action[frame_g] - output_node[frame_g]) * output_node[frame_g] * (1.0f - output_node[frame_g]);///Backpropagate. Make a gradient decent for this frame even if it may have wrong polarity | |
for(int i=0; i<Nr_of_hidden_nodes; i++) | |
{ | |
///**** Backprop delta_hid **** | |
///delta_hid = delta_out * output_weight[1]; | |
ix = (frame_g * Nr_of_hidden_nodes + i); | |
hidden_delta[frame_g * Nr_of_hidden_nodes + i] = output_delta[frame_g] * hid2out_weightB[ix];///Relu Backprop to hidden delta | |
///===== Update weights depend on the stored delta ======== | |
for(int j=0; j<(pixel_height * pixel_width); j++) | |
{ | |
ix = ((pixel_width * Nr_of_hidden_nodes) * (pixel_height * frame_g + j/pixel_width) + (pixel_width * i) + j%pixel_width); | |
pix2hid_weightB[ix] += hidden_delta[frame_g * Nr_of_hidden_nodes + i] * input_node_stored[pixel_width * pixel_height * frame_g + j] * pix2hid_learning_rate * rewards;/// input_node_stored = new float[pixel_width * pixel_height * gameObj1.nr_of_frames]; | |
} | |
ix = (frame_g * Nr_of_hidden_nodes + i); | |
hid2out_weightB[ix] += output_delta[frame_g] * hidden_node[frame_g * Nr_of_hidden_nodes + i] * hid2out_learning_rate * rewards;///Update weights | |
///=============End update weights for this position ============== | |
} | |
///printf("Rewards %f\n", rewards); | |
rewards *= gamma;///This will reduce the rewards on the older frames. The last frame (frame 99) will have highest rewards/punishments and the first fram lowers gain of rewards | |
} | |
///=================== End Backprop ==================================================== | |
waitKey(1); | |
} | |
return 0; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#ifndef PINBALL_GAME_H | |
#define PINBALL_GAME_H | |
///This is the pinball game how the Reinforcment learning will train on | |
#include <opencv2/highgui/highgui.hpp> // OpenCV window I/O | |
#include <opencv2/imgproc/imgproc.hpp> // Gaussian Blur | |
#include <stdio.h> | |
///#include <raspicam/raspicam_cv.h> | |
#include <opencv2/opencv.hpp> | |
#include <opencv2/core/core.hpp> // Basic OpenCV structures (cv::Mat, Scalar) | |
#include <cstdlib> | |
#include <ctime> | |
#include <math.h> // exp | |
#include <stdlib.h>// exit(0); | |
#include <iostream> | |
using namespace std; | |
using namespace cv; | |
class pinball_game | |
{ | |
public: | |
pinball_game()///Constructor | |
{ | |
printf("Construct a arcade game object\n"); | |
} | |
virtual ~pinball_game()///Destructor | |
{ | |
printf("Destruct game object\n"); | |
} | |
int game_Width;///Pixel width of game grapics. A constant value set in init_game | |
int game_Height;///Pixel height of game grapics. A constant value set in init_game | |
int move_up;///Input Action from Agent. 1= Move up pad. 0= Move down pad | |
int win_this_game;///1= Catched the ball this episode. 0= miss. This will be used as the reward feedback to the Reinforcment Learning | |
int nr_of_frames;///The number of frames on one episode. A constant value set in init_game | |
int slow_motion;///1= slow down speed of game 0= full speed | |
Mat gameGrapics;///This is the grapics of the game how is the enviroment | |
void init_game(void); | |
void start_episode(void); | |
void run_episode(void); | |
int frame; | |
protected: | |
private: | |
int pad_position; | |
int ball_pos_x; | |
int ball_pos_y; | |
float ball_angle_derivate;///Example 0 mean strigh forward. +1.0 mean ball go up 1 pixel on one frame 45 deg. | |
int frame_steps; | |
int ball_offset_y;/// | |
CvPoint P1;///The ball point OpenCV | |
CvPoint P2;///The pad point uppe corner OpenCV | |
CvPoint P3;///The pad point lower corner OpenCV | |
}; | |
void pinball_game::init_game(void) | |
{ | |
replay_count=0;//Fix this missing bugg 2017-11-15 | |
slow_motion=0; | |
move_up=0;///Init down if there was no Agent action done. | |
win_this_game=0;///Init | |
frame=0;///Init with frame 0 for the episode | |
pad_position = game_Height/2;///Start the game at center | |
game_Width = 220;/// | |
game_Height = 200;/// | |
nr_of_frames = 100;/// | |
gameGrapics.create(game_Height, game_Width, CV_32FC1); | |
gameGrapics = Scalar(0.0f);///Init with Black | |
srand (static_cast <unsigned> (time(0)));///Seed the randomizer | |
} | |
void pinball_game::start_episode(void) | |
{ | |
ball_angle_derivate = (float) (rand() % 65535) / 65536;///Set ball shoot angle. Random value 0..1.0 range | |
ball_angle_derivate *= 6.0; | |
ball_angle_derivate -= 3.0;/// -0.5..+0.5 will mean +/- 12.5 deg random ball angle | |
/// ball_angle_derivate *= 1.0; | |
/// ball_angle_derivate -= 0.5;/// -0.5..+0.5 will mean +/- 12.5 deg random ball angle | |
frame_steps=0; | |
ball_offset_y = game_Height/2;/// | |
pad_position = game_Height/2;///Start the game at center | |
} | |
void pinball_game::run_episode(void) | |
{ | |
int circle_zize = 5; | |
int ball_start_x = 10;///Start 10 pixel inside game plan | |
int y_bounce_constraints = 20; | |
int y_pad_constraints = 28; | |
int pad_width = 3; | |
int pad_height = 40; | |
int pad_speed = 4;//4 | |
///The frame loop is outside this class so The Agient cad do actions each frame step | |
frame_steps++;///This is need to handle bounce. This will reset when bounce | |
///=========== Draw the ball ================= | |
///Bounce handle | |
ball_pos_y = ((int) ((float)frame_steps * ball_angle_derivate)) + ball_offset_y;/// | |
if(ball_pos_y > (game_Height-y_bounce_constraints) || ball_pos_y < y_bounce_constraints) | |
{ | |
frame_steps=0; | |
ball_angle_derivate = -ball_angle_derivate; | |
ball_offset_y = ball_pos_y + ball_angle_derivate; | |
} | |
ball_pos_x = (frame * 2) + ball_start_x;///Take 2 pixel step forward | |
P1.x = ball_pos_x;///Set to control grapic OpenCV circle() below | |
P1.y = ball_pos_y;///Set to control grapic OpenCV circle() below | |
gameGrapics = Scalar(0.0f);///Begin with all black then draw up grapics ball and pad | |
circle(gameGrapics, P1, circle_zize, Scalar(1.0), 7, -1); | |
///=============================== | |
///========= Draw the Pad ============== | |
if(pad_position > (game_Height-y_pad_constraints)) | |
{ | |
///Allow only move up | |
if(move_up==1) | |
{ | |
pad_position = pad_position - pad_speed; | |
} | |
else | |
{ | |
pad_position = (game_Height-y_pad_constraints) + pad_speed; | |
} | |
} | |
else if(pad_position < y_pad_constraints) | |
{ | |
///Allow only move down | |
if(move_up==0) | |
{ | |
pad_position = pad_position + pad_speed; | |
} | |
else | |
{ | |
pad_position = (y_pad_constraints) - pad_speed; | |
} | |
} | |
else | |
{ | |
///Move up or down | |
if(move_up==1) | |
{ | |
pad_position = pad_position - pad_speed; | |
} | |
else | |
{ | |
pad_position = pad_position + pad_speed; | |
} | |
} | |
P2.y = pad_position - (pad_height/2); | |
P3.y = pad_position + (pad_height/2); | |
P2.x = - (pad_width/2) + game_Width-10; | |
P3.x = (pad_width/2) + game_Width-10; | |
rectangle(gameGrapics, P2, P3, Scalar(0.8), 2);/// C++: void rectangle(Mat& img, Point pt1, Point pt2, const Scalar& color, int thickness=1, int lineType=8, int shift=0) | |
if(frame > nr_of_frames-2) | |
{ | |
///This episode is over | |
///Is the pad catch the ball ?? | |
if(((pad_position + (pad_height/2)) < ball_pos_y) || ((pad_position - (pad_height/2)) > ball_pos_y)) | |
{ | |
///Lose | |
win_this_game = 0; | |
printf("Lose \n"); | |
} | |
else | |
{ | |
///Win catced | |
win_this_game = 1; | |
printf("Win \n"); | |
} | |
} | |
imshow("Game", gameGrapics); | |
if(slow_motion==1) | |
{ | |
waitKey(20);///Wait 100msec | |
} | |
else | |
{ | |
waitKey(1);///Wait 1msec for only OpenCV grapics | |
} | |
} | |
#endif // PINBALL_GAME_H |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment