lazarus吧 关注:430贴子:685
  • 0回复贴,共1

castlegame 可简单快速开发android游戏。我总结的教程

取消只看楼主收藏回复

安装
fpcupdeluxe-i386-win32.exe 先安装这个.
fpc 选择 304版本 即stable 版本
lazarus 选择184版本 即stable 版本
两个都安装.
-----------
然后 cpu 选择arm os选择andrid 然后install cross compiler
---------------
然后选择castle game engine 然后install module
第一步 就ok 了
---------------
先安装java(版本是1.8的) java版本必须和castle game 要求一致,版本不能太高。
然后安装android studio 用于更新android 需要的sdk ndk 等东西。
最后按照castle game 的教程再走一边就行了。
==========================================================
============================================================
============================================================
具体
castle-engine compile pc编译
castle-engine package pc打包
castle-engine package --target=android 手机 android 打包方法
castle-engine package --os=android --cpu=arm 手机 android 打包方法 推荐
-----------------------------------------------
window.open 只是打开 涂抹窗口。
application.run 是整个程序的持久运行。
两者一起 才行。
当然有一个更简单的方式就是 window.openandrun. 哈哈哈
Application.MainWindow.OpenAndRun;
=======================================================
-------------------------------打包 apk 的基本配置 少一个都不行
<?xml version="1.0" encoding="utf-8"?>
<project name="my_fantastic_game"
standalone_source="my_fantastic_game_standalone.lpr"
game_units="GameInitialize"
qualified_name="io.castleengine.portable.game.skeleton"
>
</project>
================================打包 apk 的基本配置
--------------- 转换 手按坐标 到3d坐标
WorldPosition: TVector3;
SceneManager.PositionToWorldPlane(Event.Position, true, 0, WorldPosition)
============转换 手按坐标 到3d坐标
------------------ 2d 控制坐标的方法。 手动按钮屏幕
if Event.IsMouseButton(mbLeft) then
begin
if y< Event.Position.y then y:=y+200 else y:=y-200;
if x< Event.Position.X then x:=x+200 else x:=x-200;
end;
===================== 2d 控制坐标的方法。 手动按钮屏幕
--------------------几种 窗口的区别
Window: TCastleWindowBase;(不包含TCastleSceneManager实例,需要自己创建)
Window := TCastleWindowBase.Create(Application);
Window: TCastleWindow; (包含有内建的TCastleSceneManager实例)
Window := TCastleWindow.Create(Application);
TCastleWindowCustom = TCastleWindowBase deprecated 'use TCastleWindowBase';
这两个写法一样。 TCastleWindowCustom 是历史遗留问题。最好弃用
======================几种 窗口的区别
--------------- 控件定位,以及计算动态尺寸 坐标 定位
left bottom 如果窗体大小改变,那么left bottom 也会改变。
但是 CalculatedWidth, CalculatedHeight, CalculatedRect, 的值是最初的那个值,一直不变
坐标,定位: 可以使用left ,bottom 或者 anchor
使用anchor 的好处是,当父亲尺寸改变,儿子的定位依然保持anchor的设计,稳定性好
MyLabel.Anchor(vpBottom, 10 + MyButton.CalculatedHeight + 10);
=============== 控件定位,以及计算动态尺寸 坐标 定位
-------------关于2d 控件的单元
单元 CastleUIControls,CastleControls
关于2d 控件的单元
==============关于2d 控件的单元
-----------关于颜色 的单元
CastleColors 单元 可以这样设置颜色 HexToColor('5f3939');
CastleColors 单元 可以这样设置颜色 red yellow 等;
CastleVectors 单元 可以这样设置颜色 Vector4(95/255, 57/255, 57/255, 1.0);
==========关于颜色 的单元
---------------delphi lazarus 区别
赋值 函数的时候前面要加@
==============delphi lazarus 区别
----------------TCastleLabel 在黑色背景上看不到, 其后面有其他ui控件(不需要是父亲),才能看到自己.
MyLabel := TCastleLabel.Create(Application);
===============TCastleLabel 在黑色背景上看不到, 其后面有其他ui控件(不需要是父亲),才能看到自己.
----------
控件存在,不存在。
将控件移出Window.Controls 列表。 则控件不存在。
或者设置控件的exists 属性为 false. 则控件不存在
===========
----------- 坐标 关系
左下角是原点。
往右是x.
往上是y
往屏幕外面是z
============坐标 关系
------------儿子 大于 父亲 面积
儿子,的尺寸 比父亲大的时候,儿子会显示到父亲外面。 但是父亲外面的儿子部分,不会接收事件处理,不会接收手动输入。
最好把,儿子放到父亲内部。
==============儿子 大于 父亲 面积
--------------图像 两种图像类型 都能完成同样的事情
Image: TDrawableImage;
Image := TDrawableImage.Create('castle-data:/my_image.png');
Image.Draw(X, Y);
Image2: TCastleImageControl;
Image2 := TCastleImageControl.Create(Application);
Image2.URL := ApplicationData('Female-Zombie-300px.png');
Image2.Anchor(hpMiddle);
Image2.Anchor(vpTop, -10);
InsideRect.InsertFront(Image);
==============图像 两种图像类型 都能完成同样的事情
--------------TCastleLabel 使用 html
LabelStats := TCastleLabel.Create(Application);
LabelStats.Color := Black;
LabelStats.Html := true;
{ anything, just to show off the HTML :) }
LabelStats.Caption := 'Statistics:' + NL +
'Life: <font color="#ff0000">12%</font>' + NL +
'Stamina: <font color="#ffff00">34%</font>' + NL +
'Mana: <font color="#0000ff">56%</font>';
LabelStats.Anchor(hpMiddle);
LabelStats.Anchor(vpBottom, 100);
InsideRect.InsertFront(LabelStats);
==============TCastleLabel 使用 html
----------------换行符 所在单元
CastleUtils
NL
============换行符 所在单元
------------ 游戏控件等比例 缩放,适应 窗口的大小
控件会等比例缩放,坐标会根据anchor 来定位。 当然也可以使用left bottom (但是可能不美观)
Window.Container.UIReferenceWidth := 1024;
Window.Container.UIReferenceHeight := 768;
Window.Container.UIScaling := usEncloseReferenceSize;
==============游戏控件等比例 缩放,适应 窗口的大小
---------------------2游戏控件等比例 缩放,适应 窗口的大小
在data 目录下,新建一个CastleSettings.xml文件。哪容如下
<?xml version="1.0" encoding="utf-8"?>
<castle_settings>
<ui_scaling
mode="EncloseReferenceSize"
reference_width="1024"
reference_height="768"
/>
</castle_settings>
然后可以这样调用,来改变缩放。哈哈哈
Window.Container.LoadSettings('castle-data:/CastleSettings.xml');.
另外,还可以在这个文件里 设置 默认字体 等其他设置
使用这个文件的好处是, 因为castle-editor.exe 会使用这些设置,
并且castle-editor.exe修改了一些参数后,还会自动保存设置到这个文件里。
方便,好用,美美的
======================2游戏控件等比例 缩放,适应 窗口的大小
----------加载动画 序列图变动画
Explosion := TGLVideo2D.Create(ApplicationData('explosion_320x240_frameskip2/explosion_1@counter(4).png'), false);
==========加载动画 序列图变动画
------------按键 截图
if Event.IsKey(K_F5) then
Window.SaveScreen(FileNameAutoInc(ApplicationName + '_screen_%d.png'));
============按键 截图
----------------------编译出问题的可能原因 切记切记切记
1.目录,文件 中不能有空格,否则出问题。
2.文件名,目录名,不能太长,目录嵌套不能太深,否则出问题。
3.文件名,目录名,不能有中文,否则出问题。
=====================编译出问题的可能原因 切记切记切记
---------------- 控件, 图像,遮盖问题的解决
1.非控件的图像的遮盖问题: 在render 事件中, 先画的被遮盖, 后画的显示在最前面。
2.ui控件的遮盖问题: 例如 手柄控制
aa:=TCastleTouchControl.create (Application);
aa.Anchor(hpMiddle,300);
aa.Anchor(vpBottom, 100);
// mybutton.AutoSize:=false ;
aa.Width:=350;
aa.Height:=300 ;
window.Controls.InsertFront(aa) ;
然后在render 事件中,最后一个再涂抹一边这个控件。aa.render. 完美解决
=================控件, 图像,遮盖问题的解决
------------给2d游戏添加控制手柄
单元 castlecontrols
初始化下面的代码
aa:=TCastleTouchControl.create (Application);
aa.Anchor(hpMiddle,300);
aa.Anchor(vpBottom, 100);
// mybutton.AutoSize:=false ;
aa.Width:=350;
aa.Height:=300 ;
window.Controls.InsertFront(aa) ;
然后在 render 事件中添加 aa.render 不然的话,手柄画面会被覆盖
============给2d游戏添加控制手柄
----------- 消息框,信息框 unit CastleMessages 引擎消息框
MessageOk(Window, 'Crash!');
===========消息框,信息框 unit CastleMessages 引擎消息框
-------------------free pascal 消息框。 重要发现 free pascal 可以应用到android中。 牛逼啊 暂时只能用于电脑 不能用于android
unit LConvEncoding, 暂时只能用于pc 不能用于android 因为卡单元了。是电脑,手机 不匹配的问题。
procedure TForm1.Button1Click(Sender: TObject);
var ad:widechar; s:LPCSTR; s2:string;
begin
s2:='s多少付' ;
// s:= pchar(CP936ToUTF8(s2));
s:=pchar( UTF8ToCP936(s2));
showmessage(s);
MessageBox(0,PChar(UTF8ToAnsi('正常显示中文')),'1',MB_OK or MB_ICONEXCLAMATION);
MessageBox(0,s,'1',0);
end;
参考下面的文章 成功了
https://blog.csdn.net/poolord/article/details/77488704
在Lazarus中对字符串进行代码页转换
2017年08月22日 22:29:26 池龙 阅读数 885更多
分类专栏: Delphi / Lazarus
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/poolord/article/details/77488704
由于Lazarus基于UTF-8,因此当读写Windows建立的纯文本文件的时候,由于其中的中文使用GBK(CP936)编码,可能会出现错误。此时可使用Lazarus自带的代码页转换单元LConvEncoding对编码进行转换。
如UTF8和GBK互转
function CP936ToUTF8(const s: string): string; // Chinese
function UTF8ToCP936(const s: string; SetTargetCodePage: boolean = false): RawByteString; // Chinese, essentially the same as GB 2312 and a predecessor to GB 18030
1
2
如指定代码页之间互转
function ConvertEncoding(const s, FromEncoding, ToEncoding: string
{$ifdef FPC_HAS_CPSTRING}; SetTargetCodePage: boolean = false{$endif}): string;
1
2
3
注:GB18030由于包含部分四字节字符,实际其代码页CP54936是不能使用的,但是由于GB18030向下兼容目前中文Windows系统使用的GBK,而GBK又向下兼容GB2312(CP20936),所以实际操作中按CP936处理即可。
===================free pascal 消息框。 重要发现 free pascal 可以应用到android中。 牛逼啊
----------------
lazarus LcL 的单元 也就是有窗体的应用程序的单元在 C:\fpcupdeluxe\lazarus\lcl
lazarus 控制台的单元 也就是simple program 的单元在 C:\fpcupdeluxe\fpcsrc C:\fpcupdeluxe\fpcsrc\packages\fv\src
CastleEngineManifest.xml 这个是castle game engine 的编译选项 可以添加单元路径。
但是如果单元牵扯过多的化,可能fpc 使用lazarus的单元 有不适应的地方。
但是简单的添加一个自己的单元是成功的。
所以可以说。 castle game engine 可以使用其他第三方资源。 但是要测试看看, 希望这是对的。
这样这个游戏引擎就能干很多的事情。 也可能是我想多了
================
-----------------
cge 的时候 别再借用lazarus的单元了, 现在我就是胡搞,把编译器搞失灵了。
安 省的玩。别玩火。他大爷的 重新安装很过瘾啊
==================
-----------------
fpcupdeluxe 文件夹,可以整体复制。哈哈哈。 当出现问题的时候。把另外的复制过来就好。
===============
------------给 手柄单元添加了一个属性。用于记录偏移位置 .这样可以把手柄利用到2d上面
TCastleTouchControl = class(TCastleUserInterface)
strict private
FTouchMode: TCastleTouchCtlMode;
FLeverOffset: TVector2;
FDragging: Integer; //< finger index that started drag, -1 if none
FPosition: TCastleTouchPosition;
FScale: Single;
function TotalScale: Single;
procedure SetPosition(const Value: TCastleTouchPosition);
procedure SetScale(const Value: Single);
function MaxOffsetDist: Integer;
protected
procedure PreferredSize(var PreferredWidth, PreferredHeight: Single); override;
public
constructor Create(AOwner: TComponent); override;
procedure Render; override;
function Press(const Event: TInputPressRelease): boolean; override;
function Release(const Event: TInputPressRelease): boolean; override;
function Motion(const Event: TInputMotion): boolean; override;
procedure SetTouchMode(const Value: TCastleTouchCtlMode);
procedure GetSensorRotation(var X, Y, Z, Angle: Double);
procedure GetSensorTranslation(var X, Y, Z, Length: Double);
property pianyi: TVector2
read FLeverOffset write FLeverOffset ;
published
property TouchMode: TCastleTouchCtlMode
read FTouchMode write SetTouchMode default ctcmWalking;
{ Set position of touch control. Right now this simply sets
the anchor using @link(TCastleUserInterface.Anchor) and friends.
Tip: Use @link(TUIContainer.UIScaling) to have the anchors automatically
scale with screen size.
The size of the control is set to be constant physical size,
so it's not affected by @link(TUIContainer.UIScaling), only by
@link(TUIContainer.Dpi). }
property Position: TCastleTouchPosition
read FPosition write SetPosition default tpManual;
property Scale: Single read FScale write SetScale default 1;
end;
===========给 手柄单元添加了一个属性。用于记录偏移位置 .这样可以把手柄利用到2d上面
-------------- 纵屏 转化为横屏的坐标公式
(width -1 -y , x)
这是一个伪命题。 不需要处理屏幕旋转。因为手机自己会转动。
开发者只需要判断 width height 的比较大小而已, 然后分两种情况 布置控件就行了。
屏幕旋转是自动的事情。哈哈哈
所以,软件只需要处理 窄屏 宽屏 就好
============== 纵屏 转化为横屏的坐标公式
---------------
Event.IsMouseButton(mbLeft) 这个应该是手机上的手按一样
只测试出了 左键=手机点击 手机其他按键没有测试出对应的按键。暂时这样吧
===============
-----------游戏退出
halt 退出速度快。
application.terimate; 速度慢。等待时间长。
===========游戏退出
-------------- 给lazarus 添加搜索目录
单元搜索库这样添加:
1.project菜单 - project options - other unit files (-fu) 在这个地方添加搜索目录
注意这个设置,只针对 这个工程。
如果要所有新建的工程都默认这个设置。那么要勾选最下面的 set compiler options as default 对勾,然后按下ok 按钮, 就成功了
C:\fpcupdeluxe\ccr\castle_game_engine\src\base\android
CastleAndroidNativeAppGlue 这个目录下的这个单元有点意思
===========给lazarus 添加搜索目录
-------------被360 误杀了很多次了。 很惨 深刻的教训
注意添加信任目录,否则360会杀害很多文件,然后挂掉
studio
lazarus
free pascal
castle game engine
还有其他要用的目录,都添加信任。
被360搞了很多次了
g:adt
=============被360 误杀了很多次了。 很惨 深刻的教训
-------------
多点按键的解决方式 在press 里面解决
container.touchescount 在pc里 点击鼠标显示的是1。
此时container.Touches[0]存在。
但是在android里。 一个指头按屏幕,显示的是0。 此时container.Touches[0]不存在,并且会崩溃。
=============
---------------- 两个指头点击屏幕的测试结果 别看前面的,有很多错误
container.TouchesCount >=2 代表两个指头点击了屏幕 或者大于两个指头
event.FingerIndex=0 指代的是第二个指头的点击。 这个很重要。不然容易出现混乱
测试后,搞清了这个问题。
自由的点击 无干扰的执行,只能是在一个控件上, 按坐标位置 来人为制作操纵杆了。
如此才可以,成功。暂时是在window上成功了。
明天测试给window盖一个透明控件,然后在其上搞搞,然后再把坐标位置搞准确
----结论2
onclick的句柄中 sender.container.touchescout 的值和 window.container.TouchesCount的值是一样的。
控件中的点击 touchescount fingerindex 的数值和 window press 不同坐标的点击是一样的。 唯一的区别就是控件独占。 第二个点击效果出不来。 原因是sender 不能区分是不是自己的控件被点击了。
另外,window 被点击了, 他也不能区分,是否是控件被点击了。 真坑啊
也就是说,第一个被点击的控件,具有话语权, 然后在他的onpress句柄里,重新写代码。 这个代码要包括其他控件的代码,然后要用sender 进行区分。
再次测试的结果,sender 不能区分,sender 还是认为是一个控件,只能用坐标位置区分。
这个做法 和用 window.press 的做法差不多。 看看哪个更好利用用哪个把。 重点就是处理手柄的移动。哎。 加油
再次测试的结果,sender 不能区分,sender 还是认为是一个控件,只能用坐标位置区分。
最终结果,就是只能在window.press 上搞。区分3个手指,就行了。人命了。这个破引擎。
或者覆盖一个透明控件,在上面用坐标区分3个手指,就行了。 放弃移动杆。 使用按键的按钮
也就是说,要自己编码上下左右方向键了。 真是坑爹到家了。
但是也要坚持。已经到这个地方了
====结论2
------------结论3
press 和move update 要区分开, 因为press 无法区分按住不放的坐标
新的思路,记录touchcout=1
===========
------------------0之前的结论都是混乱的,矛盾的。重新总结新的结论.
1.手动记录 第一次,第二次点击的坐标。 这个坐标才是准确的。
2.fingerindex=0 永远是第一次的手指。
fingerindex=1 永远是第二次的手指。
持续性,换手指的时候,fingerindex 值保持不变。 也就是当第二个手指不松开,再次按下第一个手指,那么第一个手指fingerindex依然是0
3.两个控件的时候。第一次持续按下的按钮 他的onpress 事件会起作用。 后面的按钮不起作用。 即使第二个按钮持续按住,重新按第一个按钮,事件依然在第一个按钮上。
所以解决方法就是,在第一个按钮的事件里,写下其他按钮的事件处理(touchescout=1 fingerindex=1 只写这一个就行,其他全部自洽的,不用管)
控件: press是按下,motion是移动,update是按下一直按下 要把这三个事件都搞一下
应该使用window.onupdate 事件。 而不应该使用application.onupdate;
因为要处理的是window里面的事情。
onupdate 事件 和重绘是一样 的。用于消息,参数等的调整。规划等等。
window 上的持续按下鼠标,移动鼠标,暂时还不知道该怎么弄。 或许应该放一个透明控件来稿
move的叠加,只能使用在控件上了,因为window没有onmotion事件。所以不能给其事件添加其他控件的move.
window只能叠加 press事件。 所以应该是给操作界面上铺一层透明控件。然后制作一个自己的操作面板
更正加载透明控件无效。
但是发现window有onmotion 事件。完美解决问题。
window的onupdate 是持续按下按钮的事件。 它还有另外一层含义,就是他和涂抹事件是匹配的。意思就是说。先进行onupdate 然后就会重绘画面,大概就是这个意思。
所以对游戏的参数设置,等等 都可以放到这个地方来进行处理
==================0之前的结论都是混乱的,矛盾的。重新总结新的结论.
==================两个指头点击屏幕的测试结果
------------
控件的left bottom 属性默认为0 代表其初始本来的位置(可能这个位置不为0.但是left就是0) 这个位置就是这个控件的0坐标,哎,Capture the current container (window) contents to an image (or straight to an image file, like png).
Note that only capturing from the double-buffered OpenGL windows (which the default for our TCastleWindow and TCastleControl) is reliable. Internally, these methods may need to redraw the screen to the back buffer, because that's the only guaranteed way to capture OpenGL drawing (you have to capture the back buffer, before swap).真坑爹
============


IP属地:陕西1楼2019-10-13 15:20回复