500行代码实现pong游戏
时间:2022-06-20
本文章向大家介绍500行代码实现pong游戏,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
全局变量是不好的、但是都用matlab了谁还管这些,全篇全局变量,把计算和绘图拆分到不同的函数中,每次先计算下一时刻数据、再统一绘制图像
function [] = pong_game()
close all
clear
clc
%----------------------参数设置----------------------
%游戏参数
MAX_POINTS = 5;
START_DELAY = 1;
%运动参数
FRAME_DELAY = .01; %刷新时间
MIN_BALL_SPEED = .8; %最小(起始)速度
MAX_BALL_SPEED = 3; %最大速度
BALL_ACCELERATION = 0.05; %反弹加速
PADDLE_SPEED = 1.3; %挡板速度
%B、P因子调节横纵向运动比例
B_FACTOR = 1;
P_FACTOR = 2;
%Y因子防止小球卡住
Y_FACTOR = 0.01;
%得分区域
GOAL_BUFFER = 5;
%绘图尺寸
BALL_RADIUS = 1.5; %小球半径
WALL_WIDTH = 3;
FIGURE_WIDTH = 800; %单位:像素
FIGURE_HEIGHT = 480;
PLOT_W = 150; %绘图宽度
PLOT_H = 100; %高度
GOAL_SIZE = 50;
GOAL_TOP = (PLOT_H+GOAL_SIZE)/2;
GOAL_BOT = (PLOT_H-GOAL_SIZE)/2;
PADDLE_H = 18; %挡板高
PADDLE_W = 3; %挡板宽
PADDLE = [0 PADDLE_W PADDLE_W 0 0; PADDLE_H PADDLE_H 0 0 PADDLE_H];
PADDLE_SPACE = 10; %挡板和空门距离
%绘图样式
FIGURE_COLOR = [0, 0, 0]; %背景
AXIS_COLOR = [.15, .15, .15]; %围墙
CENTER_RADIUS = 15; %中央圆圈
BALL_MARKER_SIZE = 10; %小球标志半径
BALL_COLOR = [.1, .7, .1];
BALL_OUTLINE = [.7, 1, .7];
BALL_SHAPE = 'o';
PADDLE_LINE_WIDTH = 2;
WALL_COLOR = [.3, .3, .8]; %墙
PADDLE_COLOR = [1, .5, 0];
CENTERLINE_COLOR = PADDLE_COLOR .* .8; %地线
PAUSE_BACKGROUND_COLOR = FIGURE_COLOR;
PAUSE_TEXT_COLOR = [.9, .9, .9];
PAUSE_EDGE_COLOR = BALL_COLOR;
TITLE_COLOR = 'w';
%提示信息
PAUSE_WIDTH = 36; %信息框宽度
MESSAGE_X = 38; %位置
MESSAGE_Y = 55;
MESSAGE_PAUSED = [' 游戏暂停' 10 10];
MESSAGE_INTRO = [...
' 先得 ' num2str(MAX_POINTS) ' 分者赢!' 10 10 ...
' 玩家1: 玩家2:' 10 ...
' a、z键 上下键' 10 10 ...
];
MESSAGE_CONTROLS = ' 暂停:(p) 重置:(r) 结束:(q)';
%----------------------全局参数初始化----------------------
fig = []; %主程序绘图句柄
quitGame = false; %主程序停止标志
paused = []; %暂停标志
score = []; %得分
winner = []; %赢家标志
ballPlot = []; %墙、球句柄
paddle1Plot = []; %挡板句柄
paddle2Plot = [];
ballVector=[]; %小球运动参数
ballSpeed=[];
ballX = []; %小球位置
ballY = [];
paddle1V = []; %挡板运动参数
paddle2V = [];
paddle1 = [];
paddle2 = [];
%-----------------------工具函数----------------------
%------------绘图------------
%初始墙、球、挡板
function createFigure
%整体尺寸: [左边位置, 底部位置, 宽度, 高度]:
scrsz = get(0,'ScreenSize');
fig = figure('Position',[(scrsz(3)-FIGURE_WIDTH)/2 ...
(scrsz(4)-FIGURE_HEIGHT)/2 ...
FIGURE_WIDTH, FIGURE_HEIGHT]);
%绑定键盘事件
set(fig,'KeyPressFcn',@keyDown, 'KeyReleaseFcn', @keyUp);
%不可拉伸窗口
set(fig, 'Resize', 'off');
axis([0 PLOT_W 0 PLOT_H]);
axis manual;
%设定边界颜色、隐藏刻度
set(gca, 'color', AXIS_COLOR, 'YTick', [], 'XTick', []);
%背景色
set(fig, 'color', FIGURE_COLOR);
hold on;
%墙
topWallXs = [0,0,PLOT_W,PLOT_W];
topWallYs = [GOAL_TOP,PLOT_H,PLOT_H,GOAL_TOP];
bottomWallXs = [0,0,PLOT_W,PLOT_W];
bottomWallYs = [GOAL_BOT,0,0,GOAL_BOT];
plot(topWallXs, topWallYs, '-', ...
'LineWidth', WALL_WIDTH, 'Color', WALL_COLOR);
plot(bottomWallXs, bottomWallYs, '-', ...
'LineWidth', WALL_WIDTH, 'Color', WALL_COLOR);
%中央圆圈
thetas = linspace(0, (2*pi), 100);
circleXs = (CENTER_RADIUS .* cos(thetas)) + (PLOT_W / 2);
circleYs = (CENTER_RADIUS .* sin(thetas))+ (PLOT_H / 2);
%地线
centerline = plot([PLOT_W/2, PLOT_W/2],[PLOT_H, 0],'--');
set(centerline, 'Color', CENTERLINE_COLOR);
centerCircle = plot(circleXs, circleYs,'--');
set(centerCircle, 'Color', CENTERLINE_COLOR);
%小球
ballPlot = plot(0,0);
set(ballPlot, 'Marker', BALL_SHAPE);
set(ballPlot, 'MarkerEdgeColor', BALL_OUTLINE);
set(ballPlot, 'MarkerFaceColor', BALL_COLOR);
set(ballPlot, 'MarkerSize', BALL_MARKER_SIZE);
%挡板
paddle1Plot = plot(0,0, '-', 'LineWidth', PADDLE_LINE_WIDTH);
paddle2Plot = plot(0,0, '-', 'LineWidth', PADDLE_LINE_WIDTH);
set(paddle1Plot, 'Color', PADDLE_COLOR);
set(paddle2Plot, 'Color', PADDLE_COLOR);
end
%------------新游戏------------
%恢复初始
function newGame
winner = 0;
score = [0, 0];
paddle1V = 0; %速度
paddle2V = 0;
paddle1 = [PADDLE(1,:)+PADDLE_SPACE; ...
PADDLE(2,:)+((PLOT_H - PADDLE_H)/2)];
paddle2 = [PADDLE(1,:)+ PLOT_W - PADDLE_SPACE - PADDLE_W; ...
PADDLE(2,:)+((PLOT_H - PADDLE_H)/2)];
resetGame;
if ~quitGame
pauseGame([MESSAGE_INTRO, MESSAGE_CONTROLS]);
end
end
%------------重置------------
%恢复初始值
function resetGame
bounce([1-(2*rand), 1-(2*rand)]);
ballSpeed=MIN_BALL_SPEED;
ballX = PLOT_W/2;
ballY = PLOT_H/2;
%19个空格
titleStr = sprintf('%d / %d%19d / %d', ...
score(1), MAX_POINTS, score(2), MAX_POINTS);
t = title(titleStr, 'Color', TITLE_COLOR);
set(t, 'FontName', 'Courier','FontSize', 15, 'FontWeight', 'Bold');
refreshPlot;
if ~quitGame
pause(START_DELAY);
end
end
%------------球的运动------------
%各种碰撞检测
function moveBall
%挡板边界
p1T = paddle1(2,1);
p1B = paddle1(2,3);
p1L = paddle1(1,1);
p1R = paddle1(1,2);
p1Center = ([p1L p1B] + [p1R p1T]) ./ 2;
p2T = paddle2(2,1);
p2B = paddle2(2,3);
p2L = paddle2(1,1);
p2R = paddle2(1,2);
p2Center = ([p2L p2B] + [p2R p2T]) ./ 2;
%下一时刻的位置
newX = ballX + (ballSpeed * ballVector(1));
newY = ballY + (ballSpeed * ballVector(2));
%是否碰撞右墙
if (newX > (PLOT_W - BALL_RADIUS) ...
&& (ballY<GOAL_BOT+BALL_RADIUS || newY>GOAL_TOP-BALL_RADIUS))
%右墙
if (newY > GOAL_BOT && newY < GOAL_TOP - BALL_RADIUS)
%空门底部
bounce([newX - PLOT_W, newY - GOAL_BOT]);
elseif (newY < GOAL_TOP && newY > GOAL_BOT + BALL_RADIUS)
%空门顶部
bounce([newX - PLOT_W, newY - GOAL_TOP]);
else
%右墙余下部分
bounce([-1 * abs(ballVector(1)), ballVector(2)]);
end
%是否碰撞左墙
elseif (newX < BALL_RADIUS ...
&& (newY<GOAL_BOT+BALL_RADIUS || newY>GOAL_TOP-BALL_RADIUS))
%左墙
if (newY > GOAL_BOT && newY < GOAL_TOP - BALL_RADIUS)
%空门底部
bounce([newX, newY - GOAL_BOT]);
elseif (newY < GOAL_TOP && newY > GOAL_BOT + BALL_RADIUS)
%空门顶部
bounce([newX, newY - GOAL_TOP]);
else
%左墙余下部分
bounce([abs(ballVector(1)), ballVector(2)]);
end
%顶部
elseif (newY > (PLOT_H - BALL_RADIUS))
bounce([ballVector(1), -1 * (Y_FACTOR + abs(ballVector(2)))]);
%底部
elseif (newY < BALL_RADIUS)
bounce([ballVector(1), (Y_FACTOR + abs(ballVector(2)))]);
%挡板1
elseif (newX < p1R + BALL_RADIUS ...
&& newX > p1L - BALL_RADIUS ...
&& newY < p1T + BALL_RADIUS ...
&& newY > p1B - BALL_RADIUS)
bounce([(ballX-p1Center(1)) * P_FACTOR, newY-p1Center(2)]);
%挡板2
elseif (newX < p2R + BALL_RADIUS ...
&& newX > p2L - BALL_RADIUS ...
&& newY < p2T + BALL_RADIUS ...
&& newY > p2B - BALL_RADIUS)
bounce([(ballX-p2Center(1)) * P_FACTOR, newY-p2Center(2)]);
else
%没有碰撞
end
%移动小球
ballX = newX;
ballY = newY;
end
%------------挡板移动------------
%更新位置
function movePaddles
%纵向位置
paddle1(2,:) = paddle1(2,:) + (PADDLE_SPEED * paddle1V);
paddle2(2,:) = paddle2(2,:) + (PADDLE_SPEED * paddle2V);
%边界确认
if paddle1(2,1) > PLOT_H
paddle1(2,:) = PADDLE(2,:) + PLOT_H - PADDLE_H;
elseif paddle1(2,3) < 0
paddle1(2,:) = PADDLE(2,:);
end
if paddle2(2,1) > PLOT_H
paddle2(2,:) = PADDLE(2,:) + PLOT_H - PADDLE_H;
elseif paddle2(2,3) < 0
paddle2(2,:) = PADDLE(2,:);
end
end
%------------更新绘图------------
%暂停时间也是刷新时间
function refreshPlot
set(ballPlot, 'XData', ballX, 'YData', ballY);
set(paddle1Plot, 'Xdata', paddle1(1,:), 'YData', paddle1(2,:));
set(paddle2Plot, 'Xdata', paddle2(1,:), 'YData', paddle2(2,:));
drawnow;
pause(FRAME_DELAY);
end
%------------得分检测------------
%只需检测横向坐标、如果赢得比赛就重置
function checkGoal
goal = false;
if ballX > PLOT_W + BALL_RADIUS + GOAL_BUFFER
score(1) = score(1) + 1;
if score(1) == MAX_POINTS
winner = 1;
end
goal = true;
elseif ballX < 0 - BALL_RADIUS - GOAL_BUFFER
score(2) = score(2) + 1;
if score(2) == MAX_POINTS
winner = 2;
end
goal = true;
end
if goal %得分
pause(START_DELAY);
resetGame;
if winner > 0 %有人赢了
pauseGame([' 玩家 ' num2str(winner) ' 赢了!!!' 10])
newGame;
else %没人赢
end
end
end
%------------暂停------------
%全局暂停标志设为真
function pauseGame(input)
paused = true;
str = ' 按任意键继续...';
spacer = 1:PAUSE_WIDTH;
spacer(:) = uint8(' ');
while paused
printText = [spacer 10 input 10 str 10];
h = text(MESSAGE_X,MESSAGE_Y,printText);
set(h, 'BackgroundColor', PAUSE_BACKGROUND_COLOR)
set(h, 'Color', PAUSE_TEXT_COLOR)
set(h,'EdgeColor',PAUSE_EDGE_COLOR);
set(h, 'FontSize',5,'FontName','Courier','LineStyle','-','LineWidth',1);
pause(FRAME_DELAY)
delete(h);
end
end
%------------从暂停中恢复------------
%全局暂停标志设为假
function unpauseGame()
paused = false;
end
%------------碰撞------------
%计算碰撞后速度
function bounce (tempV)
%确保水平速度大于垂直速度
tempV(1) = tempV(1) * ((rand/B_FACTOR) + 1);
%归一化速度
tempV = tempV ./ (sqrt(tempV(1)^2 + tempV(2)^2));
ballVector = tempV;
%碰撞后加速
if (ballSpeed + BALL_ACCELERATION < MAX_BALL_SPEED)
ballSpeed = ballSpeed + BALL_ACCELERATION;
end
end
%------------键盘按下事件------------
%按键按下后执行
function keyDown(~,event)
switch event.Key
case 'a'
paddle1V = 1;
case 'z'
paddle1V = -1;
case 'uparrow'
paddle2V = 1;
case 'downarrow'
paddle2V = -1;
case 'p'
if ~paused
pauseGame([MESSAGE_PAUSED MESSAGE_CONTROLS]);
end
case 'r'
newGame;
case 'q'
unpauseGame;
quitGame = true;
end
unpauseGame;
end
%------------键盘弹起事件------------
%按键弹起后执行
function keyUp(~,event)
switch event.Key
case 'a'
if paddle1V == 1
paddle1V = 0;
end
case 'z'
if paddle1V == -1
paddle1V = 0;
end
case 'uparrow'
if paddle2V == 1
paddle2V = 0;
end
case 'downarrow'
if paddle2V == -1
paddle2V = 0;
end
end
end
%----------------------主程序----------------------
createFigure;
newGame;
while ~quitGame
moveBall;
movePaddles;
refreshPlot;
checkGoal;
end
close(fig);
end
- Log4j官方文档翻译(四、如何在java中输出日志消息)
- 展望未来:使用 PostCSS 和 cssnext 书写 CSS
- Java多线程之Runable与Thread
- 关于 devbridge-autocomplete 插件多选操作的实现方法
- node-sass 安装失败的解决措施
- JavaMelody监控SQL
- 关于jboss的线程问题+java.lang.outofmemoryError
- 《了不起的 nodejs》中 TwitterWeb 案例 bug 解决
- java.lang.ClassNotFoundException与java.lang.NoClassDefFoundError的区别
- 【java开发系列】—— Tomcat编译报错
- java.lang.NoClassDefFoundError: org/aopalliance/aop/Advice
- 《像计算机科学家一样思考Java》—— 读后总结
- 记录安装oracle的那些事(三)之oracle Database R2安装
- Elasticsearch Javascript API增删改查
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法