c++ 按键_如何用c++做游戏

c++ 按键_如何用c++做游戏命令模式·DesignPatterns1、命令模式的定义命令模式的定义:将一个请求封装为一个对象,使发出请求的责任和执行请求的责任分割开

命令模式·Design Patterns

1、命令模式的定义

命令模式的定义
将一个请求封装为一个对象,使发出请求的责任和执行请求的责任分割开。让两者之间通过命令对象进行沟通,这样方便对命令对象进行存储、传递、调用、增加与管理。

命令模式主要包含以下主要角色
1、抽象命令类(Command)角色:声明执行命令的接口,拥有执行命令的抽象方法Execute。
2、具体命令类(Concrete Command)角色:是抽象命令类的具体实现类,它拥有接收者对象,并通过调用接受者的功能来完成命令要执行的操作。
3、实现者/接收者(Receiver)角色:执行命令功能的相关操作,是具体命令对象业务的真正实现者。
4、调用者/请求这(Invoker)角色:是请求的发送者,它通常拥有很多的命令对象,并通过访问命令对象来执行相关请求,不直接访问接收者。

其结构如下图所示:
在这里插入图片描述
该部分主要参考:命令模式详解,详情请点击该链接。

二、自定义按键功能

在《游戏设计模式》中,有提到使用命令模式来实现自定义游戏按键的功能。
详情请点击该链接,命令模式·Design Patterns
该功能的需求大致如下:
(1)玩家可以自定义按键,如:A键原本绑定的是“跳跃”功能,可改为“开火”功能。
(2)玩家可以撤销自己上一步的命令效果,如重复撤销,则会重做上一步的命令效果。如,玩家执行前进一格操作后,一次撤销会让他后退一格,二次撤销则会让他前进一格。如在撤销后在执行一次操作,则会清理储存好的命令列表。
这里的话,强烈建议阅读完命令模式·Design Patterns之后,再看下一章。

三、具体代码实现

3.1、前置准备部分

按键操作部分
用于模拟按键被按下。

//按键枚举
enum BUTTON{ 
   
	BUTTON_X,
	BUTTON_Y,
	BUTTON_A,
	BUTTON_B,
	BUTTON_CTRL_Z
};
//监测目标按键是否被按下
bool IsPressed(BUTTON pressedButton,BUTTON targetButton){ 
   
	if(pressedButton==targetButton)
	{ 
   
		switch (targetButton)
		{ 
   
			case BUTTON_X:
				std::cout<<"Pressed the BUTTON_X"<<std::endl;
				break;
			case BUTTON_Y:
				std::cout<<"Pressed the BUTTON_Y"<<std::endl;
				break;
			case BUTTON_A:
				std::cout<<"Pressed the BUTTON_A"<<std::endl;
				break;
			case BUTTON_B:
				std::cout<<"Pressed the BUTTON_B"<<std::endl;
				break;
			case BUTTON_CTRL_Z:
				std::cout<<"Pressed the BUTTON_CTRL_Z"<<std::endl;
				break;
			default:
				break;
		}
		return true;
	}

	return false;
	
}

Actor类
可以理解为Unreal中的Actor,就是一个作用物对象,后面用来创建多个玩家实例。
类图如下:
在这里插入图片描述
代码如下:


//作用物类
class Actor{ 
   
	public:
		Actor(){ 
   
		}
		Actor(std::string name){ 
   
			this->name=name;
		}
		Actor(const Actor& other){ 
   //拷贝构造函数(需name不为空时调用)
			this->name=other.name;
		}
		virtual ~Actor(){ 
   //虚析构函数,防止派生类不释放基类成员变量
		}
		const std::string GetName(){ 
   
			return name;
		}
		Actor* Clone(){ 
   //原型模型用于深拷贝
			
			return new Actor(*this);
		}
	private:
		std::string name;
};

3.2、命令类部分

抽象命令类
用于派生具体命令类。为了让命令类可以作用于更多的actor,因此在Execute部分,选择传入一个Actor*。为了内存管理,重写了拷贝构造函数和赋值函数。因此代码会有些长。
类图如下:
在这里插入图片描述
代码如下:


//抽象命令类
class Command{ 
   

	public:
	Command(){ 
   
	}
	Command(Actor* actor){ 
   
		executeObject=actor;
	}
	//因为类中有指针,所以需要重写拷贝构造函数和赋值构造函数
	Command(const Command &other){ 
   
		executeObject=other.executeObject->Clone();
	}
	Command & operator =(const Command &other){ 
   
		if(this==&other){ 
   
			return *this;
		}
		delete executeObject;
		executeObject=other.executeObject->Clone();
		return *this;
	}
	virtual ~Command(){ 
   
		delete executeObject;
	}
	//执行函数
	virtual void Execute(Actor* actor){ 
   
		executeObject=new Actor(*actor);
	};
	virtual Actor* GetExecuteObject(){ 
   
		return executeObject;
	}
	//撤销
	virtual void Undo()=0;
	//原型模式,克隆
	virtual Command* Clone(){ 
   return nullptr;}

	protected:
		Actor* executeObject;
};

具体命令类:
抽象命令类的具体实现,现有:跳跃、开枪、切换武器、倾斜等四个命令。为了方便,这里将实现者角色直接使用了一个函数来实现。
类图和抽象命令类基本一致,因此不画出。

代码如下:


//跳跃命令 具体命令
class JumpCommand:public Command{ 
   
	public:
	JumpCommand()
	{ 
   
		
	}
	~JumpCommand(){ 
   

	}
	JumpCommand(const JumpCommand &other):Command(){ 
   
		executeObject=other.executeObject->Clone();
		
	}
	JumpCommand & operator =(const JumpCommand &other){ 
   
		if(this==&other){ 
   
			return *this;
		}
		delete executeObject;
		executeObject=other.executeObject->Clone();
		return *this;
	}
	public:
	virtual void Execute(Actor* actor){ 
   
		Command::Execute(actor);
		Jump(actor);
	}
	//实施方
	void Jump(Actor* actor){ 
   
		std::cout<<actor->GetName()<<" -> Jumping"<<std::endl;
	}
	void Undo(){ 
   
		std::cout<<executeObject->GetName()<<" Undo Jumping"<<std::endl;
	}
	Command* Clone() override
	{ 
   
		return new JumpCommand(*this);
	}

};
//开枪命令 具体命令
class FireCommand:public Command{ 
   
	public:
	FireCommand(){ 
   

	}
	~FireCommand(){ 
   
	}
	FireCommand(const FireCommand &other):Command(){ 
   
		executeObject=other.executeObject->Clone();
	}
	FireCommand & operator =(const FireCommand &other){ 
   
		if(this==&other){ 
   
			return *this;
		}
		delete executeObject;
		executeObject=other.executeObject->Clone();
		return *this;
	}
	public:
	virtual void Execute(Actor* actor){ 
   
		Command::Execute(actor);
		FireGun(actor);
	}
	//实施方
	void FireGun(Actor* actor){ 
   
		std::cout<<actor->GetName()<<" -> FireGuning"<<std::endl;
	}
	void Undo(){ 
   
		std::cout<<executeObject->GetName()<<" Undo FireGuning"<<std::endl;
	}
	Command* Clone() override
	{ 
   
		return new FireCommand(*this);
	}

};
//切换武器命令 具体命令
class SwapWeaponCommand:public Command{ 
   
	public:
	SwapWeaponCommand(){ 
   

	}
	~SwapWeaponCommand(){ 
   

	}
	SwapWeaponCommand(const SwapWeaponCommand &other):Command(){ 
   
		executeObject=other.executeObject->Clone();
	}
	SwapWeaponCommand & operator =(const SwapWeaponCommand &other){ 
   
		if(this==&other){ 
   
			return *this;
		}
		delete executeObject;
		executeObject=other.executeObject->Clone();
		return *this;
	}
	public:
	virtual void Execute(Actor* actor){ 
   
		Command::Execute(actor);
		SwapWeapon(actor);
	}
	//实施方
	void SwapWeapon(Actor* actor){ 
   
		std::cout<<actor->GetName()<<" -> SwapWeaponing"<<std::endl;
	}
	void Undo(){ 
   
		std::cout<<executeObject->GetName()<<" Undo SwapWeaponing"<<std::endl;
	}
	Command* Clone() override
	{ 
   
		return new SwapWeaponCommand(*this);
	}
};
//倾斜命令 具体命令
class LurchCommand:public Command{ 
   
	public:
	LurchCommand(){ 
   

	}
	~LurchCommand(){ 
   

	}
	LurchCommand(const LurchCommand &other):Command(){ 
   
		executeObject=other.executeObject->Clone();
	}
	LurchCommand & operator =(const LurchCommand &other){ 
   
		if(this==&other){ 
   
			return *this;
		}
		delete executeObject;
		executeObject=other.executeObject->Clone();
		return *this;
	}
	public:
	virtual void Execute(Actor* actor){ 
   
		Command::Execute(actor);
		LurchIneffectively(actor);
	}
	//实施方
	void LurchIneffectively(Actor* actor){ 
   
		std::cout<<actor->GetName()<<" -> LurchIneffectivelying"<<std::endl;
	}
	void Undo(){ 
   
		std::cout<<executeObject->GetName()<<" Undo LurchIneffectivelying"<<std::endl;
	}
	Command* Clone() override
	{ 
   
		return new LurchCommand(*this);
	}
};

3.3、输入控制部分

输入控制类:
该类主要负责根据按键获取对应的命令,执行该函数。然后将该命令保存至命令列表,可以执行撤销和重做动作。
类图如下:
在这里插入图片描述代码如下:

/输入控制类 调用方
class InputHandler{ 
   
	public:
	InputHandler(){ 
   
		//默认按键绑定的方法
		buttonX_=new JumpCommand();
		buttonY_=new FireCommand();
		buttonA_=new SwapWeaponCommand();
		buttonB_=new LurchCommand();
		currentCommandIndex=0;
	}
	virtual ~InputHandler(){ 
   
		delete buttonX_;
		delete buttonY_;
		delete buttonA_;
		delete buttonB_;
	};
	//触发可变指令输入,获取对应指令
	Command* HandleCommandInput(BUTTON pressedButton){ 
   
		//pressedButton为正在被按下的按钮
		if(IsPressed(pressedButton,BUTTON_X))  return buttonX_;
		else if(IsPressed(pressedButton,BUTTON_Y)) return buttonY_;
		else if(IsPressed(pressedButton,BUTTON_A)) return buttonA_;
		else if(IsPressed(pressedButton,BUTTON_B)) return buttonB_;
		//如按下的键不是可处理按键,则返回nullptr
		return nullptr;
	}
	//触发固定输入
	void HandleFixedInput(BUTTON pressedButton){ 
   
		if(IsPressed(pressedButton,BUTTON_CTRL_Z)) RollBack();
	}
	//命令施加于对象
	void CommandInflictionToActor(Command* command,Actor* actor){ 
   
		if(currentCommandIndex!=(commandsVec.size())){ 
   
			std::cout<<"have been clear Commandvec"<<std::endl;
			for(auto it:commandsVec){ 
   
				delete it;
			}
			commandsVec.clear();
			currentCommandIndex=0;
		}
		command->Execute(actor);
		commandsVec.push_back(command->Clone());
		currentCommandIndex+=1;
		
	}
	//撤销与重做操作
	void RollBack(){ 
   
		if(currentCommandIndex!=0){ 
   
			if(currentCommandIndex==commandsVec.size())//撤销操作
			{ 
   
				std::cout<<"RollBacking"<<std::endl;
				commandsVec.back()->Undo();
				currentCommandIndex-=1;
			}
			else//重做操作
			{ 
   
				std::cout<<"reforming"<<std::endl;
				commandsVec.back()->Execute(commandsVec.back()->GetExecuteObject());
			}
		}
	}
	//设置按键对应的命令
	void SetButtonX(Command* command){ 
   
		if(command){ 
   
			delete buttonX_;
			buttonX_=command->Clone();
		}
	}
	void SetButtonY(Command* command){ 
   
		if(command){ 
   
			delete buttonY_;
			buttonY_=command->Clone();
		}
	}
	void SetButtonA(Command* command){ 
   
		if(command){ 
   
			delete buttonA_;
			buttonA_=command->Clone();
		}
	}
	void SetButtonB(Command* command){ 
   
		if(command){ 
   
			delete buttonB_;
			buttonB_=command->Clone();
		}
	}

	//用于绑定对应指令的指针
	private:
	Command* buttonX_;
	Command* buttonY_;
	Command* buttonA_;
	Command* buttonB_;
	std::vector<Command*> commandsVec;
	long long unsigned int currentCommandIndex;
};

3.4、主函数部分

主函数:
先是测试了四个按键功能的执行,后是测试是否可以撤销和重做,最后测试是否能够清除命令列表。
代码如下:


int main(void)
{ 
      
	InputHandler* inputHandler=new InputHandler();
	Actor player_1("player_1");
	Actor player_2("player_2");

	std::cout<<"测试四个按键:"<<std::endl<<"-----------------"<<std::endl;
	//依次按下四个按键
	for(int i=0;i<4;i++){ 
   
		//std::cout<<inputHandler->HandleInput((BUTTON)i)<<std::endl;
		Command* myCommand=inputHandler->HandleCommandInput((BUTTON)i);//int可以转为对应枚举值
		if(myCommand)
		{ 
   
			if(i<2){ 
   
				inputHandler->CommandInflictionToActor(myCommand,&player_1);//使用指针,是为了可以扩展Actor
			}
			else{ 
   
				inputHandler->CommandInflictionToActor(myCommand,&player_2);
			}
			
		}
	}
	std::cout<<std::endl<<"测试撤销与重做操作:"<<std::endl<<"----------------"<<std::endl;
	inputHandler->HandleFixedInput(BUTTON_CTRL_Z);
	inputHandler->HandleFixedInput(BUTTON_CTRL_Z);
	std::cout<<std::endl<<"测试清理命令列表:"<<std::endl<<"--------------------------"<<std::endl;
	Command* tempCommand=inputHandler->HandleCommandInput((BUTTON)0);//int可以转为对应枚举值
	inputHandler->CommandInflictionToActor(tempCommand,&player_1);//使用指针,是为了可以扩展Actor

	return 0;

}

四、输出结果

输出截图如下:

在这里插入图片描述

今天的文章c++ 按键_如何用c++做游戏分享到此就结束了,感谢您的阅读。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/86686.html

(0)
编程小号编程小号

相关推荐

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注