【Android游戏开发十二】(保存游戏数据 [上文])详解SharedPreference 与 FIleInputS

AI权益加码!Claude Code、Cursor等20+工具免费用! 购周边限时加赠Coding Plan Lite,畅享主流AI工具!学习进阶更高效! 阅读详情

【Android游戏开发十二】(保存游戏数据[上文])详解SharedPreference 与FIleInputStream/FileOutputStream将数据存储到SD卡中!

 

 

Himi  原创, 欢迎转载,转载请在明显处注明! 谢谢。

 

原文地址: http://blog.csdn.net/xiaominghimi/archive/2011/01/02/6113019.aspx

 

 

     对于游戏中的数据进行保存方式,在Android中常用的有四种保存方式,这里我先给大家统一先简单的介绍下:

 

1.  SharedPreference

此保存方式试用于简单数据的保存,文如其名属于配置性质的保存,不适合数据比较大的保存方式;

 

2. 文件存储(FIleInputStream/FileOutputStream)

此保存方式比较适合游戏的保存和使用,可以保存较大的数据,因为相对于SQLite来说更容易让童鞋们接受,此方式不仅能把数据存储在系统中也能将数据保存到SDcard中;

 

3.SQLite

此保存方式比较适合游戏的保存和使用,可以保存较大的数据,并且可以将自己的数据存储到文件系统或者数据库当中,也可以将自己的数据存储到SQLite数据库当中,也能将数据保存到SDcard中;

 

4.ContentProvider (不推荐用于游戏保存)

此保存方式不推荐用于游戏保存,因为此方式不仅能存储较大数据,还支持多个程序之间就的数据进行交换!!! 但是由于游戏中基本就不可能去访问外部应用的数据,所以对于此方式我不予讲解, 有兴趣的可以去自行百度google 学习;

 

以上简单的对几种常用的保存方式进行的概述,那么,下面会详细的去分析每个的优缺点以及每种保存的实现和需要注意的地方!

 

下面我首先向大家介绍第一种保存方式:

 

             保存方式之:  《SharedPreference》

 

           优点: 简单、方便、适合简单数据的快速保存

           缺点:1.存数的文件只能在同一包内使用,不能在不同包之间使用!

                   2.默认将数据存放在系统路径下/data/data/com.himi/  ,没有找到放SD卡上的方法。

           总结:其实本保存方式如同它的名字一样是个配置保存,虽然方便,但只适合存储比较简单的数据!

 

main.xml  :

 

 

 

·········10········20········30········40········50········60········70········80········90········100·······110·······120·······130·······140·······150

<?xml version="1.0" encoding="utf-8"?> 

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 

    android:orientation="vertical" android:layout_width="fill_parent" 

    android:layout_height="fill_parent"> 

    <TextView android:layout_width="fill_parent" 

        android:layout_height="wrap_content" android:text="保存数据练习!" 

        android:textSize="20sp" android:textColor="#ff0000" android:id="@+id/tv_title" /> 

    <TextView android:layout_width="fill_parent" 

        android:layout_height="wrap_content" android:text="请输入帐号" /> 

    <EditText android:layout_width="fill_parent" 

        android:layout_height="wrap_content" android:id="@+id/editText_Login" 

        android:text=""></EditText> 

    <TextView android:layout_width="fill_parent" 

        android:layout_height="wrap_content" android:text="请输入密码" /> 

    <EditText android:layout_width="fill_parent" 

        android:layout_height="wrap_content" android:id="@+id/editText_Password" 

        android:text=""></EditText> 

    <Button android:id="@+id/button_save" android:layout_width="wrap_content" 

        android:layout_height="wrap_content" android:text="保存"></Button> 

    <Button android:id="@+id/button_load" android:layout_width="wrap_content" 

        android:layout_height="wrap_content" android:text="取出数据" 

        android:visibility="invisible"></Button> 

</LinearLayout> 

 

先把xml文件放上来的原因是因为我在此篇中介绍的SharedPreference 和 文件存储(FIleInputStream/FileOutputStream),都共用此xml,很简单,两个textview 两个editview 以及两个button,这里就不多说了;

 

下面是SharedPreference 的代码实现和详细讲解:

 

 

 

·········10········20········30········40········50········60········70········80········90········100·······110·······120·······130·······140·······150

/** 

 * @author Himi 

 * @保存方式:SharedPreference 

 * @注意:SharedPreference 可以跨程序包使用,多谢二楼童鞋提醒!

 * @操作模式: Context.MODE_PRIVATE:新内容覆盖原内容 

 *            Context.MODE_APPEND:新内容追加到原内容后 

 *            Context.MODE_WORLD_READABLE:允许其他应用程序读取 

 *            Context.MODE_WORLD_WRITEABLE:允许其他应用程序写入,会覆盖原数据。 

 */   

public class MainActivity extends Activity implements OnClickListener {   

    private EditText et_login, et_password;   

    private Button btn_save;   

    private TextView tv_title;   

    private SharedPreferences sp;   

    @Override   

    public void onCreate(Bundle savedInstanceState) {   

        super.onCreate(savedInstanceState);   

        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,   

                WindowManager.LayoutParams.FLAG_FULLSCREEN);   

        this.requestWindowFeature(Window.FEATURE_NO_TITLE);   

        setContentView(R.layout.main);   

        btn_save = (Button) findViewById(R.id.button_save);   

        btn_save.setOnClickListener(this);   

        et_login = (EditText) findViewById(R.id.editText_Login);   

        et_password = (EditText) findViewById(R.id.editText_Password);   

        tv_title = (TextView) findViewById(R.id.tv_title);   

        // 这里我们先调用getSharedPreferences()来实例化一个SharedPreferences,   

        // 第二个参数是指:操作模式(上面对各种操作模式已有解释)   

        sp = getSharedPreferences("Setting_himi", MODE_PRIVATE);   

        /* 

         * 下面代码是我们要在程序刚启动的时候我们来读取之前的数据,  

         * 当然我们还没有保存任何数据所以肯定找不到!! 

         * 如果找不到也没关系会默认返回一个参数值,看下面的方法含义便知! 

         */   

        sp.getString("login", "");   

        // getString()类似哈希表,一个key 一个volue ,   

        // 这个方法如果找不到对应的第一个参数(key),那么将以第二个参数作为此key的返回值   

        et_login.setText(sp.getString("login", ""));   

        et_password.setText(sp.getString("password", ""));   

    }   

    @Override   

    public void onClick(View v) {    

        if (v == btn_save) {   

            if (et_login.getText().toString().equals(""))   

                tv_title.setText("请输入帐号!");   

            else if (et_password.getText().toString().equals(""))   

                tv_title.setText("请输入密码!");   

            else {   

                sp.edit()   

                  .putString("login", et_login.getText().toString())   

                  .putString("password", et_password.getText().toString())   

                  .commit();   

                // 从sp.edit()开始进入编辑状态,直到commit()提交!   

                tv_title.setText("保存成功!可重新打开此程序,测试是否已经保存数据!" +   

                    "/n(或者在'File Explorer'窗口下-data-data-com.himi路径下" +   

                    "是否存在" +"了'Setting_himi.xml')");   

            }   

        }   

    }   

}   

       

代码中的注释的很清楚了,比较简单,不多说了。

 

 

             保存方式之:  《文件存储OutputStream/InputStream》

 

 

           优点:1.适合游戏存储,能存储较大数据;

                     2.不仅能存储到系统中,也能存储到SD卡中!

           总结:如果童鞋们对SQL不太熟习的话那么选择此种方式最为合适的啦、嘿嘿

 

 

 

·········10········20········30········40········50········60········70········80········90········100·······110·······120·······130·······140·······150

/**

 * @author Himi

 * @保存方式:Stream 数据流方式

 * @注意1:默认情况下,使用openFileOutput 方法创建的文件只能被其调用的应用使用,

 *         其他应用无法读取这个文件,如果需要在不同的应用中共享数据;

 *         

 * @注意2:因为android  os内部闪存有限,所以适合保存较少的数据,当然我们也有解决的方法,

 *         就是把数据保存在SD开中,这样就可以了,后面我也会向大家讲解   !

 *         

 * @提醒1 调用FileOutputStream 时指定的文件不存在,Android 会自动创建它。

 *        另外,在默认情况下,写入的时候会覆盖原 文件内容,如果想把新写入的内

 *        容附加到原文件内容后,则可以指定其mode为Context.MODE_APPEND。

 *        

 * @提醒2 启动程序就初始化的时候一定要注意处理!代码中有注释!一定要仔细看!

 * 

 * @提醒3 这里我给大家讲两种方式,一种是原生态file流来写入/读入,

 *        另外一种是用Data流包装file流进行写入/读入 其实用data流来包装进行操作;

 *        原因是:包装后支持了更多的写入/读入操作,比如:file流写入不支持

 *        writeUTF(String str); 但是用Data包装后就会支持。

 *        

 * @操作模式: Context.MODE_PRIVATE:新内容覆盖原内容

 *            Context.MODE_APPEND:新内容追加到原内容后

 *            Context.MODE_WORLD_READABLE:允许其他应用程序读取

 *            Context.MODE_WORLD_WRITEABLE:允许其他应用程序写入,会覆盖原数据。

 */ 

public class MainActivity extends Activity implements OnClickListener { 

    private EditText et_login, et_password; 

    private Button btn_save; 

    private TextView tv_title; 

    private FileOutputStream fos; 

    private FileInputStream fis; 

    private DataOutputStream dos; 

    private DataInputStream dis; 

    @Override 

    public void onCreate(Bundle savedInstanceState) { 

        String temp = null; 

        super.onCreate(savedInstanceState); 

        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, 

                WindowManager.LayoutParams.FLAG_FULLSCREEN); 

        this.requestWindowFeature(Window.FEATURE_NO_TITLE); 

        setContentView(R.layout.main); 

        btn_save = (Button) findViewById(R.id.button_save); 

        btn_save.setOnClickListener(this); 

        et_login = (EditText) findViewById(R.id.editText_Login); 

        et_password = (EditText) findViewById(R.id.editText_Password); 

        tv_title = (TextView) findViewById(R.id.tv_title); 

        try { 

            // openFileInput 不像sharedPreference 中 

            // getSharedPreferences的方法那样找不到会返回默认值, 

            // 这里找不到数据文件就会报异常,所以finally里关闭流尤为重要!!!  

            if (this.openFileInput("save.himi") != null) {   

                // --------------单纯用file来读入的方式----------------- 

                // fis = this.openFileInput("save.himi"); 

                // ByteArrayOutputStream byteArray = new 

                // ByteArrayOutputStream(); 

                // byte[] buffer = new byte[1024]; 

                // int len = 0; 

                // while ((len = fis.read(buffer)) > 0) { 

                // byteArray.write(buffer, 0, len); 

                // } 

                // temp = byteArray.toString(); 

                // -------------- 用data流包装后的读入的方式------------ 

                fis = this.openFileInput("save.himi");//备注1  

                dis = new DataInputStream(fis); 

                et_login.setText(dis.readUTF()); 

                et_password.setText(dis.readUTF()); 

                // 这里也是在刚启动程序的时候去读入存储的数据 

                // 读的时候要注意顺序; 例如我们写入数据的时候 

                //先写的字符串类型,我们也要先读取字符串类型,一一对应! 

            } 

        } catch (FileNotFoundException e) { 

            // TODO Auto-generated catch block 

            e.printStackTrace(); 

        } catch (IOException e) { 

            // TODO Auto-generated catch block 

            e.printStackTrace(); 

        } finally { 

            // 在finally中关闭流!因为如果找不到数据就会异常我们也能对其进行关闭操作; 

            try { 

                if (this.openFileInput("save.himi") != null) { 

                    // 这里也要判断,因为找不到的情况下,两种流也不会实例化。 

                    // 既然没有实例化,还去调用close关闭它,肯定"空指针"异常!!! 

                    fis.close(); 

                } 

            } catch (FileNotFoundException e) { 

                // TODO Auto-generated catch block 

                e.printStackTrace(); 

            } catch (IOException e) { 

                // TODO Auto-generated catch block 

                e.printStackTrace(); 

            } 

        } 

    } 

    @Override 

    public void onClick(View v) { 

        if (Environment.getExternalStorageState() != null) { 

            // 这个方法在试探终端是否有sdcard! 

            Log.v("Himi", "有SD卡"); 

        } 

        if (v == btn_save) { 

            if (et_login.getText().toString().equals("")) 

                tv_title.setText("请输入帐号!"); 

            else if (et_password.getText().toString().equals("")) 

                tv_title.setText("请输入密码!"); 

            else { 

                try {  

                    // ------单纯用file来写入的方式-------------- 

                    //fos = new FileOutputStream(f); 

                    // fos.write(et_login.getText().toString().getBytes()); 

                    // fos.write(et_password.getText().toString().getBytes()); 

                    // ------data包装后来写入的方式-------------- 

                    fos = this.openFileOutput("save.himi", MODE_PRIVATE);//备注2 

                    dos = new DataOutputStream(fos); 

                    dos.writeUTF(et_login.getText().toString()); 

                    dos.writeUTF(et_password.getText().toString()); 

                    tv_title.setText("保存成功!可重新打开此程序,测试是" + 

                            "否已经保存数据!/n(或者在'File Explorer'" + 

                            "窗口下-data-data-com.himi-files路径下" + 

                            "是否存在了'save.himi')"); 

                } catch (FileNotFoundException e) { 

                    // TODO Auto-generated catch block 

                    e.printStackTrace(); 

                } catch (IOException e) { 

                    // TODO Auto-generated catch block 

                    e.printStackTrace(); 

                } finally { 

                    // 在finally中关闭流 这样即使try中有异常我们也能对其进行关闭操作; 

                    try { 

                        dos.close(); 

                        fos.close(); 

                    } catch (IOException e) { 

                        // TODO Auto-generated catch block 

                        e.printStackTrace(); 

                    } 

                } 

            } 

        } 

    } 

 

以上代码中实现了两种流形式来完成写入和读入,这里我们为什么要使用Data流来包装,其实不光是获得更多的操作方式,最主要的是方便快捷,你比如用file来读入的时候,明显的复杂了一些不说,它还一次性把所有数据都取出来了,不便于对数据的处理!

 

强调的有几点:

1: 在一开始对数据的访问再次提醒童鞋们,这个跟sharedPreference的获取方式不一样,sharedPreference 的获取方式可以得到一个默认的值,但是你用咱们获取的是个文件 而且直接就去open这个文件,一旦不存在必定异常,所以这一块的异常处理,以及finally的处理一定要处理得当。

2.其实在一开始用data包装的时候发现写入的字符串在读入的时候发现字符乱码了,查了api才发现,api规定当写入字符串的时候必须写入UTF-8格式的编码,但是后来不知道怎么了就没事了。- -、所以这里如果童鞋们遇到此问题,我给出大家一个解决方法,就是在写入的时候我们不要去DataOutputStream 来包装而是用,OutputStreamWriter ,因为在构造的可以设定编码!

                                 OutputStreamWriter osw = new OutputStreamWriter(fis,"UTF-8");

 String  content = EncodingUtils.getString(buffer, "UTF-8");  这个也能把字符数组转码制!

这样写入的就肯定是UTF-8编码的字符啦、

 

下面介绍如何把我们的数据通过OutputStream/InputStream 存入SD卡中!

 

   其实将我们的数据放入SD卡中,无疑就需要对代码进行两处的修改:

 

注意:一定要有SD卡!对于如何创建SD卡在前一篇文章中已经说了两种方式,不会的童鞋可以去看下;

第一:检查是否装有SD卡; 

 

第二: 修改读入的地方(备注1)

         fis = this.openFileInput("save.himi"); //这里没有路径,路径是默认的data-data-com.himi-files下

      替换成我们的SD卡的路径就可以了:

          File path = new File("/sdcard/himi/save.himi");//这里新建一个File目录路径

          fis = new FileInputStream(path);传入路径

 

第三: 修改写入的地方(备注2)

        fos = this.openFileOutput("save.himi", MODE_PRIVATE);这里也是默认路径,需要对其修改,

       注意:这里修改了,那么在finally中的判定大家也要对应的适当修改;

 

注意:如果是系统路径,当没有此文件的时候,android 会默认创建一个!但是我们放入SD卡的时候要自己创建目录路径和文件!

 

 

 

 

 

·········10········20········30········40········50········60········70········80········90········100·······110·······120·······130·······140·······150

if (Environment.getExternalStorageState() != null) {// 这个方法在试探终端是否有sdcard! 

                Log.v("Himi", "有SD卡"); 

                File path = new File("/sdcard/himi");// 创建目录 

                File f = new File("/sdcard/himi/save.himi");// 创建文件 

                if (!path.exists()) {// 目录不存在返回false 

                    path.mkdirs();// 创建一个目录 

                } 

                if (!f.exists()) {// 文件不存在返回false 

                    f.createNewFile();// 创建一个文件 

                } 

                fos = new FileOutputStream(f);// 将数据存入sd卡中 

            } 

 

 

第四: 因为我们要在SD卡中进行写入的操作,所以要在配置文件中声明权限!

 

 

AndroidMainfest.xml

 

·········10········20········30········40········50········60········70········80········90········100·······110·······120·······130·······140·······150

<?xml version="1.0" encoding="utf-8"?> 

<manifest xmlns:android="http://schemas.android.com/apk/res/android" 

      package="com.himi" 

      android:versionCode="1" 

      android:versionName="1.0"> 

    <application android:icon="@drawable/icon" android:label="@string/app_name"> 

        <activity android:name=".MainActivity" 

                  android:label="@string/app_name"> 

            <intent-filter> 

                <action android:name="android.intent.action.MAIN" /> 

                <category android:name="android.intent.category.LAUNCHER" /> 

            </intent-filter> 

        </activity>  

    </application> 

    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>  

    <uses-sdk android:minSdkVersion="4" /> 

</manifest>  

 

 

 这一句就是啦~

         <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

为了让大家看到所放的位置,所以把整个xml放出来供参考;

 

 

那么当创建路径和文件的时候,我们对其检查SD卡中是否已经存在exists()方法 ,如果已经存在就不去创建,这样避免下次再次写入数据的时候又新建了文件和路径、

 

其实我们在可以在启动程序的时候判断如果没有此文件,我们可以直接紧接着创建一个文件,这些都属于优化上的了,我主要是让大家引入,学会,那么其他的简化啦,优化啦,其他方式去实现啦都留给各位同学自己了、

 

OK、今天就先介绍到这里,后面会单独剖析SQLite如何存入数据,以及对数据操作的! 希望大家继续关注!

 

(推荐大家订阅本博客,因为咱的更新速度可是很快的~娃哈哈)

本篇源码:http://download.csdn.net/source/2959100

 

 

新的一年了小明祝福大家新的一年里,事业顺利,身体健康,全家幸福美满!

上张本项目的截图:

\

Unity 工具链修复实录:让 AI Agent 直接驱动 Unity 编辑器编译测试 工具链的价值:把 Unity Editor 变成"可编程的自动化节点",AI Agent / CI 可以直接驱动它,实现编译-测试-改资源-打包的全自动闭环。版本兼容的务实策略:旧引擎适配时,评估"被砍功能是否核心",砍边缘保核心,比硬啃 API 差异更高效。工程排坑经验:Bee 缓存要清、域重载期间服务器会断、长时间运行的编辑器需要"唤醒"、unity open会截断日志——这些坑都能省下大量排查时间。安全设计值得借鉴。 阅读详情

相关推荐

我的Android进阶之旅------>Android疯狂连连看游戏的实现之状态数据模型()

对于游戏玩家而言,游戏界面上看到的“元素”千变万化;但是对于游戏开发者而言,游戏界面上的元素在底层都是一些数据,不同数据所绘制的图片有所差异而已。因此建立游戏的状态数据模型是实现游戏逻辑的重要步骤。 1、定义数据模型 连连看的界面是一个NxM的“网格”,每个网格上显示一张图片。而这个网格只需要一个二维数组来定义即可,而每个网格上所显示的图片,对于底层数据模型来说,不同的图片对于着不同的数值即可

字节卷动 8115

android txt文件保存读取操作

android 写了一个工具类实现txt文件保存和读取

Unity零基础到进阶 | UGUI对象从创建到屏幕渲染完整流程

UGUI核心要点:脏标记驱动、分阶段重建(Layout→Graphic)、C#生成顶点数据,C++ Canvas做合批Batch,最后提交GPU 时间轴顺序:对象实例化 → Awake/OnEnable → 标记Dirty入队列 → Update执行游戏逻辑 → willRenderCanvases触发重建(Layout重建→裁剪→Graphic图形重建)→ C++ Canvas BuildBatch合批 → 提交GPU → 屏幕显示

努力前行,总会成为自己心中的那道光 598

Android游戏开发十三】(保存游戏数据 [下文])详解SQLite存储方式

本站文章均为 李华明Himi 原创,转载务必在明显处注明: 转载自【黑米GameDev街区】 原文链接: http://www.himigame.com/android-game/329.html      上一篇跟各位童鞋介绍了SharedPreferenceFile流如何存储数据,并且推荐使用FileOutputStream/FileInputStream来存储咱们游戏数据,那么这一...

weixin_34060299的博客 345

Android游戏开发十二】(保存游戏数据 [上文])详解SharedPreference FIleInputStream/FileOutputStream将数据存储到SD卡中!

李华明Himi 原创,转载务必在明显处注明:转载自【黑米GameDev街区】 原文链接: http://www.himigame.com/android-game/327.html 很多童鞋说我的代码运行后,点击home或者back后会程序异常,如果你也这样遇到过,那么你肯定没有仔细读完Himi的博文,第十九篇Himi专门写了关于这些错误的原因和解决方法,这里我在博客都补充说明下,省的童鞋们总疑惑

李华明Himi 1万+

Android游戏开发十三】(保存游戏数据 [下文])详解SQLite存储方式,并把SQLite的数据库文件存储在SD卡中!!!...

Himi 原创, 欢迎转载,转载请在明显处注明! 谢谢。 原文地址:http://blog.csdn.net/xiaominghimi/archive/2011/01/04/6114629.aspx 上一篇跟各位童鞋介绍了SharedPreferenceFile流如何存储数据,并且推荐使用FileOutputStream/FileInputStream来存储咱们游戏数...

┢┦ī М ī 263

android 存档模式

private void t() { game game = new game(); game.level=20; gameBean gameBean = game.create(); player player = new player(); player.setBean(gameBean); ...

一航jason 378

Android游戏编程之从零开始》笔记

一、游戏开发基础 1.快速进入android游戏开发 自学、demo、问题、百度&Google 2.游戏简单概括 View Canvas Paint 刷新 3.游戏开发常用三种视图 View ——>SurfaceView 2D——> GLSurfaceView 3D 4.View游戏框架 a.绘图函数onDraw 绘制图形、图片等函数都在画布类中。

张小贝的博客 3万+

【读书笔记《Android游戏编程之从零开始》】20.游戏开发基础(游戏数据存储)...

对于数据的存储,Android 提供了4种保存方式。 (1)SharedPreference 此方法适用于简单数据的保持,文如其名,属于配置性质的保存,不适合比较大的情况,默认存放在手机内存里 (2)FileInputStream/FileOutputStream 此方式比较适合游戏保存和使用,流文件数据存储可以保持较大的数据,而且通过此方式不仅能把数据存储在手机内存中,也能将...

264

Android 游戏数据的存储(上)

游戏运行的过程中,往往会有来电啊,来短信,所以对这些机制的处理也是游戏编程中的一个重要部分,大多数情况下使用文件存储的形式可以完全实现游戏数据的存储和读取。 首先回顾下Java中对文件的操作: 比如想实现存储一个对象数组放入文件中并且需要对其进行分隔,Java中有两种实现

kuku20092009的专栏 1182

Android 使用 SharePreferences 保存和读取 List

原文:Android 使用SharePreferences保存List集合,保存List集合到本地保存的基本思路是将List数据转换成json格式数据,再保存//首先引入gson库 compile 'com.google.code.gson:gson:2.8.1' 保存List集合List&lt;String&gt; list = new ArrayList&lt;String&gt;(); Gs...

DawnYu 951

android游戏引擎汇总

随着Android系统的使用越来越广泛,了解一下Android平台下的游戏引擎就非常有必要。而同时因为基于Intel x86的移动设备越来越多,我也非常关注支持x86的移动游戏引擎。然而就目前为止游戏引擎的数量已经非常之多,每个引擎都有不同的特征、价格、成熟度等。通过一些调研之后,我发现有非常多的游戏引擎可用于开发运行在android移动设备端的游戏,其中有些还支持x86系统,另外还有些通过简单的

lvjing2的专栏 1万+

威佐夫博弈(双堆取子游戏)解析

先手想赢,就要把局面送进「奇异局势」。把每对的差值d = M−m,恰好是连续整数;而较小的那个数m。这两个数序列(小值⌊kφ⌋大值⌊kφ²⌋)由贝亚蒂定理保证「每个自然数恰好进一个序列」,于是所有奇异局势两两不交且覆盖完整——只要m == ⌊d·φ⌋,当前局面就是第d个奇异局势,先手无路可胜。

IT_Scratch的博客 203

新式合成类小游戏开发的创新运营思路

在主题玩法的融合上,新式游戏不再局限于简单的数字翻倍或方块拼接,而是向“轻经营”和“强策略”方向演进。例如,可以将合成模拟经营结合,玩家合成的不仅是物品,更是解锁新场景、推动剧情发展的关键资源;同时,通过高频的限时活动、赛季通行证和阶梯式任务,确保玩家始终有短、中、长期的游戏目标,避免内容空窗期。在后期做精加法,通过精细化的数值调优持续的运营迭代,构建一个“合成→养成→反馈→再合成”的良性闭环。从最底层的代码打磨,到怎么给玩家打标签分类,方方面面都能帮你搞定,做出来的游戏肯定好玩又留得住人。

Hxzyxkf2016的博客 206

游戏宠物系统怎么测:养成、出战、继承、AI属性联动

宠物系统测试需覆盖获得、养成、编队、出战、继承分解全链路,重点验证实例唯一性、资产守恒、属性公式战力一致性。核心在于状态模型管理、多端幂等、AI异常恢复及战斗快照对账,确保主战/助战/派遣不重复占用,断线、死亡、跨区后能安全恢复。关键追问包括缓存刷新、行为树节点记录配置热更一致性,杜绝重复奖励数据偏差。

m0_59437018的博客 110

# 【Unity UI 进阶】仿 Element UI 打造企业级 Unity UI 组件库(08)

建议使用同系列版本打开工程。本文实现均在下验证。上篇(07)讲完;本篇是侧栏常见的 EleTree,以及和右键菜单的组合。

zhchyun 171

slg游戏面试复盘

我没有思路的原因:不清楚服务端在这里承担什么角色。

weixin_40453090的博客 166

AI复刻街头霸王到 Unity

基于Unity 2021.3 LTS开发的2D街霸格斗游戏项目,纯内置模块实现,无第三方依赖。涵盖角色控制、连招系统、动画状态机、打击判定及完整HUD界面,代码结构清晰,适合初学者学习二次开发。项目已开源,支持快速克隆体验,助力开发者掌握格斗游戏核心机制。

WarrenMondeville的博客 195

Unity · 性能优化:内存管理完全指南:从托管堆到跨桥开销

在 Unity 中,托管内存(C# 对象)本机内存(引擎对象) 之间存在频繁的数据交换。这种跨越两个内存域的操作,被称为“跨桥”(Crossing the Bridge)。本机部分:场景中的 GameObject、Transform、Mesh、Texture 等,其核心数据存储在本机内存中。托管部分:我们在 C# 中持有的引用(如 Transform变量),实际上是一个托管包装器(Wrapper),它指向本机对象,但自身只占很少的内存。

gghhb12的博客 356
上一篇: 在SurfaceView中添加组件!并且相互交互数据!
下一篇: Android Activity 生命周期的透彻理解
namecyf
博客等级 码龄24年 127粉丝 13原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值