【C++游戏开发-03】贪吃蛇

文章目录

  • 前言
  • 一、工具准备
    • 1.1游戏开发框架
    • 1.2visual studio2022下载
    • 1.3easyX下载
    • 1.4图片素材
  • 二、逻辑分析
    • 2.1数据结构
    • 2.2蛇的移动
    • 2.3吃食物
    • 2.4游戏失败
  • 三、DEMO代码实现
  • 四、完整源代码
  • 总结


🐱‍🚀个人博客https://blog.csdn.net/qq_51000584?type=blog
🐱‍👤收录专栏:C++游戏开发探索
🐱‍👓专栏目标:通过所学知识和自己对游戏的理解去开发一系列游戏提高自己的编码和逻辑能力
🐱‍💻作者:敲代码的猫(Codemon)


前言

上次我们通过qt工具实现了推箱子的图形化编程http://t.csdnimg.cn/08AY9,本节我们将使用Visual Studio2022和easyX图形库来实现贪吃蛇的demo。成品如下:
在这里插入图片描述

一、工具准备

1.1游戏开发框架

代码链接:http://t.csdnimg.cn/iAvkm
经过对推箱子的开发,相信大家对游戏开发的流程已经有了一定的理解,那么为了方便我将游戏demo开发做成了框架,我们直接在这基础上实现即可。

1.2visual studio2022下载

转载博客:VS2022的下载和使用(作者:羽舟_)

1.3easyX下载

easyX官网
在这里插入图片描述
下载后直接运行exe文件,单击下一步,然后选择vs2022安装即可
在这里插入图片描述

1.4图片素材

链接:https://pan.baidu.com/s/1pOJxEfaePlcN-lVAJ0mFRA
提取码:1025
下载并解压到本地即可

二、逻辑分析

在逻辑分析前,同样我们先来了解一下贪吃蛇的游戏规则,
游戏规则:
贪吃蛇游戏的基本规则如下:
玩家通过控制蛇的移动来寻找并吃掉地图上的食物,每次吃掉食物后,蛇的身体会相应加长。
蛇的移动方向由玩家通过键盘上的上下左右键来控制。
在游戏过程中,蛇不能碰到墙壁或者自己的身体
如果蛇在移动过程中撞到墙壁或者咬到自己的身体,游戏会立即结束。

2.1数据结构

根据游戏规则我们会发现,蛇的身体分为一节一节的,并且连续,这会让我们联想到相关的数据结构——链表。如果我们能维护一个链表,那么它的头节点就是蛇的头,每当头节点移动,全身的节点都移动到上一个节点的位置,这样就实现了蛇的移动。
在这里插入图片描述
为了方便蛇身之间可以找到相邻的节点,蛇身长度增加,我们实现一个双向链表的创建、尾添加、删除功能。

//双向链表节点
struct Node {
	struct Node* pNext;
	struct Node* pPre;
	Point pos;
	Node() {//节点初始化
		pNext = nullptr;//下一个节点
		pPre = nullptr;//上一个节点
	}
};

//双向链表
struct List {
	struct Node* pHead;
	struct Node* pTail;
	int length;
	List() {
		pHead = nullptr;//头节点
		pTail = nullptr;//尾节点
		length = 0;//链表长度
	}
};

//创建双向链表
void CreateList(List** L) {*L) = new List;
}

//双向链表尾添加节点
void AddNode(List* L, Point p) {
	if (L->pHead == nullptr) {//空链表
		L->pHead = new Node;
		L->pHead->pos = p;
		L->pHead->pNext = L->pHead;
		L->pTail = L->pHead;
		L->length++;
	}
	else {//尾添加
		Node* temp = new Node;
		temp->pos = p;
		L->pTail->pNext = temp;
		temp->pPre = L->pTail;
		L->pTail = temp;
		L->length++;
	}
}

//链表资源释放
void DeleteList(List* L) {
	Node* pNode = L->pHead;
	while (pNode != nullptr) {
		Node* temp = pNode;
		pNode = pNode->pNext;
		delete temp;
		temp = nullptr;
	}
	delete L;
	L = nullptr;
}

2.2蛇的移动

蛇的移动和推箱子比起来就容易了很多,我们不需要再去判断复杂的地形,只需要保证蛇头没有碰到边界、没有咬到身体、对吃到食物进行处理即可。
蛇的移动是由程序自动控制的,玩家通过键盘的输入控制的只是改变了蛇的方向,因此我们定义一个全局变量和相应的宏

#define UP 0
#define LEFT 1
#define DOWN 2
#define RIGHT 3
int direct;

当我们按下键盘后只改变direct的值,然后每次刷新根据direct决定蛇向哪个方向移动。

2.3吃食物

我们假设蛇吃的是苹果,那么苹果每次出现在地图上的位置则是随机选定的,我们需要加入随机数种子的初始化。当蛇移动后的位置和苹果重合时,我们要更新苹果的位置,并且为蛇进行尾部添加节点的操作。

2.4游戏失败

当蛇移动后的位置超过了我们的地图边界即碰到了墙壁,此时失败。或者蛇移动后的位置是自己的身体时代表蛇咬到了自己,此时也会失败。我们可以在全局加入一个布尔值:

bool m_isQuit;

由m_isQuit的值来决定游戏的运行,当游戏 初始化时m_isQuit为true,当游戏失败条件触发时,将m_isQuit更改为false,这样就实现了游戏的失败退出功能。
综上来看贪吃蛇的逻辑要比推箱子容易很多。

三、DEMO代码实现

在游戏框架的代码基础上,首先我们要在GreedySnake类中添加我们需要使用的游戏相关全局变量:

bool m_isQuit;//游戏退出标识
List* snake;//存储蛇的双向链表
int direct;//记录当前方向
//屏幕大小
int screenWidth;
int screenHeight;
//苹果坐标
int appleX;
int appleY;
//格子大小
int base;
//蛇头坐标
Point m_point;

定义IMAGE对象来存储我们需要绘制的图,该类是easyX图形库中的成员,可以帮我们很方便的绘制图片。因此要加入头文件

#include <easyx.h>
IMAGE map;
IMAGE head_up;
IMAGE head_down;
IMAGE head_left;
IMAGE head_right;
IMAGE apple;
IMAGE body;

右键我们的vs项目,选择在文件资源管理器中打开文件夹
在这里插入图片描述
将我们的图片素材文件夹拖入到此处
在这里插入图片描述
进入该文件夹,点击map.bmp图片的属性
在这里插入图片描述
点击详细信息
在这里插入图片描述
可以看到该图片的大小为600*600像素,也就是说一格的大小为30*30,而蛇可移动的范围只有18*18格。我们设置窗口大小就为600*600
在构造函数中为成员变量初始化:

public:
	GreedySnake() {
		m_isQuit = true;//游戏运行
		//窗口大小
		screenWidth = 600;
		screenHeight = 600;
		srand((unsigned)time(NULL));//初始化随机数种子
		OnInit();//游戏初始化
	}

由于调用了time函数作为随机数种子,所以我们要加入头文件

#include <ctime>

对游戏进行初始化

void OnInit() {

	direct = UP;//初始化蛇的方向为向上
	base = 30;//格子大小30*30
	//随机初始化苹果的位置
	appleX = rand() % 18 + 1;
	appleY = rand() % 18 + 1;

	//初始化蛇
	m_point.setPoint(9, 9);//蛇头坐标初始化
	CreateList(&snake);//蛇双向链表初始化
	//-------------------------------------------
	Point temp;//定义坐标变量
	temp.setPoint(9, 9);
	AddNode(snake, temp);
	temp.setPoint(9, 10);
	AddNode(snake, temp);
	temp.setPoint(9, 11);
	AddNode(snake, temp);
	//-------------------------初始化三个节点长的蛇
	//加载图片(注意图片的路径)
	loadimage(&map, L".\\image\\map.bmp");
	loadimage(&head_right, L".\\image\\head0.bmp");//R
	loadimage(&head_up, L".\\image\\head1.bmp");//U
	loadimage(&head_left, L".\\image\\head2.bmp");//L
	loadimage(&head_down, L".\\image\\head3.bmp");//D
	loadimage(&apple, L".\\image\\apple.bmp");
	loadimage(&body, L".\\image\\body.bmp");

	initgraph(screenWidth, screenHeight);//初始化窗口大小

}

下面是游戏运行函数

void OnRun() {
	while (m_isQuit) {//m_isQuit控制游戏的运行
		if (_kbhit())//处理键盘输入-----------需要头文件conio.h
		{
			int k = _getch();//获取键盘输入
			//需要头文件conio.h

			switch (k)
			{
			case 'A':
			case 'a':
			case 75://左
				direct = LEFT;
				break;
			case 'S':
			case 's':
			case 80://下
				direct = DOWN;
				break;
			case 'D':
			case 'd':
			case 77://右
				direct = RIGHT;
				break;
			case 'W':
			case 'w':
			case 72://上
				direct = UP;
				break;
			}

		}//------------------------------------

		SnakeMove();//蛇的移动
		if (!m_isQuit) {
			break;
		}
		OnDraw();//绘制图片

		Sleep(200);//控制刷新率,不易太快或太慢,以毫秒为单位
	}
}

蛇的移动

void SnakeMove() {
	switch (direct)//根据当前方向决定蛇头的移动
	{
	case UP:
		m_point.y--;
		break;
	case DOWN:
		m_point.y++;
		break;
	case LEFT:
		m_point.x--;
		break;
	case RIGHT:
		m_point.x++;
		break;
	}

	if (m_point.x < 1 || m_point.x>18 || m_point.y < 1 || m_point.y>18) {
		//移动后出界(碰墙)
		m_isQuit = false;
		return;
	}
	if (appleX == m_point.x && appleY == m_point.y) {
		//和苹果坐标重叠(吃到苹果)
		AddNode(snake, snake->pTail->pos);//给蛇添加节点
		//更新苹果坐标
		appleX = rand() % 18 + 1;
		appleY = rand() % 18 + 1;
	}
	
	//从蛇尾向蛇头遍历,每一个节点移动到前一个节点的位置(思靠一下为什么从蛇尾向蛇头遍历)
	Node* pNode = snake->pTail;
	while (pNode->pPre != NULL) {
		pNode->pos.x = pNode->pPre->pos.x;
		pNode->pos.y = pNode->pPre->pos.y;
		pNode = pNode->pPre;
	}
	snake->pHead->pos = m_point;

	//从蛇头向蛇尾遍历检测是否咬到了蛇身
	pNode = snake->pHead->pNext;
	while (pNode != NULL) {
		if (pNode->pos.x == m_point.x && pNode->pos.y == m_point.y) {
			m_isQuit = false;
			return;
		}
		pNode = pNode->pNext;
	}
}

图片绘制
BeginBatchDraw()函数和EndBatchDraw()函数用于打开和关闭缓冲区,也是easyX中的函数,要配对使用,我们将绘制图片的函数放在他们中间即可。

void OnDraw() {
	::BeginBatchDraw();//打开缓冲区开始绘制

	putimage(0, 0, &map);//绘制背景从(0,0)开始
	putimage(appleX * base, appleY * base, &apple);//绘制苹果
	Node* pNode = snake->pHead->pNext;
	//绘制蛇头
	switch (direct)
	{
	case UP:
		putimage(m_point.x * base, m_point.y * base, &head_up);
		break;
	case DOWN:
		putimage(m_point.x * base, m_point.y * base, &head_down);
		break;
	case LEFT:
		putimage(m_point.x * base, m_point.y * base, &head_left);
		break;
	case RIGHT:
		putimage(m_point.x * base, m_point.y * base, &head_right);
		break;
	}
	//绘制蛇身
	while (pNode != NULL) {
		putimage(pNode->pos.x * base, pNode->pos.y * base, &body);
		pNode = pNode->pNext;
	}

	::EndBatchDraw();//关闭缓冲区结束绘制
}

游戏关闭:
由于我们使用到了链表,并且申请了堆的空间,因此在程序结束时需要对这一部分的资源进行释放。
先前在链表实现的地方已经写好了相应的函数,这里直接调用即可。

void OnClose() {

	DeleteList(snake);
}

运行后就是下面的样子啦
在这里插入图片描述

四、完整源代码

#include <iostream>
#include <easyx.h>
#include <conio.h>
#include <ctime>
using namespace std;

//坐标结构体
struct Point {
	int x;
	int y;
	void setPoint(int px, int py) {
		this->x = px;
		this->y = py;
	}
};

//游戏框架类
class CGameFrame {
public:
	CGameFrame() {

	}
	virtual ~CGameFrame() {

	}

	virtual void OnInit() = 0;//初始化

	virtual void OnRun() = 0;//游戏运行

	virtual void OnDraw() = 0;//绘制

	virtual void OnClose() = 0;//游戏关闭

};

//双向链表节点
struct Node {
	struct Node* pNext;
	struct Node* pPre;
	Point pos;
	Node() {
		pNext = nullptr;
		pPre = nullptr;
	}
};

//双向链表
struct List {
	struct Node* pHead;
	struct Node* pTail;
	int length;
	List() {
		pHead = nullptr;
		pTail = nullptr;
		length = 0;
	}
};

//创建双向链表
void CreateList(List** L) {
	*L = new List;
	(*L)->length = 0;
}

//双向链表尾添加节点
void AddNode(List* L, Point p) {
	if (L->pHead == nullptr) {
		L->pHead = new Node;
		L->pHead->pos = p;
		L->pHead->pNext = L->pHead;
		L->pTail = L->pHead;
		L->length++;
	}
	else {
		Node* temp = new Node;
		temp->pos = p;
		L->pTail->pNext = temp;
		temp->pPre = L->pTail;
		L->pTail = temp;
		L->length++;
	}
}

//链表资源释放
void DeleteList(List* L) {
	Node* pNode = L->pHead;
	while (pNode != nullptr) {
		Node* temp = pNode;
		pNode = pNode->pNext;
		delete temp;
		temp = nullptr;
	}
	delete L;
	L = nullptr;
}

#define UP 0
#define LEFT 1
#define DOWN 2
#define RIGHT 3


//贪吃蛇类
class GreedySnake :public CGameFrame
{
private:
	bool m_isQuit;//游戏退出标识
	List* snake;//存储蛇
	int direct;//记录当前方向
	IMAGE map;
	IMAGE head_up;
	IMAGE head_down;
	IMAGE head_left;
	IMAGE head_right;
	IMAGE apple;
	IMAGE body;
	//屏幕大小
	int screenWidth;
	int screenHeight;
	//苹果坐标
	int appleX;
	int appleY;
	//格子大小
	int base;

	//蛇头坐标
	Point m_point;

public:
	GreedySnake() {
		m_isQuit = true;
		screenWidth = 600;
		screenHeight = 600;
		srand((unsigned)time(NULL));
		OnInit();
	}
	~GreedySnake() {

	}
	void OnInit() {

		direct = UP;
		base = 30;
		//初始化苹果
		appleX = rand() % 18 + 1;
		appleY = rand() % 18 + 1;

		//初始化蛇
		m_point.setPoint(9, 9);
		CreateList(&snake);//蛇初始化
		Point temp;
		temp.setPoint(9, 9);
		AddNode(snake, temp);
		temp.setPoint(9, 10);
		AddNode(snake, temp);
		temp.setPoint(9, 11);
		AddNode(snake, temp);

		//加载图片
		loadimage(&map, L".\\image\\map.bmp");
		loadimage(&head_right, L".\\image\\head0.bmp");//R
		loadimage(&head_up, L".\\image\\head1.bmp");//U
		loadimage(&head_left, L".\\image\\head2.bmp");//L
		loadimage(&head_down, L".\\image\\head3.bmp");//D
		loadimage(&apple, L".\\image\\apple.bmp");
		loadimage(&body, L".\\image\\body.bmp");

		initgraph(screenWidth, screenHeight);

	}

	void OnRun() {
		while (m_isQuit) {
			if (_kbhit())//处理键盘输入-----------
			{
				int k = _getch();

				switch (k)
				{
				case 'A':
				case 'a':
				case 75://左
					direct = LEFT;
					break;
				case 'S':
				case 's':
				case 80://下
					direct = DOWN;
					break;
				case 'D':
				case 'd':
				case 77://右
					direct = RIGHT;
					break;
				case 'W':
				case 'w':
				case 72://上
					direct = UP;
					break;
				}

			}//------------------------------------

			SnakeMove();
			if (!m_isQuit) {
				break;
			}
			OnDraw();

			Sleep(200);
		}
	}

	void OnDraw() {
		::BeginBatchDraw();

		putimage(0, 0, &map);
		putimage(appleX * base, appleY * base, &apple);
		Node* pNode = snake->pHead->pNext;
		//绘制蛇头
		switch (direct)
		{
		case UP:
			putimage(m_point.x * base, m_point.y * base, &head_up);
			break;
		case DOWN:
			putimage(m_point.x * base, m_point.y * base, &head_down);
			break;
		case LEFT:
			putimage(m_point.x * base, m_point.y * base, &head_left);
			break;
		case RIGHT:
			putimage(m_point.x * base, m_point.y * base, &head_right);
			break;
		}
		//绘制蛇身
		while (pNode != NULL) {
			putimage(pNode->pos.x * base, pNode->pos.y * base, &body);
			pNode = pNode->pNext;
		}

		::EndBatchDraw();
	}

	void OnClose() {

		DeleteList(snake);
	}

	void SnakeMove() {
		switch (direct)
		{
		case UP:
			m_point.y--;
			break;
		case DOWN:
			m_point.y++;
			break;
		case LEFT:
			m_point.x--;
			break;
		case RIGHT:
			m_point.x++;
			break;
		}

		if (m_point.x < 1 || m_point.x>18 || m_point.y < 1 || m_point.y>18) {
			m_isQuit = false;
			return;
		}
		if (appleX == m_point.x && appleY == m_point.y) {
			AddNode(snake, snake->pTail->pos);
			appleX = rand() % 18 + 1;
			appleY = rand() % 18 + 1;
		}

		Node* pNode = snake->pTail;
		while (pNode->pPre != NULL) {
			pNode->pos.x = pNode->pPre->pos.x;
			pNode->pos.y = pNode->pPre->pos.y;
			pNode = pNode->pPre;
		}
		snake->pHead->pos = m_point;


		pNode = snake->pHead->pNext;
		while (pNode != NULL) {
			if (pNode->pos.x == m_point.x && pNode->pos.y == m_point.y) {
				m_isQuit = false;
				return;
			}
			pNode = pNode->pNext;
		}
	}

};



int main() {
	GreedySnake* pGame = new GreedySnake;
	pGame->OnRun();
	pGame->OnClose();
	delete pGame;
	pGame = nullptr;
	return 0;
}

总结

在前两节推箱子中已经实现过很多细节的部分,因此本篇贪吃蛇更多的是干货。下期我将继续使用qt工具实现贪吃蛇的完整版开发,敬请期待…

Codemon2024.02.21

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/400237.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【hoare基础版】快速排序算法(1)

目录 交换排序 QuickSort快速排序 Hoare整体思路 图解分析 ​ Hoare版本代码 总代码 时间复杂度 交换排序 基本思想&#xff1a;所谓交换&#xff0c;就是根据序列中两个记录键值的比较结果来对换这两个记录在序列中的位置&#xff0c;交换排序的特点是&#xff1a;将键…

论文阅读:How Do Neural Networks See Depth in Single Images?

是由Technische Universiteit Delft(代尔夫特理工大学)发表于ICCV,2019。这篇文章的研究内容很有趣,没有关注如何提升深度网络的性能&#xff0c;而是关注单目深度估计的工作机理。 What they find&#xff1f; 所有的网络都忽略了物体的实际大小&#xff0c;而关注他们的垂直…

java调摄像头和人脸比对

我需要做一个功能&#xff0c;就是网站页面调用摄像头截图。现在由于要用java&#xff0c;就得研究用java怎么调用摄像头。顺带玩了一下人脸比对&#xff0c;资料有点少。 效果 采用javacv实现&#xff0c;先加Maven引用&#xff0c;后面把下载的包再独立引用不用Maven了 …

UI自动化测试篇 :webdriver+ant+jenkins自动化测试实践

&#x1f525; 交流讨论&#xff1a;欢迎加入我们一起学习&#xff01; &#x1f525; 资源分享&#xff1a;耗时200小时精选的「软件测试」资料包 &#x1f525; 教程推荐&#xff1a;火遍全网的《软件测试》教程 &#x1f4e2;欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1…

OpenCV笔记2:鼠标事件实现绘制直线、矩阵、曲线

OpenCV 鼠标事件 创建窗口设置窗口大小鼠标事件监听 判断事件更新起始点和终点绘制线显示图片 打开背景图 """ 鼠标事件 down up move """ import cv2 import numpy as npWINNAME DRAWBOARD st_point (-1, -1) end_point (-1, -1)def draw…

【Unity】管道流动模拟Shader

【Unity】管道流动模拟Shader 抽象模拟管道介质流动的效果&#xff0c;使用顶点片元着色器。可以调整管线光泽&#xff0c;颜色&#xff0c;流动方向&#xff0c;透明度&#xff0c;流动体粗细&#xff0c;流动速度和横断面。 实现效果 Demo效果 Demo下载地址 管线光泽调整 …

proteus8.15图文安装教程

proteus8.15版本可以用STM32系列单片机来进行仿真设计&#xff0c;比7.8版本方便多了&#xff0c;有需要的朋友们可以在公众号后台回复 proteus8.15 获取软件包。 1、下载好软件包&#xff0c;解压如下&#xff0c;右键proteus8.15.sp1以管理员身份运行。 2、第一次安装&#x…

【蓝桥杯单片机入门记录】独立按键

目录 一、键盘、微动开关概述 二、按键工作原理 &#xff08;1&#xff09;按键构成 &#xff08;2&#xff09;&#xff08;蓝桥杯开发板&#xff09;独立按键电路图&#xff08;非实际&#xff0c;参考理解&#xff09; &#xff08;3&#xff09;独立按键工作原理 三、…

【J1939】一、概述,协议基础

文章目录 1. 背景2. 要点3. J1939帧细节3.1 协议数据单元(Protocol Data Unit,PDU)3.2 参数组编号(PGN)3.3 可疑参数编号(Suspect Parameter Number,SPN)参考1. 背景 J1939是一种用于商用车辆的通信协议,它定义了一套车辆电子控制单元之间进行数据通信的规范。J1939协议…

OpenAI 发布文生视频模型 Sora,普通人应该怎么做才能利益最大化?

原文链接&#xff1a; OpenAI 发布文生视频模型 Sora&#xff0c;普通人应该怎么做才能利益最大化&#xff1f; 自从 2022 年 11 月 30 日 ChatGPT 发布之后&#xff0c;每次 OpenAI 再发布新功能都跟过年一样&#xff0c;那叫一个热闹。 包括 GPT 4.0&#xff0c;GPT Store&…

滚雪球学Java(65):深入理解Java中的Map接口:实现原理剖析

咦咦咦&#xff0c;各位小可爱&#xff0c;我是你们的好伙伴——bug菌&#xff0c;今天又来给大家普及Java SE相关知识点了&#xff0c;别躲起来啊&#xff0c;听我讲干货还不快点赞&#xff0c;赞多了我就有动力讲得更嗨啦&#xff01;所以呀&#xff0c;养成先点赞后阅读的好…

2024年单服务器部署Mongodb三节点副本集自动化部署脚本

该脚本是为了方便自己学习和工作中部署服务器从而节省时间进行编写&#xff0c;目前能正常部署&#xff0c;创建集群&#xff0c;管理员用户&#xff0c;以及连接都没问题&#xff0c;但是没有开启验证&#xff0c;后续找时间补充。 完整的教程请参考一下我写的技术文章。 20…

十六进制数

1.做一个收电费程序&#xff0c;要求输入使用的电的度数&#xff08;整数&#xff09;以及电费单价&#xff08;实数&#xff09;&#xff0c;输出总的用电费用。 2.提示并输入一个小写字母数据&#xff0c;输出其对应的ASCII值&#xff0c;以及该小写字母对应的大写字母。 3.提…

软件测试工程师linux学习之系统层面相关命令总结

1 linux系统重启和关机的命令 重启命令&#xff1a;reboot 关机命令&#xff1a;shutdown 这两个命令一般很少用到&#xff0c;我们了解即可。 2 查看日志信息命令 什么是日志&#xff0c;日志就是一个一个普通的文本文件&#xff0c;文件里面记录的是软件运行过程中的信息…

市场复盘总结 20240221

仅用于记录当天的市场情况&#xff0c;用于统计交易策略的适用情况&#xff0c;以便程序回测 短线核心&#xff1a;不参与任何级别的调整&#xff0c;采用龙空龙模式 一支股票 10%的时候可以操作&#xff0c; 90%的时间适合空仓等待 二进三&#xff1a; 进级率中 33% 最常用…

搜维尔科技:用于运动科学的 OptiTrack,范围标记、步态捕捉!

OptiTrack 系统提供世界领先的测量精度和简单易用的工作流程&#xff0c;为研究人员和生物力学师的研究提供理想的 3D 跟踪数据。 对所有主要数字测力台、EMG 和模拟设备的本机即插即用支持为研究人员提供了在 Visual3D、MotionMonitor、MATLAB 和其他第三方生物力学软件包中进…

MySQL数据库基础(十二):子查询(三步走)

文章目录 子查询&#xff08;三步走&#xff09; 一、子查询&#xff08;嵌套查询&#xff09;的介绍 二、子查询的使用 三、总结 子查询&#xff08;三步走&#xff09; 一、子查询&#xff08;嵌套查询&#xff09;的介绍 在一个 select 语句中,嵌入了另外一个 select …

如何使用Coded UI Test对Webpage进行自动化测试

&#x1f525; 交流讨论&#xff1a;欢迎加入我们一起学习&#xff01; &#x1f525; 资源分享&#xff1a;耗时200小时精选的「软件测试」资料包 &#x1f525; 教程推荐&#xff1a;火遍全网的《软件测试》教程 &#x1f4e2;欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1…

2024 年了,如何 0 基础开始学习 Vue ?

最近 5 个月&#xff0c;我都在忙着构建我的第一开源项目 HexoPress&#xff0c;这个项目是使用 Electron Vue 3 TypeScript 等技术实现的&#xff0c;一方面&#xff0c;我真的很需要一款合自己心意的博客编辑器&#xff0c;另一方面&#xff0c;我也是真心想学习 Electron …

App Inventor 2 Activity启动器技巧:如何查看并启动其他App

App包名和类名的查看 由 App Inventor 2 创建的应用要弄清包名和类名&#xff0c;可通过下载其应用程序的源代码&#xff0c;然后使用文件资源管理器或解压缩程序解压 .aia源文件&#xff08;文件的扩展名修改成.zip 或.rar&#xff0c;然后解压&#xff09;&#xff0c;在解压…