本人目前是大三考研党,之前有学过一些杂七杂八的知识,但是没有办法利用这些知识制作一些真正有用的东西出来。后来自学了android开发,学会使用了android studio,终于决定利用android studio 开发一个游戏出来,也算是我一直以来的梦想吧。但是由于制作水平有限,很多部分只能停留在文字上,请各位看客多见谅。
本博客会介绍本人在此游戏开发中的过程与困难,希望能够帮助同在学习android开发的同学。
(本文章创作于游戏框架已基本完成时)
1、游戏主页面(开始页面)
开始页面是游戏的重中之重。我最开始利用android studio开发时,曾制作过一个纯文字剧情类的游戏(后面因为故事情节创作停滞加上代码很费时间,最后游戏至今尚未完成,如果有兴趣的童鞋可以看看这个链接:https://pan.baidu.com/s/1SxBmWYbLqLuXW3peKkbdJQ
提取码:rjzb)那个游戏的页面并没怎么做好。
当然这是题外话了,回到正题,如果你已经有自学过android studio的使用,并有着一定的基础,你就知道一个页面需要一个java文件和与其对应的xml文件,这样才是一个完整的页面并能够正常显示。因此,下面的每一个模块我都会给出java文件和于其对应的xml文件的实现,以后将不再赘述。
作为游戏的开始页面,美观大气自然是必要的。然而本人美术水平有限,再加上没有经费支撑,最后只能选择自己制作一个较为生动的页面。下面是页面的具体效果。
虽然看起来比较一般,但确实拥有了一定的动态效果。实现起来也非常简单:我使用了多个TextView,填入对应的文字,随后将他们的visiability属性设为INVISABLE。随后我在主文件编写函数对他们的属性进行调整 ,就形成了这样的闪烁的效果。
同时,我在主页面添加了四个按钮,分别是开始游戏,读取存档,游戏介绍和设置。这样乍一看,是不是真的有内味了?这主页面虽然并不是特别美观,但是也确实实现了一个游戏开始页面所需要达到的效果。当然,这只是一个开头,我们接下来需要做的事远比编写开始页面要复杂。
(下面是开始页面的java文件和xml文件的代码)
package com.example.dungeonsimulator;
import android.content.Context;
import android.content.Intent;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.media.MediaPlayer;
import android.os.Handler;
import android.os.Message;
import android.util.AttributeSet;
import android.util.Log;
import android.app.Activity;
import android.os.Bundle;
import android.view.KeyEvent;
import android.widget.Button;
import android.view.View;
import android.widget.EditText;
import android.media.MediaPlayer;
import androidx.appcompat.app.AppCompatActivity;
import android.database.sqlite.SQLiteDatabase;
import android.database.Cursor;
import android.widget.TextView;
import android.widget.Toast;
import android.graphics.Canvas;
import android.app.Person;
import java.util.Timer;
import java.util.TimerTask;
import android.view.KeyEvent;
public class MainActivity extends AppCompatActivity {
Button button1,button2,button3,setting;
public static MediaPlayer player=null;
Timer timer;
public static int back=0;
public static person lead;
public static int du=0;
public static float volume=1.0f;
int i=0;
public static int num=0;
public static int weapon_num=9;
TextView textview5,textview6,textview4,textview7,textview8;
@Override
public boolean onKeyDown(int keyCode,KeyEvent event){
if(keyCode== android.view.KeyEvent.KEYCODE_BACK)
return true;
return super.onKeyDown(keyCode, event);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
/*
main.text="";
main.index=0;
main.refresh=true;
lead=new person("",0,0,0,0,0,0,0,10,0,10);
lead.level=1;
lead.exp=lead.level_exp[0];
lead.nowexp=0;
num=0;
lead.gold=0;
lead.init();
main.first=false;
for(int i=0;i
xml文件:
xml文件的RainPlay模块(从一个大佬那里借鉴的,忘了是谁了,见谅):
package com.example.dungeonsimulator;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.util.AttributeSet;
import java.util.ArrayList;
import java.util.List;
public class Rainplay extends BaseView {
List list = new ArrayList();
//控制雨滴的数量
private int num = 80;
public Rainplay(Context context) {
super(context);
}
public Rainplay(Context context, AttributeSet attrs) {
super(context, attrs);
//与xml链接起来
TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.RainView);
num = ta.getInteger(R.styleable.RainView_rainnum,80);
ta.recycle();
}
@Override
protected void drawsub(Canvas canvas) {
for (RainItem item : list) {
item.draw(canvas);
}
}
@Override
protected void move() {
for (RainItem item : list) {
item.movestep();
}
}
/**
* 因为获取长宽是放在layout之后才可以获取,所以需要
* 放在线程里面初始化
*/
@Override
protected void init() {
for (int i = 0; i < num; i++) {
RainItem item = new RainItem(getHeight(), getWidth());
list.add(item);
}
}
}
2、游戏加载页面
一款游戏,对游戏的背景介绍也是十分重要的。因此我特意写了一个页面用于介绍这款游戏的背景,便于游玩的人能够知道游戏的背景,不至于玩的糊里糊涂。
既然说到这里,就不得不简单介绍一下我为这个游戏设置的背景,男主作为勇者,要去偶然发现的地牢中进行探险。在此之前,老国王已然消失在地牢的深处,正是在这样一个人人自危的时间点,男主毅然决然地选择了前进。(差不多得了哈哈)
这次的页面的编写与开始页面类似,通过定时器的设置使得原本被设置为隐藏不可见的TextView内容在到达对应时间时显示出来,从而达到逐条出现的效果。当然应该会有更好的办法达到这一点,然而我选择了较容易实现的办法,当然代码量也显得较为冗余。
下面是页面的具体效果。
(由于制作成Gif图有问题,没办法只好截图)
代码:
story.java
package com.example.dungeonsimulator;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.media.MediaPlayer;
import android.os.Handler;
import android.os.Message;
import android.util.AttributeSet;
import android.util.Log;
import android.app.Activity;
import android.os.Bundle;
import android.widget.Button;
import android.view.View;
import android.widget.EditText;
import android.media.MediaPlayer;
import androidx.appcompat.app.AppCompatActivity;
import android.database.sqlite.SQLiteDatabase;
import android.database.Cursor;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
import android.graphics.Canvas;
import java.util.Timer;
import java.util.TimerTask;
import android.view.KeyEvent;
public class story extends AppCompatActivity {
Button button1,button2,button5;
EditText editText1;
ImageView imageview2;
MediaPlayer player=null;
Context context;
AttributeSet attr;
Canvas canvas;
Timer timer;
int i=0;
TextView textview1,textview2,textview3,textview4,textview5,textview6,textview7,textview8,textview9;
TextView textview10,textview11,textview12,textview13;
@Override
public boolean onKeyDown(int keyCode, KeyEvent event){
if(keyCode== android.view.KeyEvent.KEYCODE_BACK)
return true;
return super.onKeyDown(keyCode, event);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.story);
SharedPreferences sharedPreferences= getSharedPreferences("data",Context.MODE_PRIVATE);
SharedPreferences.Editor editor = sharedPreferences.edit();
editor.putInt("story",1);
editor.commit();
imageview2=findViewById(R.id.imageView2);
textview1=findViewById(R.id.textView1);
textview2=findViewById(R.id.textView2);
textview3=findViewById(R.id.textView3);
textview4=findViewById(R.id.textView4);
textview5=findViewById(R.id.textView5);
textview6=findViewById(R.id.textView6);
textview7=findViewById(R.id.textView7);
textview8=findViewById(R.id.textView8);
textview9=findViewById(R.id.textView9);
textview10=findViewById(R.id.textView10);
textview11=findViewById(R.id.textView11);
textview12=findViewById(R.id.textView12);
textview13=findViewById(R.id.textView13);
imageview2.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if(i>=13){
timer.cancel();
Intent intent=new Intent(story.this,choose_job.class);
startActivity(intent);}
}
});
Handler handler=new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
if (msg.what==0){
i+=1;
if(i==1){
textview1.setVisibility(View.VISIBLE);
}
if(i==2){
textview2.setVisibility(View.VISIBLE);
}
if(i==3){
textview3.setVisibility(View.VISIBLE);
}
if(i==4){
textview4.setVisibility(View.VISIBLE);
}
if(i==5){
textview5.setVisibility(View.VISIBLE);
}
if(i==6){
textview6.setVisibility(View.VISIBLE);
}
if(i==7){
textview7.setVisibility(View.VISIBLE);
}
if(i==8){
textview8.setVisibility(View.VISIBLE);
}
if(i==9){
textview9.setVisibility(View.VISIBLE);
}
if(i==10){
textview10.setVisibility(View.VISIBLE);
}
if(i==11){
textview11.setVisibility(View.VISIBLE);
}
if(i==12){
textview12.setVisibility(View.VISIBLE);
}
if(i==13){
textview13.setVisibility(View.VISIBLE);
}
}
}
};
timer = new Timer();
timer.schedule(new TimerTask() {
@Override
public void run() {
handler.sendEmptyMessage(0);
}
},0,2200);
}
}
xml文件:
3、选职页面
本游戏作为一款类RPG的打怪升级类游戏,没有职业的选择可不行。
因此我编写了这个页面用于供玩家选择他们喜欢的职业。玩家可以通过还是那句话,朴实无华的游戏页面,但是也确实完成了相应的功能。
我对这个游戏设定了四个职业,分别是战士,刺客,魔法师和新皇。设置更多职业当然也可以,但是也会更复杂。每个职业都有对应的特点,战士防高血高,但是魔法值较低,刺客在战斗中可以永远先手,且攻击力很高,对血量较低的怪物可以做到一击必杀,但是对应的是其防御和血量相较战士比较低;魔法师拥有着大量的魔法值,可以不断释放技能,然而各个方面都不如前两者,而新皇相对中庸,他突出的点在于他有着高额的幸运值。说到这里,就不得不说一下,这款游戏的设定了,对于攻击,幸运值越高,闪避率越高,一旦成功闪避将不受到伤害。
回到正题,下面是选职页面的实现效果。
choose_job.java
package com.example.dungeonsimulator;
import android.content.Context;
import android.content.Intent;
import android.media.MediaPlayer;
import android.util.AttributeSet;
import android.os.Bundle;
import android.view.KeyEvent;
import android.widget.Button;
import android.view.View;
import android.widget.EditText;
import androidx.appcompat.app.AppCompatActivity;
import android.widget.TextView;
import android.graphics.Canvas;
import java.util.Timer;
public class choose_job extends AppCompatActivity {
Button button1,button2,button3,button4;
EditText editText1;
MediaPlayer player=null;
Context context;
AttributeSet attr;
Canvas canvas;
Timer timer;
int i=0;
TextView textview5,textview6,textview4,textview7,textview8;
@Override
public boolean onKeyDown(int keyCode, KeyEvent event){
if(keyCode== android.view.KeyEvent.KEYCODE_BACK)
return true;
return super.onKeyDown(keyCode, event);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.choose_job);
button1 = findViewById(R.id.button1);
button2 = findViewById(R.id.button2);
button3 = findViewById(R.id.button3);
button4 = findViewById(R.id.button4);
button1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
MainActivity.lead=new person("剑士",1,15,10,5,100,20,20,10,2,100);
Intent intent = new Intent(choose_job.this, stage.class);
startActivity(intent);
}
});
button2.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
MainActivity.lead=new person("刺客",11,20,5,5,80,1,10,10,2,10000);
MainActivity.lead.First_Hand=true;
Intent intent = new Intent(choose_job.this, stage.class);
startActivity(intent);
}
});
button3.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
MainActivity.lead=new person("魔法师",1,10,10,20,70,15,10,40,2,70);
MainActivity.lead.set_lucky(2);
Intent intent = new Intent(choose_job.this, stage.class);
startActivity(intent);
}
});
button4.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
MainActivity.lead=new person("新皇",1,12,10,5,100,15,15,10,20,90);
Intent intent = new Intent(choose_job.this, stage.class);
startActivity(intent);
}
});
}
}
choose_job.xml:
4.设置页面
每个游戏都有一个设置页面,以便于玩家对游戏中的一些设置进行调整,以达到最好的游戏效果。那我们的这款游戏自然也要有。
对于一些基本的操作,我们需要对其功能进行编写,如存档,开/关音乐等。
下面是页面的具体实现效果:
其中开关音乐的操作相对来说并不复杂,只需要为音乐设置一个全局变量,然后在这里进行调整即可,而存档/读档的功能相对比较复杂,如果可以的话,我希望放在下一篇中进行详细讲述,这里就不过多赘述了。
下面是代码实现:
setting.java
package com.example.dungeonsimulator;
import android.content.Context;
import android.content.Intent;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.media.MediaPlayer;
import android.os.Handler;
import android.os.Message;
import android.util.AttributeSet;
import android.util.Log;
import android.app.Activity;
import android.os.Bundle;
import android.view.KeyEvent;
import android.widget.Button;
import android.view.View;
import android.widget.EditText;
import android.media.MediaPlayer;
import androidx.appcompat.app.AppCompatActivity;
import android.database.sqlite.SQLiteDatabase;
import android.database.Cursor;
import android.widget.TextView;
import android.widget.Toast;
import android.graphics.Canvas;
import android.app.Person;
import java.util.Timer;
import java.util.TimerTask;
import android.view.KeyEvent;
public class setting extends AppCompatActivity {
Button button1,button2,button3,button5,button6,button7;
EditText editText1;
MediaPlayer player=null;
Timer timer;
int i=0;
@Override
public boolean onKeyDown(int keyCode, KeyEvent event){
if(keyCode== android.view.KeyEvent.KEYCODE_BACK)
return true;
return super.onKeyDown(keyCode, event);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.setting);
button1=findViewById(R.id.button1);
button2=findViewById(R.id.button2);
button3=findViewById(R.id.button3);
button5=findViewById(R.id.button5);
button6=findViewById(R.id.button6);
button7=findViewById(R.id.button7);
button1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent=new Intent(setting.this,cundang.class);
startActivity(intent);
}
});
button6.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
MainActivity.volume=1.0f;
MainActivity.player.setVolume(MainActivity.volume,MainActivity.volume);
}
});
button7.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
MainActivity.volume=0.0f;
MainActivity. player.setVolume(MainActivity.volume,MainActivity.volume);
}
});
button2.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent=new Intent(setting.this,dudang.class);
startActivity(intent);
}
});
button3.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent=new Intent(setting.this,MainActivity.class);
MainActivity.back=0;
startActivity(intent);
}
});
button5.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if(MainActivity.back==0){
MainActivity.player.release();
Intent intent=new Intent(setting.this,MainActivity.class);
startActivity(intent);}
else{
Intent intent=new Intent(setting.this,main.class);
startActivity(intent);
}
}
});
}}
setting.xml
(今天就先更新到这里吧,如果有人希望看到后续,记得在评论区私信我,我会尽快赶出来的,游戏app链接:链接:https://pan.baidu.com/s/1l_Fet3NdGlLSwcWn8Wrn5A
提取码:s07o,目前只有前十五级的怪物以及装备,主要是忙着准备考研,没有时间再写下去,当然如果有人催更,我也会接着写下去的哈哈)