p5结合做自动井字小游戏
Posted 阿宝逃离地球
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了p5结合做自动井字小游戏相关的知识,希望对你有一定的参考价值。
p5结合做自动井字小游戏
B站上看到的教程:https://www.bilibili.com/video/BV12i4y157wh?p=1
视频教程的作者的关于这个小游戏的Github地址:https://github.com/CodingTrain/website/tree/main/CodingChallenges/CC_149_Tic_Tac_Toe
一、效果展示
在视频教程中,作者是用p5的网页编辑器(需要科学上网才比较好加载出来的样子),我是直接用html+js调用p5的库来制作网页查看效果。
效果如下图所示
二、思路整理
做完之后整理一下思路如下:
1.确定全局所需变量:井字面板内容数组变量(board),存放数组全部元素的下标索引的数组(available),玩家内容(players),当前玩家内容(currentPlayer),绘制井字格的宽高(w,h)
2.绘制背景
3.初始化各个变量的值
4.确度每个方格的位置,遍历面板数组的内容,查看其内容,绘制“X"/“O”,每一个方格出现内容就判断以下有无输赢情况出现,有的话则结束游戏,无的且方格已经填满完成就退出游戏,宣布结局,如果方格还没有被填满的话就进入下一回合。
三、代码部分和源代码理解
1.函数大体框架
//file:sketch.js
let board;//面板内容
let availble;//存储面板元素下标
let players;//玩家
let currentPlayer;//当前玩家
let w,h;
function equals3(a,b,c){}//判断是否构成一条线
function checkWinner(){}//判断胜出玩家
function nextTurn(){} //下一回合
function setup(){}
function draw() {}
2.初始化各个变量和细化函数体
//file:sketch.js
//井字格的元素内容用二维数组来表示board[3][3],一开始元素皆为空''
let board = [
['','',''],
['','',''],
['','',''],
];
let availble = [];//存储面板元素下标,一开始声明为空,在函数setup()中初始化每一个元素的值
let players = ['X','O'];//玩家代表内容'X'或'O'
let currentPlayer;//当前玩家
function setup(){
//绘制画布大小400*400
createCanvas(400,400);
background(200);
frameRate(1);//指定每秒显示的帧数
//绘制井字格
w = width/3;
h = height/3;
//画背景图层的井字线
line(w,0,w,height);
line(w*2,0,w*2,height);
line(0,h,width,h);
line(0,h*2,width,h*2);
//初始化available和currentPlayer
currentPlayer = floor(random(players.length));//随机指定玩家代表内容的下标
for(let i=0;i<3;i++){
for(let j=0;j<3;j++){
available.push([i,j]);//存储board中的每个元素的位置
}
}
}
3.绘制背景和遍历面板元素确认其是否输赢以及下一回合
判断成线方格的内容是否相同的函数
//file:sketch.js
function equals3(a,b,c){
return a==b && b==c && a!='';
}//判断是否构成一条线
判断输赢的函数
function checkWinner(){
let winner = null;//结果
for(let i=0;i<3;i++){
//横向判断
if(equals3(board[i][0],board[i][1],board[i][2])){
winner = board[i][0];
}
//纵向判断
if(equals3(board[0][i],board[1][i],board[2][i])){
winner = board[0][i];
}
}
//对角线
if (equals3(board[0][0],board[1][1],board[2][2])) {
winner = board[0][0];
}
if (equals3(board[2][0],board[1][1],board[0][2])) {
winner = board[2][0];
}
// available.length==0是确保可以填的方格无了
if (winner == null && available.length == 0) {
return 'tie';//平局
}else{
return winner;//‘X’或‘O’获胜
}
}
进入下一回合函数
//file:sketch.js
function nextTurn(){
//floor()函数,向下取最大整数;在数组available长度中随机取一个作为参数
let index = floor(random(availble.length));
//利用随机获得的参数作来指定面板中玩家选择绘制‘X’或‘O’的位置(available的元素),并在数组删除该元素
let spot = available.splice(index,1)[0];
let i = spot[0];
let j = spot[1];
console.log(i,j);//可以查看控制台输出d的i,j,即选择的位置
//指定玩家在该位置所要的符号
board[i][j] = players[currentPlayer];
//更新currentPlayer的值,使其与上一个符号的下标相反
currentPlayer = (currentPlayer+1)%players.length;
}
进入执行setup()和draw()
//file:sketch.js
function draw(){
//遍历面板元素绘制玩家的下落方格,i是行,j是列,x是横向坐标,y是纵向坐标
for(let i=0;i<3;i++){
for(let j=0;j<3;j++){
//每个方格的中心坐标点
let x = j*w+w/2;
let y = i*w+w/2;
//声明一个坐标点变量,等于面板数组中对应坐标点的值
let spot = board[i][j];
//如果面板中对应元素的值为‘O’,则在该坐标点画圆
if(spot == players[1]){
ellipse(x, y, w/2);
}else if (spot == players[0]) {
//如果面板中对应元素的值为‘X’,则在该坐标点画两条交叉的线
let xr = w/4;
line(x - xr,y-xr,x+xr,y+xr);
line(x + xr,y-xr,x-xr,y+xr);
}
}
}
//判断输赢
let end = checkWinner();
if(end!=null){
noLoop();//停止持续执行draw()中的代码
let resultP = createP(''); 用给定的内部HTML在DOM中创建<p></p>元素。
resultP.style('font-size', '32pt');
if(end == 'tie'){
resultP.html('Tie!');
}else{
resultP.html(end +'wins!');
}
}else{
nextTurn();
}
}
网页文件
<!-- file:index.html -->
<!DOCTYPE html>
<html>
<head>
<!-- 调用p5函数库的函数大的第一种方式: 绝对文件路径-->
<script src="https://cdn.jsdelivr.net/npm/p5@1.4.0/lib/p5.min.js"></script>
<!--第二种:相对路径,可以在官网下载这个p5.min.js文件,放在同一个文件夹下-->
<script src="p5.min.js"></script>
<meta charset="utf-8"/>
</head>
<body>
<script src="sketch.js"></script>
</body>
</html>
四、一点点修改
增加一个按钮和增加一个对应使用的函数,其它的尝试都失败了,先存着最简单粗暴的办法
<button id="but" onclick="myfun()">Again</button>
//file:sketch.js
function myfun() {
// location.replace(location.href);
location.reload();
console.log("--------");
}
五、收获和总结
- 了解到JS中的关键词let和var的区别,在这个小游戏中的源码中变量都是用let关键字来声明的,而在之前我一直都习惯用var来声明变量
对于javascript 块作用域
- 通过 var 关键词声明的变量没有块作用域。在块 {} 内声明的变量可以从块之外进行访问。
{
var x = 10;
}
// 此处可以使用 x- 在 ES2015 之前,JavaScript 是没有块作用域的,可以使用 let 关键词声明拥有块作用域的变量。
在块 {} 内声明的变量无法从块外访问。
{
let x = 10;
}
// 此处不可以使用 x
对于重新声明变量
- 使用 var 关键字重新声明变量会带来问题, 在块中重新声明变量也将重新声明块外的变量。
var x = 10; // 此处 x 为 10
{
var x = 6; // 此处 x 为 6
}
// 此处 x 为 6- 使用 let 关键字重新声明变量可以解决这个问题,在块中重新声明变量不会重新声明块外的变量
var x = 10; // 此处 x 为 10
{
let x = 6; // 此处 x 为 6
}
// 此处 x 为 10
-
熟悉JS中floor()、splice()、数组的push()函数的使用,在使用中脑海复习了一遍栈的入栈和出栈知识。
-
了解到这个井字游戏中的实现原理
-
熟悉了一些p5的函数比如floor()、random()、createP()、loop()、noLopp(),区别其与在JavaScript的同名函数的区别
- floor():计算最接近的小于或等于参数值的int值。映射到Math.floor()。
语法:floor(n)。
而在JavaScript里的floor()调用语法是Math.floor(x)- random():返回一个随机浮点数。接受0、1或2个参数。如果没有给出参数,则返回一个从0到(但不包括)1的随机数。如果给定一个参数,并且它是一个数字,则返回一个从0到(但不包括)该数字的随机数。如果给定一个参数,并且它是一个数组,则返回该数组中的随机元素。
语法:random([min], [max])或者random(choices)
JavaScript:random() 方法可返回介于 0 ~ 1 之间的一个随机数。语法:Math.random()- createP(): 用给定的内部HTML在DOM中创建<p></p>元素。用于段落长度的文本。
语法:createP([html]),实例:
let p = createP(‘this is some text’);
p.style(‘font-size’, ‘16px’);
p.position(10, 0);
以上是关于p5结合做自动井字小游戏的主要内容,如果未能解决你的问题,请参考以下文章