Kotlinとゲーム開発のコスト(+少しオフトピック)

こんにちは 今日は、Kotlinプログラミング言語を使用したゲームの開発についてお話したいと思います。 また、記事の最後でRxJavaを使用した小さな例を紹介します。



このゲームの最初のコミットは今年の6月4日に発生しました。つまり、約3週間半でオープンベータに達しました。 これは、これが私が開発しているAndroid向けの最初のゲームまたはプログラムであるとは言えませんが、Android向けの経験豊富な開発者でもありません。 私の以前の経験は主にエンタープライズ開発でした。



この記事のいくつかのトピックの概要を説明し、簡単に説明します。 Kotlinのトピックを詳細に開示するようにします。残りについては、そのようなリクエストがあれば追加の記事を掲載できます(さらに、コメントの質問を明確にすると、資料の表示が改善されます)。 リストのとおり、これはKotlinとJavaのコスト比較開発であり、ゲームのグラフィックスを取得する場所です。 少しお金について(これまでのところ、収入についての統計がまだないので、費用について)。 また、モチベーションの部分に触れることは非常に重要だと思います。 最後から始めましょう。



やる気
なぜ私はこの記事をモチベーションのような些細なことから始めているのですか? 結局のところ、アプリケーションを作成したい場合は、すでにやる気があります。 そして、すべてが順調であり、成功が私を待っています。 問題は、頻繁に仕事に就くと、本当のモチベーションに気付かないことです。お金を待っているのか、個人的なニーズがあるのか​​、ポートフォリオの例を作りたいのか。 多くのオプションがあります。 とにかくやる気があるなら、それはどのような違いをもたらすのでしょうか? しかし、たとえばポートフォリオを取ると、それは良い投資のようです。 あなたはあなたの潜在的な雇用者に完成品を見せることができ、彼らは確かに感銘を受け、すぐに莫大な給料を任命します。 したがって、開発するにつれて、時間とエネルギーを投資すると、ポートフォリオの価値が背景に消え始めます(特に視覚的な魅力を達成できない場合)。 すでにお金を稼ぎたいのですが、最初にアプリケーションを収益化する計画がなかったら、次の日にはますます意欲が必要になります。 それで問題は何ですか? 彼は1つの動機で作業を開始し、開発プロセスの途中で収益化を追加し、Google Playに投稿して100,500ルーブルを獲得したようです。 残念ながら、これは機能しません。 ユーザーは、バグの多い、生の、または面白くないアプリケーションで時間を無駄にしたくありません。 つまり、開発の途中でプロジェクトをレイアウトすることはできません。 そうすると、ほとんどの場合、単に評価の低下とダウンロードの不足につながります。 つまり、すべての作業は基本的にゴミ箱に移動します。



仕事の開始前であっても、収益化を自分の関心事の1つとして最初に検討する場合、お金を稼ぐことを理解する必要があります。 最も単純で効果のないものはバナー広告です。 広告をフルスクリーンで表示するのと同じくらい、少し複雑です。 次はお店です。 ただし、ストアが機能するためには、ユーザーを何かにフックする必要があります。 広告の表示が早くなるほど、さらに作業を続けるモチベーションが高まります。



グラフィックス
プログラマーにとってのグラフィックスの問題は、おそらく主な問題です。 もちろんゲームです。 開発を始めたばかりの頃、私は主なことはコードを書くことだと思っていました。グラフィックスを見つけることはそれほど大きな問題ではありません。 たぶん注文も。



グラフィックスが販売されているリソースにはかなりの数の在庫があり、無料の写真付きのリソースがあります。 そして原則として、はい、確かにそうです。 問題は1つだけです。これらのリソースは異なるアートスタイルで作成されており、それらを組み合わせると非常に奇妙な結果になります。 したがって、最初のゲームを開発している場合、私の最も強力なアドバイスはあなたです-あなたのアイデアのグラフィックを探してはいけません。 ゲーム用の既製のグラフィックセットを探し、そのグラフィックに基づいて、実装できるものを決定します。 そのようなセットがありますが、それほど多くはありませんが、少なくとも最初の2回目は十分です。



私の場合、開発に2週間を費やし、市場でいくつかのリソースを購入しましたが、当然のことながら私のアイデアを実現するには十分ではありませんでした。 率直に言って、購入したグラフィックは必要なものの30%未満を占めています。 しかし、解決できない質問はありません。必要なものを描くアーティストを見つけることができます。 そして、ここでは、これがそれほど単純ではないことを知って驚く。 特に質の高い結果に関心がある場合。 私は何をしましたか-株式を調べ、グラフィックスの観点から興味深いコピーを見つけ、著者の説明に切り替えて連絡しようとしました。



すでにこの段階で、注文する要素のリストが必要です。すでにこの段階で、ピンクの象はほとんどの場合トランクを取り付けます。 しかし、これまでのところこれは単なる予言です。 「注文スケジュールに申し込むことはできますか?」という質問を書いた手紙を送ります。パフォーマーのプロフェッショナリズム(および私が連絡した人は1人を除いてプロでした)に応じて、ご要望は、コメントによる修正を含めずに30〜40時間で完了します(注文の自由時間は1か月半です)。 または「1か月半でできるので、5万ルーブルかかります。」 または「いいえ、仕事が多すぎて、追加の注文は受け付けていません。」 これらはすべてプロフェッショナルな回答オプションです。 そして、私に起こった最も不幸なことは次のとおりです。



「いくら支払うつもりですか?」 (つまり、人はタスクのリソースの強度や複雑さを評価するのではなく、顧客のソルベンシーに適応しようとします)

-10,000から20,000ルーブル(これは私が最初に連絡したアーティストであり、その瞬間、私はこの量が、私が思ったように、小さな仕事に非常に適していると思いました)

男はあまり興味を示さなかった、彼は同意するように見えた。 彼は、この金額に対して私に何を提供できるかを説明するときに期限を設定しました...そして姿を消しました。 それは鐘でさえありません。そのような人とのさらなる仕事があなたのために失敗するのは鐘です。 それでも、締め切りが発表されてから3日後、彼は私に連絡し、15,000ルーブルに必要なことはすべてやると言った。 私は一般化に非常に警戒しているので、この「すべて」に何が含まれるかをポイントごとにリストするように頼みました。 その後、人は姿を消し、これが物語のハッピーエンドだと思います。



コトリン



個人プロジェクトの開発は、実際のプロジェクトとは大きく異なります。 いくつかの違いがありますが、最も重要なもの(私にとって)に焦点を当てます。 これは開発コストに関連しています。 大半の場合、雇用主は要件を決定します。多くの場合、これは手段です。 彼は経済的に責任があります。 テストするかどうか、どのライブラリとどのテクノロジースタックか。 個人的なプロジェクトでは、すべての権利と義務はすべてあなたにあります。 新しいフレームワークを使いたい-神のために。 しかし、その開発に費やす時間は、ポケットから「支払う」ことになります。 そして、はい、あなたは無料で働くと考えるべきではありません。 このアイデアを頭から出して、ステッカーに1時間あたりの料金を書いてください。少なくとも市の資格の専門家の平均費用に相当することが非常に望ましいです。 価格を下げないでください。



したがって、あなたの仕事の有効性の問題が前面に出てきます。 しかし、私はこれらの8時間で何か有用なことをしましたか、さもなければ4,000ルーブルを受け取りましたか? つまり、Kotlin対Javaの問題を金銭的な観点からのみ解決することを提案します。 どちらの言語もチューリング完全です。つまり、Kotlinで記述されたプログラムはすべてJavaで実装でき、その逆も可能です。 製品の開発コスト/所有コストの差を得ることができるのは何ですか?



開発コストは、機能を実装するための金額です。 所有コスト=開発コスト+サポートコスト。 場合によっては、サポートのコストは開発のコストよりも不均衡に高くなります。 これは特に、書き込み専用言語の場合に当てはまります(RegExpの例。既存の式のどこにエラーがあるかを理解するよりも、新しい式を書く方がはるかに簡単です)。



理想的には、言語は開発とサポートの両方で安価でなければなりません。 定型コードを削減することで、開発コストを独自に削減できます。 構文糖は開発コストを削減しますが、所有コストを増やすことはできます(できると強調しますが、義務ではありません)。 シンタクティックソルトは、開発コストを増加させますが、所有コストを削減します。 以下に、KotlinとJavaのコードの例を示し、どのオプションが安いかを私の意見と理由で説明します。 私のプロジェクトからの例とそうでない例があります。



class Car(val id: String) {
    var speed: Double = 0.0
}

      
      





public class Car() {

    public final String id;
    public Double speed;

    public Car(String id) {
        this.id = id;
        this.speed = 0.0;
    }
}

      
      





* DTO /

** / ,



Kotlin “ ” — NPE. id, speed Kotlin null.



var car: Car = Car(null) // compile error
car.speed = null // compile error

      
      









fun toRoman(value: Int): String {
   val singles = arrayOf("", "I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX")
   val tens = arrayOf("", "X", "XX", "XXX", "XL", "L", "LX", "LXX", "LXXX", "XC")
   val hundreds = arrayOf("", "C", "CC", "CCC", "CD", "D", "DC", "DCC", "DCCC", "CM")
   val thousands = arrayOf("", "M", "MM", "MMM")

   val roman = thousands[value / 1000] + hundreds[value % 1000 / 100] + tens[value % 100 / 10] + singles[value % 10]

   return roman
}

      
      





public String toRoman(int value) {
   final String[] singles = new String[] { "", "I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX" };
   final String[] tens = new String[] { "", "X", "XX", "XXX", "XL", "L", "LX", "LXX", "LXXX", "XC" };
   final String[] hundreds = new String[] { "", "C", "CC", "CCC", "CD", "D", "DC", "DCC", "DCCC", "CM" };
   final String[] thousands = new String[] { "", "M", "MM", "MMM" };

   final String roman = thousands[value / 1000] + hundreds[value % 1000 / 100] + tens[value % 100 / 10] + singles[value % 10];
   return roman;
}

      
      





, ? final . , final Java . .



:



val data:List<Int> = ArrayList()
val sum = data.filter { it > 0 }.sum()

      
      





List<Integer> data = new ArrayList<>();
final Integer[] sum = { 0 }; //Variable used in lambda expression should be final or effectively final
data.stream().filter(value -> value > 0).forEach(value -> sum[0] += value);

      
      





. Kotlin jvm 6, Java jvm 8 . , 24 API. 5 9,5% . — final or effectively final Java.




 
private val buttonGroup = ButtonGroup<Button>().apply {
   setMinCheckCount(0)
}

      
      





private ButtonGroup<Button> buttonGroup = new ButtonGroup<>();
public constructor(...) {
    buttonGroup.setMinCheckCount(0);
}

      
      





Kotlin’e



, Kotlin , . data classes, , string template, lazy properties .. , .



Kotlin + RxJava + Jackson. dto , , . .



interface Property<T> {
   var value: T
   val rx: Observable<T>
}

open class BaseProperty<T>(defaultValue: T) : Property<T> {

   override var value: T = defaultValue
       set(value) {
           field = value
           _rx.onNext(field)
       }

   private val _rx = PublishSubject.create<T>()
   override val rx: Observable<T> = _rx
       get() {
           return field.startWith(value)
       }
}

      
      









class Car {
   private val _speed = BaseProperty(0.0)

   var speed: Double
       get() = _speed.value
       set(value) {
           _speed.value = value
       }
  
   @JsonIgnore
   val rxSpeed: Observable<Double> = _speed.rx
}

class Police {
   val cars: List<Car> = listOf(Car("1st"), Car("2nd"), Car("3rd"))

   init {
       cars.forEach {
           car -> car.rxSpeed
                   .map { speed -> speed > 60 } //  double   boolean 
                   .distinctUntilChanged()
                   .filter { aboveLimit -> aboveLimit == true }
                   .subscribe { writeTicket(car) }
       }
   }

   private fun writeTicket(car: Car) {
       // do some stuff
   }
}

      
      





Car / Jackson', dto , .



Label :



Label("", assets.skin, "progress-bar-time-indicator").apply {
                        setAlignment(Align.center)
                        craft.rx(DURATION).subscribe {
                            setText(TimeFormat.format(it))
                        }
                    })

      
      





:



Kotlin'e Java. . , 1.5 — 2 . Java Kotlin, - . NPE-proof, immutable, lambda & .



Upd:




All Articles