🖥 许的数据库+为了做好游戏学游戏引擎

🌱游戏开发的工作流程(Haxe学习篇)


①安装{Haxe|Haxe Flixel|lime|编辑器Visual Studio Code|OpenFL|heaps}
②"Hello World",创建新文件
'flixel create'可以创建自带一些代码demo
'flixel tpl -n Hello World'可以创建自己的游戏项目《Hello World》
'dir'显示文件夹里的内容
'code .'在visual studio 里面显示内容
③理解内容
Main.hx是核心源代码。其他模块功能的代码都放在文件夹里
project.xml是一些依赖和安装库
bulid.xml是用来配置和指定路径
是用来放游戏资产
④尝试测试它,让它动起来
visual studio code 里面选run and debug
bulid.json是用来指导visual studio做测试的
或者选Command Palette然后输入'run build task'
或者在命令行输入'haxe run lime' 'lime test html5' 编译代码为h5

#PART2.0

①bulid.hxml具体功能是可以用来输出不同平台的代码包
[python bin/Main.py]->一键生成python代码包在bin文件夹里
[node bin/Main.js]->一键生成js代码包在bin文件夹里
②每个类(Class)的命名首字母都要大写,否则无法识别。
③代码的分段测试是通过在VC code 里面按Ctrl+Shrft+B来运行完成的,这个步骤用于跟踪单个模块的错误和异常行为,必须先测试单个模块,之后才进行集成测试,让不同模块正确交互,观察接口是否按预期工作,不要急着冲,会有BUG(怎么在CodeSpace里面调试程序还在研究)
④目前已知的Haxe Flixel的开源项目可以实现的功能有:1.存档;2方向键控制; 3.敌人auto巡路行为算法;4.烛光的明暗渲染效果;5交互对话系统;6藏经阁书籍显示内容;7.玩家动画sprite;
未找到的功能:1.随时间消耗SAN值的系统机制;2.合成道具系统机制;3.背包机制;4谜题推理系统;5使用PlayState回收使用资产避免摧毁物体造成内存消耗的具体实例;6Tilesheet和场景代码的关联和参考demo;7.场景边缘黑暗模糊的特效;8.技能发动系统机制及UI设计框架;

#Haxe代码格式开头是 import XXX
[import openfl.display.Sprite]->导入openfl文件夹里的display文件夹里的Sprite.hx代码;此步骤确保import包含所有导入代码
#接着我们就可以写相关的Sprite函数,命名各种类(Class)了

Sprite是指角色所有动作的图,要PNG格式,最好是64乘64的像素,然后240p(4.5:1)的画面是最兼容各种尺寸的平台格式。可以用TexturePacker来分割处理每个动作的数据坐标,对应生成的json文件放在文件夹里(目前没搞懂为什么有些Sprite图不是彩色的反而是灰阶的)
Class new (一个首字母大写的新名字)就是新增类;
Class override (Name)就是添加新功能;
Class super (Name) 就是可以积累使用的拓展覆盖功能;

此步骤要验证所有函数和变量都正确声明和使用+审查逻辑+Debug跟踪程序的流程+使用不同输入和场景测试代码+检测语法和缺少的分号(;)
当在做游戏玩法开发的时候,主屏幕改成PlayState.hx,出错的话要分析错误信息,定位漏洞点,进行必要的修复和重复调试过程,不出错的话,不要再手贱修改无问题的代码了:(。全部无误就可以改回主屏幕MenuState.hx
⑥function init{} function regularUpdate(dt:float){}是用来更新函数
function init{} if (state.time==0){} 是用来在游戏一开始就更新
这两个函数用来重复使用,定期更新游戏现状,查看游戏胜利条件是否达成
(没弄懂什么防止排队函数叠堆,要在循环中使用@sYnc 插队进行同步?)

⑦ Var +(分大小写的名字):{Int=0(整数)|Float=0(浮点小数点)|Bool(Yes or No)|String(文本字符串text)}(++是数字加一,==是检测两个值相同否,<=是检测前值是否小于后值)
⑧访问权。super是自下而上拥有所有hx的通行权,可以向上拓展覆盖,但不是全部;private是只在当前.hx有访问权;public是可以访问任何实例位置;inline则是将变量或函数定义成固定值,死也不改了。

#Review
FlxEmitter和FlxParticle类用于粒子效果。
使用FlxSprite类来显示精灵。
FlxGroup类是我们扩展的类,用来当作回收站节省内存。(子弹)
TexturePackerData类将用于处理从Texture Packer精灵表加载的精灵。
FlxTween和FlxEase类将用于缓动。

private var texturePackerData:
TexturePackerData;这个变量将存储用于从精灵表中获取精灵的数据:
private var explosionLine:FlxSprite;private var lineXOffset:Float =
0;private var lineYOffset:Float = 30;这些变量包含了爆炸线的精
灵,并且我们将使用x和y偏移量来定位消灭的敌人上方的线条。

#Mechaniucs
使用haxe可创建一个openfl项目,下载必须的openfl库
创建角色和敌人的动画表sprite sheet,找资产->FlxSprite[[20240110023445]]
创建系统来在openfl加载管理这些资产
创建藏经阁关卡地图->Playstate [[20240110023727]]
为玩家和敌人和环境实现碰撞系统 ->FlxGroup
玩家移动功能
玩家不同动作的动画
管理玩家的统治数据(san值/进度条/决心)
敌人的巡逻/追逐/攻击寻路行为算法,
编写玩家与敌人的交互机制,玩家的理智系统
游戏开始菜单,包括游戏统计数据和反馈系统
时时动态照明效果来营造气氛和可视范围
为拾取物品或遇到敌人添加视觉效果
音效和背景音乐,管理音频资产和播放

玩家碰触书可以显示文字,增加理智
碰触无双纸条,解锁方向
使用着色器(GLSL)来创建黑色剪影效果,并为灯光投影创建混合模式。
检测玩家输入,激活技能,
将玩家的ui改变为书本内容状态
用着色器创建渲染轮廓效果
调整播放器周围的照明
游戏逻辑,当玩家在书本里,无法被鬼魂察觉
//
#Story
#objectives
#User Interface

#Coding for Music(Rich Vreeland)

// For the purposes of these examples I'm using Flixel and AS3, because it's what I'm familiar with.

/** The last note played, stored after each new note is played. */

public static var lastNotePlayed: Class;

/** Play a note! */

public static function playNote():void

{

var noteToPlay: Class = getNote();

// This is Flixel's function for playing sounds.

FlxG.play(noteToPlay);

lastNotePlayed = noteToPlay;

}

/** Get a new series of note choices, based on what the previous note was. */

private static function getNote():Class

{

var noteChoices: Array = [];

if (lastNotePlayed == C3) noteChoices = [D3, E3, F3, G3, A3, B3, C4];

else if (lastNotePlayed == D3) noteChoices = [C3, E3, G3];

else if (lastNotePlayed == E3) noteChoices = [F3, G3, C4];

else if (lastNotePlayed == F3) noteChoices = [E3, G3];

else if (lastNotePlayed == G3) noteChoices = [C3, D3, E3, F3, A3, B3, C4];

else if (lastNotePlayed == A3) noteChoices = [G3, B3, C4];

else if (lastNotePlayed == B3) noteChoices = [G3, A3, C4];

else if (lastNotePlayed == C4) noteChoices = [C3, G3, B3];

else noteChoices = [C3, G3, C4];

var choice: int = Math.round(Math.random() * (noteChoices.length - 1));

var note: Class = noteChoices[choice];

return note;

}

#继续加强版音阶狂魔code
public static const IONIAN: Object = { position: 1 };

IONIAN.logic = [ /* 00 one */ ['two', 'thr', 'for', 'fiv', 'six', 'sev', 'one'],

/* 01 two */ ['one', 'thr', 'fiv'],

/* 02 thr */ ['for', 'fiv', 'oct'],

/* 03 for */ ['thr', 'fiv'],

/* 04 fiv */ ['one', 'two', 'thr', 'for', 'six', 'sev', 'oct'],

/* 05 six */ ['fiv', 'sev', 'oct'],

/* 06 sev */ ['fiv', 'six', 'oct'],

/* 07 oct */ ['one', 'fiv', 'sev'],

/* 08 else */ ['one', 'fiv', 'oct']

];

public static const DORIAN: Object = { position: 2 };

DORIAN.logic = [ /* 00 one */ ['thr', 'fiv', 'sev', 'oct'],

/* 01 two */ ['fiv', 'six', 'sev'],

/* 02 thr */ ['one', 'for', 'fiv', 'six', 'sev', 'oct'],

/* 03 for */ ['fiv', 'six', 'sev', 'oct'],

/* 04 fiv */ ['thr', 'six', 'sev', 'oct'],

/* 05 six */ ['one', 'for', 'fiv', 'sev', 'oct'],

/* 06 sev */ ['thr', 'fiv', 'six', 'oct'],

/* 07 oct */ ['one', 'thr', 'for', 'fiv', 'sev'],

/* 08 else */ ['one', 'fiv', 'oct']

];

This is all fine and dandy, but these strings need to be hooked up to the sound assets in order to work. As a way of dealing with different modes, we can create a for loop that will fill a 'loadout' object with the proper notes, assigned to the proper scale degrees.

/** An array of the scale degrees, used as a reference for populating the loadout object. */

public static const DEGREES: Array = ['one', 'two', 'thr', 'for', 'fiv', 'six', 'sev', 'oct'];

/** An array of all the notes needed to potentially form an eight note scale in any mode (Ionian is C3 - C4, Dorian is D3 - D4, Phrygian's E3 - E4, etc.) */

public static const C_MAJOR: Array = [C3, D3, E3, F3, G3, A3, B3, C4, D4, E4, F4, G4, A4, B4];

/** The loadout object, to be filled with the notes of the current mode/key. */

public static var loadout: Object = {};

/** The last note played, stored after each new note is played. */

public static var lastNotePlayed: Class;

// For the sake of the example, let's say the current key is F# Major.

public static varcurrentMode: Object = DORIAN;

/** Play a note! */

public static function playNote():void

{

var noteToPlay: Class = getNote(currentMode); // Pass the current mode into getNote(), whatever mode you want it to be!

FlxG.play(noteToPlay);

lastNotePlayed = noteToPlay;

}

/** Get a new series of note choices, based on what the previous note was. */

private static function getNote(modeToUse: Object):Class

{

/** Whether we've found the last note played in the current loadout. */

var found: Boolean = false;

/** The note choices that we'll use to decide the next note to get. */

var noteChoices: Array = [];

/** Make sure that the current scale we're using to make logic decisions starts on the first note of the current mode.

ie. in Ionian, loadout['one'] = C3, loadout['two'] = D3, etc.

in Dorian, loadout['one'] = D3, loadout['two'] = E3, etc. */

for (var i:int = 0; i <= DEGREES.length - 1; i++)

loadout[DEGREES[i]] = C_MAJOR[i + modeToUse.position - 1]; // - 1 is to account for starting at Zero.

/** Iterate through the loadout, find which is the last note played, then store the associated set of choices to noteChoices. */

loop: for (var j: int = 0; j < DEGREES.length - 1; j++)

{

if (lastNotePlayed == loadout[DEGREES[j]])

{

noteChoices = modeToUse.logic[j];

found = true;

break loop;

}

}

/** If the last note played was not found in the loadout, use the 'else' choices from the logic array. */

if (found == false)

noteChoices = modeToUse.logic[08]; // [08], or the last set of arguments in the logic array, used like an else statement.

/** The numerical choice from the array of choices that we will use. */

var choice: int = Math.round(Math.random() * (noteChoices.length - 1));

/** The note that we will return to the playNote() function and eventually play. */

var note: Class = loadout[noteChoices[choice]] as Class;

return note;

}

The system above will work great for moving through various modes in a single key, but what if you want to move through the other 11 keys, too? The most straightforward solution would be to create arrays for all of the keys. You also would of course need to create assets for all the new notes that you are using.

// Arrays of all the notes in needed to potentially form an eight note scale in any mode, in any key. s = #, ie. Cs3 = C#3

public static const C_MAJOR : Array = [C3, D3, E3, F3, G3, A3, B3, C4, D4, E4, F4, G4, A4, B4];

public static const Cs_MAJOR: Array = [Cs3, Ds3, F3, Fs3, Gs3, As3, C4, Cs4, Ds4, F4, Fs4, Gs4, As4, C5];

public static const D_MAJOR : Array = [D3, E3, Fs3, G3, A3, Cs4, D4, E4, Fs4, G4, A4, Cs5];

public static const Ds_MAJOR: Array = [Ds3, F3, G3, Gs3, As3, D4, Ds4, F4, G4, Gs4, As4, D5];

public static const E_MAJOR : Array = [E3, Fs3, Gs3, A3, B3, Ds4, E4, Fs4, Gs4, A4, B4, Ds5];

public static const F_MAJOR : Array = [F3, G3, A3, As3, C4, E4, F4, G4, A4, As4, C5, E5];

public static const Fs_MAJOR: Array = [Fs3, Gs3, As3, B3, Cs4, F4, Fs4, Gs4, As4, B4, Cs5, F5];

public static const G_MAJOR : Array = [G3, A3, B3, C4, D4, F4, G4, A4, B4, C5, D5, F5];

public static const Gs_MAJOR: Array = [Gs3, As3, C4, Cs4, Ds4, Fs4, Gs4, As4, C5, Cs5, Ds5, Fs5];

public static const A_MAJOR : Array = [A3, B3, Cs4, D4, E4, G4, A4, B4, Cs5, D5, E5, G5];

public static const As_MAJOR: Array = [As3, C4, D4, Ds4, F4, Gs4, As4, C5, D5, Ds5, F5, Gs5];

public static const B_MAJOR : Array = [B3, Cs4, Ds4, E4, Fs4, A4, B4, Cs5, Ds5, E5, Fs5, A5];

// For the sake of the example, let's say the current key is F# Major.

public static var currentKey: Array = Fs_MAJOR;

Then, you would adjust the for loop that fills the loadout to check for the current key's scale:

for (var i:int = 0; i <= DEGREES.length - 1; i++)

loadout[DEGREES[i]] = currentKey[i + modeToUse.position - 1];

#🌱游戏开发的工作流程(Unity学习篇)

①{编辑器Visual Studio Code or Cursor | Unity |Github Desktop }
②类的继承者们就是我需要写的代码。一般继承的类都是: MonoBehaviour;
public class MyScript : MonoBehaviour
{
// 用于组件脚本
// 包含 Start(), Update(), Awake() 等生命周期方法
}

但Unity官方教程里面继承的是Player : MovingObject,这似乎是Player族的大名!然后就直接省略移动相关的代码工作了。Enemy和NPC似乎也能使用相同的族类呢!
public class CustomPropertyDrawer : PropertyDrawer
{
// 用于自定义Inspector中属性的显示方式
}
public class ItemData : ScriptableObject
{
// 用于创建可重用的数据资源
}
public class CustomEditorWindow : EditorWindow
{
// 用于创建自定义编辑器窗口
}
Destructible : TileBase 这个是继承TileBase,可以用来设置多层遮罩和精灵切换,也可以设置不同破坏状态的动画
public class CustomTile : TileBase
{
// 用于创建自定义瓦片
}
public class CustomAnimationBehaviour : StateMachineBehaviour
{
// 用于控制动画状态机的行为
}

public class CustomInspector : Editor
{
// 用于自定义组件的Inspector界面
}

③GameManager相当于三权分立里面的联邦中央政府+FBI+白宫国会
GameManager一并管理其他BoardManager+SoundManager...
杰克有茶偏心使用的Entity实体
官方指引下的不同平台正确编译依靠一下代码
#if UNITY_STANDALONE || UNITY_WEBPLAYER horizontal = (int) (Input.GetAxisRaw ("Horizontal")); vertical = (int) (Input.GetAxisRaw ("Vertical")); #elif UNITY_IOS || UNITY_ANDROID || UNITY_WP8 || UNITY_IPHONE // 移动端触摸输入处理 #endif
音效系统的SoundManager
AudioClip是指定某一首歌;AudioSource是控制播放音乐

④GameController相当于三权分立里面的法庭,就是逆转裁判,就是Coc桌游的KP
玩家和敌人的攻击/玩家和NPC的互动对话情报交流/玩家和世界的交互关系都可以在这里得到处理
⑤我偏爱的微交互系统如何实现呢?
首先要给不同类型的交互物体打Tag区分开来,然后根据tag来做出不同的交互反馈。
1.
public enum AABBType {AABB, BBCC,}; private void OnTriggerEnter2D (Collider2D other) { if(other.tag == "Exit") { Invoke ("Restart", restartLevelDelay); enabled = false; } else if(other.tag == "Food") { // 处理食物收集 } }//这里出口的交互反馈是离开这一关卡(Unity官方程序员使用了随机迷宫生成所以是restartLevelDelay),我也可以改成进入第二关。然后如果是碰到Tag是Food的物体就把食物收集起来,我可以在这里加入一个拾取食物的anim.=>animator.SetTrigger ("playerCollect");
⑥**[SerializeField]配置Unity的inspector,相当于三权分立里面剩下的啊那个没有人比我更懂的总统。**
如果提供权力给总统inspector,比如让他可以合法提供武器给乌克兰or以色列,就要在代码前面加[SerializeField] ,于是乎大总统就能察觉还能这个样子操作啊,果然没有人比我更懂
~
除此之外,总统可以自己调数值看看接下来会发生什么,出错了就自己改回去呗,同时可以保存Prefab和场景数据存档

#AI写代码

#让Github copliot写代码的提示语
Based on the provided player movement code in Haxe/OpenFL, create a 'fog of war' mechanic for a library exploration game. the player should only be able to see a limited area around them, with the rest of the map initially obscured. As the player moves, nearby areas become visible. Focus on efficient visibility updates and ensure that the mechanic integrates seamlessly with the existing movement system. Provide code snippets for the visibility calculation, graphical updates, and any necessary modifications to the player class