SDL2 游戏开发日记(八) 按钮、对话框的绘制

SDL2 游戏开发日记(八) 按钮、对话框的绘制

在游戏中,会弹出各种各样的对话框,用来显示游戏中的一些信息,或者要求玩家进行相应的输入。

对话框的基类

创建一个纹理,把对话框的背景,按钮都绘制在这个纹理上。如果按钮状态没有发生改变,直接在主循环里绘制这个纹理。如果按钮状态改变,重新绘制纹理后再绘制到主循环里。

#pragma once
#include "Renderable.h"
#include "Button.h"
#include "Common.h"
#include "MessageListener.h"
#include <vector>
using namespace std;

class Dialog : public Renderable{
protected:
	//对话框背景
	Renderable *mBackground;
	//按钮列表
	vector<Button *>mButtonList;
	//是否需要重绘Texture;
	bool mIsChange;
public:
	Dialog(){
		mBackground = NULL;
	}
	//创建Texture;
	void CreateRenderTexture(int x, int y, int width, int height);
	virtual ~Dialog(){
		SAFE_DELETE(mBackground);
		
		SDL_DestroyTexture(mTexture);
	}
	//设置背景
	void SetBackground(Renderable*background){
		SAFE_DELETE(mBackground);
		mBackground = background;
	}
	//绘图
	virtual void Render();
	//加载按钮
	virtual void LoadButtons(){}
	//处理消息
	virtual void HandleEvent(SDL_Event &ev);
	//处理鼠标消息
	void HandleMouseEvent(int eventType, int x, int y);

	添加按钮
	void AddButton(Button *button){
		mButtonList.push_back(button);
	}

	void Refresh(){
		mIsChange = true;
	}
};

//Dialog.cpp
#include "stdafx.h"

#include "Dialog.h"
#include "SDLGame.h"

void Dialog::CreateRenderTexture(int x, int y, int width, int height){
	mTexture = SDL_CreateTexture(theGame.getRenderer(),
		SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, width, height);
	if (mRenderRect == NULL)
		mRenderRect = new SDL_Rect();
	mTextureWidth = width;
	mTextureHeight = height;
	mRenderRect->w = width;
	mRenderRect->h = height;
	SetPos(x, y);
	mIsChange = true;
	SetLayer(10);
}

void Dialog::HandleEvent(SDL_Event &ev){
	if (ev.type == SDL_MOUSEMOTION){
		HandleMouseEvent(ev.type,ev.motion.x, ev.motion.y);
	}
	else if (ev.type == SDL_MOUSEBUTTONDOWN && ev.button.button == SDL_BUTTON_LEFT){
		HandleMouseEvent(ev.type,ev.button.x, ev.button.y);
	}
	else if (ev.type == SDL_MOUSEBUTTONUP && ev.button.button == SDL_BUTTON_LEFT){
		HandleMouseEvent(ev.type,ev.button.x, ev.button.y);
	}
}

void Dialog::Render(){
	if (!mIsVisible)
		return;
	if (mIsChange){
		SDL_SetRenderTarget(theGame.getRenderer(), mTexture);
		SDL_SetRenderDrawColor(theGame.getRenderer(), 0x00, 0x00, 0x00, 0x00);
		SDL_RenderClear(theGame.getRenderer());
		//			
		if (mBackground != NULL)
			mBackground->Render();
		vector<Button*>::iterator iter = mButtonList.begin();
		while (iter != mButtonList.end()){
			(*iter)->Render();
			iter++;
		}
		SDL_SetRenderTarget(theGame.getRenderer(), NULL);
		SDL_SetTextureBlendMode(mTexture, SDL_BLENDMODE_BLEND);
		mIsChange = false;
	}
	SDL_RenderCopyEx(theGame.getRenderer(), mTexture, mClipRect, mRenderRect, 0, NULL, SDL_FLIP_NONE);
}

void Dialog::HandleMouseEvent(int eventType, int x, int y){
	x = x - mRenderRect->x;
	y = y - mRenderRect->y;
	vector<Button*>::iterator iter = mButtonList.begin();
	while (iter != mButtonList.end()){
		Button *btn = (*iter);
		if (btn->GetButtonState() == DISABLE)
		{
			iter++;
			continue;
		}
		if (eventType == SDL_MOUSEMOTION){
			if (btn->HandleMotion(x, y)){
				mIsChange = true;
			}
		}
		else if (eventType == SDL_MOUSEBUTTONDOWN){
			if (btn->HandleClick(x, y)){
				btn->SetButtonState(PRESS);
				mIsChange = true;
			}
		}
		else if (eventType == SDL_MOUSEBUTTONUP){
			if (btn->GetButtonState() != NORMAL){
				btn->SetButtonState(NORMAL);
				mIsChange = true;
			}
		}
		iter++;
	}
}

按钮类

#pragma once 
#include "Renderable.h"
#include "Common.h"

#include <SDL.h>
#include <cassert>
#include <functional>	

//按钮状态
enum BUTTON_STATE{ NORMAL = 0, HOVER = 1,PRESS ,CHECK,UNCHECK, DISABLE };

//消息处理使用了回调函数的方式
//回调函数定义
typedef std::function <void(void *sender, void *args)>OnClickCallback;

class Button : public Renderable{
private:
	Renderable *mNormal;
	Renderable *mHover;
	Renderable *mPress;
	Renderable *mDisable;
	BUTTON_STATE mButtonState;
	OnClickCallback mClickCallback;
	void *mCallbackArgs;
public:	
	Button(){
		mNormal = NULL;
		mHover = NULL;
		mDisable = NULL;
		mPress = NULL;
	}
	Button(char*normal, char*hover,char *press, char *disable){
		assert(normal != NULL &&"normal state texture can't be NULL");

		if (normal != NULL){
			SetNormalRenderable(normal);
		}
		if (hover != NULL){
			SetHoverRenderable(hover);
		}
		if (disable != NULL){
			SetDisableRenderable(disable);
		}
		if (press != NULL){
			SetPressRenderable(press);
		}
	}
	virtual ~Button(){
		SAFE_DELETE(mNormal);
		SAFE_DELETE(mHover);
		SAFE_DELETE(mPress);
		SAFE_DELETE(mDisable);
	}
	
	//绘图
	virtual void Render();
	void SetNormalRenderable(string fileName);
	void SetHoverRenderable(string fileName);
	void SetDisableRenderable(string fileName);
	void SetPressRenderable(string fileName);
	//设置按钮状态
	void SetButtonState(BUTTON_STATE state){
		mButtonState = state;
	}
	//获取按钮状态
	BUTTON_STATE GetButtonState(){
		return mButtonState;
	}
	//处理鼠标移动消息
	bool HandleMotion(int x, int y);
	//处理鼠标左键单击消息
	bool HandleClick(int x, int y);
	//设置单击回调函数
	void SetClickCallbackFunc(OnClickCallback func,void *callbackArgs){
		mClickCallback = func;
		mCallbackArgs = callbackArgs;
	}
};	

//按钮的实现

#include "stdafx.h"
#include "Button.h"

void Button::SetHoverRenderable(string fileName){
	if (mHover == NULL){
		mHover = new Renderable();		
	}
	mHover->LoadTexture(fileName);
}
void Button::SetDisableRenderable(string fileName){
	if (mDisable == NULL){
		mDisable = new Renderable();
	}
	mDisable->LoadTexture(fileName);
}

void Button::SetNormalRenderable(string fileName){
	if (mNormal == NULL){
		mNormal = new Renderable();
		if (mRenderRect == NULL)
			mRenderRect = new SDL_Rect();		
	}
	mNormal->LoadTexture(fileName);
	mRenderRect->x = 0;
	mRenderRect->y = 0;
	mRenderRect->w = mNormal->GetWidth();
	mRenderRect->h = mNormal->GetHeight();
	mTextureWidth = mNormal->GetWidth();
	mTextureHeight = mNormal->GetHeight();
}
void Button::SetPressRenderable(string fileName){
	if (mPress == NULL){
		mPress = new Renderable();
	}
	mPress->LoadTexture(fileName);
}
//按钮的绘制,根据按钮的状态绘制对应的纹理
void Button::Render(){
	bool IsRender = false;
	if (mRenderRect == NULL)
		return;
	if (!mIsVisible){
		return;
	}
	switch (mButtonState){	
	case HOVER:
		if (mHover != NULL){
			IsRender = true;
			mHover->SetPos(mRenderRect->x, mRenderRect->y);
			mHover->Render();
		}
		break;
	case PRESS:
		if (mPress != NULL){
			IsRender = true;
			mPress->SetPos(mRenderRect->x, mRenderRect->y);
			mPress->Render();
		}
		break;
	case DISABLE:
		if (mDisable != NULL){
			IsRender = true;
			mDisable->SetPos(mRenderRect->x, mRenderRect->y);
			mDisable->Render();
		}
		break;
	}
	if (mNormal != NULL && !IsRender){
		mNormal->SetPos(mRenderRect->x, mRenderRect->y);
		mNormal->Render();
	}
}

bool Button::HandleMotion(int x, int y){
	if (mButtonState == DISABLE)
		return false;
	if (IsHit(x, y)){
		SetButtonState(HOVER);
		return true;
	}
	else{
		if (mButtonState == HOVER){
			SetButtonState(NORMAL);
			return true;
		}
	}
	return false;
}

bool Button::HandleClick(int x, int y){
	if (mButtonState == DISABLE)
		return false;
	if (IsHit(x, y)){
		SetButtonState(PRESS);
		//调用回调函数
		if (mClickCallback != NULL){
			mClickCallback(this, mCallbackArgs);
		}
		return true;
	}
	else{
		SetButtonState(NORMAL);
		return false;
	}
	return false;
}

使用示例:

这是一个麻将游戏的事件对话框。当产生碰、杠、胡的事件时,显示该对话框。

#pragma once
#include "../SDLGame/Button.h"
#include "../SDLGame/Renderable.h"
#include "../SDLGame/MessageListener.h"
#include "../SDLGame/Dialog.h"
#include <vector>
using namespace std;
class EventDialog : public Dialog{
private:	
	Button *mBtnPeng;
	Button *mBtnGang;
	Button *mBtnHu;
	Button *mBtnGiveup;			
	MessageListener *mReceiver;

public:
	EventDialog(){
		mBtnGang = NULL;
		mBtnHu = NULL;
		mBtnPeng = NULL;
		mBtnGiveup = NULL;			
	}
	virtual ~EventDialog(){

	}	
	virtual void LoadButtons(){
		mBackground = new Renderable();
		mBackground->LoadTexture("eventuibg.png");
		mBtnPeng = new Button("evtpeng0.png", "evtpeng1.png", NULL, "evtpeng2.png");
		mBtnGang = new Button("evtgang0.png", "evtgang1.png", NULL, "evtgang2.png");
		mBtnHu = new Button("evthu0.png", "evthu1.png", NULL, "evthu2.png");
		mBtnGiveup = new Button("giveup0.png", "giveup1.png", NULL, NULL);

		mBtnGiveup->SetPos((mTextureWidth - mBtnGiveup->GetWidth()) / 2, 5);
		mBtnPeng->SetPos(55, 105);
		mBtnGang->SetPos(145, 105);
		mBtnHu->SetPos(230, 105);
		//回调函数设置
		OnClickCallback callback = std::bind(&EventDialog::ButtonClick, this, std::placeholders::_1, std::placeholders::_2);
		mBtnGang->SetClickCallbackFunc(callback, NULL);
		mBtnPeng->SetClickCallbackFunc(callback, NULL);
		mBtnGiveup->SetClickCallbackFunc(callback, NULL);
		mBtnHu->SetClickCallbackFunc(callback, NULL);

		mIsChange = true;
		mButtonList.push_back(mBtnPeng);
		mButtonList.push_back(mBtnGang);
		mButtonList.push_back(mBtnHu);
		mButtonList.push_back(mBtnGiveup);
	}	

	//回调函数
	void ButtonClick(void*sender, void*args);
	//注册消息接收端
	void RegisterListener(MessageListener *listener){
		mReceiver = listener;
	}
	//
	void ShowEvent(int ev){
	
		if (ev & EVENT_HU){
			mBtnHu->SetButtonState(NORMAL);
		}
		else {
			mBtnHu->SetButtonState(DISABLE);
		}
		if (ev & EVENT_GANG){
			mBtnGang->SetButtonState(NORMAL);
		}
		else{
			mBtnGang->SetButtonState(DISABLE);
		}
		if (ev & EVENT_PENG){
			mBtnPeng->SetButtonState(NORMAL);
		}
		else {
			mBtnPeng->SetButtonState(DISABLE);
		}
		mIsChange = true;
		SetVisible(true);
	
	}
};

//回调函数
void EventDialog::ButtonClick(void *sender, void*args){
	if (mReceiver != NULL){
		int e = 0;
		if (sender == mBtnPeng)
			e = 1;
		else if (sender == mBtnGang)
			e = 2;
		else if (sender == mBtnHu)
			e = 3;
		//自定义消息
		Dispatcher.DispatchMsg(0.0f, this, mReceiver, e);
	}
}

在这里插入图片描述

  • 1
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
SDL2是一款跨平台的图形库,可以用来绘制RGB24格式的图像。RGB24是一种常用的颜色表示方式,每个像素由红、绿、蓝三个分量组成,每个分量占8位。下面是使用SDL2绘制RGB24图像的示例代码: ```c++ #include <SDL2/SDL.h> int main() { int width = 640; int height = 480; SDL_Init(SDL_INIT_VIDEO); SDL_Window* window = SDL_CreateWindow("SDL2 RGB24", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, width, height, 0); SDL_Renderer* renderer = SDL_CreateRenderer(window, -1, 0); // 创建一个RGB24格式的SDL_Surface SDL_Surface* surface = SDL_CreateRGBSurface(0, width, height, 24, 0x000000FF, 0x0000FF00, 0x00FF0000, 0); // 获取RGB24像素数据 Uint8* pixels = reinterpret_cast<Uint8*>(surface->pixels); int pitch = surface->pitch; // 绘制RGB24图像 for (int y = 0; y < height; ++y) { for (int x = 0; x < width; ++x) { // 计算当前像素在内存中的位置 Uint8* pixel = pixels + y * pitch + x * 3; // 设置红、绿、蓝三个分量的值 pixel[0] = 255; // 红色分量 pixel[1] = 0; // 绿色分量 pixel[2] = 0; // 蓝色分量 } } // 创建一个纹理,并将RGB24的像素数据拷贝到纹理中 SDL_Texture* texture = SDL_CreateTextureFromSurface(renderer, surface); // 将纹理渲染到屏幕上 SDL_RenderCopy(renderer, texture, nullptr, nullptr); SDL_RenderPresent(renderer); // 等待用户关闭窗口 bool running = true; while (running) { SDL_Event event; while (SDL_PollEvent(&event)) { if (event.type == SDL_QUIT) { running = false; } } } // 释放资源 SDL_DestroyTexture(texture); SDL_FreeSurface(surface); SDL_DestroyRenderer(renderer); SDL_DestroyWindow(window); SDL_Quit(); return 0; } ``` 上述代码首先使用SDL_Init函数进行初始化,然后创建窗口和渲染器。接着,通过调用SDL_CreateRGBSurface创建一个指定宽度、高度和像素格式(RGB24)的SDL_Surface。我们可以通过修改每个像素的红、绿、蓝分量的值来绘制不同的颜色。最后,将绘制好的图像拷贝到纹理中,并在屏幕上渲染出来。用户可以通过关闭窗口来退出程序。最后,释放使用的资源,完成绘制RGB24图像的过程。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值