当前位置: 首页 > news >正文

【C++】做一个飞机空战小游戏(九)——发射子弹的编程技巧

 [导读]本系列博文内容链接如下:

【C++】做一个飞机空战小游戏(一)——使用getch()函数获得键盘码值

【C++】做一个飞机空战小游戏(二)——利用getch()函数实现键盘控制单个字符移动
【C++】做一个飞机空战小游戏(三)——getch()函数控制任意造型飞机图标移动

【C++】做一个飞机空战小游戏(四)——给游戏添加背景音乐(多线程技巧应用)

【C++】做一个飞机空战小游戏(五)——getch()控制两个飞机图标移动(控制光标位置)

【C++】做一个飞机空战小游戏(六)——给两架飞机设置不同颜色(cout输出彩色字符、结构体使用技巧)

【C++】做一个飞机空战小游戏(七)——两组按键同时检测平滑移动(GetAsyncKeyState()函数应用)

【C++】做一个飞机空战小游戏(八)——生成敌方炮弹(rand()函数应用)

【C++】做一个飞机空战小游戏(九)——发射子弹的编程技巧

【C++】做一个飞机空战小游戏(十)——子弹击落炮弹、炮弹与飞机相撞 

今天介绍飞机发射子弹的内容。发射的子弹和敌方炮弹有些类似,炮弹和子弹死亡的时候不在屏幕出现,存活期内位置由系统确定,不再受玩家控制,都是是沿着直线匀速运动,定时更新等等。但也有很多不同的地方,区别如下。

目录

一、发射子弹与敌方炮弹的区别

(一)死亡期间位置不同

1、敌方炮弹

2、飞机子弹

(二)存活期初始位置

1、敌方炮弹

2、飞机子弹

(三)出现时间不同

1、敌方炮弹

2、飞机子弹

(四)数量不同

1、敌方炮弹

2、飞机子弹

(五)飞行方向不同

1、敌方炮弹

2、飞机子弹

二、程序代码

(一)新增子弹相关代码

1、构造Bullet结构体

2、新增子弹相关函数

(二)最终程序代码

1、主程序

2、头文件

3、库函数

三、运行效果


一、发射子弹与敌方炮弹的区别

(一)死亡期间位置不同

1、敌方炮弹

敌方炮弹死亡期间的位置x坐标是随机生成的,y坐标为游戏可见区域下一行。

2、飞机子弹

飞机子弹死亡期间的位置x坐标为0,y坐标为游戏可见区域下两行。

(二)存活期初始位置

1、敌方炮弹

敌方炮弹存活期初始位置x坐标与死亡期间一致,y坐标为0。

2、飞机子弹

飞机子弹存活期初始位置x坐标为飞机正中心,y坐标为飞机y坐标上一行。

(三)出现时间不同

1、敌方炮弹

敌方炮弹死亡后的复活时间是随机生成的,复活时间减少到0时,炮弹出现在屏幕上,出现时间由系统决定。

2、飞机子弹

飞机子弹是在飞机的开火键按下后出现的,出现时间由玩家控制。

(四)数量不同

1、敌方炮弹

敌方炮弹同一波数量在同一关是固定的,死亡一个复活一个。屏幕中出现的总的炮弹数量保持不变。在存放炮弹的数组中,数组的角标是固定不变的。

2、飞机子弹

飞机子弹是数量由玩家开火的频率确定,数量不固定。但是炮弹的数量有上限,每架飞机发射的子弹最密集为每行一个子弹,最少为0个。所以存放子弹数组的角标不固定,本例采用的方法为从头开始查询,哪个位置的子弹是死亡状态,那么飞机开火后的存活子弹就存放到这个位置,这个位置赋值为存活状态。当子弹冲出屏幕上方或者击中敌方炮弹,存放子弹的位置赋值为死亡状态。

(五)飞行方向不同

1、敌方炮弹

敌方炮弹从屏幕上方向下飞行,y坐标为自增1。

2、飞机子弹

飞机子弹从飞机前端向屏幕上方飞行,y坐标为自减1。

二、程序代码

(一)新增子弹相关代码

1、构造Bullet结构体

//定义子弹结构体 
typedef struct{Location location;	//子弹位置 bool alive;			//子弹是否存活 int color;			//子弹颜色string icon;		//子弹图标	int hp;				//hp=hit point 生命值,子弹击中炮弹或冲出屏幕上方hp直接降为0,子弹死亡 int dam;			//dam=damage 伤害值int type;			//子弹类型 
}Bullet;

2、新增子弹相关函数

void bullet_location_update();			//子弹位置更新 
void* thread_bullet(void* arg);			//子弹线程函数 
Bullet init_bullet(Bullet bullet);		//单个子弹初始化
void init_bullets(void);				//所有子弹初始化
Bullet fire(Plane plane,Bullet bullet);	//飞机开火函数,确定子弹出现的起始位置 
void show_bullet(Bullet bullet);		//显示子弹图标 

(二)最终程序代码

1、主程序

#include "control_plane.h"
#include "quenue.h"
using namespace std; Plane plane[eq_plane];
Game game;
Bomb bomb[eq_bombs_round];
Bullet bullet[eq_plane][eq_bullets_round];int main(int argc, char** argv) {	init();	//初始化					 bgmusic();//播放背景音乐getkey();    bomb_location_update();	bullet_location_update();while(1)					//循环等待键盘指令 {if(plane[0].keycmd!=none_cmd ||plane[1].keycmd!=none_cmd ||game.bomb_move ||game.bullet_move){game.bomb_move=false;game.bullet_move=false;system("cls");for(int i=0;i<game.num_plane;i++){show_plane(plane[i]);	//刷新飞机图标}for(int i=0;i<game.bombs_round;i++){if(bomb[i].alive){show_bomb(bomb[i]);}}for(int i=0;i<eq_plane;i++){for(int j=0;j<eq_bullets_round;j++){				if(bullet[i][j].alive){show_bullet(bullet[i][j]);}}	}	}	}return 0; 	
}

2、头文件

#ifndef CONTROL_PLANE_H
#define CONTROL_PLANE
#include <iostream>
#include <ctime>
#include <string>
#include<stdlib.h>
#include<windows.h>
#include <pthread.h>//导入线程头文件库
#include <mmsystem.h> //导入声音头文件库
#pragma comment(lib,"winmm.lib")//导入声音的链接库
#define _CRT_SECURE_NO_WARNINGS 
using namespace std;#define t_b 0  	//图形显示区域上侧边界 
#define l_b 0	//图形显示区域左侧边界
#define r_b 100	//图形显示区域右侧边界
#define b_b 20	//图形显示区域下侧边界
#define plane_width 9
#define plane_height 6#define eq_plane 2	//飞机架数
#define eq_bombs_round 23	//eq=end quantity最终炮弹数量 
#define eq_rt 10	//复活最大时间
#define eq_bullets_round 20	//eq=end quantity飞机一次发射最多子弹数量 //定义飞机造型 
const string icon_plane1[]={"    ■","■  ■  ■","■■■■■","■  ■  ■","    ■","  ■■■"};
const string icon_plane2[]={"    ■","■  ■  ■","■■■■■","    ■","  ■■■","■■■■■"};//定义炮弹造型
const string icon_bomb="■";//定义子弹造型
const string icon_bullet="■";//定义坐标结构体 
typedef struct{int x;int y;
} Location;//定义移动方向命令枚举类型 
typedef  enum {none_cmd,up_cmd,down_cmd,left_cmd,right_cmd} direction_cmd; //定义游戏结构体 
typedef struct{int stage;					//游戏当前关 	int bombs_round;			//敌方每轮发射炮弹数量 int bombs_stage;			//每关总计出现炮弹数量 bool clear;					//游戏过关 bool complete;				//游戏通关 bool gameover;				//游戏结束int num_plane;				//飞机数量 int cur_num_bomb;			//当前已发射炮弹数量 int bomb_interval; 			//位置更新间隔 bool bomb_move;				//炮弹是否移动bool bullet_move; 
}Game;//定义飞机结构体 
typedef struct{Location location;int color;int icon;direction_cmd keycmd;bool fire;int cnt_bullets; //按一次开火键加1,然后初始化bullet[cnt_bullets],子弹死亡一个减1 
}Plane;//定义敌方炮弹结构体 
typedef struct{Location location;	//炮弹位置 bool alive;			//炮弹是否存活 int color;			//炮弹颜色string icon;		//炮弹图标int rt;				//rt=respawn time复活时间 int hp;				//hp=hit point 生命值,此值<=0时,敌方炮弹死亡,敌方炮弹被飞机子弹击中hp会减少,坠地或与飞机相撞hp直接降为0 int dam;			//dam=damage 伤害值int type;			//炮弹类型 
}Bomb;//定义子弹结构体 
typedef struct{Location location;	//子弹位置 bool alive;			//子弹是否存活 int color;			//子弹颜色string icon;		//子弹图标	int hp;				//hp=hit point 生命值,子弹击中炮弹或冲出屏幕上方hp直接降为0,子弹死亡 int dam;			//dam=damage 伤害值int type;			//子弹类型 
}Bullet;extern Plane plane[eq_plane];
extern Game game;
extern Bomb bomb[eq_bombs_round];
extern Bullet bullet[eq_plane][eq_bullets_round];//声明刷新飞机位置函数
void show_plane(Plane plane);//获取键盘指令 
void key(void);//更新所有飞机坐标
void plane_location_update(void);//初始化函数 
void init(void);//播放背景音乐线程 
void* thread_bgmusic(void* arg);
void play_bgmusic();
void bgmusic();//获取按键指令线程
void* thread_key(void* arg);
void getkey();//输出彩色字符函数
template<typename T>	//T表示任何可以被cout输出的类型 
void ColorCout(T t, const int ForeColor = 7, const int BackColor = 0);void init_bombs(void);
Bomb init_(Bomb bomb);
void* thread_bomb(void* arg);
void bomb_location_update();
void show_bomb(Bomb bomb);void bullet_location_update();			//子弹位置更新 
void* thread_bullet(void* arg);			//子弹线程函数 
Bullet init_bullet(Bullet bullet);		//单个子弹初始化
void init_bullets(void);				//所有子弹初始化
Bullet fire(Plane plane,Bullet bullet);	//飞机开火函数,确定子弹出现的起始位置 
void show_bullet(Bullet bullet);		//显示子弹图标 #endif

3、库函数

#include <iostream>
#include "conio.h"
#include <string>
#include "control_plane.h"
#include<windows.h>
using namespace std;//彩色输出函数
template<typename T>	//T表示任何可以被cout输出的类型
void ColorCout(T t, const int ForeColor = 7, const int BackColor = 0)
{//	0 = 黑色	1 = 蓝色	 2 = 绿色	 3 = 浅绿色		 4 = 红色	 5 = 紫色	 6 = 黄色	 7 = 白色//	8 = 灰色	9 = 淡蓝色	10 = 淡绿色	11 = 淡浅绿色	12 = 淡红色	13 = 淡紫色	14 = 淡黄色	15 = 亮白色SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), ForeColor + BackColor * 0x10);cout << t;SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 7);
}//隐藏光标函数
HANDLE han = GetStdHandle(-11);
void hide(){CONSOLE_CURSOR_INFO cursor;cursor.bVisible = 0;cursor.dwSize = 1;SetConsoleCursorInfo(han,&cursor);
}//初始化函数 
void init(void)
{plane[0].location={2*r_b/3,b_b};plane[1].location={r_b/3,b_b};plane[0].color=1;plane[1].color=2;plane[0].icon=1;plane[1].icon=2;srand(time(NULL));game.num_plane=2;game.bombs_round=3;game.bomb_move=false;game.bullet_move=false;game.bomb_interval=1000;	init_bombs();init_bullets();system("cls");for(int i=0;i<game.num_plane;i++)//刷新飞机图标{		show_plane(plane[i]);	plane[i].keycmd=none_cmd;		}		
//	game.num_plane=2;	game.bombs_round=3;hide();//隐藏光标
}//********************************************************************************//以下三个函数为获得按键指令线程函数 
//********************************************************************************void* thread_key(void* arg)
{while(1){Sleep(60); 		//获取指令延时一定时间,起滤波作用,延缓获取指令的响应速度 key();			//获取按键指令plane_location_update() ;//获取完指令马上更新飞机坐标 }
}
void getkey()
{pthread_t tid; pthread_create(&tid, NULL, thread_key, NULL);
}//获取键盘指令函数
void key(void)
{direction_cmd c=none_cmd;direction_cmd d=none_cmd;	if (GetAsyncKeyState(VK_UP) & 0x8000)		c = up_cmd;if (GetAsyncKeyState(VK_DOWN) & 0x8000)		c = down_cmd;if (GetAsyncKeyState(VK_LEFT) & 0x8000)		c = left_cmd;if (GetAsyncKeyState(VK_RIGHT) & 0x8000)	c = right_cmd;if (GetAsyncKeyState('W') & 0x8000)	d = up_cmd;if (GetAsyncKeyState('S') & 0x8000)	d = down_cmd;if (GetAsyncKeyState('A') & 0x8000)	d = left_cmd;if (GetAsyncKeyState('D') & 0x8000)	d = right_cmd;plane[0].keycmd=c;plane[1].keycmd=d;if (GetAsyncKeyState('P') & 0x8000)			plane[0].fire = true;if (GetAsyncKeyState('F') & 0x8000)			plane[1].fire = true;
}void gotoxy(int x, int y) {COORD pos = { x,y };HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);//获取标准输出设备句柄SetConsoleCursorPosition(hOut, pos);//两个参数分别指定哪个窗口,具体位置
}//飞机图标刷新函数 
void show_plane(Plane plane)		//预先定义字符定位显示函数,x是列坐标,y是行坐标,原点(x=0,y=0)位于屏幕左上角 
{int x,y;int i,j;int rows;x=plane.location.x;y=plane.location.y;switch(plane.icon){case 1://第一种造型 rows=sizeof(icon_plane1)/sizeof(icon_plane1[0]);for(i=0;i<rows;i++)				 {gotoxy(x,y+i);				ColorCout(icon_plane1[i],plane.color);}break;case 2://第二种造型 rows=sizeof(icon_plane2)/sizeof(icon_plane2[0]);for(i=0;i<rows;i++)				{gotoxy(x,y+i);				ColorCout(icon_plane2[i],plane.color);}break;				}
}//更新两个飞机的坐标 
void plane_location_update(void)
{ 	for(int i=0;i<2;i++){if(plane[i].keycmd!=none_cmd) {int x,y;x=plane[i].location.x;y=plane[i].location.y;switch(plane[i].keycmd){case up_cmd:y--;				//字符上移一行,行值y减1if(y<t_b)			//限定y值最小值为0{y=t_b;}break;case down_cmd:y++;				//字符下移一行,行值y加1if(y>b_b)			//限定y高度 {y=b_b;}break;case left_cmd:x--;				//字符左移一列,列值x减1if(x<l_b){x=l_b;			//限定x最小值为0; }break;case right_cmd:x++;				//字符右移一列,列值x加1if(x>r_b){x=r_b;			//限定x宽度}break;}plane[i].location.x=x;plane[i].location.y=y;plane[i].keycmd=none_cmd;	}} 		
}//单个炮弹初始化函数 
Bomb init_bomb(Bomb bomb)
{bomb.location.x=rand()%r_b;	bomb.location.y=b_b+6;bomb.icon=icon_bomb;bomb.color=6;bomb.dam=1;bomb.hp=1;bomb.alive=false;bomb.rt=rand()%(eq_rt+1)+1;	return bomb;			
}//所有炮弹初始化函数 
void init_bombs(void)
{game.bomb_move=false;for(int i=0;i<game.bombs_round;i++){bomb[i]=init_bomb(bomb[i]);	}
}//炮弹位置更新 线程 
void* thread_bomb(void* arg)
{while(1){Sleep(game.bomb_interval);game.bomb_move=true;for(int i=0;i<game.bombs_round;i++){			if(bomb[i].alive){bomb[i].location.y++;			}else{bomb[i].rt--;if(bomb[i].rt<=0){bomb[i].alive=true;bomb[i].location.y=0;}			}if(bomb[i].location.y>b_b+5){bomb[i].hp=0;									}if(bomb[i].hp<=0){bomb[i]=init_bomb(bomb[i]);				}}		}
}
//炮弹位置更新 
void bomb_location_update()
{pthread_t tid; pthread_create(&tid, NULL, thread_bomb, NULL);
}炮弹图标刷新函数
void show_bomb(Bomb bomb)		//预先定义字符定位显示函数,x是列坐标,y是行坐标,原点(x=0,y=0)位于屏幕左上角 
{int x,y;	x=bomb.location.x;y=bomb.location.y;hide();//隐藏光标gotoxy(x,y);ColorCout(bomb.icon,bomb.color);} //发射子弹 
Bullet fire(Plane plane,Bullet bullet)
{game.bullet_move=true;bullet.location.x=plane.location.x+plane_width/2;	bullet.location.y=plane.location.y-1;bullet.alive=true;		return bullet;			
}//单个子弹初始化函数
Bullet init_bullet(Bullet bullet)
{bullet.icon=icon_bullet;bullet.location.x=0;bullet.location.y=b_b+7; bullet.alive=false;bullet.color=4;bullet.dam=1;bullet.hp=1;	return bullet;			
}//所有子弹初始化函数 
void init_bullets(void)
{game.bullet_move=false;	for(int i=0;i<eq_plane;i++){for(int j=0;j<eq_bullets_round;j++){bullet[i][j]=init_bullet(bullet[i][j]);	}	}
}//子弹位置更新 线程 
void* thread_bullet(void* arg)
{while(1){Sleep(game.bomb_interval);for(int i=0;i<eq_plane;i++){if(plane[i].fire){					game.bullet_move=true;	for(int j=0;j<eq_bullets_round;j++){if(!bullet[i][j].alive){bullet[i][j]=fire(plane[i],bullet[i][j]);break;}	}}plane[i].fire=false;}for(int i=0;i<eq_plane;i++){for(int j=0;j<eq_bullets_round;j++){				if(bullet[i][j].alive){bullet[i][j].location.y--;if(bullet[i][j].location.y<0){bullet[i][j].hp=0;									}if(bullet[i][j].hp<=0){//bullet[i][j].alive=false;bullet[i][j]=init_bullet(bullet[i][j]);									}				}}	}	}
}
//子弹位置更新 
void bullet_location_update()
{pthread_t tid; pthread_create(&tid, NULL, thread_bullet, NULL);
}子弹图标刷新函数
void show_bullet(Bullet bullet)		//预先定义字符定位显示函数,x是列坐标,y是行坐标,原点(x=0,y=0)位于屏幕左上角 
{int x,y;	x=bullet.location.x;y=bullet.location.y;hide();//隐藏光标gotoxy(x,y);ColorCout(bullet.icon,bullet.color);} //********************************************************************************//以下三个函数为播放背景音乐功能 
//********************************************************************************//播放一遍背景音乐 void play_bgmusic() {  mciSendString(TEXT("open hero.mp3 alias s1"),NULL,0,NULL);mciSendString(TEXT("play s1"),NULL,0,NULL);Sleep(153*1000);//153*1000意思是153秒,是整首音乐的时长 mciSendString(TEXT("close S1"),NULL,0,NULL); }//循环播放音乐线程函数 
void* thread_bgmusic(void* arg) //
{ while(1){  	play_bgmusic();}
} //创建音乐播放线程,开始循环播放音乐 
void bgmusic()
{pthread_t tid; pthread_create(&tid, NULL, thread_bgmusic, NULL);
}

三、运行效果

运行效果如下,注意本节只介绍了子弹实现的方法,后边会介绍子弹与炮弹相撞、炮弹与飞机相撞的算法。

(未完待续)

相关文章:

【C++】做一个飞机空战小游戏(九)——发射子弹的编程技巧

[导读]本系列博文内容链接如下&#xff1a; 【C】做一个飞机空战小游戏(一)——使用getch()函数获得键盘码值 【C】做一个飞机空战小游戏(二)——利用getch()函数实现键盘控制单个字符移动【C】做一个飞机空战小游戏(三)——getch()函数控制任意造型飞机图标移动 【C】做一个飞…...

34.SpringMVC获取请求参数

SpringMVC获取请求参数 通过ServletAPI获取 将HttpServletRequest作为控制器方法的形参&#xff0c;此时HttpServletRequest类型的参数表示封装了当前请求的请求报文的对象 index.html <form th:action"{/test/param}" method"post">用户名&#…...

TC1016-同星4路CAN(FD),2路LIN转USB接口卡

TC1016是同星智能推出的一款多通道CAN&#xff08;FD&#xff09;和LIN总线接口设备&#xff0c;CANFD总线速率最高支持8M bps&#xff0c;LIN支持速率0~20K bps&#xff0c;产品采用高速USB2.0接口与PC连接&#xff0c;Windows系统免驱设计使得设备具备极佳的系统兼容性。 支…...

Android源码——从Looper看ThreadLocal

1 概述 ThreadLocal用于在当前线程中存储数据&#xff0c;由于存储的数据只能在当前线程内使用&#xff0c;所以自然是线程安全的。 Handler体系中&#xff0c;Looper只会存在一个实例&#xff0c;且只在当前线程使用&#xff0c;所以使用ThreadLocal进行存储。 2 存储原理 …...

16、Flink 的table api与sql之连接外部系统: 读写外部系统的连接器和格式以及JDBC示例(4)

Flink 系列文章 1、Flink 部署、概念介绍、source、transformation、sink使用示例、四大基石介绍和示例等系列综合文章链接 13、Flink 的table api与sql的基本概念、通用api介绍及入门示例 14、Flink 的table api与sql之数据类型: 内置数据类型以及它们的属性 15、Flink 的ta…...

MySQL 自定义 split 存储过程

MySQL 没有提供 split 函数&#xff0c;但可以自己建立一个存储过程&#xff0c;将具有固定分隔符的字符串转成多行。之所以不能使用自定义函数实现此功能&#xff0c;是因为 MySQL 的自定义函数自能返回标量值&#xff0c;不能返回多行结果集。 MySQL 8&#xff1a; drop pr…...

专题-【十字链表】

有向图的十字链表表示法&#xff1a;...

微信小程序教学系列(2)

第二章&#xff1a;小程序开发基础 1. 小程序页面布局与样式 在小程序开发中&#xff0c;我们可以使用 WXML&#xff08;WeiXin Markup Language&#xff09;和 WXSS&#xff08;WeiXin Style Sheet&#xff09;来定义页面的布局和样式。 1.1 WXML基础 WXML 是一种类似于 H…...

社科院与美国杜兰大学金融管理硕士项目——畅游于金融世界

随着社会经济的不断发展&#xff0c;职场竞争愈发激烈&#xff0c;很多同学都打算通过报考研究生来实现深造&#xff0c;提升自己的综合能力和竞争优势&#xff0c;获得优质的证书。而对于金融专业的学生和在职人员来说&#xff0c;社科院与美国杜兰大学金融管理硕士项目是一个…...

功能强大、超低功耗的STM32WL55JCI7、STM32WL55CCU7、STM32WL55CCU6 32位无线远距离MCU

STM32WL55xx 32位无线远距离MCU嵌入了功能强大、超低功耗、符合LPWAN标准的无线电解决方案&#xff0c;可提供LoRa、(G)FSK、(G)MSK和BPSK等各种调制。STM32WL55xx无线MCU的功耗超低&#xff0c;基于高性能Arm Cortex-M4 32位RISC内核&#xff08;工作频率高达48MHz&#xff09…...

【自适应稀疏度量方法和RQAM】疏度测量、RQAM特征、AWSPT和基于AWSPT的稀疏度测量研究(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…...

sql递归查询

一、postgresql 递归sql with recursive p as(select t1.* from t_org_test t1 where t1.id2union allselect t2.*from t_org_test t2 join p on t2.parent_idp.id) select id,name,parent_id from p; sql中with xxxx as () 是对一个查询子句做别名&#xff0c;同时数据库会对…...

常见前端面试之VUE面试题汇总三

7. Vue 中封装的数组方法有哪些&#xff0c;其如何实现页面更新 在 Vue 中&#xff0c;对响应式处理利用的是 Object.defineProperty 对数据进 行拦截&#xff0c;而这个方法并不能监听到数组内部变化&#xff0c;数组长度变化&#xff0c;数 组的截取变化等&#xff0c;所以需…...

Three.js 实现模型材质分解,拆分,拆解效果

原理&#xff1a;通过修改模型材质的 x,y,z 轴坐标 positon.set( x,y,z) 来实现拆解&#xff0c;分解的效果。 注意&#xff1a;支持模型材质position 修改的材质类型为 type“Mesh” ,其他类型的材质修改了position 可能没有实际效果 在上一篇 Three.js加载外部glb,fbx,gltf…...

《JVM修仙之路》初入JVM世界

《JVM修仙之路》初入JVM世界 博主目前正在学习JVM的相关知识&#xff0c;想以一种不同的方式记录下&#xff0c;娱乐一下 清晨&#xff0c;你睁开双眼&#xff0c;看到刺眼的阳光&#xff0c;你第一反应就是完了完了&#xff0c;又要迟到了。刚准备起床穿衣的你突然意识到不对&…...

苍穹外卖 day1 搭建成功环境

引入 idea找不到打包生成的文件目录怎么办&#xff0c;首先点击这个小齿轮 show ecluded files然后就能找到隐藏的文件 这个jar包内含tomcat&#xff0c;可以直接丢在linux上用 开发环境&#xff1a;开发人员在开发阶段使用的环境&#xff0c;一般外部用户无法访问 测试环…...

智能主体按照功能划分

(1) 构件接口主体 构件接口主体提供构件与用户之间的接口。当一个用户通过代理主体向 元组空间提出申请&#xff0c;并找到相匹配的构件主体时&#xff0c;此构件主体会将其所在构件主体 组中的构件接口主体通过申请用户的代理主体传送到用户的界面。 (2) 构件主体 通过构…...

python中的matplotlib画折线图(数据分析与可视化)

先导包&#xff08;必须安装了numpy 、pandas 和matplotlib才能导包&#xff09;&#xff1a; import numpy as np import pandas as pd import matplotlib.pyplot as plt核心代码&#xff1a; import numpy as np import pandas as pd import matplotlib.pyplot as pltpd.se…...

大数据数据仓库

一.在线教育 1.数据采集 1.数仓概念 数据仓库是为企业制定决策&#xff0c;提供数据支持的。数据采集和存储、对数据进行计算和分析 2.项目架构 2.数据分类 业务数据 用户行为数据 爬虫数据 2.离线数仓 3.实时数仓...

Java“牵手“速卖通商品详情页面数据获取方法,速卖通API实现批量商品数据抓取示例

速卖通商城是一个网上购物平台&#xff0c;售卖各类商品&#xff0c;包括服装、鞋类、家居用品、美妆产品、电子产品等。要获取速卖通商品详情数据&#xff0c;您可以通过开放平台的接口或者直接访问速卖通商城的网页来获取商品详情信息。以下是两种常用方法的介绍&#xff1a;…...

超实用AI教材写作攻略!低查重工具助你快速完成教材编写!

AI教材编写工具&#xff1a;解决传统困境&#xff0c;开启高效新时代 编写教材需要丰富的资料支持&#xff0c;但传统的资料整合方法已经无法满足现代需求。以往&#xff0c;我们从课标、学术资料到教学案例&#xff0c;这些信息分散在知网和教研平台等多个渠道&#xff0c;需…...

从零开始:OCAT图形化配置工具让OpenCore黑苹果安装变得简单

从零开始&#xff1a;OCAT图形化配置工具让OpenCore黑苹果安装变得简单 【免费下载链接】OCAuxiliaryTools Cross-platform GUI management tools for OpenCore&#xff08;OCAT&#xff09; 项目地址: https://gitcode.com/gh_mirrors/oc/OCAuxiliaryTools 还在为复杂的…...

Uvicorn与Packet.net:高性能服务器部署Python服务的完整指南

Uvicorn与Packet.net&#xff1a;高性能服务器部署Python服务的完整指南 【免费下载链接】uvicorn An ASGI web server, for Python. &#x1f984; 项目地址: https://gitcode.com/GitHub_Trending/uv/uvicorn Uvicorn是一个专为Python设计的ASGI Web服务器&#xff0c…...

League-Toolkit启动故障系统性排查方案:从现象到根治的完整解决路径

League-Toolkit启动故障系统性排查方案&#xff1a;从现象到根治的完整解决路径 【免费下载链接】League-Toolkit 兴趣使然的、简单易用的英雄联盟工具集。支持战绩查询、自动秒选等功能。基于 LCU API。 项目地址: https://gitcode.com/gh_mirrors/le/League-Toolkit 问…...

Revolut警告支持高耗能AI和加密货币业务可能面临声誉风险

英国银行应用Revolut表示&#xff0c;由于支持加密货币和AI等高耗能行业&#xff0c;公司可能面临声誉风险&#xff0c;同时该公司公布去年利润增长57%。这家金融科技公司在等待监管批准五年后&#xff0c;现在终于可以作为正式的英国银行启动业务。Revolut在其2025年年报中警告…...

OpenOCD配置文件进阶指南:手把手教你定制STM32F0x的swj-dp.tcl脚本

OpenOCD深度定制&#xff1a;STM32F0x调试接口脚本开发实战 嵌入式开发中&#xff0c;调试工具的灵活配置往往决定着开发效率。对于STM32F0x系列芯片而言&#xff0c;OpenOCD作为开源调试工具链的核心组件&#xff0c;其配置文件的可定制性为开发者提供了极大的灵活性。本文将深…...

3D打印键帽革命:如何用开源模型实现机械键盘的个性化定制

3D打印键帽革命&#xff1a;如何用开源模型实现机械键盘的个性化定制 【免费下载链接】cherry-mx-keycaps 3D models of Chery MX keycaps 项目地址: https://gitcode.com/gh_mirrors/ch/cherry-mx-keycaps 机械键盘爱好者们是否曾为寻找完美键帽而苦恼&#xff1f;传统…...

DLL与静态库怎么选?5个真实案例解析动态链接库的优劣

DLL与静态库的架构决策&#xff1a;5个实战场景下的技术选型指南 1. 模块化开发中的DLL实践 在大型软件系统中&#xff0c;模块化设计是降低复杂度的关键策略。我们曾为某金融交易系统设计插件架构时&#xff0c;DLL的动态加载特性展现出独特优势&#xff1a; 内存共享机制&…...

Python+Spire.Doc实战:5分钟搞定Word邮件合并批量生成邀请函(附完整代码)

PythonSpire.Doc实战&#xff1a;5分钟搞定Word邮件合并批量生成邀请函&#xff08;附完整代码&#xff09; 行政和市场人员经常面临批量发送个性化邀请函的挑战。传统手动修改不仅耗时费力&#xff0c;还容易出错。今天我们将用Python和Spire.Doc库&#xff0c;实现高效精准的…...

GPIO输入模式深度解析:STM32按键检测中IDR寄存器的使用技巧与常见问题

STM32 GPIO输入模式实战&#xff1a;从IDR寄存器到工业级按键检测方案 在嵌入式开发中&#xff0c;GPIO输入模式是实现人机交互的基础功能之一。对于STM32开发者而言&#xff0c;深入理解IDR寄存器的工作原理和按键检测的实现技巧&#xff0c;往往决定着产品交互的可靠性和响应…...