2015年7月18日 (土)

Kerbal Space ProgramのパーツMODを作る 8

とりあえずx, y, zそれぞれの軸について拡大縮小可能なパーツを作ることはできた。

KSPFieldでVector3型を使う場合、cfgファイルにはカンマ区切りで書けばよい。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;
namespace JustFitStructures
{
    public class JustFit : PartModule
    {
        [KSPField(isPersistant = true, guiActiveEditor = true)]
        public Vector3 Size = new Vector3(1, 1, 1);
        [KSPField(isPersistant = true, guiActiveEditor = false)]
        public Vector3 SizeMax = new Vector3(5, 5, 5);
        [KSPField(isPersistant = true, guiActiveEditor = false)]
        public Vector3 SizeMin = new Vector3(1, 1, 1);
        [KSPField(isPersistant = true, guiActiveEditor = false)]
        public Vector3 SizeStep = new Vector3(1, 1, 1);
        [KSPField(isPersistant = true, guiActiveEditor = false)]
        public string FitY = "Independent";
        [KSPField(isPersistant = true, guiActiveEditor = false)]
        public string FitZ = "Independent";
        public override void OnStart(PartModule.StartState state)
        {
            base.OnStart(state);
            if (FitY == "FollowX" || FitY == "FollowZ")
                Events["IncreaseY"].active = Events["DecreaseY"].active = false;
            if (FitZ == "FollowX" || FitZ == "FollowY")
                Events["IncreaseZ"].active = Events["DecreaseZ"].active = false;
            FitPart();
        }
        [KSPEvent(active = true, guiActiveEditor = true)]
        public void IncreaseX()
        {
            Size.x = Math.Min(SizeMax.x, Size.x + SizeStep.x);
            FitPart();
        }
        [KSPEvent(active = true, guiActiveEditor = true)]
        public void DecreaseX()
        {
            Size.x = Math.Max(SizeMin.x, Size.x - SizeStep.x);
            FitPart();
        }
        [KSPEvent(active = true, guiActiveEditor = true)]
        public void IncreaseY()
        {
            Size.y = Math.Min(SizeMax.y, Size.y + SizeStep.y);
            FitPart();
        }
        [KSPEvent(active = true, guiActiveEditor = true)]
        public void DecreaseY()
        {
            Size.y = Math.Max(SizeMin.y, Size.y - SizeStep.y);
            FitPart();
        }
        [KSPEvent(active = true, guiActiveEditor = true)]
        public void IncreaseZ()
        {
            Size.z = Math.Min(SizeMax.z, Size.z + SizeStep.z);
            FitPart();
        }
        [KSPEvent(active = true, guiActiveEditor = true)]
        public void DecreaseZ()
        {
            Size.z = Math.Max(SizeMin.z, Size.z - SizeStep.z);
            FitPart();
        }
        private void FitPart()
        {
            transform.localScale = Size;
        }
    }
}
現状の問題点。
  • サイズ変更をしたときに親パーツの位置が変わらない
  • 子パーツを付けた状態でサイズ変更すると、子パーツのサイズも変更される
  • サイズ変更してもコストや質量が変わらない
PartModule直下のtransform.localScaleを書き換えるだけではダメだ。

Screenshot8

2015年7月15日 (水)

Kerbal Space ProgramのパーツMODを作る 7

今日読んだページの中で役に立ったもの。

Kerbal Space ProgramのパーツMODを作る 6

transformを変更するだけなら、可変サイズのパーツを作ることは簡単だ。この方向で行こう。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;
namespace KSPFieldTest1
{
    public class KSPFieldTest : PartModule
    {
        public override void OnStart(PartModule.StartState state)
        {
            Debug.Log("KSPFieldTest OnStart");
            base.OnStart(state);
        }
        [KSPField(isPersistant = true, guiActive = false, guiActiveEditor = true)]
        public float length;
        [KSPEvent(active = true, guiActive = false, guiActiveEditor = true)]
        public void IncreaseLength()
        {
            length += 1;
            transform.localScale = new Vector3(1, length, 1);
        }
        [KSPEvent(active = true, guiActive = false, guiActiveEditor = true)]
        public void DecreaseLength()
        {
            length -= 1;
            transform.localScale = new Vector3(1, length, 1);
        }
    }
}

Screenshot13

Kerbal Space ProgramのパーツMODを作る 5

KSPFieldは勝手に*.cfgファイルから読み込んでくれる。

Class1.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;
namespace KSPFieldTest1
{
    public class KSPFieldTest : PartModule
    {
        public override void OnStart(PartModule.StartState state)
        {
            Debug.Log("KSPFieldTest OnStart");
            base.OnStart(state);
        }
        [KSPField(isPersistant = true, guiActive = false, guiActiveEditor = true)]
        public float length;
        [KSPEvent(active = true, guiActive = false, guiActiveEditor = true)]
        public void IncreaseLength()
        {
            length += 1;
        }
        [KSPEvent(active = true, guiActive = false, guiActiveEditor = true)]
        public void DecreaseLength()
        {
            length -= 1;
        }
    }
}
NewModel.cfg
PART
{
 name = NewModelRightClick
 module = Part
 author = nishina
 mesh = NewModel.mu
 rescaleFactor = 1
 node_stack_bottom = 0.0, 0.5, 0.0, 0.0, -1.0, 0.0, 1
 node_stack_top = 0.0, -0.5, 0.0, 0.0, 1.0, 0.0, 1
 node_attach = 0.0, -0.5, 0.0, 0.0, -1.0, 0.0
 TechRequired = start
 entryCost = 0
 cost = 1
 category = Structural
 subcategory = 0
 title = MODTestRightClick
 manufacturer = nishina
 description = modtest
 attachRules = 1,1,1,1,0
 mass = 0.1
 dragModelType = default
 maximum_drag = 0.2
 minimum_drag = 0.2
 angularDrag = 1
 crashTolerance = 80
 breakingForce = 200
 breakingTorque = 200
 maxTemp = 2000 // = 5000
 bulkheadProfiles = size1, srf
 MODULE
 {
 name=KSPFieldTest
 length = 3
 }
}
パーツを新規設置した時点でlengthが3になっている。

Screenshot11

2015年7月14日 (火)

Kerbal Space ProgramのパーツMODを作る 4

パーツにモジュールとして機能を追加するプログラム。KSPEventとKSPActionを使うことには成功した。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;
namespace PartModule1
{
    public class RightClickPart : PartModule
    {
        public override void OnStart(StartState state)
        {
            Debug.Log("RightClickPart OnStart");
        }
        [KSPEvent(guiActive = true, guiName = "Activate")]
        public void Activate()
        {
            ScreenMessages.PostScreenMessage("RightClickPart Activated", 5.0f, ScreenMessageStyle.UPPER_CENTER);
            Debug.Log("RightClickPart Activated!");
        }
        [KSPAction("ActivateAction")]
        public void ActivateAction(KSPActionParam param)
        {
            Activate();
        }
    }
}

Screenshot10

次回はKSPFieldに挑戦予定。

Kerbal Space ProgramのパーツMODを作る 3

パーツの振る舞いをバニラとは変えたいので、コードを書かなければならない。

KSPのMODはUnityが提供するMonoBehaviourを継承する必要がある。
Microsoftが「Visual Studio Tools for Unity」というツールを提供しており、これを使えばUnityからVisual Studioを呼び出せるようだ。しかし、Unityは重いから使いたくない。どうせデバッグはKSPでするのだし。
ということでUnityに乗っからず開発する方法を試してみる。
Visual C#でC:\Program Files\Unity\Editor\Data\PlaybackEngines\windowsstandalonesupport\Variations\win64_nondevelopment_mono\Data\Managed\UnityEngine.dllを参照に追加することでMonoBehaviourを継承できるようになった。
クラスにKSPAddon属性を追加する必要があるのだが、これはC:\Program Files (x86)\Steam\SteamApps\common\Kerbal Space Program\KSP_Data\Managed\Assembly-CSharp.dllを参照に追加すればよい。
コード:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;
namespace ClassLibrary1
{
    [KSPAddon(KSPAddon.Startup.Flight, false)]
    public class Class1 : MonoBehaviour
    {
        void Awake()
        {
            Debug.Log("Hello World!");
        }
    }
}
LaunchしたときのKSP.log:
[LOG 19:50:57.695] Hello World!
フォーラムにMOD開発に関するリンクがたくさんあるが、NoAttach tagは使いそう。
CFG File Documentationも役に立つ。

2015年7月13日 (月)

Kerbal Space ProgramのパーツMODを作る 1

  1. Unityのアカウントを作ってダウンロード
  2. PartToolsをこのスレッドの#77からダウンロードして"\Program Files\Unity\Editor\Standard Assets"に置く
  3. Unityを起動
  4. Asset packagesでPartTools023xを追加して新規プロジェクトを作成
  5. UnityのメニューでGameObject→CreateEmpty
  6. UnityのメニューでGameObject→3D Object→Sphere
  7. 画面右のInspectorでAdd Component→KSP→Part Tools
  8. Part Tools(Script)の下にあるSet GameData directoryボタンを押す
  9. C:\Program Files (x86)\Steam\SteamApps\common\Kerbal Space Programを指定
  10. File URLにC:\Program Files (x86)\Steam\SteamApps\common\Kerbal Space Program\GameData\MODTESTを指定
  11. Writeボタンを押す
  12. C:\Program Files (x86)\Steam\SteamApps\common\Kerbal Space Program\GameData\MODTESTにNewModel.muができているはず
  13. C:\Program Files (x86)\Steam\SteamApps\common\Kerbal Space Program\GameData\Squad\Parts\Structural\trussGirderL\trussGirderL.cfgを参考に、NewModel.cfgを書く

PART

{

 name = NewModel

 module = Part

 author = nishina

 mesh = NewModel.mu

 rescaleFactor = 1

 node_stack_bottom = 0.0, 1.0, 0.0, 0.0, -1.0, 0.0, 1

 node_stack_top = 0.0, -1.0, 0.0, 0.0, 1.0, 0.0, 1

 node_attach = 0.0, -1.0, 0.0, 0.0, -1.0, 0.0

 TechRequired = start

 entryCost = 0

 cost = 1

 category = Structural

 subcategory = 0

 title = MODTest

 manufacturer = nishina

 description = modtest

 attachRules = 1,1,1,1,0

 mass = 0.1

 dragModelType = default

 maximum_drag = 0.2

 minimum_drag = 0.2

 angularDrag = 1

 crashTolerance = 80

 breakingForce = 200

 breakingTorque = 200

 maxTemp = 2000 // = 5000

 bulkheadProfiles = size1, srf

}


[Alt]+[F12]を押してMODを再読み込み。
取り付け位置がおかしいが、パーツを読み込めた。

Screenshot8

参考リンク:

2014年12月15日 (月)

Minecraft MOD開発 22

Minecraft 1.7.10
Minecraft Forge forge-1.7.10-10.13.2.1230
用の独自ブロック追加MODのサンプルコード。
テクスチャファイルpink_block.pngはforge-1.7.10-10.13.2.1230-src\src\main\resources\assets\nishina\textures\blocksに置く。

仕様:
ブロックが破壊されると標準出力にメッセージを吐く
エンティティが上に乗るとジャンプさせる
クリックされるとチャットメッセージを表示する

上(y+)方向に速度1を与えるようにしたが、結構ジャンプする。落下時に0.5ハートのダメージが入るくらい。

onBlockDestroyedByPlayerとonBlockClickedのメッセージは2回ずつ表示される。@SideOnlyの使い方がまだ分からない。

nishinaCore.java

package nishina;
 
import net.minecraft.block.Block;
import cpw.mods.fml.common.Mod;
import cpw.mods.fml.common.Mod.EventHandler;
import cpw.mods.fml.common.event.FMLInitializationEvent;
import cpw.mods.fml.common.event.FMLPreInitializationEvent;
import cpw.mods.fml.common.registry.GameRegistry;
import cpw.mods.fml.common.registry.LanguageRegistry;
 
@Mod( modid = "nishinaCore")
public class nishinaCore
{
 public static Block pinkblock;
 
 @EventHandler
 public void preInit( FMLPreInitializationEvent event)
 {
  pinkblock = new pinkBlock();
  GameRegistry.registerBlock( pinkblock, "pinkBlock");
 }
 
 @EventHandler
 public void init( FMLInitializationEvent event)
 {
  LanguageRegistry.addName( pinkblock, "pinkblock");
 }
}

pinkBlock.java

package nishina;
 
import net.minecraft.block.Block;
import net.minecraft.block.material.Material;
import net.minecraft.creativetab.CreativeTabs;
import net.minecraft.entity.Entity;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.util.ChatComponentText;
import net.minecraft.world.World;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
 
public class pinkBlock extends Block
{
 
 public pinkBlock()
 {
  super( Material.rock);
  // TODO Auto-generated constructor stub
 
  this.setCreativeTab( CreativeTabs.tabBlock);
  this.setBlockName( "pinkblock");
  this.setBlockTextureName( "nishina:pink_block");
 }
 
 @Override
 public void onBlockDestroyedByPlayer( World world, int x, int y, int z,
   int meta)
 {
  // TODO Auto-generated method stub
  super.onBlockDestroyedByPlayer( world, x, y, z, meta);
 
  System.out.println( "onBlockDestroyedByPlayer is called.");
 }
 
 @Override
 public void onEntityWalking( World world, int x, int y, int z, Entity entity)
 {
  // TODO Auto-generated method stub
  super.onEntityWalking( world, x, y, z, entity);
 
  entity.setVelocity( 0, 1, 0);
 }
 
 @SideOnly( Side.CLIENT)
 @Override
 public void onBlockClicked( World world, int x, int y, int z,
   EntityPlayer player)
 {
  // TODO Auto-generated method stub
  super.onBlockClicked( world, x, y, z, player);
 
  player.addChatMessage( new ChatComponentText(
    "onBlockClicked is called."));
 }
}

2014年11月30日 (日)

続・C言語で要素を数える

昨日の続き。 中身が入っている配列の数をlast_indexに覚えさせる方式は分からないと言われたので、ID:zJNKuV6Eが書いたコードに近づけてみた。
// total.cpp : コンソール アプリケーションのエントリ ポイントを定義します。
//

#include "stdafx.h"


int _tmain(int argc, char* argv[])
{
	char code3[50][100];
	int data3[50];

	// 初期化
	for( int i=0; i<50; i++)
	{
		strcpy( code3[i], "\0");
		data3[i] = 0;
	}

	if (argc != 4)
	{
		fprintf( stderr, "Usage: %s inputfile1 inputfile2 outputfile\n", argv[0]);
		exit(-1);
	}
	
	// 入力ファイル読み込み
	for( int file_index=1; file_index<=2; file_index++)
	{
		FILE* fp_in = fopen( argv[file_index], "r");
		if( fp_in == NULL)
		{
			fprintf( stderr, "Cannot open input file %s\n", argv[file_index]);
			exit(-2);
		}

		char read_code[100];
		int read_data;
		while( fscanf( fp_in, "%s %d", read_code, &read_data) != EOF)
		{
			for( int i=0; i<50; i++)
			{
				if( strcmp( code3[i], read_code) == 0) // ヒット
				{
					data3[i] += read_data;
					break;
				}
				if( strcmp( code3[i], "\0") == 0) // code3配列の最後まで探してもread_codeは無かった
				{
					strcpy( code3[i], read_code);
					data3[i] = read_data;
					break;
				}
				// 結論が出ないので次のdata3[i]をチェック
			}
		}

		fclose( fp_in);
	}

	// ファイル出力
	FILE* fp_out = fopen(argv[3], "w");
	if (fp_out == NULL)
	{
		fprintf(stderr, "Cannot open file %s\n", argv[3]);
		exit(-3);
	}

	for (int i = 0; i < 50; i++)
	{
		if( strcmp( code3[i], "\0") == 0)
			break;
		fprintf(fp_out, "%s %d\n", code3[i], data3[i]);
	}

	fclose(fp_out);

	return 0;
}

2014年11月29日 (土)

C言語で要素を数える

プログラム技術板スレ立てるまでもない質問はここで 139匹目において、C言語で要素を数えたいという話題があった。

文字列を引数とするハッシュを使いたいので、はっきりいってC言語で実装したくない。でも頑張って書いてみた。

// total.cpp : コンソール アプリケーションのエントリ ポイントを定義します。
//
#include "stdafx.h"

int _tmain(int argc, char* argv[])
{
	char label[50][5];
	int count[50];
	int last_index = 0;

	if (argc != 4)
	{
		fprintf( stderr, "Usage: %s inputfile1 inputfile2 outputfile\n", argv[0]);
		exit(-1);
	}

	for (int file_index = 1; file_index <= 2; file_index++)
	{
		FILE* fp = fopen(argv[file_index], "r");
		if (fp == NULL)
		{
			fprintf( stderr, "Cannot open input file %s\n", argv[file_index]);
			exit(-2);
		}

		char read_label[5];
		int read_count;
		while (fscanf(fp, "%s %d", read_label, &read_count)!=EOF)
		{
			for (int i = 0; i < last_index; i++)
			{
				if (strcmp(read_label, label[i]) == 0)
				{
					count[i] += read_count;
					goto next_loop;
				}
			}
			strcpy(label[last_index], read_label);
			count[last_index] = read_count;
			last_index++;
		next_loop:
			;
		}
		fclose(fp);
	}

	FILE* fp = fopen(argv[3], "w");
	if (fp == NULL)
	{
		fprintf(stderr, "Cannot open file %s\n", argv[3]);
		exit(-3);
	}
	for (int i = 0; i < last_index; i++)
		fprintf(fp, "%s %d\n", label[i], count[i]);

	fclose(fp);

	return 0;
}
入力ファイル1
0001 3
0002 11
0003 6
入力ファイル2
0003 2
0004 8
出力ファイル
0001 3
0002 11
0003 8
0004 8

より以前の記事一覧

その他のカテゴリー