回溯算法是一种选优搜索法,按选优条件向前搜索,以达到目标。简单的说是在搜索过程中寻找问题的解,当发现已不满足求解条件时,就回溯返回,尝试别的路径。

当探索到某一步时,发现原先选择不是目前的最优解或不满足问题条件时,就退回一步重新选择,并减去当前步骤的节点对应的值,这种方法为回溯法

回溯法解题步骤
(1)针对所给问题,确定问题的解空间: 首先应明确定义问题的解空间,问题的解空间应至少包含问题的一个(最优)解。

(2)确定结点的扩展搜索规则 

(3)以深度优先方式搜索解空间,并在搜索过程中用剪枝函数避免无效搜索。

AM1ng’s Algorithm Blog!

实验题目: 最小重量机器设计问题

设某一机器由n个部件组成,每一种部件都可以从m个不同的供应商处购得。设wij​是从供应商j 处购得的部件i的重量,cij​是相应的价格。 试设计一个算法,给出总价格不超过d的最小重量机器设计。
输入格式:
第一行有3 个正整数n ,m和d, 接下来的2n 行,每行n个数。前n行是c,后n行是w。
输出格式:
输出计算出的最小重量,以及每个部件的供应商

算法描述

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
void BackTrack(int t)
{
if(t==n)//到达最后一层
{
for(int i=1; i<=m; i++)//遍历所有叶子节点
{
cw+=w[t][i];
cc+=c[t][i];
x[t]=i;
if(cc<=max_c&&cw<bestw)//若费用不超过最大费用并且重量小于之前的最优解
{
//更新最优解
bestw=cw;
for(int j=1; j<=n; j++)
bestx[j]=x[j];
}
cc-=c[t][i];//返回上一层
cw-=w[t][i];
x[t]=0;
}
}
else//未到达最后一层
{
for(int i=1; i<=m; i++)//遍历该层节点
{
x[t]=i;
cw+=w[t][i];
cc+=c[t][i];
if(cc<max_c&&cw<bestw)//费用小于最小费用重量小于最优解时进入下一层
{
BackTrack(t+1);
}
cc-=c[t][i];//返回上一层
cw-=w[t][i];
x[t]=0;

}
}
}

思路描述

1.回溯法

初始化供应商数量及部件数量,然后初始化部件的一些属性作为测试数据。程序关键点是中间变量的总价值取较小的那个,
总重量与最小重量c的比对是否达到最小,最优。

2.算法解释

利用总长为l,利用数组存储每一个程序占用大小,每存储一个程序,总长l减去对应存储进去程序所需占用的大小,
此时计数器count加一,每次循环更新剩余的l的长度,判断是否够存储下一个程序。

贪回溯法心得体会

回溯法模板

1
2
3
4
5
6
7
8
9
10
11
12
void Backtrack(int t)
{//以深度优先的方式遍历第t层中的某棵子树
if(t>n) { Output(x); return; }
if (……) {
x[t]=1; Backtrack(t+1);
}
if (……) {
x[t]=0; Backtrack(t+1);
}
}


回溯法是一种选优搜索法,即探索与回溯法,又称为试探法,安选优条件向前搜索,以达到目标。
如果探索到某一步时,发现无法达到最优解或者无解,则退回到上一步,即回溯,直到选出最优解为止。
回溯过程中之前走到的位置,可以是上个选择,也可以是根据算法自定条件的位置,甚至可以是原点,但是一般不考虑原点,会出现死循环。
回溯算法解题的一个显著特征,是在搜索解的过程中动态的产生问题的解空间。在任何时候,算法只保存从根节点到当前扩展结点的路劲。
如果解空间树中从根节点到叶节点的最长路径的长度为h(n),则回溯法所需要的计算空间通常为O(h(n))。

More info: 回溯法

See U next time!

2021年12月08日
阅读更多...

贪心算法是指在对问题求解时,总是做出在当前看来是最好的选择。也就是说,不从整体最优上加以考虑,只做出在某种意义上的局部最优解。贪心算法不是对所有问题都能得到整体最优解,关键是贪心策略的选择,选择的贪心策略必须具备无后效性,即某个状态以前的过程不会影响以后的状态,只与当前状态有关。
解题的一般步骤是:
1.建立数学模型来描述问题;
2.把求解的问题分成若干个子问题;
3.对每一子问题求解,得到子问题的局部最优解;
4.把子问题的局部最优解合成原来问题的一个解。

AM1ng’s Algorithm Blog!

实验题目: 程序存储问题

设有n 个程序{1,2,…, n }要存放在长度为L的磁带上。程序i存放在磁带上的长度是 li,1≤i≤n。 程序存储问题要求确定这n 个程序在磁带上的一个存储方案, 使得能够在磁带上存储尽可能多的程序。 对于给定的n个程序存放在磁带上的长度,计算磁带上最多可以存储的程序数。
input:第一行是2 个正整数,分别表示文件个数n和磁带的长度L。接下来的1行中,有n个正整数,表示程序存放在磁带上的长度。
output:输出最多可以存储的程序数。

算法描述

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
int main()
{
int n,l;
int count =0; //计数器计算存储了几个
cin>>n>>l;

int a[n+1];
for(int i = 0;i<n;i++)
{
cin>>a[i];
}

sort(a,a+n);//默认升序

for(int i = 0;i<n;i++)
{
if(a[i]<=l)
{
l -=a[i];//l 代表总长
count++;
}
}

cout<<count;

return 0;
}

思路描述

1.贪心算法(贪心策略)

目的是要存储最多的程序,贪心算法策略为利用sort函数对程序占用量进行排序,选择最小的,从最小的开始存储,验证得到最优方案里面一定也包含从最小开始选的方案,
说明此策略符合最优解,贪心算法成立。

2.算法解释

利用总长为l,利用数组存储每一个程序占用大小,每存储一个程序,总长l减去对应存储进去程序所需占用的大小,
此时计数器count加一,每次循环更新剩余的l的长度,判断是否够存储下一个程序。

3 复杂度分析
时间复杂度:利用了sort函数对占用大小进行排序,其原理是依据快排,时间复杂度O(n²)

空间复杂度:一维数组O(n)

贪心算法的个人体会和思考

贪心算法总是作出在当前看来最好的选择。
所以难想到利用初步的排序或者按照一定自己来定义的方法进行择优处理,从而达到选取最好的过程。
贪心算法常用于解决最大值或最小值的优化问题。贪心算法能求得最优解的问题一般具有两个重要性质:
贪心选择性质:问题的整体最优解可以通过一系列局部最优的选择达到。这是贪心算法可行的第一个基本要素,也是贪心算法问题和动态规划问题的主要区别。贪心算法通常自顶向下,以迭代的方式做出相继的贪心选择。
最优子结构性质:问题的整体最优解包含子问题的最优解。
贪心算法的基本要素:

1.贪心选择性质。所谓贪心选择性质是指所求问题的整体最优解可以通过一系列局部最优的选择,即贪心选择来达到。这是贪心算法可行的第一个基本要素,也是贪心算法与动态规划算法的主要区别。

动态规划算法通常以自底向上的方式解各子问题,而贪心算法则通常以自顶向下的方式进行,以迭代的方式作出相继的贪心选择,每作一次贪心选择就将所求问题简化为规模更小的子问题。

对于一个具体问题,要确定它是否具有贪心选择性质,必须证明每一步所作的贪心选择最终导致问题的整体最优解。

2.当一个问题的最优解包含其子问题的最优解时,称此问题具有最优子结构性质。问题的最优子结构性质是该问题可用动态规划算法或贪心算法求解的关键特征。

More info: 贪心算法

See U next time!

2021年11月15日
阅读更多...

算法导论这本书是这样介绍这个算法的,动态规划与分治方法类似,都是通过组合子问题的解来来求解原问题的。再来了解一下什么是分治方法,以及这两者之间的差别,分治方法将问题划分为互不相交的子问题,递归的求解子问题,再将它们的解组合起来,求出原问题的解。而动态规划与之相反,动态规划应用与子问题重叠的情况,即不同的子问题具有公共的子子问题(子问题的求解是递归进行的,将其划分为更小的子子问题)。
态规划对于每一个子子问题只求解一次,将其解保存在一个表格里面,从而无需每次求解一个子子问题时都重新计算,避免了不必要的计算工作。

AM1ng’s Algorithm Blog!

实验题目:单调递增最长子序列

算法描述

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
void solve()
{
for(int i = 1; i <= n; ++i)
F[i] = 1;
for(int i = 1; i <= n; ++i)
{
for(int j = 1; j < i; ++j)
{
if(a[i] > a[j] && F[i] < F[j] + 1)
F[i] = F[j] + 1;
}
}
for(int i = 1; i <= n; ++i)
if(F[i] > max_)
max_ = F[i];
}

More info: 单调递增最长子序列

思路描述

1 各数组解释
int a[1024]; //原数组

int F[1024]; //在i处的长度

int n; //目标数组

2 算法思路
F[i]的含义为:在“可取元素为前i”且“取第i个元素”时最长递增序列的长度。

列出递归关系为: F[i] = max(F[k]) + 1, 1 <= k <= i - 1 && a[i] > a[k]

其实就是利用动态规划的一种思想

采用遍历数组序列,不断更新递增序列的长度以至于来找到最长单调递增序列。

3 复杂度分析
时间复杂度:遍历两个数组,双循环 T=O(n2)

空间复杂度:O(n)

动态规划的个人体会和思考

动态规划又叫做填表法,就是说动态规划就是个填表游戏。
1、自底向上:思想是逆向的,但也能正向解答。两者是相同的,只是求解顺序不一样。
2、状态转移方程:对于这个,我只能说,暴力怎么解,动态规划就怎么解。因为求解动态规划的顺序是先暴力递归——带备忘录的递归——动态规划。并且看博客多了的人会发现,其实递归的递归体就是动态规划的状态转移方程。不同的思考,得出的状态转移方程也不一样。
3、最优子问题:大问题分成小问题,小问题寻找最优解构成大问题的最优解。这一点不必太在意,因为求解的过程就是在求解小问题的最优解。

More info: 动态规划例题

See U next time!

2021年10月24日
阅读更多...

在计算机科学中,分治法是一种很重要的算法。字面上的解释是“分而治之”,就是把一个复杂的问题分成两个或更多的相同或相似的子问题,再把子问题分成更小的子问题……直到最后子问题可以简单的直接求解,原问题的解即子问题的解的合并。

任何一个可以用计算机求解的问题所需的计算时间都与其规模有关。问题的规模越小,越容易直接求解,解题所需的计算时间也越少。例如,对于n个元素的排序问题,当n=1时,不需任何计算。n=2时,只要作一次比较即可排好序。n=3时只要作3次比较即可,…。而当n较大时,问题就不那么容易处理了。要想直接解决一个规模较大的问题,有时是相当困难的。

AM1ng’s Algorithm Blog!

实验题目:maximum number in a unimodal array(单峰数组中的最大数目)

算法描述

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
int biosearch( int a[],int left,int right)
{
while(left<=right)//满足二分法的条件,同时可以用于判断二分法何时停止
{
int max=(left+right)/2; //二分法循环后缩小范围
if(a[max]>a[max-1]&&a[max]>a[max+1])//max大于左右,即为峰值,符合目的
{
return max;

}
if(a[max]>a[max+1]&&a[max]<a[max-1])//max大于右边小于左边 最大值在right左边 从右往左缩小范围 更新右指针
{
right=max-1;
}
else{
left = max+1;//同上理 最大值在left右边 从左往右缩小范围 更新左指针
}

}

}

More info: 二分法

分治法的个人体会和思考

分治法解释:面上的解释是“分而治之”,就是把一个复杂的问题分成两个或更多的相同或相似的子问题,再把子问题分成更小的子问题……直到最后子问题可以简单的直接求解,原问题的解即子问题的解的合并。

基本步骤:分解、求解子问题、合并。

思考:分治法很直观明了的让我们作为计算机系的学生去体会到了算法的意义和目的,联想到数据结构课上学的快排,二分法,堆排等算法,不难理解分治法其实早已穿插在以前的学习中。但是总的目的都是要对算法进行优化,寻找最优解,过程中要进行复杂度分析,不一定所有情况都必须用分治法或者分治法里是否还需要考虑最优解。

More info: 分治法

See U next time!

2021年10月03日
阅读更多...

关于实践周的第一个项目选择了制作Flying Birds小游戏,预备知识包括面向对象的封装,swing和awt包,Math类,事件监听器,多线程。
关于一些具体参数为何设置实际上应该是和所给素材图片的大小有关,其实也可以利用相关get函数读取相关参数输出后,就可以知道。
以此造成的影响包括图片设置的位置x,y的设定以及小鸟初始位置的设定,以及窗口大小设定。
总的来说,关于设计一个完整项目,最重要的是了解类的属性关系以及类的相关方法。
回顾总设计流程如下
1.绘制面板,放入背景图。
2.设计地面、柱子类完成移动的效果(移动方法实现)。
3.设计小鸟,完成飞行轨迹、与柱子是否碰撞的方法等。
4.设计游戏类,完成游戏类界面的绘制。
5.设计游戏开始的方法与流程。
6.增加鼠标监听器完成对小鸟飞行及游戏运行的控制。
具体知识点包括
变量
1.分支语句
2.循环语句
3.面向对象
4.异常处理
5.Random随机数
6.StringBuffer字符串操作
7.IO操作
8.多线程
9.swing组件和awt组件
10.Math类函数调用
相关知识点是在边学习边使用,需要更加理解并灵活运使用

Flying Birds总结回顾要点

动画参数中重要参数循环中的i

1
2
3
4
5
6
7
8
9
10
11
//初始化动画帧参数
images=new Image[8];

for(int i=0;i<8;i++)
{
images[i]=new ImageIcon("source/"+i+".png").getImage();
}
index=0;

}

由于在source的文件里表示小鸟的图片有8张i是从0开始对应图片source0.jpg,所以i的循环中从0到7满足就是对souce里面source0.jpg到source7.jpg的遍历。

此处弧度作用

1
2
3
4
5
6
7
8
9
10
11
public boolean hit(Ground ground)
{
boolean hit =y+size/2>ground.y;
if(hit)
{
y=ground.y-size/2;
alpha=Math.PI/2;
}
return hit;
}

判断条件中判断到撞击地面后, alpha=Math.PI/2实际上将小鸟的弧度重置为Math.PI/2,表现在游戏中gameover的时候小鸟摔了个底朝天。

More info: 小鸟被撞翻啦

repaint()方法

1
2
3
//休眠1000/60毫秒
Thread.sleep(1000/60);
repaint();

repaint()这个方法是一个具有刷新页面效果的方法,如果你要页面进行重画就可以调用.一般都是在AWT的图形绘制当中调用的到
工作原理如下:
repaint()方法
|
|
V
AWT线程--->paint()方法-->图形绘制
   |
   |
   V
update()方法--->paint()方法--图形绘制

主要需要判断出现的两大界面

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
int state;//游戏状态
//状态常量
public static final int START=0;//开始
public static final int RUNNING=1;//运行
public static final int GAME_OVER=2;//结束


public void mousePressed(MouseEvent e)
{
try {
switch(state) {
case START:
//在开始前按下鼠标转为运行状态
state=RUNNING;
break;
case RUNNING:
//在运行状态,按下鼠标小鸟向上飞行
bird.flappy();
break;
case GAME_OVER:
//在结束状态,按下鼠标重置数据变为开始
column1=new Column(1);
column2=new Column(2);
bird=new Bird();
score=0;
state=START;
break;
}
}
//绘制开始和结束界面
switch(state)
{
case START:
g.drawImage(startImage, 0, 0, null);
break;
case GAME_OVER:
g.drawImage(overImage, 0, 0, null);
break
}

通过Bird类里面的碰撞判断再来判断Birdgame类里面的state//状态常量,通过状态常量在switch语句里面的条件判断情况后,绘制
不同情况下所应该显示的对应图片。

JFrame的使用到的代码

1
2
3
4
5
6
7
8
9
10
11
12
13
 
public static void main(String[] args) throws Exception
{

JFrame frame=new JFrame();
BirdGame game=new BirdGame();
frame.add(game);
frame.setSize(440,670);
frame.setLocationRelativeTo(null);//设置窗口相对于指定组件的位置。如果组件当前未显示或者 为 null,则此窗口将置于屏幕的中央
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//如果在代码里没加这个方法,那么在点击框架的”叉叉“退出框架后,程序仍然没有退出,只是JFrame被关闭了。
frame.setVisible(true);
game.action();
}

JFrame是最底层,JPanel是置于其面上,同一个界面只有一个JFrame,一个JFrame可以放多个JPanel。
JFrame 用来设计类似于 Windows 系统中窗口形式的界面。JFrame 是 Swing 组件的顶层容器,该类继承了 AWT 的 Frame 类,支持 Swing 体系结构的高级 GUI 属性。
JPanel 是一种中间层容器,它能容纳组件并将组件组合在一起,但它本身必须添加到其他容器中使用。

JFrame常见使用方法

1
2
3
4
5
6
7
JFrame jf = new JFrame("我是标题鸭!!!");//创建一个JFrame对象
jf.setTitle("我是标题鸭!!!");//标题的设置
jf.setSize(20,10)//设置了一个长为20,高为10的框图。
jf.setBounds(1,2,20,10)//设置一个左上角顶点在(1,2),长为20,宽为10的窗体。
jf.setLocation(1,2)//设置一个左上角顶点在(1,2)的窗体。
jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//设置同步开关
jf.setVisible(true);//设置窗体可见

JPanel常见使用方法

1
2
3
4
5
6
7
8
9
//构造方法
JPanel():使用默认的布局管理器创建新面板,默认的布局管理器为 FlowLayout。
JPanel(LayoutManagerLayout layout):创建指定布局管理器的 JPanel 对象。
//常见函数
Component add(Component comp) 将指定的组件追加到此容器的尾部
void remove(Component comp) 从容器中移除指定的组件
void setFont(Font f) 设置容器的字体
void setLayout(LayoutManager mgr) 设置容器的布局管理器
void setBackground(Color c) 设置组件的背景色

More info: JPanel和JFrame的使用方法

Welcome back AM1ng!

2021年07月17日
阅读更多...

关于实践周的第一个项目选择了制作Flying Birds小游戏。接下来是地面类和柱子类详细参数的设置。

地面类初始化

1
2
3
4
5
6
7
8
public Ground() throws Exception
{
image =new ImageIcon("source/ground.png").getImage();//原图片
width=image.getWidth(null);//使用 img.getWidth(null); 图片加载到内存中,可获图片真实宽度
height=image.getHeight(null);//使用 img.getHeight(null); 图片加载到内存中,可获图片真实高度
x=0;
y=500;
}

设计Gound类里默认读取图片资源中的ground的图片利用image.getWidth(null) image.getHeight(null)读取图片的高宽。
x y来控制图片放置的位置。

Ground类左移

1
2
3
4
5
6
7
8
9
//左移
public void step()
{
x-=4;
if(x<=-109)
{
x=0;
}
}

同样名为step类意味小鸟移动其实是用地面的图像左移的动画来实现的。

柱子类初始化

1
2
3
4
5
6
7
8
9
10
public Column(int n) throws Exception
{
image=new ImageIcon("source/column.png").getImage();
width=image.getWidth(null);
height=image.getHeight(null);
gap=144;
distance=245;
x=550+(n-1)*distance;
y=random.nextInt(218)+132;
}

同理可以默认读取图片资源中的clolumn的图片利用image.getWidth(null) image.getHeight(null)读取图片的高宽。
利用random类使游戏过程中柱子不断刷新后的纵坐标不同,所以柱子出现的高矮就会不同甚至没有上柱子。
gap是柱子之间缝隙(上下),由于贴图原因实际上gap应该为定制,如果缩小gap可能在间隙也会发生碰撞,如果扩大gap虽然确实可以增加通过的间隙,但是部分
间隙和柱子重叠,显示的是鸟经过了柱子但是没有发生碰撞。
由于柱子类出现X可以有distance控制,所以改变distance实际上是可以改变柱子出现的间隔距离(左右)。可以通过此处来改变游戏难度。

柱子类移动

1
2
3
4
5
6
7
8
9
public void step()
{
x-=4;
if(x<= -width/2)
{
x=distance*2-width/2;
y=random.nextInt(218);
}
}

柱子随地面按step函数移动。

Welcome back AM1ng!

2021年07月17日
阅读更多...

Bird类思路要点

关于实践周的第一个项目选择了制作Flying Birds小游戏,此小游戏的易上手之处其实还在于通过几帧的小鸟图片来代表小鸟的运动形态。
飞行动作(变化一帧)依靠以图片类型构成的数组内重复调用小鸟状态的图片来显示。
移动一步需要依靠计算上跑位移、计算鸟的坐标、计算下次移动速度、计算倾角(反正切函数),向上飞行时按照惯性需要重置速度。
其中设计小鸟的另外两个关键函数在于判断小鸟是否碰撞到地面或者检测小鸟是否撞到柱子,此为游戏规则。

Bird动画原理

1
2
3
4
5
6
7
8
9
10
11
12
13
Image[] images;//一组图片记录小鸟动画帧(images类数组的一组照片,Source里面的小鸟的不同照片完成小鸟的动作动画)
int index;//帧数下标
...
...
//初始化动画帧参数
images=new Image[8];

for(int i=0;i<8;i++)
{
images[i]=new ImageIcon("source/"+i+".png").getImage();
}
index=0;//利用source后面i++来访问souce里面的Bird照片,所以照片存储摆放会有影响

首先有一个Souce文件里面需要收集小鸟多个状态的图片,在此次项目中放置在Source的文件包里面,关于小鸟的每一帧形态的图片为该包内的0-7个文件。
此处文件顺序对动作会有影响,上述代码附带解释。

Bird中step:移动一步

1
2
3
4
5
6
7
8
9
10
11
12
13
public void step()
{
double v0=speed;
//计算上跑位移
s=v0*t+g*t*t/2;
//计算鸟的坐标
y=y-(int)s;
//计算下次移动速度
double v=v0-g*t;
speed =v;
//计算倾角(反正切函数)
alpha=Math.atan(s/8);
}

移动中根据间隔时间需要计算鸟出现的坐标以及倾斜角展示鸟下落或者上飞的一个过程。

Bird类碰撞判断(游戏不碰撞的规则)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

//检测小鸟是否碰撞到地面
public boolean hit(Ground ground)
{
boolean hit =y+size/2>ground.y;
if(hit)
{
y=ground.y-size/2;
alpha=Math.PI/2;
}
return hit;
}

//检测小鸟是否撞到柱子
public boolean hit(Column column)
{
//检测是否在柱子范围内
if(x>column.x-column.width/2-size/2&&x<column.x+column.width/2+size/2)
{
if(y>column.y-column.gap/2+size/2&&y<column.y+column.gap/2-size/2) return false;
return true;
}
return false;
}
}

hit类用boolean类型定义返回值可以选用0或1方便之后的判断是否碰撞(即0或1)
考虑碰撞的两个需要同时满足的因素:一是小鸟是否会从侧面撞到柱子所以调用到column.width 二是在满足一的条件下小鸟坐标是否位于间隙(gap)坐标内

Bird起飞

1
2
3
4
5
6
//向上飞行
public void flappy()
{
//重置速度
speed=v0;
}

对鼠标左键进行监听,当点击鼠标左键时,小鸟会获得一个向上的速度,当松开鼠标左键的时候,小鸟就会坠落。

Welcome back AM1ng!

2021年07月16日
阅读更多...

Birdgame类

关于实践周的第一个项目选择了制作Flying Birds小游戏,首先会考虑到最直观的界面设计。
其中主要运用swing和awt包:图形界面工具,绘制出游戏场景。
主要设计对象包括游戏开始界面,游戏分数统计,游戏结束界面。

整个Birdgame类继承JPanel

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class BirdGame extends JPanel {
...
...
}
JPanel中常用方法
void add(Component):添加组件。
void add(Component,int):添加组件至索引指定位置。
void add(Component,Object):按照指定布局限制添加组件。
void add(Component,Object,int):按照指定布局管理器限制添加组件到指定位置。
void remove(Component):移除组件。
void remove(int):移除指定位置的组件。
void removeAll():移除所有组件。
void paintComponent(Graphics):绘制组件。``
void repaint():重新绘制。
void setPreferredSize(Dimension):设置组件尺寸。
Dimension getPreferredSize():获取最佳尺寸。

组件是构成应用程序界面的基本元素,按钮、文本框、进度条等,都是组件。可视化组件又可以分为容器组件和非容器组件,可以在JPanel中放置按钮、文本框等非容器组件,甚至可以在JPanel中再放置若干个JPanel组件,顶层容器也是容器组件,每一个窗口应用程序中有且只能有一个顶层容器组件。
经常使用JPanel先创建一个面板,在向这个面板添加组件,然后把这个面板添加到其他容器中。
JPanel面板的默认布局是FlowLayout布局**
More info: JFrame,JPanel,JLabel详解

Graphics2D类基本使用

1
2
3
4
//绘制小鸟
Graphics2D g2=(Graphics2D) g;
g2.rotate(-bird.alpha,bird.x,bird.y);//rotate(double arc,double x, double y):图形以点(x,y)为轴点,旋转arc弧度。
g2.rotate(bird.alpha,bird.x,bird.y);//rotate(double arc,double x, double y):图形以点(x,y)为轴点,旋转arc弧度。

Java语言在Graphics类提供绘制各种基本的几何图形的基础上,扩展Graphics类提供一个Graphics2D类,它拥用更强大的二维图形处理能力,提供、坐标转换、颜色管理以及文字布局等更精确的控制。
Graphics2D定义了几种方法,用于添加或改变图形的状态属性。可以通过设定和修改状态属性,指定画笔宽度和画笔的连接方式;设定平移、旋转、缩放或修剪变换图形;以及设定填充图形的颜色和图案等。图形状态属性用特定的对象存储。
More info: Graphics2D类基本使用

与鼠标互动

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
不断重复和绘制
MouseListener l=new MouseAdapter()
{
public void mousePressed(MouseEvent e)
{
try {
switch(state) {
case START:
//在开始前按下鼠标转为运行状态
state=RUNNING;
break;
case RUNNING:
//在运行状态,按下鼠标小鸟向上飞行
bird.flappy();
break;
case GAME_OVER:
//在结束状态,按下鼠标重置数据变为开始
column1=new Column(1);
column2=new Column(2);
bird=new Bird();
score=0;
state=START;
break;
}
}
catch (Exception ex)
{
ex.printStackTrace();
}
}

};
addMouseListener(l);

java中 addMouseListener()方法用于接收组件上“感兴趣”的鼠标事件(按下、释放、单击、进入或离开)的侦听器接口。(要跟踪鼠标移动和鼠标拖动,请使用 MouseMotionListener。)
MouseListener与MouseAdapter的区别在于一个是类,一个是接口。
适配器已经实现了相应的接口,例如MouseAdapter类实现了MouseListener接口,因此可以使用MouseAdapter的子类创建的对象做监视器,只需重写需要的接口方法即可。

启动方法

1
2
3
4
5
6
7
8
9
10
11
12
13

public static void main(String[] args) throws Exception
{

JFrame frame=new JFrame();
BirdGame game=new BirdGame();
frame.add(game);
frame.setSize(440,670);
frame.setLocationRelativeTo(null);//设置窗口相对于指定组件的位置。如果组件当前未显示或者 为 null,则此窗口将置于屏幕的中央
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//如果在代码里没加这个方法,那么在点击框架的”叉叉“退出框架后,程序仍然没有退出,只是JFrame被关闭了。
frame.setVisible(true);
game.action();
}

关于Java的setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE) 这个方法是JFrame类的一个方法,EXIT_ON_CLOSE是JFrame的一个静态常量。
该方法的翻译大概是“设置默认的关闭操作,参数”在关闭动作时退出“。

Welcome back AM1ng!

2021年07月13日
阅读更多...
404 Oh>..< 我找不到回家的路了
2021年07月12日
阅读更多...

关于实践周的第一个项目选择了制作Flying Birds小游戏,预备知识包括面向对象的封装,swing和awt包,Math类,事件监听器,多线程。

新的需要了解的包

AWT

1
import java.awt.*;

AWT(Abstract Window Toolkit),中文译为抽象窗口工具包,是Java提供的用来建立和设置Java的 图形用户界面 的基本工具。
AWT由Java中的java.awt包提供,里面包含了许多可用来建立与平台无关的图形用户界面(GUI)的类,这些类又被称为组件( component s)。

More info: AWT

Swing

1
import javax.swing.*;

Swing 包含了构建图形界面(GUI)的各种组件,如: 窗口、标签、按钮、文本框等。
Swing 提供了许多比 AWT 更好的屏幕显示元素,使用纯 Java 实现,能够更好的兼容跨平台运行。
为了和AWT组件区别,Swing组件在javax.swing.包下,类名均以 J 开头,例如: JFrame、JLabel、JButton等.

More info: Swing

imageIO

1
import javax.imageio.ImageIO;

Java使用imageio 读写图像,比较常见。读取如Bird的状态,Ground,Column类的图像(这里用已有素材,自己就PS了)

源码分类

1
2
3
4
Birdgame.java //绘制面板,放入背景图 增加鼠标监听器完成对小鸟飞行及游戏运行的控制,设计游戏开始的方法与流程。
Bird.java //设计小鸟,完成飞行轨迹、与柱子是否碰撞的方法等。
Ground.java //设计地面类完成移动的效果(移动方法实现)。
Column.java //设计柱子类完成移动的效果(移动方法实现)。

综上:
面向对象的封装:设计包装出小鸟、地面、柱子、游戏四个类。
swing和awt包:图形界面工具,绘制出游戏场景。
Math类:运用atan等方法辅助完成小鸟旋转角度转换。
事件监听器:运用鼠标监听器完成游戏状态转换及小鸟移动。
多线程:该项目就用到了一个sleep休眠。

Welcome back AM1ng!

2021年07月12日
阅读更多...