首页 > Python资料 博客日记
【掘金高手:谁能拒绝一只可爱的乌萨奇的矿工之旅游戏(上)】
2025-01-06 03:00:05Python资料围观10次
🌈个人主页: Aileen_0v0
🔥热门专栏: 华为鸿蒙系统学习|计算机网络|数据结构与算法
💫个人格言:“没有罗马,那就自己创造罗马~”
前言
本文主要是根据我小时候玩的一款游戏——黄金矿工,来进行创新的游戏项目编写过程,内容较多,所以分为多篇。
JAVA项目——Usaqi矿工创新版
窗口绘制
package com.sxt;
import javax.swing.*;
public class GameWin extends JFrame {
void launch(){
this.setVisible(true);
this.setSize(500,500);
this.setLocationRelativeTo(null);
this.setTitle("AileenGoldMiner");
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
}
public static void main(String[] args) {
GameWin gameWin = new GameWin();
gameWin.launch();
}
}
绘制图片
package com.sxt;
import javax.swing.*;
import java.awt.*;
public class GameWin extends JFrame {
Bg bg = new Bg();
void launch(){
this.setVisible(true);
this.setSize(768,1000);
this.setLocationRelativeTo(null);
this.setTitle("AileenGoldMiner");
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
}
@Override
public void paint(Graphics g){
bg.paintSelf(g);
}
public static void main(String[] args) {
GameWin gameWin = new GameWin();
gameWin.launch();
}
}
package com.sxt;
import java.awt.*;
public class Bg {
Image bg = Toolkit.getDefaultToolkit().getImage("C://Users//admin//IdeaProjects//The Gold Miner//imgs//bg.jpg");
Image bg1 = Toolkit.getDefaultToolkit().getImage("C://Users//admin//IdeaProjects//The Gold Miner//imgs//bg1.jpg");
Image usaqi = Toolkit.getDefaultToolkit().getImage("C://Users//admin//IdeaProjects//The Gold Miner//imgs//usaqi.gif");
void paintSelf(Graphics g){
g.drawImage(bg1,0,0,null);
g.drawImage(bg,0,200,null);
g.drawImage(usaqi,310,50,null);
}
}
红线绘制
package com.sxt;
import java.awt.*;
public class Line {
//起点坐标
int x = 380;
int y = 180;
//终点坐标
int endx = 500;
int endy = 500;
void paintSelf(Graphics g){
g.setColor(Color.red);
g.drawLine(x,y,endx,endy);
}
}
package com.sxt;
import javax.swing.*;
import java.awt.*;
public class GameWin extends JFrame {
Bg bg = new Bg();
Line line = new Line();
void launch(){
this.setVisible(true);
this.setSize(768,1000);
this.setLocationRelativeTo(null);
this.setTitle("AileenGoldMiner");
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
}
@Override
public void paint(Graphics g){
bg.paintSelf(g);
line.paintSelf(g);
}
public static void main(String[] args) {
GameWin gameWin = new GameWin();
gameWin.launch();
}
}
模拟分析红线摇摆情况
- 根据绘图我们可以知道,线长不变,起点坐标不变,终点坐标与角度偏移量有关,它可以通过已知条件计算得出,如上图所示,终点坐标表达式为:
endx = x + length ⋅ cos ( α ) endy = y + length ⋅ sin ( α ) \begin{align*} \text{endx} &= x + \text{length} \cdot \cos(\alpha) \\ \text{endy} &= y + \text{length} \cdot \sin(\alpha) \end{align*} endxendy=x+length⋅cos(α)=y+length⋅sin(α)
- 代码实现:
- 当我们的角度值为1时,红线往右偏;角度值为2时,红线往左偏。这是因为在计算机中,x轴正方向向右,y轴正方向向下,角度起点是x轴正方向,角度顺时针旋转,旋转到y轴的时候是直角,角度制当中是90度,在弧度制中是π/2(约为1.57),当jiaodu为1时,小于1.57,所以在y轴右边,当角度为2时大于1.57,所以在y轴的左边。
- 为了让红线动起来,我们可以根据游戏使用界面知道这个角度的变化是从0到π变化的,我们可以设置一个取值范围在(0-1)的系数n,这样n*π的范围就是(0-π),所以我们之前设置的角度可以换为(0-π),也就是说,我们只需要操作n就可以实现角度的变化。
- 现在,想要让红线动起来,只需要不断改变n的值即可,这样旋转角度就会发生变化
- 先让n+0.005看看效果,我们可以看到线有错位,但是并未转动,这是因为图片只绘制了一次,我们需要实现不停地绘制,可以通过死循环,让它重复绘制。
- 现在这条红色就会移动了,但是移动速度比较快,可以通过调用内置的sleep方法来限制红线的绘制速度;此外摆动的区域也要尽量控制在地面下方,可以通过控制n来控制摆动的角度,通过变量dir的正负来控制其摆动方向。
- 代码如下:
package com.sxt;
import java.awt.*;
public class Line {
//起点坐标
int x = 380;
int y = 180;
//终点坐标
int endx = 500;
int endy = 500;
//线长
double length = 100;
//为了使其从x轴右边开始转动,所以n设为0
double n = 0;
//红线摆动方向限定 -> 1表示角度增加往左边移动,-1表示角度减小往右边移动
int dir = 1;
void paintSelf(Graphics g){
//红线摆动范围限定 ->根据之前限定可知n的范围是(0-1),
// 所以n最小我们可以设为0.1,最大可设为0.9.
if(n<0.01){
dir = 1;
} else if (n > 0.9) {
dir = -1;
}
n = n + 0.005*dir;
endx = (int) (x + length*Math.cos(n*Math.PI)); //因为角度是double类型所以要强制转换成int类型
endy = (int) (y + length*Math.sin(n*Math.PI));
g.setColor(Color.red);
g.drawLine(x,y,endx,endy);
}
}
package com.sxt;
import javax.swing.*;
import java.awt.*;
public class GameWin extends JFrame {
Bg bg = new Bg();
Line line = new Line();
void launch(){
this.setVisible(true);
this.setSize(768,1000);
this.setLocationRelativeTo(null);
this.setTitle("AileenGoldMiner");
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
while(true){
repaint();
//限制摆动速度
try {
Thread.sleep(10);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
@Override
public void paint(Graphics g){
bg.paintSelf(g);
line.paintSelf(g);
}
public static void main(String[] args) {
GameWin gameWin = new GameWin();
gameWin.launch();
}
}
红线抓取
- 我们可以设置一个状态参数,通过控制这个状态参数来实现状态的改变。(状态:0表示摇摆,1表示抓取,2表示收回)
- 以下是完整的红线的绘制及操作的逻辑代码
package com.sxt;
import java.awt.*;
public class Line {
//起点坐标
int x = 380;
int y = 180;
//终点坐标
int endx = 500;
int endy = 500;
//线长
double length = 100;
//为了使其从x轴右边开始转动,所以n设为0
double n = 0;
//红线摆动方向限定 -> 1表示角度增加往左边移动,-1表示角度减小往右边移动
int dir = 1;
//状态: 0->摇摆 1->抓取 2->收回
int state;
void paintSelf(Graphics g){
//线的状态设置
switch(state){
case 0://左右摇摆
if (n < 0.1) {dir = 1;}
else if (n > 0.9){dir = -1;}
n = n + 0.005*dir;
endx = (int) (x + length*Math.cos(n*Math.PI)); //因为角度是double类型所以要强制转换成int类型
endy = (int) (y + length*Math.sin(n*Math.PI));
g.setColor(Color.red);
g.drawLine(x,y,endx,endy);
break;
case 1://延长线长度
if(length < 500){//如果线长小于500就可以延长
length = length + 10;
endx = (int) (x + length*Math.cos(n*Math.PI)); //因为角度是double类型所以要强制转换成int类型
endy = (int) (y + length*Math.sin(n*Math.PI));
g.setColor(Color.red);
g.drawLine(x,y,endx,endy);
} else {state = 2 ;}//延长后无其他操作,可以将其状态置为0,让它继续执行左右摇摆以及红线的绘制
break;
case 2://红线收回
if(length > 100){
length = length - 10;
endx = (int) (x + length*Math.cos(n*Math.PI)); //因为角度是double类型所以要强制转换成int类型
endy = (int) (y + length*Math.sin(n*Math.PI));
g.setColor(Color.red);
g.drawLine(x,y,endx,endy);
}else{
state = 0;
}
}
}
}
- 为了减少代码的冗余量,我们将其操作的共性全部抽取到一个新的函数中
void lines(Graphics g){
endx = (int) (x + length*Math.cos(n*Math.PI)); //因为角度是double类型所以要强制转换成int类型
endy = (int) (y + length*Math.sin(n*Math.PI));
g.setColor(Color.red);
g.drawLine(x,y,endx,endy);
}
void lines(Graphics g){
endx = (int) (x + length*Math.cos(n*Math.PI)); //因为角度是double类型所以要强制转换成int类型
endy = (int) (y + length*Math.sin(n*Math.PI));
g.setColor(Color.red);
g.drawLine(x,y,endx,endy);
}
void paintSelf(Graphics g){
//线的状态设置
switch(state){
case 0://左右摇摆
if (n < 0.1) {dir = 1;}
else if (n > 0.9){dir = -1;}
n = n + 0.005*dir;
lines(g);
break;
case 1://延长线长度
if(length < 500){//如果线长小于500就可以延长
length = length + 10;
lines(g);
} else {state = 2 ;}//延长后无其他操作,可以将其状态置为0,让它继续执行左右摇摆以及红线的绘制
break;
case 2://红线收回
if(length > 100){
length = length - 10;
lines(g);
}else{
state = 0;
}
}
运行效果
创建金块
- 由于金块和石块有很多共同的属性,所以我们可以先创建一个
Object
类作为他们的父类
实现代码
package com.sxt;
import java.awt.*;
/**
* 石块和金块的父类,用于抽取共性
*/
public class Object {
//坐标
int x;
int y;
//宽高
int width;
int height;
//图片
Image img;
void paintSelf(Graphics g){
g.drawImage(img,x,y,null);
}
}
package com.sxt;
import java.awt.*;
public class Gold extends Object{
Gold(){
this.x = 300;
this.y = 500;
this.width = 32;
this.height = 52;
this.img = Toolkit.getDefaultToolkit().getImage("C://Users//admin//IdeaProjects//The Gold Miner//imgs//gold1.gif");
}
}
package com.sxt;
import javax.swing.*;
import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
public class GameWin extends JFrame {
Bg bg = new Bg();
Line line = new Line();
Gold gold = new Gold();
void launch(){
this.setVisible(true);
this.setSize(768,1000);
this.setLocationRelativeTo(null);
this.setTitle("AileenGoldMiner");
this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
super.mouseClicked(e);
if(e.getButton() == 1){
line.state=1;
}
}
});
while(true){
repaint();
//限制摆动速度
try {
Thread.sleep(10);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
@Override
public void paint(Graphics g){
bg.paintSelf(g);
line.paintSelf(g);
gold.paintSelf(g);
}
public static void main(String[] args) {
GameWin gameWin = new GameWin();
gameWin.launch();
}
}
双缓存技术解决物体闪动问题
-
根据我们的运行结果,我们可以看到存在物体闪动问题,现在让我们先分析出现这个现象的原因。
-
根据这段代码,我们可以知道我们的绘制顺序是:背景->人物->金块;所以我们需要将它们依次画入到一个画布中,变成一个整体一起传入窗体中,就不会出现闪动问题。
package com.sxt;
import javax.swing.*;
import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
public class GameWin extends JFrame {
Bg bg = new Bg();
Line line = new Line();
Gold gold = new Gold();
//定义一个画布
Image offScreenImage;
void launch(){
this.setVisible(true);
this.setSize(768,1000);
this.setLocationRelativeTo(null);
this.setTitle("AileenGoldMiner");
this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
super.mouseClicked(e);
if(e.getButton() == 1){
line.state=1;
}
}
});
while(true){
repaint();
//限制摆动速度
try {
Thread.sleep(10);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
@Override
public void paint(Graphics g){
//定义画布大小,使其与窗口大小一致
offScreenImage = this.createImage(768,1000);
Graphics gImage = offScreenImage.getGraphics();
//将背景,人物,金块依次画入到画布中
bg.paintSelf(gImage);
line.paintSelf(gImage);
gold.paintSelf(gImage);
//将画布导入到窗体中
g.drawImage(offScreenImage,0,0,null);
}
public static void main(String[] args) {
GameWin gameWin = new GameWin();
gameWin.launch();
}
}
现在我们的537,就不会闪动啦~
抓取判定
-
其实金块在程序中实际上是一个矩形,红线末尾是一个点,抓取判定(碰撞检测)实质上就是检测点是否在矩形中。
- 横坐标的范围是
x加上宽度
- 纵坐标的范围是
y加上高度
- 相当于判断这个红线的
endx
和endy
是否在这个区域当中。
- 横坐标的范围是
-
根据上面的分析,为了检查我们的检测是否成功,我们可以假设当红线进入到金块的范围中时,程序就会打印出1,代码如下:
-
实现代码:
//判断红线的终点是否在金块矩形的范围内
void logic(){
if (endx > this.frame.gold.x && endx < this.frame.gold.x+this.frame.gold.width
&& endy > this.frame.gold.y && endy < this.frame.gold.y+this.frame.gold.height){
System.out.println(1);
}
}
抓取返回
//线的状态设置
switch(state){
case 0://左右摇摆
if (n < 0.1) {dir = 1;}
else if (n > 0.9){dir = -1;}
n = n + 0.005*dir;
lines(g);
break;
case 1://延长线长度
if(length < 500){//如果线长小于500就可以延长
length = length + 10;
lines(g);
} else {state = 2 ;}//延长后无其他操作,可以将其状态置为0,让它继续执行左右摇摆以及红线的绘制
break;
case 2://红线收回
if(length > 100){
length = length - 10;
lines(g);
}else{
state = 0;
}
break;
case 3://红线碰到晶块,红线返回的情况
if(length > 100){
length = length - 10;
lines(g);
//金块偏移
this.frame.gold.x = endx - 26;
this.frame.gold.y = endy;
}else {
//金块移除 - >将金块移动到屏幕外
this.frame.gold.x = -150;
this.frame.gold.y = -150;
state = 0;
}
break;
}
标签:
相关文章
最新发布
- 小波变换算法详解(附Python和C++代码)
- WxPython跨平台开发框架之使用PyInstaller 进行打包处理
- 【Python】正则表达式
- manim边做边学--动画组合
- Outlook不支持账号密码改OAuth2.0认证方式获取outlook邮箱收件箱以及附件(python)
- Python毕业设计选题:基于Python的社区爱心养老管理系统设计与实现_django
- 华为OD机试E卷 --最左侧冗余覆盖子串--24年OD统一考试(Java & JS & Python & C & C++)
- python graphviz 中文乱码
- 华为OD机试E卷 --贪心歌手--24年OD统一考试(Java & JS & Python & C & C++)
- 【Python】装饰器、正则表达式
点击排行
- 版本匹配指南:Numpy版本和Python版本的对应关系
- 版本匹配指南:PyTorch版本、torchvision 版本和Python版本的对应关系
- Python 可视化 web 神器:streamlit、Gradio、dash、nicegui;低代码 Python Web 框架:PyWebIO
- 相关性分析——Pearson相关系数+热力图(附data和Python完整代码)
- Anaconda版本和Python版本对应关系(持续更新...)
- Python与PyTorch的版本对应
- Windows上安装 Python 环境并配置环境变量 (超详细教程)
- Python pyinstaller打包exe最完整教程