SDL游戏之路(七)--屏幕自适应+图片加载+配置文件



屏幕自适应:

实现方法:定义一个游戏的基础屏幕大小:1366*768.

游戏中所有的坐标和长宽都是基于游戏基础坐标体系

然后定义一个 游戏坐标到屏幕坐标体系的转换函数。

在所有绘图的地方,都通过坐标转换:

#define _S2B(input) (g_m_bRatio ? (((int)input)*1000/g_m_fRatio): ((int)input))
#define _B2S(input) (g_m_bRatio ? (((int)input)*g_m_fRatio/1000): ((int)input))
#define _S2BX(input) (g_m_bRatio ? ((((int)input)-g_m_iPositionX)*1000/g_m_fRatio): ((int)input)-g_m_iPositionX)
#define _B2SX(input) (g_m_bRatio ? (g_m_iPositionX+((int)input)*g_m_fRatio/1000): g_m_iPositionX+((int)input))
#define _S2BY(input) (g_m_bRatio ? ((((int)input)-g_m_iPositionY)*1000/g_m_fRatio): ((int)input)-g_m_iPositionY)
#define _B2SY(input) (g_m_bRatio ? (g_m_iPositionY+((int)input)*g_m_fRatio/1000): g_m_iPositionY+((int)input))


ScreenParameter::ScreenParameter() {
	m_iBaseWidth = 1366;
	m_iBaseHeight = 768;
	m_iPositionX = 0;
	m_iPositionY = 0;
	m_bRatio = false;
	m_fRatio = 1.0;
}
//用来调节屏幕自动适应的参数
class ScreenParameter {
public:
	Sint32 m_iBaseWidth; //默认宽度=1366
	Sint32 m_iBaseHeight; //默认高度=768
	Sint32 m_iPositionX; //左顶点位置
	Sint32 m_iPositionY;
	Sint32 m_iScreenWidth;
	Sint32 m_iScreenHeight;
	Sint32 m_iWindowWidth;
	Sint32 m_iWindowHeight;

	bool m_bRatio; //是否图形有屏幕自适应
	float m_fRatio; //屏幕自适应系数
	ScreenParameter();
	//设置屏幕分辨率,计算最适合的变化比例
	void setScreen(Sint32 iWidth, Sint32 iHeight);
};


void ScreenParameter::setScreen(Sint32 iWidth, Sint32 iHeight) {
	m_iScreenWidth = iWidth;
	m_iScreenHeight = iHeight;
	if (m_iBaseWidth == iWidth && iHeight >= m_iBaseHeight) {
		m_iPositionY = (iHeight - m_iBaseHeight) / 2;
		m_iWindowWidth = m_iBaseWidth;
		m_iWindowHeight = m_iBaseHeight;
		return;
	}
	int fw = (iWidth * 1000 / m_iBaseWidth);
	int fh = (iHeight * 1000 / m_iBaseHeight);
	if (fw > fh) {
		fw = fh;
		m_iPositionX = (iWidth - m_iBaseWidth * fw / 1000) / 2;
	} else {
		m_iPositionY = (iHeight - m_iBaseHeight * fw / 1000) / 2;
	}
	m_bRatio = true;
	m_fRatio = fw / 1000.0;

	g_m_bRatio = m_bRatio;
	g_m_iPositionX = m_iPositionX;
	g_m_iPositionY = m_iPositionY;
	g_m_fRatio = fw;
	m_iWindowWidth = m_iBaseWidth * fw / 1000;
	m_iWindowHeight = m_iBaseHeight * fw / 1000;
}


图片加载:

主要注意路径的问题

windows+mac+ios+linux:程序相当路径

android:通过AAssetManager_open

wp8:使用D2D,相对路径

加载图片代码:

#ifndef SKIMAGE_H_
#define SKIMAGE_H_

#include "SkComm.h"
namespace sk_park {
class SkImage {
public:
	Sint32 m_iWidth;
	Sint32 m_iHeight;
	SkSurface m_skSurface;
	SkImage();
	~SkImage();
	int load(const char * pFilePath, Sint32 iWidth = 0, Sint32 iHeight = 0);
	void init(Sint32 iWidth, Sint32 iHeight,
			SkSurface & skSurface);
	void init(SkImage & obj);
};
}

extern sk_park::SkImage g_SkImage;

#endif /* SKIMAGE_H_ */

#include "pch.h"

#include "SkImage.h"
#include "SkFile.h"
#include "SkShow.h"
using namespace sk_park;

SkImage::SkImage() {
	m_iWidth = 0;
	m_iHeight = 0;
}
SkImage::~SkImage() {

}
void SkImage::init(Sint32 iWidth, Sint32 iHeight, SkSurface & skSurface) {
	m_iWidth = iWidth;
	m_iHeight = iHeight;
	m_skSurface = skSurface;
}
void SkImage::init(SkImage & obj) {
	m_iWidth = obj.m_iWidth;
	m_iHeight = obj.m_iHeight;
	m_skSurface = obj.m_skSurface;
}
int SkImage::load(const char * pFilePath, Sint32 iWidth, Sint32 iHeight) {
#ifndef __WP8__
	SDL_Surface * pSDL_Surface = g_SkFile.getPic(pFilePath);
	m_iWidth = pSDL_Surface->w;
	m_iHeight = pSDL_Surface->h;
	g_SkComm.log("name:%s w:%d h:%d",pFilePath,m_iWidth,m_iHeight);

	if (iWidth != 0) {
		if (iHeight == 0) {
			iHeight = (int) (iWidth * 1.0 / m_iWidth * m_iHeight);
		}
		m_iWidth = (iWidth);
		m_iHeight = (iHeight);
	} else if (iHeight != 0) {
		iWidth = (int) (iHeight * 1.0 / m_iHeight * m_iWidth);
		m_iWidth = (iWidth);
		m_iHeight = (iHeight);
	}
	SDL_Texture * pSDL_Texture = SDL_CreateTextureFromSurface(
			g_SkShow.m_pSkRenderer, pSDL_Surface);
	SDL_FreeSurface(pSDL_Surface);
	m_skSurface.setSurface(pSDL_Texture);
	m_skSurface.w = m_iWidth;
	m_skSurface.h = m_iHeight;
#else
	ComPtr<IWICBitmapDecoder> decoder;
	g_SkComm.getRenderer()->m_wicFactory->CreateDecoderFromFilename(
			stows(pFilePath).c_str(),
			nullptr,
			GENERIC_READ,
			WICDecodeMetadataCacheOnDemand,
			&decoder
			);
	 ComPtr<IWICBitmapFrameDecode> frame;
	 decoder->GetFrame(0, &frame);

	 Microsoft::WRL::ComPtr<IWICFormatConverter> wicFormatConverter;
	g_SkComm.getRenderer()->m_wicFactory->CreateFormatConverter(&wicFormatConverter);

	UINT originalWidth, originalHeight;
	frame->GetSize(&originalWidth, &originalHeight);
	m_iWidth = originalWidth;
	m_iHeight = originalHeight;
	if (iWidth != 0 )
	{
		if(iHeight==0){
			iHeight = (int)(iWidth*1.0/m_iWidth*m_iHeight);
		}
		Microsoft::WRL::ComPtr<IWICBitmapScaler> pScaler;
		g_SkComm.getRenderer()->m_wicFactory->CreateBitmapScaler(&pScaler);
		pScaler->Initialize(
			frame.Get(),
			_B2S(iWidth),
			_B2S(iHeight),
			WICBitmapInterpolationModeCubic
			);
		m_iWidth = iWidth;
		m_iHeight = iHeight;
			
		wicFormatConverter->Initialize(
			pScaler.Get(),
			GUID_WICPixelFormat32bppPBGRA,
			WICBitmapDitherTypeNone,
			nullptr,
			0.0f,
			WICBitmapPaletteTypeCustom // premultiplied BGRA has no paletting, so this is ignored
			);
	}else if (iHeight != 0 ){
		iWidth = (int)(iHeight*1.0/m_iHeight*m_iWidth);
		Microsoft::WRL::ComPtr<IWICBitmapScaler> pScaler;
		g_SkComm.getRenderer()->m_wicFactory->CreateBitmapScaler(&pScaler);
		pScaler->Initialize(
			frame.Get(),
			_B2S(iWidth),
			_B2S(iHeight),
			WICBitmapInterpolationModeCubic
			);
		m_iWidth = iWidth;
		m_iHeight = iHeight;

		wicFormatConverter->Initialize(
			pScaler.Get(),
			GUID_WICPixelFormat32bppPBGRA,
			WICBitmapDitherTypeNone,
			nullptr,
			0.0f,
			WICBitmapPaletteTypeCustom // premultiplied BGRA has no paletting, so this is ignored
			);
	}
	else{
		if(g_SP.m_bRatio){
			Microsoft::WRL::ComPtr<IWICBitmapScaler> pScaler;
					g_SkComm.getRenderer()->m_wicFactory->CreateBitmapScaler(&pScaler);
					pScaler->Initialize(
						frame.Get(),
						_B2S(m_iWidth),
						_B2S(m_iHeight),
						WICBitmapInterpolationModeCubic
						);
			wicFormatConverter->Initialize(
				pScaler.Get(),
				GUID_WICPixelFormat32bppPBGRA,
				WICBitmapDitherTypeNone,
				nullptr,
				0.0f,
				WICBitmapPaletteTypeCustom // premultiplied BGRA has no paletting, so this is ignored
				);
		}
		else{
		wicFormatConverter->Initialize(
			frame.Get(),
			GUID_WICPixelFormat32bppPBGRA,
			WICBitmapDitherTypeNone,
			nullptr,
			0.0f,
			WICBitmapPaletteTypeCustom // premultiplied BGRA has no paletting, so this is ignored
			);
		}
	 }

	g_SkComm.getRenderer()->m_d2dContext->CreateEffect(CLSID_D2D1BitmapSource, &m_skSurface.m_pSurface);
	m_skSurface.m_pSurface->SetValue(
			 D2D1_BITMAPSOURCE_PROP_WIC_BITMAP_SOURCE,
			 wicFormatConverter.Get() // IWICFormatConverter inherits from IWICBitmapSource
			 );
	 m_skSurface.m_pSurface->SetValue(
			 D2D1_BITMAPSOURCE_PROP_INTERPOLATION_MODE,
			 D2D1_BITMAPSOURCE_INTERPOLATION_MODE_LINEAR
			 );
	  m_skSurface.m_pSurface->SetValue(
			 D2D1_PROPERTY_CACHED,
			 TRUE // Direct2D effect properties use TRUE/FALSE instead of true/false.
			 );
#endif
	return 0;
}

SkImage g_SkImage;


配置文件:

使用tinyxml 作为配置读写解析器。

在android上,读自有目录用SDL_AndroidGetInternalStoragePath,读原始目录用AAssetManager_open

读写文件代码:

#ifndef SKFILE_H_
#define SKFILE_H_

#include "SkComm.h"
#include "SkString.h"

namespace sk_park {
class SkFile {
public:
#ifndef __WP8__
	SDL_Surface * getPic(const char * pPath);
#endif
	const char * getRootPath();
	int readTxtFile(const char * pPath, SkString & sData);
	int saveTxtFile(const char * pPath, const char * pData);
#ifdef __ANDROID__
	int readAndroidFile(const char * pPath, SkString & sData);
#endif
};

class SkDoc: public SkFile {
public:
	bool init(const char * pPath);
	bool save(SkString & data);
	void clear();
	SkString m_path;
	SkString m_data;
};
}
extern sk_park::SkFile g_SkFile;
extern sk_park::SkDoc g_SkDoc;

#endif /* SKFILE_H_ */

#include "pch.h"
#ifdef __ANDROID__
#include "../src/SkyparkJni.hpp"
#endif
#include "SkFile.h"
using namespace sk_park;
#ifndef __WP8__

SDL_Surface * SkFile::getPic(const char * pPath) {
#ifdef __ANDROID__
	SDL_Surface *temp = NULL;

	JNIEnv* pJNIEnv = (JNIEnv*) SDL_AndroidGetJNIEnv();
	jboolean iscopy;
	jstring filename = pJNIEnv->NewStringUTF(pPath);
	const char *mfile = pJNIEnv->GetStringUTFChars(filename, &iscopy);
	AAsset* asset = AAssetManager_open(g_SkyparkJni.m_pAAssetManager, mfile,
			AASSET_MODE_UNKNOWN);
	if (asset != 0) {
		off_t bufferSize = AAsset_getLength(asset);
		//SDL_Log("[%s][%d]file size:%d\n", __FILE__, __LINE__, bufferSize);
		char *buffer = (char *) malloc(bufferSize + 1);
		buffer[bufferSize] = 0;
		int numBytesRead = AAsset_read(asset, buffer, bufferSize);
		//SDL_Log("[%s][%d]read numBytesRead:%d\n", __FILE__, __LINE__,numBytesRead);
		if (numBytesRead == bufferSize) {
			SDL_RWops *src;
			src = SDL_RWFromMem(buffer, bufferSize);
			/* 将BMP文件加载到一个surface*/
			temp = IMG_Load_RW(src, 1);
		}
		free(buffer);
		AAsset_close(asset);

	}
	pJNIEnv->ReleaseStringUTFChars(filename, mfile);
	pJNIEnv->DeleteLocalRef(filename);

	return temp;
#else
	char filepath[256];
	snprintf(filepath, sizeof(filepath), "%s/%s", getRootPath(), pPath);
	SDL_Surface *surface = IMG_Load(filepath);
	g_SkComm.log("[%s][%d]path:%s ptr:%d err:%s", __FILE__, __LINE__, filepath,
			surface, g_SkComm.getErrMsg());
	return surface;
#endif
}

#endif

const char * SkFile::getRootPath() {
#ifdef __SKYPARK_MAC__
	return "/Users/vickenyang/Desktop/test/SkyparkGame/assets";
#endif
#ifdef __ANDROID__
	return SDL_AndroidGetInternalStoragePath();
#endif
	return ".";
}
#ifdef __ANDROID__
int SkFile::readAndroidFile(const char * pPath, SkString & sData) {
	int iRet = -1;

	JNIEnv* m_pJNIEnv = (JNIEnv*) SDL_AndroidGetJNIEnv();
	jboolean iscopy;
	jstring filename = m_pJNIEnv->NewStringUTF(pPath);
	const char *mfile = m_pJNIEnv->GetStringUTFChars(filename, &iscopy);
	AAsset* asset = AAssetManager_open(g_SkyparkJni.m_pAAssetManager, mfile,
			AASSET_MODE_UNKNOWN);
	if (asset != 0) {
		off_t bufferSize = AAsset_getLength(asset);
		//SDL_Log("[%s][%d]file size:%d\n", __FILE__, __LINE__, bufferSize);
		char * buffer = (char *) malloc(bufferSize + 1);
		buffer[bufferSize] = 0;
		int numBytesRead = AAsset_read(asset, buffer, bufferSize);
		//SDL_Log("[%s][%d]read numBytesRead:%d\n", __FILE__, __LINE__,numBytesRead);
		if (numBytesRead == bufferSize) {
			iRet = 0;
			sData.append(buffer,bufferSize);
		} else {
			free(buffer);
			iRet = -1;
		}

		AAsset_close(asset);
		free(buffer);
	}
	m_pJNIEnv->ReleaseStringUTFChars(filename, mfile);
	m_pJNIEnv->DeleteLocalRef(filename);

	return iRet;
}
#endif
int SkFile::readTxtFile(const char * pPath, SkString & sData) {
	char tmpFile[256];
	snprintf(tmpFile, sizeof(tmpFile), "%s/%s", getRootPath(), pPath);
	FILE *fp2 = fopen(tmpFile, "rb");
	if (fp2 == NULL) {
		return -2;
	}
	sData.clear();
	char buf[1024];
	while (true) {
		int iLen = fread(buf, 1, sizeof(buf), fp2);
		if (iLen <= 0) {
			break;
		}
		sData.append(buf, iLen);
	}
	fclose(fp2);
	return 0;
}
int SkFile::saveTxtFile(const char * pPath, const char * pData) {
	char tmpFile[256];
	snprintf(tmpFile, sizeof(tmpFile), "%s/%s", getRootPath(), pPath);
	FILE *fp2 = fopen(tmpFile, "wb");
	if (fp2 == NULL) {
		return -2;
	}
	fwrite(pData, strlen(pData), 1, fp2);
	fclose(fp2);
	return 0;
}

bool SkDoc::init(const char * pPath) {
	m_path = pPath;
#ifdef __ANDROID__
	m_path.replaceAll('/','-');
#endif
	SkString sData;
	//先读保存的文件
	SkString m_savePath = m_path;
	m_savePath.append(".save");
	int iRet = readTxtFile(m_savePath.c_str(), sData);
	g_SkComm.log("[%s][%d]init SkDoc:%s ret=%d len=%d", __FILE__, __LINE__,
			m_savePath.c_str(), iRet, sData.length());
	if (iRet == 0 && sData.length() > 0) {
		m_data = sData;
		return true;
	}
	//读取失败,再读取原始文件
#ifdef __ANDROID__
	iRet = readAndroidFile(pPath, sData);
#else
	iRet = readTxtFile(m_path.c_str(), sData);
#endif
	g_SkComm.log("[%s][%d]init SkDoc:%s ret=%d len=%d", __FILE__, __LINE__,
			m_path.c_str(), iRet, sData.length());
	if (iRet == 0 && sData.length() > 0) {
		m_data = sData;
		return true;
	}
	return false;
}
bool SkDoc::save(SkString & data) {
	m_data = data;
	SkString m_savePath = m_path;
	m_savePath.append(".save");
	int iRet = saveTxtFile(m_savePath.c_str(), m_data.c_str());
	g_SkComm.log("[%s][%d]saveMyFile:%s ret=%d len=%d", __FILE__, __LINE__,
			m_savePath.c_str(), iRet, m_data.length());
	if (iRet == 0) {
		return true;
	}
	return false;
}
void SkDoc::clear() {
	m_data = "";
}

SkFile g_SkFile;
SkDoc g_SkDoc;

配置文件代码:

#ifndef SKCONFXML_H_
#define SKCONFXML_H_

#include "SkComm.h"
#include "SkFile.h"
#include "../tinyxml/tinyxml.h"

namespace sk_park {
class SkConfXml {
public:
	TiXmlDocument m_xml;
	SkDoc m_doc;
	SkConfXml();
	bool init(const char * filename);
	bool save();
	bool delfile();

	Sint32 getKKValueInt32(const char * K1, const char * K2);
	bool setKKValueInt32(const char * K1, const char * K2, Sint32 iValue);
	bool setKKValueStr(const char * K1, const char * K2, const char * pStr);
	SkString getKKValueStr(const char * K1, const char * K2);
private:
	std::string m_filename;
	SkConfXml(const SkConfXml & obj);

};
}
extern sk_park::SkConfXml g_SkConfXml;

#endif /* SKCONFXML_H_ */

#include "pch.h"

#include "SkConfXml.h"
using namespace sk_park;

SkConfXml::SkConfXml() {
}
bool SkConfXml::init(const char * filename) {
	m_filename = filename;
	bool bRet = m_doc.init(filename);
	if (bRet == true) {
		SkString sData = m_doc.m_data;
		m_xml.Parse(sData.c_str());
		return true;
	}
	return false;
}
bool SkConfXml::save() {
	TiXmlPrinter printer;
	printer.SetIndent("    ");
	m_xml.Accept(&printer);
	SkString xmltext = printer.CStr();
	return m_doc.save(xmltext);
}
bool SkConfXml::delfile() {
	SkString stmp = "";
	return m_doc.save(stmp);
}

Sint32 SkConfXml::getKKValueInt32(const char * K1, const char * K2) {
	SkString sData = getKKValueStr(K1, K2);
	return atoi(sData.c_str());
}
bool SkConfXml::setKKValueInt32(const char * K1, const char * K2,
		Sint32 iValue) {
	char pStr[24];
	snprintf(pStr, sizeof(pStr), "%d", iValue);
	return setKKValueStr(K1, K2, pStr);
}
bool SkConfXml::setKKValueStr(const char * K1, const char * K2,
		const char * pStr) {
	TiXmlHandle docHandle(&m_xml);
	TiXmlElement * pRootTiXmlElement =
			docHandle.FirstChildElement("root").ToElement();
	if (pRootTiXmlElement == NULL) {
		pRootTiXmlElement = new TiXmlElement("root");
		docHandle.ToElement()->LinkEndChild(pRootTiXmlElement);
	}
	TiXmlElement * pK1TiXmlElement = pRootTiXmlElement->FirstChildElement(K1);
	if (pK1TiXmlElement == NULL) {
		pK1TiXmlElement = new TiXmlElement(K1);
		pRootTiXmlElement->LinkEndChild(pK1TiXmlElement);
	}
	TiXmlElement * pK2TiXmlElement = pK1TiXmlElement->FirstChildElement(K2);
	if (pK2TiXmlElement == NULL) {
		pK2TiXmlElement = new TiXmlElement(K2);
		pK1TiXmlElement->LinkEndChild(pK2TiXmlElement);
	}
	const char * pOldData = pK2TiXmlElement->GetText();
	if (pOldData != NULL) {
		if (strcmp(pOldData, pStr) == 0) {
			return true;
		}
	}
	pK2TiXmlElement->Clear();
	TiXmlText *pValue = new TiXmlText(pStr);
	pK2TiXmlElement->LinkEndChild(pValue);
	return true;
}

SkString SkConfXml::getKKValueStr(const char * K1, const char * K2) {
	SkString sRet = "";
	TiXmlHandle docHandle(&m_xml);
	TiXmlHandle rootHandle = docHandle.FirstChildElement("root");
	if (rootHandle.ToElement() != NULL) {
		TiXmlHandle handleK1 = rootHandle.FirstChildElement(K1);
		if (handleK1.ToElement() != NULL) {
			TiXmlHandle handleK2 = handleK1.FirstChildElement(K2);
			if (handleK2.ToElement() != NULL) {
				const char * pData = handleK2.ToElement()->GetText();
				if (pData != NULL) {
					sRet = SkString(pData);
				}
			}
		}
	}
	return sRet;
}

SkConfXml g_SkConfXml;


  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值